summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/rendering
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/rendering')
-rw-r--r--Source/WebCore/rendering/AutoTableLayout.cpp37
-rw-r--r--Source/WebCore/rendering/AutoTableLayout.h3
-rw-r--r--Source/WebCore/rendering/BidiRun.h7
-rw-r--r--Source/WebCore/rendering/EllipsisBox.cpp49
-rw-r--r--Source/WebCore/rendering/EllipsisBox.h3
-rw-r--r--Source/WebCore/rendering/ExclusionPolygon.cpp379
-rw-r--r--Source/WebCore/rendering/ExclusionPolygon.h138
-rw-r--r--Source/WebCore/rendering/ExclusionRectangle.cpp118
-rw-r--r--Source/WebCore/rendering/ExclusionRectangle.h69
-rw-r--r--Source/WebCore/rendering/ExclusionShape.cpp162
-rw-r--r--Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp121
-rw-r--r--Source/WebCore/rendering/ExclusionShapeInsideInfo.h105
-rw-r--r--Source/WebCore/rendering/FilterEffectRenderer.cpp84
-rw-r--r--Source/WebCore/rendering/FilterEffectRenderer.h29
-rw-r--r--Source/WebCore/rendering/FixedTableLayout.cpp46
-rw-r--r--Source/WebCore/rendering/FixedTableLayout.h5
-rw-r--r--Source/WebCore/rendering/FlowThreadController.cpp137
-rw-r--r--Source/WebCore/rendering/FlowThreadController.h22
-rw-r--r--Source/WebCore/rendering/HitTestLocation.cpp201
-rw-r--r--Source/WebCore/rendering/HitTestLocation.h107
-rw-r--r--Source/WebCore/rendering/HitTestRequest.h11
-rw-r--r--Source/WebCore/rendering/HitTestResult.cpp268
-rw-r--r--Source/WebCore/rendering/HitTestResult.h68
-rw-r--r--Source/WebCore/rendering/InlineBox.cpp19
-rw-r--r--Source/WebCore/rendering/InlineBox.h12
-rw-r--r--Source/WebCore/rendering/InlineFlowBox.cpp89
-rw-r--r--Source/WebCore/rendering/InlineFlowBox.h46
-rw-r--r--Source/WebCore/rendering/InlineIterator.h47
-rw-r--r--Source/WebCore/rendering/InlineTextBox.cpp324
-rw-r--r--Source/WebCore/rendering/InlineTextBox.h35
-rw-r--r--Source/WebCore/rendering/LayoutState.cpp19
-rw-r--r--Source/WebCore/rendering/LayoutState.h16
-rw-r--r--Source/WebCore/rendering/LogicalSelectionOffsetCaches.h183
-rw-r--r--Source/WebCore/rendering/PaintInfo.h32
-rw-r--r--Source/WebCore/rendering/PaintPhase.h4
-rw-r--r--Source/WebCore/rendering/RegionOversetState.h33
-rw-r--r--Source/WebCore/rendering/RenderApplet.h2
-rw-r--r--Source/WebCore/rendering/RenderArena.cpp8
-rw-r--r--Source/WebCore/rendering/RenderArena.h9
-rw-r--r--Source/WebCore/rendering/RenderBR.h6
-rw-r--r--Source/WebCore/rendering/RenderBlock.cpp2107
-rw-r--r--Source/WebCore/rendering/RenderBlock.h401
-rw-r--r--Source/WebCore/rendering/RenderBlockLineLayout.cpp1233
-rw-r--r--Source/WebCore/rendering/RenderBox.cpp1094
-rw-r--r--Source/WebCore/rendering/RenderBox.h155
-rw-r--r--Source/WebCore/rendering/RenderBoxModelObject.cpp513
-rw-r--r--Source/WebCore/rendering/RenderBoxModelObject.h61
-rw-r--r--Source/WebCore/rendering/RenderButton.cpp39
-rw-r--r--Source/WebCore/rendering/RenderButton.h14
-rw-r--r--Source/WebCore/rendering/RenderCombineText.cpp2
-rw-r--r--Source/WebCore/rendering/RenderCombineText.h4
-rw-r--r--Source/WebCore/rendering/RenderCounter.cpp176
-rw-r--r--Source/WebCore/rendering/RenderCounter.h7
-rw-r--r--Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp243
-rw-r--r--Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h13
-rw-r--r--Source/WebCore/rendering/RenderDetailsMarker.cpp9
-rw-r--r--Source/WebCore/rendering/RenderDetailsMarker.h8
-rw-r--r--Source/WebCore/rendering/RenderDialog.cpp2
-rw-r--r--Source/WebCore/rendering/RenderDialog.h4
-rw-r--r--Source/WebCore/rendering/RenderEmbeddedObject.cpp355
-rw-r--r--Source/WebCore/rendering/RenderEmbeddedObject.h32
-rw-r--r--Source/WebCore/rendering/RenderFieldset.cpp11
-rw-r--r--Source/WebCore/rendering/RenderFieldset.h5
-rw-r--r--Source/WebCore/rendering/RenderFileUploadControl.cpp95
-rw-r--r--Source/WebCore/rendering/RenderFileUploadControl.h5
-rw-r--r--Source/WebCore/rendering/RenderFlexibleBox.cpp501
-rw-r--r--Source/WebCore/rendering/RenderFlexibleBox.h84
-rw-r--r--Source/WebCore/rendering/RenderFlowThread.cpp711
-rw-r--r--Source/WebCore/rendering/RenderFlowThread.h149
-rw-r--r--Source/WebCore/rendering/RenderFrame.cpp2
-rw-r--r--Source/WebCore/rendering/RenderFrame.h2
-rw-r--r--Source/WebCore/rendering/RenderFrameBase.cpp9
-rw-r--r--Source/WebCore/rendering/RenderFrameSet.cpp52
-rw-r--r--Source/WebCore/rendering/RenderFrameSet.h4
-rw-r--r--Source/WebCore/rendering/RenderFullScreen.cpp35
-rw-r--r--Source/WebCore/rendering/RenderFullScreen.h12
-rw-r--r--Source/WebCore/rendering/RenderGeometryMap.cpp3
-rw-r--r--Source/WebCore/rendering/RenderGeometryMap.h2
-rw-r--r--Source/WebCore/rendering/RenderGrid.cpp706
-rw-r--r--Source/WebCore/rendering/RenderGrid.h107
-rw-r--r--Source/WebCore/rendering/RenderHTMLCanvas.cpp5
-rw-r--r--Source/WebCore/rendering/RenderHTMLCanvas.h2
-rw-r--r--Source/WebCore/rendering/RenderIFrame.cpp28
-rw-r--r--Source/WebCore/rendering/RenderIFrame.h6
-rw-r--r--Source/WebCore/rendering/RenderImage.cpp125
-rw-r--r--Source/WebCore/rendering/RenderImage.h16
-rw-r--r--Source/WebCore/rendering/RenderImageResource.cpp32
-rw-r--r--Source/WebCore/rendering/RenderImageResource.h13
-rw-r--r--Source/WebCore/rendering/RenderImageResourceStyleImage.cpp1
-rw-r--r--Source/WebCore/rendering/RenderInline.cpp101
-rw-r--r--Source/WebCore/rendering/RenderInline.h16
-rw-r--r--Source/WebCore/rendering/RenderInputSpeech.cpp3
-rw-r--r--Source/WebCore/rendering/RenderLayer.cpp2256
-rw-r--r--Source/WebCore/rendering/RenderLayer.h370
-rw-r--r--Source/WebCore/rendering/RenderLayerBacking.cpp1070
-rw-r--r--Source/WebCore/rendering/RenderLayerBacking.h96
-rw-r--r--Source/WebCore/rendering/RenderLayerCompositor.cpp1083
-rw-r--r--Source/WebCore/rendering/RenderLayerCompositor.h147
-rw-r--r--Source/WebCore/rendering/RenderLayerFilterInfo.h9
-rw-r--r--Source/WebCore/rendering/RenderLayerModelObject.cpp12
-rw-r--r--Source/WebCore/rendering/RenderLayerModelObject.h13
-rw-r--r--Source/WebCore/rendering/RenderLineBoxList.cpp8
-rw-r--r--Source/WebCore/rendering/RenderLineBoxList.h2
-rw-r--r--Source/WebCore/rendering/RenderListBox.cpp105
-rw-r--r--Source/WebCore/rendering/RenderListBox.h15
-rw-r--r--Source/WebCore/rendering/RenderListItem.cpp123
-rw-r--r--Source/WebCore/rendering/RenderListItem.h9
-rw-r--r--Source/WebCore/rendering/RenderListMarker.cpp140
-rw-r--r--Source/WebCore/rendering/RenderListMarker.h15
-rw-r--r--Source/WebCore/rendering/RenderMarquee.cpp3
-rw-r--r--Source/WebCore/rendering/RenderMedia.cpp15
-rw-r--r--Source/WebCore/rendering/RenderMedia.h4
-rw-r--r--Source/WebCore/rendering/RenderMediaControlElements.cpp106
-rw-r--r--Source/WebCore/rendering/RenderMediaControlElements.h (renamed from Source/WebCore/rendering/RenderMediaControlsChromium.h)54
-rw-r--r--Source/WebCore/rendering/RenderMediaControls.cpp2
-rw-r--r--Source/WebCore/rendering/RenderMediaControlsChromium.cpp463
-rw-r--r--Source/WebCore/rendering/RenderMenuList.cpp123
-rw-r--r--Source/WebCore/rendering/RenderMenuList.h24
-rw-r--r--Source/WebCore/rendering/RenderMeter.cpp7
-rw-r--r--Source/WebCore/rendering/RenderMeter.h8
-rw-r--r--Source/WebCore/rendering/RenderMultiColumnBlock.cpp138
-rw-r--r--Source/WebCore/rendering/RenderMultiColumnBlock.h20
-rw-r--r--Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp71
-rw-r--r--Source/WebCore/rendering/RenderMultiColumnFlowThread.h10
-rw-r--r--Source/WebCore/rendering/RenderMultiColumnSet.cpp387
-rw-r--r--Source/WebCore/rendering/RenderMultiColumnSet.h70
-rw-r--r--Source/WebCore/rendering/RenderNamedFlowThread.cpp150
-rw-r--r--Source/WebCore/rendering/RenderNamedFlowThread.h22
-rw-r--r--Source/WebCore/rendering/RenderObject.cpp608
-rw-r--r--Source/WebCore/rendering/RenderObject.h290
-rw-r--r--Source/WebCore/rendering/RenderObjectChildList.cpp361
-rw-r--r--Source/WebCore/rendering/RenderObjectChildList.h22
-rw-r--r--Source/WebCore/rendering/RenderOverflow.h15
-rw-r--r--Source/WebCore/rendering/RenderPart.cpp37
-rw-r--r--Source/WebCore/rendering/RenderPart.h6
-rw-r--r--Source/WebCore/rendering/RenderProgress.cpp4
-rw-r--r--Source/WebCore/rendering/RenderProgress.h4
-rw-r--r--Source/WebCore/rendering/RenderQuote.cpp577
-rw-r--r--Source/WebCore/rendering/RenderQuote.h32
-rw-r--r--Source/WebCore/rendering/RenderRegion.cpp300
-rw-r--r--Source/WebCore/rendering/RenderRegion.h82
-rw-r--r--Source/WebCore/rendering/RenderRegionSet.cpp4
-rw-r--r--Source/WebCore/rendering/RenderRegionSet.h5
-rw-r--r--Source/WebCore/rendering/RenderReplaced.cpp113
-rw-r--r--Source/WebCore/rendering/RenderReplaced.h10
-rw-r--r--Source/WebCore/rendering/RenderReplica.cpp15
-rw-r--r--Source/WebCore/rendering/RenderReplica.h7
-rw-r--r--Source/WebCore/rendering/RenderRuby.cpp23
-rw-r--r--Source/WebCore/rendering/RenderRuby.h4
-rw-r--r--Source/WebCore/rendering/RenderRubyBase.cpp11
-rw-r--r--Source/WebCore/rendering/RenderRubyBase.h5
-rw-r--r--Source/WebCore/rendering/RenderRubyRun.cpp19
-rw-r--r--Source/WebCore/rendering/RenderRubyRun.h7
-rw-r--r--Source/WebCore/rendering/RenderRubyText.cpp15
-rw-r--r--Source/WebCore/rendering/RenderRubyText.h4
-rw-r--r--Source/WebCore/rendering/RenderScrollbar.cpp23
-rw-r--r--Source/WebCore/rendering/RenderScrollbar.h5
-rw-r--r--Source/WebCore/rendering/RenderScrollbarPart.cpp16
-rw-r--r--Source/WebCore/rendering/RenderScrollbarPart.h12
-rw-r--r--Source/WebCore/rendering/RenderSearchField.cpp42
-rw-r--r--Source/WebCore/rendering/RenderSearchField.h8
-rw-r--r--Source/WebCore/rendering/RenderSlider.cpp19
-rw-r--r--Source/WebCore/rendering/RenderSlider.h7
-rw-r--r--Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp167
-rw-r--r--Source/WebCore/rendering/RenderSnapshottedPlugIn.h17
-rw-r--r--Source/WebCore/rendering/RenderTable.cpp115
-rw-r--r--Source/WebCore/rendering/RenderTable.h17
-rw-r--r--Source/WebCore/rendering/RenderTableCaption.cpp4
-rw-r--r--Source/WebCore/rendering/RenderTableCaption.h6
-rw-r--r--Source/WebCore/rendering/RenderTableCell.cpp149
-rw-r--r--Source/WebCore/rendering/RenderTableCell.h26
-rw-r--r--Source/WebCore/rendering/RenderTableCol.cpp7
-rw-r--r--Source/WebCore/rendering/RenderTableCol.h9
-rw-r--r--Source/WebCore/rendering/RenderTableRow.cpp47
-rw-r--r--Source/WebCore/rendering/RenderTableRow.h10
-rw-r--r--Source/WebCore/rendering/RenderTableSection.cpp130
-rw-r--r--Source/WebCore/rendering/RenderTableSection.h12
-rw-r--r--Source/WebCore/rendering/RenderText.cpp124
-rw-r--r--Source/WebCore/rendering/RenderText.h28
-rw-r--r--Source/WebCore/rendering/RenderTextControl.cpp96
-rw-r--r--Source/WebCore/rendering/RenderTextControl.h41
-rw-r--r--Source/WebCore/rendering/RenderTextControlMultiLine.cpp16
-rw-r--r--Source/WebCore/rendering/RenderTextControlMultiLine.h8
-rw-r--r--Source/WebCore/rendering/RenderTextControlSingleLine.cpp150
-rw-r--r--Source/WebCore/rendering/RenderTextControlSingleLine.h16
-rw-r--r--Source/WebCore/rendering/RenderTextFragment.h4
-rw-r--r--Source/WebCore/rendering/RenderTextTrackCue.cpp154
-rw-r--r--Source/WebCore/rendering/RenderTextTrackCue.h8
-rw-r--r--Source/WebCore/rendering/RenderTheme.cpp813
-rw-r--r--Source/WebCore/rendering/RenderTheme.h22
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp113
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumAndroid.h74
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumCommon.cpp68
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumCommon.h46
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumDefault.cpp389
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumDefault.h109
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp55
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumFontProvider.h50
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp69
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp192
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumLinux.cpp385
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumLinux.h112
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumMac.h88
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumMac.mm250
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumSkia.cpp658
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumSkia.h197
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumWin.cpp679
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumWin.h123
-rw-r--r--Source/WebCore/rendering/RenderThemeMac.h190
-rw-r--r--Source/WebCore/rendering/RenderThemeMac.mm1897
-rw-r--r--Source/WebCore/rendering/RenderThemeMacShared.h227
-rw-r--r--Source/WebCore/rendering/RenderThemeMacShared.mm1835
-rw-r--r--Source/WebCore/rendering/RenderThemeSafari.cpp162
-rw-r--r--Source/WebCore/rendering/RenderThemeSafari.h11
-rw-r--r--Source/WebCore/rendering/RenderThemeWin.cpp284
-rw-r--r--Source/WebCore/rendering/RenderThemeWin.h17
-rw-r--r--Source/WebCore/rendering/RenderThemeWinCE.cpp14
-rw-r--r--Source/WebCore/rendering/RenderThemeWinCE.h4
-rw-r--r--Source/WebCore/rendering/RenderTreeAsText.cpp77
-rw-r--r--Source/WebCore/rendering/RenderTreeAsText.h2
-rw-r--r--Source/WebCore/rendering/RenderVideo.cpp16
-rw-r--r--Source/WebCore/rendering/RenderVideo.h6
-rw-r--r--Source/WebCore/rendering/RenderView.cpp344
-rw-r--r--Source/WebCore/rendering/RenderView.h77
-rw-r--r--Source/WebCore/rendering/RenderWidget.cpp102
-rw-r--r--Source/WebCore/rendering/RenderWidget.h8
-rw-r--r--Source/WebCore/rendering/RenderWidgetProtector.h2
-rw-r--r--Source/WebCore/rendering/RenderingAllInOne.cpp4
-rw-r--r--Source/WebCore/rendering/RootInlineBox.cpp94
-rw-r--r--Source/WebCore/rendering/RootInlineBox.h49
-rw-r--r--Source/WebCore/rendering/TableLayout.h9
-rw-r--r--Source/WebCore/rendering/TextAutosizer.cpp421
-rw-r--r--Source/WebCore/rendering/TextAutosizer.h40
-rw-r--r--Source/WebCore/rendering/TrailingFloatsRootInlineBox.h2
-rw-r--r--Source/WebCore/rendering/break_lines.cpp19
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp274
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLBlock.h27
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp4
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp13
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLFraction.h15
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp23
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLOperator.h7
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp97
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLRoot.h17
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLRow.cpp16
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLRow.h3
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLSpace.cpp101
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLSpace.h76
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp38
-rw-r--r--Source/WebCore/rendering/shapes/PolygonShape.cpp512
-rw-r--r--Source/WebCore/rendering/shapes/PolygonShape.h112
-rw-r--r--Source/WebCore/rendering/shapes/RectangleShape.cpp231
-rw-r--r--Source/WebCore/rendering/shapes/RectangleShape.h91
-rw-r--r--Source/WebCore/rendering/shapes/Shape.cpp203
-rw-r--r--Source/WebCore/rendering/shapes/Shape.h (renamed from Source/WebCore/rendering/ExclusionShape.h)36
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInfo.cpp81
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInfo.h131
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp74
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInsideInfo.h115
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInterval.cpp (renamed from Source/WebCore/rendering/ExclusionInterval.cpp)28
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInterval.h (renamed from Source/WebCore/rendering/ExclusionInterval.h)20
-rw-r--r--Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp68
-rw-r--r--Source/WebCore/rendering/shapes/ShapeOutsideInfo.h66
-rw-r--r--Source/WebCore/rendering/style/BasicShapes.cpp81
-rw-r--r--Source/WebCore/rendering/style/BasicShapes.h75
-rw-r--r--Source/WebCore/rendering/style/ContentData.cpp15
-rw-r--r--Source/WebCore/rendering/style/CursorData.h1
-rw-r--r--Source/WebCore/rendering/style/DataRef.h8
-rw-r--r--Source/WebCore/rendering/style/FillLayer.cpp84
-rw-r--r--Source/WebCore/rendering/style/FillLayer.h37
-rw-r--r--Source/WebCore/rendering/style/GridTrackSize.h53
-rw-r--r--Source/WebCore/rendering/style/NinePieceImage.cpp61
-rw-r--r--Source/WebCore/rendering/style/NinePieceImage.h153
-rw-r--r--Source/WebCore/rendering/style/QuotesData.cpp66
-rw-r--r--Source/WebCore/rendering/style/QuotesData.h32
-rw-r--r--Source/WebCore/rendering/style/RenderStyle.cpp471
-rw-r--r--Source/WebCore/rendering/style/RenderStyle.h424
-rw-r--r--Source/WebCore/rendering/style/RenderStyleConstants.h72
-rw-r--r--Source/WebCore/rendering/style/SVGRenderStyle.cpp3
-rw-r--r--Source/WebCore/rendering/style/SVGRenderStyle.h24
-rw-r--r--Source/WebCore/rendering/style/SVGRenderStyleDefs.h6
-rw-r--r--Source/WebCore/rendering/style/ShadowData.cpp14
-rw-r--r--Source/WebCore/rendering/style/ShadowData.h18
-rw-r--r--Source/WebCore/rendering/style/ShapeValue.h (renamed from Source/WebCore/rendering/style/ExclusionShapeValue.h)58
-rw-r--r--Source/WebCore/rendering/style/StyleBackgroundData.cpp9
-rw-r--r--Source/WebCore/rendering/style/StyleBackgroundData.h2
-rw-r--r--Source/WebCore/rendering/style/StyleCachedImage.cpp4
-rw-r--r--Source/WebCore/rendering/style/StyleCachedImage.h5
-rw-r--r--Source/WebCore/rendering/style/StyleCachedImageSet.cpp4
-rw-r--r--Source/WebCore/rendering/style/StyleCachedImageSet.h5
-rw-r--r--Source/WebCore/rendering/style/StyleCachedShader.h1
-rw-r--r--Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp49
-rw-r--r--Source/WebCore/rendering/style/StyleCustomFilterProgram.h67
-rw-r--r--Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp89
-rw-r--r--Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h65
-rw-r--r--Source/WebCore/rendering/style/StyleGeneratedImage.cpp6
-rw-r--r--Source/WebCore/rendering/style/StyleGeneratedImage.h2
-rw-r--r--Source/WebCore/rendering/style/StyleGridData.cpp6
-rw-r--r--Source/WebCore/rendering/style/StyleGridData.h8
-rw-r--r--Source/WebCore/rendering/style/StyleGridItemData.cpp12
-rw-r--r--Source/WebCore/rendering/style/StyleGridItemData.h9
-rw-r--r--Source/WebCore/rendering/style/StyleImage.h4
-rw-r--r--Source/WebCore/rendering/style/StylePendingImage.h4
-rw-r--r--Source/WebCore/rendering/style/StyleRareInheritedData.cpp59
-rw-r--r--Source/WebCore/rendering/style/StyleRareInheritedData.h14
-rw-r--r--Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp47
-rw-r--r--Source/WebCore/rendering/style/StyleRareNonInheritedData.h14
-rw-r--r--Source/WebCore/rendering/style/StyleVisualData.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGBlock.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGBlock.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGContainer.cpp13
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGContainer.h7
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGEllipse.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGEllipse.h4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp5
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGForeignObject.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp3
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGGradientStop.h3
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGImage.cpp38
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGImage.h16
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInline.cpp8
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInline.h4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInlineText.cpp5
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInlineText.h4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGModelObject.cpp14
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGModelObject.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGPath.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGPath.h10
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGRect.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResource.cpp2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp19
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp18
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceContainer.h1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp41
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilter.h14
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp6
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp9
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp19
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMarker.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp8
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp10
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGRoot.cpp56
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGRoot.h14
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGShape.cpp24
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGShape.h15
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTSpan.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTSpan.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.cpp9
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.h6
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTextPath.cpp6
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTextPath.h4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp10
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp19
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGViewportContainer.h6
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp8
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineFlowBox.h8
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.cpp30
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.h14
-rw-r--r--Source/WebCore/rendering/svg/SVGMarkerData.h18
-rw-r--r--Source/WebCore/rendering/svg/SVGPathData.cpp3
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderSupport.cpp25
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderSupport.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp12
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderingContext.cpp78
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderingContext.h6
-rw-r--r--Source/WebCore/rendering/svg/SVGResources.cpp12
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCache.cpp49
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCache.h4
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.cpp30
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp24
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp2
-rw-r--r--Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp3
-rw-r--r--Source/WebCore/rendering/svg/SVGTextQuery.cpp12
-rw-r--r--Source/WebCore/rendering/svg/SVGTextQuery.h7
-rw-r--r--Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp12
380 files changed, 22913 insertions, 16653 deletions
diff --git a/Source/WebCore/rendering/AutoTableLayout.cpp b/Source/WebCore/rendering/AutoTableLayout.cpp
index 8a712c74f..4f6d432c0 100644
--- a/Source/WebCore/rendering/AutoTableLayout.cpp
+++ b/Source/WebCore/rendering/AutoTableLayout.cpp
@@ -50,9 +50,12 @@ void AutoTableLayout::recalcColumn(unsigned effCol)
RenderTableCell* maxContributor = 0;
for (RenderObject* child = m_table->children()->firstChild(); child; child = child->nextSibling()) {
- if (child->isRenderTableCol())
- toRenderTableCol(child)->computePreferredLogicalWidths();
- else if (child->isTableSection()) {
+ if (child->isRenderTableCol()){
+ // RenderTableCols don't have the concept of preferred logical width, but we need to clear their dirty bits
+ // so that if we call setPreferredWidthsDirty(true) on a col or one of its descendants, we'll mark it's
+ // ancestors as dirty.
+ toRenderTableCol(child)->clearPreferredLogicalWidthsDirtyBits();
+ } else if (child->isTableSection()) {
RenderTableSection* section = toRenderTableSection(child);
unsigned numRows = section->numRows();
for (unsigned i = 0; i < numRows; i++) {
@@ -72,8 +75,6 @@ void AutoTableLayout::recalcColumn(unsigned effCol)
columnLayout.maxLogicalWidth = max<int>(columnLayout.maxLogicalWidth, 1);
if (cell->colSpan() == 1) {
- if (cell->preferredLogicalWidthsDirty())
- cell->computePreferredLogicalWidths();
columnLayout.minLogicalWidth = max<int>(cell->minPreferredLogicalWidth(), columnLayout.minLogicalWidth);
if (cell->maxPreferredLogicalWidth() > columnLayout.maxLogicalWidth) {
columnLayout.maxLogicalWidth = cell->maxPreferredLogicalWidth();
@@ -93,7 +94,7 @@ void AutoTableLayout::recalcColumn(unsigned effCol)
case Fixed:
// ignore width=0
if (cellLogicalWidth.isPositive() && !columnLayout.logicalWidth.isPercent()) {
- LayoutUnit logicalWidth = cell->adjustBorderBoxLogicalWidthForBoxSizing(cellLogicalWidth.value());
+ int logicalWidth = cell->adjustBorderBoxLogicalWidthForBoxSizing(cellLogicalWidth.value());
if (columnLayout.logicalWidth.isFixed()) {
// Nav/IE weirdness
if ((logicalWidth > columnLayout.logicalWidth.value())
@@ -209,7 +210,7 @@ static bool shouldScaleColumns(RenderTable* table)
return scale;
}
-void AutoTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth)
+void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth)
{
fullRecalc();
@@ -246,25 +247,13 @@ void AutoTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, Layout
}
maxWidth = max<int>(maxWidth, spanMaxLogicalWidth);
+}
- int bordersPaddingAndSpacing = m_table->bordersPaddingAndSpacingInRowDirection();
- minWidth += bordersPaddingAndSpacing;
- maxWidth += bordersPaddingAndSpacing;
-
+void AutoTableLayout::applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
+{
Length tableLogicalWidth = m_table->style()->logicalWidth();
- if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive()) {
- minWidth = max<int>(minWidth, tableLogicalWidth.value());
- maxWidth = minWidth;
- } else if (!remainingPercent && maxNonPercent) {
- // if there was no remaining percent, maxWidth is invalid
- maxWidth = tableMaxWidth;
- }
-
- Length tableLogicalMinWidth = m_table->style()->logicalMinWidth();
- if (tableLogicalMinWidth.isFixed() && tableLogicalMinWidth.isPositive()) {
- minWidth = max<int>(minWidth, tableLogicalMinWidth.value());
- maxWidth = max<int>(minWidth, maxWidth);
- }
+ if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive())
+ minWidth = maxWidth = max<int>(minWidth, tableLogicalWidth.value());
}
/*
diff --git a/Source/WebCore/rendering/AutoTableLayout.h b/Source/WebCore/rendering/AutoTableLayout.h
index 9d0adc1cd..a1fdad048 100644
--- a/Source/WebCore/rendering/AutoTableLayout.h
+++ b/Source/WebCore/rendering/AutoTableLayout.h
@@ -36,7 +36,8 @@ public:
AutoTableLayout(RenderTable*);
~AutoTableLayout();
- virtual void computePreferredLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth);
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) OVERRIDE;
+ virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE;
virtual void layout();
private:
diff --git a/Source/WebCore/rendering/BidiRun.h b/Source/WebCore/rendering/BidiRun.h
index 694cbca77..e1c725223 100644
--- a/Source/WebCore/rendering/BidiRun.h
+++ b/Source/WebCore/rendering/BidiRun.h
@@ -39,7 +39,12 @@ struct BidiRun : BidiCharacterRun {
, m_object(object)
, m_box(0)
{
- m_hasHyphen = false; // Stored in base class to save space.
+ ASSERT(!object->isText() || static_cast<unsigned>(stop) <= toRenderText(object)->textLength());
+ // Stored in base class to save space.
+ m_hasHyphen = false;
+#if ENABLE(CSS_SHAPES)
+ m_startsSegment = false;
+#endif
}
void destroy();
diff --git a/Source/WebCore/rendering/EllipsisBox.cpp b/Source/WebCore/rendering/EllipsisBox.cpp
index 902df2b0a..6d90e386c 100644
--- a/Source/WebCore/rendering/EllipsisBox.cpp
+++ b/Source/WebCore/rendering/EllipsisBox.cpp
@@ -36,13 +36,13 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La
{
GraphicsContext* context = paintInfo.context;
RenderStyle* style = m_renderer->style(isFirstLineStyle());
- Color textColor = style->visitedDependentColor(CSSPropertyColor);
+ Color textColor = style->visitedDependentColor(CSSPropertyWebkitTextFillColor);
if (textColor != context->fillColor())
context->setFillColor(textColor, style->colorSpace());
bool setShadow = false;
if (style->textShadow()) {
context->setShadow(LayoutSize(style->textShadow()->x(), style->textShadow()->y()),
- style->textShadow()->blur(), style->textShadow()->color(), style->colorSpace());
+ style->textShadow()->radius(), style->textShadow()->color(), style->colorSpace());
setShadow = true;
}
@@ -51,7 +51,7 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La
paintSelection(context, paintOffset, style, font);
// Select the correct color for painting the text.
- Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor();
+ Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor();
if (foreground.isValid() && foreground != textColor)
context->setFillColor(foreground, style->colorSpace());
}
@@ -69,26 +69,35 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La
paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style);
}
-void EllipsisBox::paintMarkupBox(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, RenderStyle* style)
+InlineBox* EllipsisBox::markupBox() const
{
if (!m_shouldPaintMarkupBox || !m_renderer->isRenderBlock())
- return;
+ return 0;
RenderBlock* block = toRenderBlock(m_renderer);
RootInlineBox* lastLine = block->lineAtIndex(block->lineCount() - 1);
if (!lastLine)
- return;
+ return 0;
// If the last line-box on the last line of a block is a link, -webkit-line-clamp paints that box after the ellipsis.
// It does not actually move the link.
InlineBox* anchorBox = lastLine->lastChild();
if (!anchorBox || !anchorBox->renderer()->style()->isLink())
+ return 0;
+
+ return anchorBox;
+}
+
+void EllipsisBox::paintMarkupBox(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, RenderStyle* style)
+{
+ InlineBox* markupBox = this->markupBox();
+ if (!markupBox)
return;
LayoutPoint adjustedPaintOffset = paintOffset;
- adjustedPaintOffset.move(x() + m_logicalWidth - anchorBox->x(),
- y() + style->fontMetrics().ascent() - (anchorBox->y() + anchorBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent()));
- anchorBox->paint(paintInfo, adjustedPaintOffset, lineTop, lineBottom);
+ adjustedPaintOffset.move(x() + m_logicalWidth - markupBox->x(),
+ y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent()));
+ markupBox->paint(paintInfo, adjustedPaintOffset, lineTop, lineBottom);
}
IntRect EllipsisBox::selectionRect()
@@ -121,8 +130,28 @@ void EllipsisBox::paintSelection(GraphicsContext* context, const LayoutPoint& pa
context->drawHighlightForText(font, RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), roundedIntPoint(LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + top)), h, c, style->colorSpace());
}
-bool EllipsisBox::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, LayoutUnit, LayoutUnit)
+bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
{
+ LayoutPoint adjustedLocation = accumulatedOffset + roundedLayoutPoint(topLeft());
+
+ // Hit test the markup box.
+ if (InlineBox* markupBox = this->markupBox()) {
+ RenderStyle* style = m_renderer->style(isFirstLineStyle());
+ LayoutUnit mtx = adjustedLocation.x() + m_logicalWidth - markupBox->x();
+ LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent());
+ if (markupBox->nodeAtPoint(request, result, locationInContainer, LayoutPoint(mtx, mty), lineTop, lineBottom)) {
+ renderer()->updateHitTestResult(result, locationInContainer.point() - LayoutSize(mtx, mty));
+ return true;
+ }
+ }
+
+ LayoutRect boundsRect(adjustedLocation, LayoutSize(m_logicalWidth, m_height));
+ if (visibleToHitTesting() && boundsRect.intersects(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0))) {
+ renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
+ if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, boundsRect))
+ return true;
+ }
+
return false;
}
diff --git a/Source/WebCore/rendering/EllipsisBox.h b/Source/WebCore/rendering/EllipsisBox.h
index 699767847..7c60b18bd 100644
--- a/Source/WebCore/rendering/EllipsisBox.h
+++ b/Source/WebCore/rendering/EllipsisBox.h
@@ -27,7 +27,7 @@ namespace WebCore {
class HitTestRequest;
class HitTestResult;
-class EllipsisBox : public InlineBox {
+class EllipsisBox FINAL : public InlineBox {
public:
EllipsisBox(RenderObject* obj, const AtomicString& ellipsisStr, InlineFlowBox* parent,
int width, int height, int y, bool firstLine, bool isVertical, InlineBox* markupBox)
@@ -49,6 +49,7 @@ private:
virtual int height() const { return m_height; }
virtual RenderObject::SelectionState selectionState() { return m_selectionState; }
void paintSelection(GraphicsContext*, const LayoutPoint&, RenderStyle*, const Font&);
+ InlineBox* markupBox() const;
bool m_shouldPaintMarkupBox;
int m_height;
diff --git a/Source/WebCore/rendering/ExclusionPolygon.cpp b/Source/WebCore/rendering/ExclusionPolygon.cpp
deleted file mode 100644
index 21beac1ec..000000000
--- a/Source/WebCore/rendering/ExclusionPolygon.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ExclusionPolygon.h"
-
-#include <wtf/MathExtras.h>
-
-namespace WebCore {
-
-enum EdgeIntersectionType {
- Normal,
- VertexMinY,
- VertexMaxY,
- VertexYBoth
-};
-
-struct EdgeIntersection {
- const ExclusionPolygonEdge* edge;
- FloatPoint point;
- EdgeIntersectionType type;
-};
-
-static inline float determinant(const FloatSize& a, const FloatSize& b)
-{
- return a.width() * b.height() - a.height() * b.width();
-}
-
-static inline bool areCollinearPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2)
-{
- return !determinant(p1 - p0, p2 - p0);
-}
-
-static inline bool areCoincidentPoints(const FloatPoint& p0, const FloatPoint& p1)
-{
- return p0.x() == p1.x() && p0.y() == p1.y();
-}
-
-static inline unsigned nextVertexIndex(unsigned vertexIndex, unsigned nVertices, bool clockwise)
-{
- return ((clockwise) ? vertexIndex + 1 : vertexIndex - 1 + nVertices) % nVertices;
-}
-
-unsigned ExclusionPolygon::findNextEdgeVertexIndex(unsigned vertexIndex1, bool clockwise) const
-{
- unsigned nVertices = numberOfVertices();
- unsigned vertexIndex2 = nextVertexIndex(vertexIndex1, nVertices, clockwise);
-
- while (vertexIndex2 && areCoincidentPoints(vertexAt(vertexIndex1), vertexAt(vertexIndex2)))
- vertexIndex2 = nextVertexIndex(vertexIndex2, nVertices, clockwise);
-
- while (vertexIndex2) {
- unsigned vertexIndex3 = nextVertexIndex(vertexIndex2, nVertices, clockwise);
- if (!areCollinearPoints(vertexAt(vertexIndex1), vertexAt(vertexIndex2), vertexAt(vertexIndex3)))
- break;
- vertexIndex2 = vertexIndex3;
- }
-
- return vertexIndex2;
-}
-
-ExclusionPolygon::ExclusionPolygon(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule)
- : ExclusionShape()
- , m_vertices(vertices)
- , m_fillRule(fillRule)
-{
- unsigned nVertices = numberOfVertices();
- m_edges.resize(nVertices);
- m_empty = nVertices < 3;
-
- if (nVertices)
- m_boundingBox.setLocation(vertexAt(0));
-
- if (m_empty)
- return;
-
- unsigned minVertexIndex = 0;
- for (unsigned i = 1; i < nVertices; ++i) {
- const FloatPoint& vertex = vertexAt(i);
- if (vertex.y() < vertexAt(minVertexIndex).y() || (vertex.y() == vertexAt(minVertexIndex).y() && vertex.x() < vertexAt(minVertexIndex).x()))
- minVertexIndex = i;
- }
- FloatPoint nextVertex = vertexAt((minVertexIndex + 1) % nVertices);
- FloatPoint prevVertex = vertexAt((minVertexIndex + nVertices - 1) % nVertices);
- bool clockwise = determinant(vertexAt(minVertexIndex) - prevVertex, nextVertex - prevVertex) > 0;
-
- unsigned edgeIndex = 0;
- unsigned vertexIndex1 = 0;
- do {
- m_boundingBox.extend(vertexAt(vertexIndex1));
- unsigned vertexIndex2 = findNextEdgeVertexIndex(vertexIndex1, clockwise);
- m_edges[edgeIndex].polygon = this;
- m_edges[edgeIndex].vertexIndex1 = vertexIndex1;
- m_edges[edgeIndex].vertexIndex2 = vertexIndex2;
- m_edges[edgeIndex].edgeIndex = edgeIndex;
- edgeIndex++;
- vertexIndex1 = vertexIndex2;
- } while (vertexIndex1);
-
- if (edgeIndex > 3) {
- const ExclusionPolygonEdge& firstEdge = m_edges[0];
- const ExclusionPolygonEdge& lastEdge = m_edges[edgeIndex - 1];
- if (areCollinearPoints(lastEdge.vertex1(), lastEdge.vertex2(), firstEdge.vertex2())) {
- m_edges[0].vertexIndex1 = lastEdge.vertexIndex1;
- edgeIndex--;
- }
- }
-
- m_edges.resize(edgeIndex);
- m_empty = m_edges.size() < 3;
-
- if (m_empty)
- return;
-
- for (unsigned i = 0; i < m_edges.size(); i++) {
- ExclusionPolygonEdge* edge = &m_edges[i];
- m_edgeTree.add(EdgeInterval(edge->minY(), edge->maxY(), edge));
- }
-}
-
-static bool computeXIntersection(const ExclusionPolygonEdge* edgePointer, float y, EdgeIntersection& result)
-{
- const ExclusionPolygonEdge& edge = *edgePointer;
-
- if (edge.minY() > y || edge.maxY() < y)
- return false;
-
- const FloatPoint& vertex1 = edge.vertex1();
- const FloatPoint& vertex2 = edge.vertex2();
- float dy = vertex2.y() - vertex1.y();
-
- float intersectionX;
- EdgeIntersectionType intersectionType;
-
- if (!dy) {
- intersectionType = VertexYBoth;
- intersectionX = edge.minX();
- } else if (y == edge.minY()) {
- intersectionType = VertexMinY;
- intersectionX = (vertex1.y() < vertex2.y()) ? vertex1.x() : vertex2.x();
- } else if (y == edge.maxY()) {
- intersectionType = VertexMaxY;
- intersectionX = (vertex1.y() > vertex2.y()) ? vertex1.x() : vertex2.x();
- } else {
- intersectionType = Normal;
- intersectionX = ((y - vertex1.y()) * (vertex2.x() - vertex1.x()) / dy) + vertex1.x();
- }
-
- result.edge = edgePointer;
- result.type = intersectionType;
- result.point.set(intersectionX, y);
-
- return true;
-}
-
-static inline bool getVertexIntersectionVertices(const EdgeIntersection& intersection, FloatPoint& prevVertex, FloatPoint& thisVertex, FloatPoint& nextVertex)
-{
- if (intersection.type != VertexMinY && intersection.type != VertexMaxY)
- return false;
-
- ASSERT(intersection.edge && intersection.edge->polygon);
- const ExclusionPolygon& polygon = *(intersection.edge->polygon);
- const ExclusionPolygonEdge& thisEdge = *(intersection.edge);
-
- if ((intersection.type == VertexMinY && (thisEdge.vertex1().y() < thisEdge.vertex2().y()))
- || (intersection.type == VertexMaxY && (thisEdge.vertex1().y() > thisEdge.vertex2().y()))) {
- prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex1);
- thisVertex = polygon.vertexAt(thisEdge.vertexIndex1);
- nextVertex = polygon.vertexAt(thisEdge.vertexIndex2);
- } else {
- prevVertex = polygon.vertexAt(thisEdge.vertexIndex1);
- thisVertex = polygon.vertexAt(thisEdge.vertexIndex2);
- nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex2);
- }
-
- return true;
-}
-
-static inline bool appendIntervalX(float x, bool inside, Vector<ExclusionInterval>& result)
-{
- if (!inside)
- result.append(ExclusionInterval(x));
- else
- result[result.size() - 1].x2 = x;
-
- return !inside;
-}
-
-static bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, const EdgeIntersection& intersection2)
-{
- float x1 = intersection1.point.x();
- float x2 = intersection2.point.x();
- return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2;
-}
-
-void ExclusionPolygon::computeXIntersections(float y, bool isMinY, Vector<ExclusionInterval>& result) const
-{
- Vector<ExclusionPolygon::EdgeInterval> overlappingEdges;
- m_edgeTree.allOverlaps(ExclusionPolygon::EdgeInterval(y, y, 0), overlappingEdges);
-
- Vector<EdgeIntersection> intersections;
- EdgeIntersection intersection;
- for (unsigned i = 0; i < overlappingEdges.size(); i++) {
- ExclusionPolygonEdge* edge = static_cast<ExclusionPolygonEdge*>(overlappingEdges[i].data());
- if (computeXIntersection(edge, y, intersection) && intersection.type != VertexYBoth)
- intersections.append(intersection);
- }
- if (intersections.size() < 2)
- return;
-
- std::sort(intersections.begin(), intersections.end(), WebCore::compareEdgeIntersectionX);
-
- unsigned index = 0;
- int windCount = 0;
- bool inside = false;
-
- while (index < intersections.size()) {
- const EdgeIntersection& thisIntersection = intersections[index];
- if (index + 1 < intersections.size()) {
- const EdgeIntersection& nextIntersection = intersections[index + 1];
- if ((thisIntersection.point.x() == nextIntersection.point.x()) && (thisIntersection.type == VertexMinY || thisIntersection.type == VertexMaxY)) {
- if (thisIntersection.type == nextIntersection.type) {
- // Skip pairs of intersections whose types are VertexMaxY,VertexMaxY and VertexMinY,VertexMinY.
- index += 2;
- } else {
- // Replace pairs of intersections whose types are VertexMinY,VertexMaxY or VertexMaxY,VertexMinY with one intersection.
- index++;
- }
- continue;
- }
- }
-
- const ExclusionPolygonEdge& thisEdge = *thisIntersection.edge;
- bool evenOddCrossing = !windCount;
-
- if (fillRule() == RULE_EVENODD) {
- windCount += (thisEdge.vertex2().y() > thisEdge.vertex1().y()) ? 1 : -1;
- evenOddCrossing = evenOddCrossing || !windCount;
- }
-
- if (evenOddCrossing) {
- bool edgeCrossing = thisIntersection.type == Normal;
- if (!edgeCrossing) {
- FloatPoint prevVertex;
- FloatPoint thisVertex;
- FloatPoint nextVertex;
-
- if (getVertexIntersectionVertices(thisIntersection, prevVertex, thisVertex, nextVertex)) {
- if (nextVertex.y() == y)
- edgeCrossing = (isMinY) ? prevVertex.y() > y : prevVertex.y() < y;
- else if (prevVertex.y() == y)
- edgeCrossing = (isMinY) ? nextVertex.y() > y : nextVertex.y() < y;
- else
- edgeCrossing = true;
- }
- }
- if (edgeCrossing)
- inside = appendIntervalX(thisIntersection.point.x(), inside, result);
- }
-
- index++;
- }
-}
-
-// Return the X projections of the edges that overlap y1,y2.
-void ExclusionPolygon::computeEdgeIntersections(float y1, float y2, Vector<ExclusionInterval>& result) const
-{
- Vector<ExclusionPolygon::EdgeInterval> overlappingEdges;
- m_edgeTree.allOverlaps(ExclusionPolygon::EdgeInterval(y1, y2, 0), overlappingEdges);
-
- EdgeIntersection intersection;
- for (unsigned i = 0; i < overlappingEdges.size(); i++) {
- const ExclusionPolygonEdge *edge = static_cast<ExclusionPolygonEdge*>(overlappingEdges[i].data());
- float x1;
- float x2;
-
- if (edge->minY() < y1) {
- computeXIntersection(edge, y1, intersection);
- x1 = intersection.point.x();
- } else
- x1 = (edge->vertex1().y() < edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x();
-
- if (edge->maxY() > y2) {
- computeXIntersection(edge, y2, intersection);
- x2 = intersection.point.x();
- } else
- x2 = (edge->vertex1().y() > edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x();
-
- if (x1 > x2)
- std::swap(x1, x2);
-
- if (x2 > x1)
- result.append(ExclusionInterval(x1, x2));
- }
-
- sortExclusionIntervals(result);
-}
-
-void ExclusionPolygon::getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList& result) const
-{
- if (isEmpty())
- return;
-
- float y1 = minYForLogicalLine(logicalTop, logicalHeight);
- float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
-
- Vector<ExclusionInterval> y1XIntervals, y2XIntervals;
- computeXIntersections(y1, true, y1XIntervals);
- computeXIntersections(y2, false, y2XIntervals);
-
- Vector<ExclusionInterval> mergedIntervals;
- mergeExclusionIntervals(y1XIntervals, y2XIntervals, mergedIntervals);
-
- Vector<ExclusionInterval> edgeIntervals;
- computeEdgeIntersections(y1, y2, edgeIntervals);
-
- Vector<ExclusionInterval> excludedIntervals;
- mergeExclusionIntervals(mergedIntervals, edgeIntervals, excludedIntervals);
-
- for (unsigned i = 0; i < excludedIntervals.size(); i++) {
- ExclusionInterval interval = excludedIntervals[i];
- result.append(LineSegment(interval.x1, interval.x2));
- }
-}
-
-void ExclusionPolygon::getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList& result) const
-{
- if (isEmpty())
- return;
-
- float y1 = minYForLogicalLine(logicalTop, logicalHeight);
- float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
-
- Vector<ExclusionInterval> y1XIntervals, y2XIntervals;
- computeXIntersections(y1, true, y1XIntervals);
- computeXIntersections(y2, false, y2XIntervals);
-
- Vector<ExclusionInterval> commonIntervals;
- intersectExclusionIntervals(y1XIntervals, y2XIntervals, commonIntervals);
-
- Vector<ExclusionInterval> edgeIntervals;
- computeEdgeIntersections(y1, y2, edgeIntervals);
-
- Vector<ExclusionInterval> includedIntervals;
- subtractExclusionIntervals(commonIntervals, edgeIntervals, includedIntervals);
-
- for (unsigned i = 0; i < includedIntervals.size(); i++) {
- ExclusionInterval interval = includedIntervals[i];
- result.append(LineSegment(interval.x1, interval.x2));
- }
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/ExclusionPolygon.h b/Source/WebCore/rendering/ExclusionPolygon.h
deleted file mode 100644
index 647eb172e..000000000
--- a/Source/WebCore/rendering/ExclusionPolygon.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ExclusionPolygon_h
-#define ExclusionPolygon_h
-
-#include "ExclusionInterval.h"
-#include "ExclusionShape.h"
-#include "FloatPoint.h"
-#include "FloatRect.h"
-#include "PODIntervalTree.h"
-#include "WindRule.h"
-#include <wtf/MathExtras.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-struct ExclusionPolygonEdge;
-
-// This class is used by PODIntervalTree for debugging.
-#ifndef NDEBUG
-template <class> struct ValueToString;
-#endif
-
-class ExclusionPolygon : public ExclusionShape {
- WTF_MAKE_NONCOPYABLE(ExclusionPolygon);
-public:
- ExclusionPolygon(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule);
-
- const FloatPoint& vertexAt(unsigned index) const { return (*m_vertices)[index]; }
- unsigned numberOfVertices() const { return m_vertices->size(); }
- WindRule fillRule() const { return m_fillRule; }
-
- const ExclusionPolygonEdge& edgeAt(unsigned index) const { return m_edges[index]; }
- unsigned numberOfEdges() const { return m_edges.size(); }
-
- virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return internalToLogicalBoundingBox(m_boundingBox); }
- virtual bool isEmpty() const OVERRIDE { return m_empty; }
- virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
- virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
-
-private:
- void computeXIntersections(float y, bool isMinY, Vector<ExclusionInterval>&) const;
- void computeEdgeIntersections(float minY, float maxY, Vector<ExclusionInterval>&) const;
- unsigned findNextEdgeVertexIndex(unsigned vertexIndex1, bool clockwise) const;
-
- typedef PODInterval<float, ExclusionPolygonEdge*> EdgeInterval;
- typedef PODIntervalTree<float, ExclusionPolygonEdge*> EdgeIntervalTree;
-
- OwnPtr<Vector<FloatPoint> > m_vertices;
- WindRule m_fillRule;
- FloatRect m_boundingBox;
- Vector<ExclusionPolygonEdge> m_edges;
- EdgeIntervalTree m_edgeTree;
- bool m_empty;
-};
-
-// EdgeIntervalTree nodes store minY, maxY, and a ("UserData") pointer to an ExclusionPolygonEdge. Edge vertex
-// index1 is less than index2, except the last edge, where index2 is 0. When a polygon edge is defined by 3
-// or more colinear vertices, index2 can be the the index of the last colinear vertex.
-struct ExclusionPolygonEdge {
- const FloatPoint& vertex1() const
- {
- ASSERT(polygon);
- return polygon->vertexAt(vertexIndex1);
- }
-
- const FloatPoint& vertex2() const
- {
- ASSERT(polygon);
- return polygon->vertexAt(vertexIndex2);
- }
-
- const ExclusionPolygonEdge& previousEdge() const
- {
- ASSERT(polygon && polygon->numberOfEdges() > 1);
- return polygon->edgeAt((edgeIndex + polygon->numberOfEdges() - 1) % polygon->numberOfEdges());
- }
-
- const ExclusionPolygonEdge& nextEdge() const
- {
- ASSERT(polygon && polygon->numberOfEdges() > 1);
- return polygon->edgeAt((edgeIndex + 1) % polygon->numberOfEdges());
- }
-
- float minX() const { return std::min(vertex1().x(), vertex2().x()); }
- float minY() const { return std::min(vertex1().y(), vertex2().y()); }
- float maxX() const { return std::max(vertex1().x(), vertex2().x()); }
- float maxY() const { return std::max(vertex1().y(), vertex2().y()); }
-
- const ExclusionPolygon* polygon;
- unsigned vertexIndex1;
- unsigned vertexIndex2;
- unsigned edgeIndex;
-};
-
-// These structures are used by PODIntervalTree for debugging.1
-#ifndef NDEBUG
-template <> struct ValueToString<float> {
- static String string(const float value) { return String::number(value); }
-};
-
-template<> struct ValueToString<ExclusionPolygonEdge*> {
- static String string(const ExclusionPolygonEdge* edge) { return String::format("%p (%f,%f %f,%f)", edge, edge->vertex1().x(), edge->vertex1().y(), edge->vertex2().x(), edge->vertex2().y()); }
-};
-#endif
-
-} // namespace WebCore
-
-#endif // ExclusionPolygon_h
diff --git a/Source/WebCore/rendering/ExclusionRectangle.cpp b/Source/WebCore/rendering/ExclusionRectangle.cpp
deleted file mode 100644
index 328cba2f3..000000000
--- a/Source/WebCore/rendering/ExclusionRectangle.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ExclusionRectangle.h"
-
-#include <wtf/MathExtras.h>
-
-namespace WebCore {
-
-static inline float ellipseXIntercept(float y, float rx, float ry)
-{
- ASSERT(ry > 0);
- return rx * sqrt(1 - (y*y) / (ry*ry));
-}
-
-void ExclusionRectangle::getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList& result) const
-{
- if (isEmpty())
- return;
-
- float y1 = minYForLogicalLine(logicalTop, logicalHeight);
- float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
-
- if (y2 < m_y || y1 >= m_y + m_height)
- return;
-
- float x1 = m_x;
- float x2 = m_x + m_width;
-
- if (m_ry > 0) {
- if (y2 < m_y + m_ry) {
- float yi = y2 - m_y - m_ry;
- float xi = ellipseXIntercept(yi, m_rx, m_ry);
- x1 = m_x + m_rx - xi;
- x2 = m_x + m_width - m_rx + xi;
- } else if (y1 > m_y + m_height - m_ry) {
- float yi = y1 - (m_y + m_height - m_ry);
- float xi = ellipseXIntercept(yi, m_rx, m_ry);
- x1 = m_x + m_rx - xi;
- x2 = m_x + m_width - m_rx + xi;
- }
- }
-
- result.append(LineSegment(x1, x2));
-}
-
-void ExclusionRectangle::getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList& result) const
-{
- if (isEmpty())
- return;
-
- float y1 = minYForLogicalLine(logicalTop, logicalHeight);
- float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
-
- if (y1 < m_y || y2 > m_y + m_height)
- return;
-
- float x1 = m_x;
- float x2 = m_x + m_width;
-
- if (m_ry > 0) {
- bool y1InterceptsCorner = y1 < m_y + m_ry;
- bool y2InterceptsCorner = y2 > m_y + m_height - m_ry;
- float xi = 0;
-
- if (y1InterceptsCorner && y2InterceptsCorner) {
- if (y1 < m_height + 2*m_y - y2) {
- float yi = y1 - m_y - m_ry;
- xi = ellipseXIntercept(yi, m_rx, m_ry);
- } else {
- float yi = y2 - (m_y + m_height - m_ry);
- xi = ellipseXIntercept(yi, m_rx, m_ry);
- }
- } else if (y1InterceptsCorner) {
- float yi = y1 - m_y - m_ry;
- xi = ellipseXIntercept(yi, m_rx, m_ry);
- } else if (y2InterceptsCorner) {
- float yi = y2 - (m_y + m_height - m_ry);
- xi = ellipseXIntercept(yi, m_rx, m_ry);
- }
-
- if (y1InterceptsCorner || y2InterceptsCorner) {
- x1 = m_x + m_rx - xi;
- x2 = m_x + m_width - m_rx + xi;
- }
- }
-
- result.append(LineSegment(x1, x2));
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/ExclusionRectangle.h b/Source/WebCore/rendering/ExclusionRectangle.h
deleted file mode 100644
index 5839eec47..000000000
--- a/Source/WebCore/rendering/ExclusionRectangle.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ExclusionRectangle_h
-#define ExclusionRectangle_h
-
-#include "ExclusionShape.h"
-#include "FloatSize.h"
-#include <wtf/Assertions.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class ExclusionRectangle : public ExclusionShape {
-public:
- ExclusionRectangle(const FloatRect& bounds, const FloatSize& radii)
- : ExclusionShape()
- , m_x(bounds.x())
- , m_y(bounds.y())
- , m_width(bounds.width())
- , m_height(bounds.height())
- , m_rx(radii.width())
- , m_ry(radii.height())
- {
- }
-
- virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return internalToLogicalBoundingBox(FloatRect(m_x, m_y, m_width, m_height)); }
- virtual bool isEmpty() const OVERRIDE { return m_width <= 0 || m_height <= 0; }
- virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
- virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
-
-private:
- float m_x;
- float m_y;
- float m_width;
- float m_height;
- float m_rx; // corner X radius
- float m_ry; // corner Y radius
-};
-
-} // namespace WebCore
-
-#endif // ExclusionRectangle_h
diff --git a/Source/WebCore/rendering/ExclusionShape.cpp b/Source/WebCore/rendering/ExclusionShape.cpp
deleted file mode 100644
index 5e0ea8bf1..000000000
--- a/Source/WebCore/rendering/ExclusionShape.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ExclusionShape.h"
-
-#include "BasicShapeFunctions.h"
-#include "ExclusionPolygon.h"
-#include "ExclusionRectangle.h"
-#include "FloatSize.h"
-#include "LengthFunctions.h"
-#include "WindRule.h"
-#include <wtf/MathExtras.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-
-namespace WebCore {
-
-static PassOwnPtr<ExclusionShape> createExclusionRectangle(const FloatRect& bounds, const FloatSize& radii)
-{
- ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0);
- return adoptPtr(new ExclusionRectangle(bounds, radii));
-}
-
-static PassOwnPtr<ExclusionShape> createExclusionCircle(const FloatPoint& center, float radius)
-{
- ASSERT(radius >= 0);
- return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius)));
-}
-
-static PassOwnPtr<ExclusionShape> createExclusionEllipse(const FloatPoint& center, const FloatSize& radii)
-{
- ASSERT(radii.width() >= 0 && radii.height() >= 0);
- return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii));
-}
-
-static PassOwnPtr<ExclusionShape> createExclusionPolygon(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule)
-{
- return adoptPtr(new ExclusionPolygon(vertices, fillRule));
-}
-
-// If the writingMode is vertical, then the BasicShape's (physical) x and y coordinates are swapped, so that
-// line segments are parallel to the internal coordinate system's X axis.
-
-PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape* basicShape, float logicalBoxWidth, float logicalBoxHeight, WritingMode writingMode)
-{
- ASSERT(basicShape);
-
- bool horizontalWritingMode = isHorizontalWritingMode(writingMode);
- float boxWidth = horizontalWritingMode ? logicalBoxWidth : logicalBoxHeight;
- float boxHeight = horizontalWritingMode ? logicalBoxHeight : logicalBoxWidth;
- OwnPtr<ExclusionShape> exclusionShape;
-
- switch (basicShape->type()) {
-
- case BasicShape::BASIC_SHAPE_RECTANGLE: {
- const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape);
- FloatRect bounds(
- floatValueForLength(rectangle->x(), boxWidth),
- floatValueForLength(rectangle->y(), boxHeight),
- floatValueForLength(rectangle->width(), boxWidth),
- floatValueForLength(rectangle->height(), boxHeight));
- Length radiusXLength = rectangle->cornerRadiusX();
- Length radiusYLength = rectangle->cornerRadiusY();
- FloatSize cornerRadii(
- radiusXLength.isUndefined() ? 0 : floatValueForLength(radiusXLength, boxWidth),
- radiusYLength.isUndefined() ? 0 : floatValueForLength(radiusYLength, boxHeight));
-
- exclusionShape = horizontalWritingMode
- ? createExclusionRectangle(bounds, cornerRadii)
- : createExclusionRectangle(bounds.transposedRect(), cornerRadii.transposedSize());
- exclusionShape->m_boundingBox = bounds;
- break;
- }
-
- case BasicShape::BASIC_SHAPE_CIRCLE: {
- const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
- float centerX = floatValueForLength(circle->centerX(), boxWidth);
- float centerY = floatValueForLength(circle->centerY(), boxHeight);
- float radius = floatValueForLength(circle->radius(), std::max(boxHeight, boxWidth));
-
- exclusionShape = horizontalWritingMode
- ? createExclusionCircle(FloatPoint(centerX, centerY), radius)
- : createExclusionCircle(FloatPoint(centerY, centerX), radius);
- exclusionShape->m_boundingBox = FloatRect(centerX - radius, centerY - radius, radius * 2, radius * 2);
- break;
- }
-
- case BasicShape::BASIC_SHAPE_ELLIPSE: {
- const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
- float centerX = floatValueForLength(ellipse->centerX(), boxWidth);
- float centerY = floatValueForLength(ellipse->centerY(), boxHeight);
- float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth);
- float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
-
- exclusionShape = horizontalWritingMode
- ? createExclusionEllipse(FloatPoint(centerX, centerY), FloatSize(radiusX, radiusY))
- : createExclusionEllipse(FloatPoint(centerY, centerX), FloatSize(radiusY, radiusX));
- exclusionShape->m_boundingBox = FloatRect(centerX - radiusX, centerY - radiusY, radiusX * 2, radiusY * 2);
- break;
- }
-
- case BasicShape::BASIC_SHAPE_POLYGON: {
- const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape);
- const Vector<Length>& values = polygon->values();
- size_t valuesSize = values.size();
- ASSERT(!(valuesSize % 2));
- FloatRect boundingBox;
- Vector<FloatPoint>* vertices = new Vector<FloatPoint>(valuesSize / 2);
- for (unsigned i = 0; i < valuesSize; i += 2) {
- FloatPoint vertex(
- floatValueForLength(values.at(i), boxWidth),
- floatValueForLength(values.at(i + 1), boxHeight));
- (*vertices)[i / 2] = horizontalWritingMode ? vertex : vertex.transposedPoint();
- if (!i)
- boundingBox.setLocation(vertex);
- else
- boundingBox.extend(vertex);
- }
- exclusionShape = createExclusionPolygon(adoptPtr(vertices), polygon->windRule());
- exclusionShape->m_boundingBox = boundingBox;
- break;
- }
-
- default:
- ASSERT_NOT_REACHED();
- }
-
- exclusionShape->m_logicalBoxWidth = logicalBoxWidth;
- exclusionShape->m_logicalBoxHeight = logicalBoxHeight;
- exclusionShape->m_writingMode = writingMode;
-
- return exclusionShape.release();
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp b/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp
deleted file mode 100644
index 934e3f299..000000000
--- a/Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ExclusionShapeInsideInfo.h"
-
-#if ENABLE(CSS_EXCLUSIONS)
-
-#include "NotImplemented.h"
-#include "RenderBlock.h"
-#include <wtf/HashMap.h>
-#include <wtf/OwnPtr.h>
-
-namespace WebCore {
-
-typedef HashMap<const RenderBlock*, OwnPtr<ExclusionShapeInsideInfo> > ExclusionShapeInsideInfoMap;
-
-static ExclusionShapeInsideInfoMap& exclusionShapeInsideInfoMap()
-{
- DEFINE_STATIC_LOCAL(ExclusionShapeInsideInfoMap, staticExclusionShapeInsideInfoMap, ());
- return staticExclusionShapeInsideInfoMap;
-}
-
-ExclusionShapeInsideInfo::ExclusionShapeInsideInfo(RenderBlock* block)
- : m_block(block)
- , m_shapeSizeDirty(true)
-{
-}
-
-ExclusionShapeInsideInfo::~ExclusionShapeInsideInfo()
-{
-}
-
-ExclusionShapeInsideInfo* ExclusionShapeInsideInfo::ensureExclusionShapeInsideInfoForRenderBlock(RenderBlock* block)
-{
- ExclusionShapeInsideInfoMap::AddResult result = exclusionShapeInsideInfoMap().add(block, create(block));
- return result.iterator->value.get();
-}
-
-ExclusionShapeInsideInfo* ExclusionShapeInsideInfo::exclusionShapeInsideInfoForRenderBlock(const RenderBlock* block)
-{
- ASSERT(block->style()->shapeInside());
- return exclusionShapeInsideInfoMap().get(block);
-}
-
-bool ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock(const RenderBlock* block)
-{
- // FIXME: Bug 89707: Enable shape inside for non-rectangular shapes
- ExclusionShapeValue* shapeValue = block->style()->shapeInside();
- BasicShape* shape = (shapeValue && shapeValue->type() == ExclusionShapeValue::SHAPE) ? shapeValue->shape() : 0;
- return shape && (shape->type() == BasicShape::BASIC_SHAPE_RECTANGLE || shape->type() == BasicShape::BASIC_SHAPE_POLYGON);
-}
-
-void ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(const RenderBlock* block)
-{
- if (!block->style() || !block->style()->shapeInside())
- return;
- exclusionShapeInsideInfoMap().remove(block);
-}
-
-void ExclusionShapeInsideInfo::computeShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight)
-{
- if (!m_shapeSizeDirty && logicalWidth == m_logicalWidth && logicalHeight == m_logicalHeight)
- return;
-
- m_shapeSizeDirty = false;
- m_logicalWidth = logicalWidth;
- m_logicalHeight = logicalHeight;
-
- // FIXME: Bug 89993: The wrap shape may come from the parent object
- ExclusionShapeValue* shapeValue = m_block->style()->shapeInside();
- BasicShape* shape = (shapeValue && shapeValue->type() == ExclusionShapeValue::SHAPE) ? shapeValue->shape() : 0;
-
- ASSERT(shape);
-
- m_shape = ExclusionShape::createExclusionShape(shape, logicalWidth, logicalHeight, m_block->style()->writingMode());
- ASSERT(m_shape);
-}
-
-bool ExclusionShapeInsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
-{
- ASSERT(lineHeight >= 0);
- m_lineTop = lineTop;
- m_lineHeight = lineHeight;
- m_segments.clear();
-
- if (lineOverlapsShapeBounds()) {
- ASSERT(m_shape);
- m_shape->getIncludedIntervals(lineTop, std::min(lineHeight, shapeLogicalBottom() - lineTop), m_segments);
- }
- return m_segments.size();
-}
-
-}
-#endif
diff --git a/Source/WebCore/rendering/ExclusionShapeInsideInfo.h b/Source/WebCore/rendering/ExclusionShapeInsideInfo.h
deleted file mode 100644
index 8be114d4b..000000000
--- a/Source/WebCore/rendering/ExclusionShapeInsideInfo.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef ExclusionShapeInsideInfo_h
-#define ExclusionShapeInsideInfo_h
-
-#if ENABLE(CSS_EXCLUSIONS)
-
-#include "ExclusionShape.h"
-#include "FloatRect.h"
-#include "LayoutUnit.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class RenderBlock;
-
-class ExclusionShapeInsideInfo {
- WTF_MAKE_FAST_ALLOCATED;
-public:
- ~ExclusionShapeInsideInfo();
-
- static PassOwnPtr<ExclusionShapeInsideInfo> create(RenderBlock* block) { return adoptPtr(new ExclusionShapeInsideInfo(block)); }
- static ExclusionShapeInsideInfo* exclusionShapeInsideInfoForRenderBlock(const RenderBlock*);
- static ExclusionShapeInsideInfo* ensureExclusionShapeInsideInfoForRenderBlock(RenderBlock*);
- static void removeExclusionShapeInsideInfoForRenderBlock(const RenderBlock*);
- static bool isExclusionShapeInsideInfoEnabledForRenderBlock(const RenderBlock*);
-
- LayoutUnit shapeLogicalTop() const { return shapeLogicalBoundsY(); }
- LayoutUnit shapeLogicalBottom() const { return shapeLogicalBoundsMaxY(); }
- bool lineOverlapsShapeBounds() const { return m_lineTop < shapeLogicalBottom() && m_lineTop + m_lineHeight >= shapeLogicalTop(); }
-
- bool hasSegments() const
- {
- return lineOverlapsShapeBounds() && m_segments.size();
- }
- const SegmentList& segments() const
- {
- ASSERT(hasSegments());
- return m_segments;
- }
- bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);
- void computeShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight);
- void dirtyShapeSize() { m_shapeSizeDirty = true; }
-
-private:
- ExclusionShapeInsideInfo(RenderBlock*);
-
- inline LayoutUnit shapeLogicalBoundsY() const
- {
- ASSERT(m_shape);
- // Use fromFloatCeil() to ensure that the returned LayoutUnit value is within the shape's bounds.
- return LayoutUnit::fromFloatCeil(m_shape->shapeLogicalBoundingBox().y());
- }
-
- inline LayoutUnit shapeLogicalBoundsMaxY() const
- {
- ASSERT(m_shape);
- // Use fromFloatFloor() to ensure that the returned LayoutUnit value is within the shape's bounds.
- return LayoutUnit::fromFloatFloor(m_shape->shapeLogicalBoundingBox().maxY());
- }
-
- RenderBlock* m_block;
- OwnPtr<ExclusionShape> m_shape;
-
- LayoutUnit m_lineTop;
- LayoutUnit m_lineHeight;
- LayoutUnit m_logicalWidth;
- LayoutUnit m_logicalHeight;
-
- SegmentList m_segments;
- bool m_shapeSizeDirty;
-};
-
-}
-#endif
-#endif
diff --git a/Source/WebCore/rendering/FilterEffectRenderer.cpp b/Source/WebCore/rendering/FilterEffectRenderer.cpp
index d47340ece..9f168c8bb 100644
--- a/Source/WebCore/rendering/FilterEffectRenderer.cpp
+++ b/Source/WebCore/rendering/FilterEffectRenderer.cpp
@@ -48,6 +48,7 @@
#include "CustomFilterProgram.h"
#include "CustomFilterValidatedProgram.h"
#include "FECustomFilter.h"
+#include "GraphicsContext3D.h"
#include "RenderView.h"
#include "ValidatedCustomFilterOperation.h"
#endif
@@ -97,16 +98,12 @@ static PassRefPtr<FECustomFilter> createCustomFilterEffect(Filter* filter, Docum
return 0;
return FECustomFilter::create(filter, globalContext->context(), operation->validatedProgram(), operation->parameters(),
- operation->meshRows(), operation->meshColumns(), operation->meshBoxType(), operation->meshType());
+ operation->meshRows(), operation->meshColumns(), operation->meshType());
}
#endif
FilterEffectRenderer::FilterEffectRenderer()
- : m_topOutset(0)
- , m_rightOutset(0)
- , m_bottomOutset(0)
- , m_leftOutset(0)
- , m_graphicsBufferAttached(false)
+ : m_graphicsBufferAttached(false)
, m_hasFilterThatMovesPixels(false)
#if ENABLE(CSS_SHADERS)
, m_hasCustomShaderFilter(false)
@@ -125,9 +122,15 @@ GraphicsContext* FilterEffectRenderer::inputContext()
return sourceImage() ? sourceImage()->context() : 0;
}
-PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* document, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation)
+PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderObject* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation)
{
#if ENABLE(SVG)
+ if (!renderer)
+ return 0;
+
+ Document* document = renderer->document();
+ ASSERT(document);
+
CachedSVGDocumentReference* cachedSVGDocumentReference = filterOperation->cachedSVGDocumentReference();
CachedSVGDocument* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : 0;
@@ -140,8 +143,12 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* do
return 0;
Element* filter = document->getElementById(filterOperation->fragment());
- if (!filter)
+ if (!filter) {
+ // Although we did not find the referenced filter, it might exist later
+ // in the document
+ document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), toElement(renderer->node()));
return 0;
+ }
RefPtr<FilterEffect> effect;
@@ -156,7 +163,7 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* do
if (!node->isSVGElement())
continue;
- SVGElement* element = static_cast<SVGElement*>(node);
+ SVGElement* element = toSVGElement(node);
if (!element->isFilterEffect())
continue;
@@ -172,25 +179,21 @@ PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* do
}
return effect;
#else
- UNUSED_PARAM(document);
+ UNUSED_PARAM(renderer);
UNUSED_PARAM(previousEffect);
UNUSED_PARAM(filterOperation);
return 0;
#endif
}
-bool FilterEffectRenderer::build(Document* document, const FilterOperations& operations)
+bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations)
{
-#if !ENABLE(CSS_SHADERS) || !USE(3D_GRAPHICS)
- UNUSED_PARAM(document);
-#endif
-
#if ENABLE(CSS_SHADERS)
m_hasCustomShaderFilter = false;
#endif
m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels();
if (m_hasFilterThatMovesPixels)
- operations.getOutsets(m_topOutset, m_rightOutset, m_bottomOutset, m_leftOutset);
+ m_outsets = operations.outsets();
// Keep the old effects on the stack until we've created the new effects.
// New FECustomFilters can reuse cached resources from old FECustomFilters.
@@ -204,7 +207,7 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
switch (filterOperation->getOperationType()) {
case FilterOperation::REFERENCE: {
ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation);
- effect = buildReferenceFilter(document, previousEffect, referenceOperation);
+ effect = buildReferenceFilter(renderer, previousEffect, referenceOperation);
referenceOperation->setFilterEffect(effect);
break;
}
@@ -308,8 +311,8 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
ComponentTransferFunction transferFunction;
transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
- transferFunction.slope = 1;
- transferFunction.intercept = narrowPrecisionToFloat(componentTransferOperation->amount());
+ transferFunction.slope = narrowPrecisionToFloat(componentTransferOperation->amount());
+ transferFunction.intercept = 0;
ComponentTransferFunction nullFunction;
effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
@@ -347,6 +350,7 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
break;
case FilterOperation::VALIDATED_CUSTOM: {
ValidatedCustomFilterOperation* customFilterOperation = static_cast<ValidatedCustomFilterOperation*>(filterOperation);
+ Document* document = renderer ? renderer->document() : 0;
effect = createCustomFilterEffect(this, document, customFilterOperation);
if (effect)
m_hasCustomShaderFilter = true;
@@ -360,7 +364,7 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
if (effect) {
// Unlike SVG, filters applied here should not clip to their primitive subregions.
effect->setClipsToBounds(false);
- effect->setColorSpace(ColorSpaceDeviceRGB);
+ effect->setOperatingColorSpace(ColorSpaceDeviceRGB);
if (filterOperation->getOperationType() != FilterOperation::REFERENCE) {
effect->inputEffects().append(previousEffect);
@@ -413,11 +417,9 @@ void FilterEffectRenderer::clearIntermediateResults()
void FilterEffectRenderer::apply()
{
- lastEffect()->apply();
-
-#if !USE(CG)
- output()->transformColorSpace(lastEffect()->colorSpace(), ColorSpaceDeviceRGB);
-#endif
+ RefPtr<FilterEffect> effect = lastEffect();
+ effect->apply();
+ effect->transformResultColorSpace(ColorSpaceDeviceRGB);
}
LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
@@ -434,8 +436,8 @@ LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const Layout
if (hasFilterThatMovesPixels()) {
// Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and
// need to find out what is the rectangle that might influence the result inside that dirty rect.
- rectForRepaint.move(-m_rightOutset, -m_bottomOutset);
- rectForRepaint.expand(m_leftOutset + m_rightOutset, m_topOutset + m_bottomOutset);
+ rectForRepaint.move(-m_outsets.right(), -m_outsets.bottom());
+ rectForRepaint.expand(m_outsets.left() + m_outsets.right(), m_outsets.top() + m_outsets.bottom());
}
rectForRepaint.intersect(filterBoxRect);
return rectForRepaint;
@@ -468,8 +470,17 @@ bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, c
}
return true;
}
-
-GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* oldContext)
+
+GraphicsContext* FilterEffectRendererHelper::filterContext() const
+{
+ if (!m_haveFilterEffect)
+ return 0;
+
+ FilterEffectRenderer* filter = m_renderLayer->filterRenderer();
+ return filter->inputContext();
+}
+
+bool FilterEffectRendererHelper::beginFilterEffect()
{
ASSERT(m_renderLayer);
@@ -480,21 +491,20 @@ GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext*
if (!sourceGraphicsContext || !isFilterSizeValid(filter->filterRegion())) {
// Disable the filters and continue.
m_haveFilterEffect = false;
- return oldContext;
+ return false;
}
- m_savedGraphicsContext = oldContext;
-
// Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer.
sourceGraphicsContext->save();
sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y());
sourceGraphicsContext->clearRect(m_repaintRect);
sourceGraphicsContext->clip(m_repaintRect);
-
- return sourceGraphicsContext;
+
+ m_startedFilterEffect = true;
+ return true;
}
-GraphicsContext* FilterEffectRendererHelper::applyFilterEffect()
+void FilterEffectRendererHelper::applyFilterEffect(GraphicsContext* destinationContext)
{
ASSERT(m_haveFilterEffect && m_renderLayer->filterRenderer());
FilterEffectRenderer* filter = m_renderLayer->filterRenderer();
@@ -506,11 +516,9 @@ GraphicsContext* FilterEffectRendererHelper::applyFilterEffect()
LayoutRect destRect = filter->outputRect();
destRect.move(m_paintOffset.x(), m_paintOffset.y());
- m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver);
+ destinationContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver);
filter->clearIntermediateResults();
-
- return m_savedGraphicsContext;
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/FilterEffectRenderer.h b/Source/WebCore/rendering/FilterEffectRenderer.h
index f73188f5c..0d3ac4017 100644
--- a/Source/WebCore/rendering/FilterEffectRenderer.h
+++ b/Source/WebCore/rendering/FilterEffectRenderer.h
@@ -34,6 +34,7 @@
#include "FloatRect.h"
#include "GraphicsContext.h"
#include "ImageBuffer.h"
+#include "IntRectExtent.h"
#include "LayoutRect.h"
#include "SVGFilterBuilder.h"
#include "SourceGraphic.h"
@@ -50,30 +51,33 @@ class CustomFilterProgram;
class Document;
class GraphicsContext;
class RenderLayer;
+class RenderObject;
class FilterEffectRendererHelper {
public:
FilterEffectRendererHelper(bool haveFilterEffect)
- : m_savedGraphicsContext(0)
- , m_renderLayer(0)
+ : m_renderLayer(0)
, m_haveFilterEffect(haveFilterEffect)
+ , m_startedFilterEffect(false)
{
}
bool haveFilterEffect() const { return m_haveFilterEffect; }
- bool hasStartedFilterEffect() const { return m_savedGraphicsContext; }
+ bool hasStartedFilterEffect() const { return m_startedFilterEffect; }
bool prepareFilterEffect(RenderLayer*, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect);
- GraphicsContext* beginFilterEffect(GraphicsContext* oldContext);
- GraphicsContext* applyFilterEffect();
+ bool beginFilterEffect();
+ void applyFilterEffect(GraphicsContext* destinationContext);
+
+ GraphicsContext* filterContext() const;
const LayoutRect& repaintRect() const { return m_repaintRect; }
private:
- GraphicsContext* m_savedGraphicsContext;
- RenderLayer* m_renderLayer;
+ RenderLayer* m_renderLayer; // FIXME: this is mainly used to get the FilterEffectRenderer. FilterEffectRendererHelper should be weaned off it.
LayoutPoint m_paintOffset;
LayoutRect m_repaintRect;
bool m_haveFilterEffect;
+ bool m_startedFilterEffect;
};
class FilterEffectRenderer : public Filter
@@ -100,8 +104,8 @@ public:
GraphicsContext* inputContext();
ImageBuffer* output() const { return lastEffect()->asImageBuffer(); }
- bool build(Document*, const FilterOperations&);
- PassRefPtr<FilterEffect> buildReferenceFilter(Document*, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation*);
+ bool build(RenderObject* renderer, const FilterOperations&);
+ PassRefPtr<FilterEffect> buildReferenceFilter(RenderObject* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation*);
bool updateBackingStoreRect(const FloatRect& filterRect);
void allocateBackingStoreIfNeeded();
void clearIntermediateResults();
@@ -139,11 +143,8 @@ private:
FilterEffectList m_effects;
RefPtr<SourceGraphic> m_sourceGraphic;
- int m_topOutset;
- int m_rightOutset;
- int m_bottomOutset;
- int m_leftOutset;
-
+ IntRectExtent m_outsets;
+
bool m_graphicsBufferAttached;
bool m_hasFilterThatMovesPixels;
#if ENABLE(CSS_SHADERS)
diff --git a/Source/WebCore/rendering/FixedTableLayout.cpp b/Source/WebCore/rendering/FixedTableLayout.cpp
index e75764ac7..a6b65e934 100644
--- a/Source/WebCore/rendering/FixedTableLayout.cpp
+++ b/Source/WebCore/rendering/FixedTableLayout.cpp
@@ -77,8 +77,9 @@ FixedTableLayout::FixedTableLayout(RenderTable* table)
{
}
-int FixedTableLayout::calcWidthArray(int)
+int FixedTableLayout::calcWidthArray()
{
+ // FIXME: We might want to wait until we have all of the first row before computing for the first time.
int usedWidth = 0;
// iterate over all <col> elements
@@ -88,7 +89,10 @@ int FixedTableLayout::calcWidthArray(int)
unsigned currentEffectiveColumn = 0;
for (RenderTableCol* col = m_table->firstColumn(); col; col = col->nextColumn()) {
- col->computePreferredLogicalWidths();
+ // RenderTableCols don't have the concept of preferred logical width, but we need to clear their dirty bits
+ // so that if we call setPreferredWidthsDirty(true) on a col or one of its descendants, we'll mark it's
+ // ancestors as dirty.
+ col->clearPreferredLogicalWidthsDirtyBits();
// Width specified by column-groups that have column child does not affect column width in fixed layout tables
if (col->isTableColumnGroupWithColumnChildren())
@@ -138,12 +142,12 @@ int FixedTableLayout::calcWidthArray(int)
continue;
RenderTableCell* cell = toRenderTableCell(child);
- if (cell->preferredLogicalWidthsDirty())
- cell->computePreferredLogicalWidths();
Length logicalWidth = cell->styleOrColLogicalWidth();
unsigned span = cell->colSpan();
int fixedBorderBoxLogicalWidth = 0;
+ // FIXME: Support other length types. If the width is non-auto, it should probably just use
+ // RenderBox::computeLogicalWidthInRegionUsing to compute the width.
if (logicalWidth.isFixed() && logicalWidth.isPositive()) {
fixedBorderBoxLogicalWidth = cell->adjustBorderBoxLogicalWidthForBoxSizing(logicalWidth.value());
logicalWidth.setValue(fixedBorderBoxLogicalWidth);
@@ -161,32 +165,28 @@ int FixedTableLayout::calcWidthArray(int)
usedSpan += eSpan;
++currentColumn;
}
+
+ // FixedTableLayout doesn't use min/maxPreferredLogicalWidths, but we need to clear the
+ // dirty bit on the cell so that we'll correctly mark its ancestors dirty
+ // in case we later call setPreferredLogicalWidthsDirty(true) on it later.
+ if (cell->preferredLogicalWidthsDirty())
+ cell->setPreferredLogicalWidthsDirty(false);
}
return usedWidth;
}
-void FixedTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth)
+void FixedTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth)
{
- // FIXME: This entire calculation is incorrect for both minwidth and maxwidth.
-
- // we might want to wait until we have all of the first row before
- // layouting for the first time.
-
- // only need to calculate the minimum width as the sum of the
- // cols/cells with a fixed width.
- //
- // The maximum width is max(minWidth, tableWidth).
- int bordersPaddingAndSpacing = m_table->bordersPaddingAndSpacingInRowDirection();
-
- int tableLogicalWidth = m_table->style()->logicalWidth().isFixed() ? m_table->style()->logicalWidth().value() - bordersPaddingAndSpacing : 0;
- int mw = calcWidthArray(tableLogicalWidth) + bordersPaddingAndSpacing;
+ minWidth = maxWidth = calcWidthArray();
+}
- minWidth = max(mw, tableLogicalWidth);
- maxWidth = minWidth;
+void FixedTableLayout::applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
+{
+ Length tableLogicalWidth = m_table->style()->logicalWidth();
+ if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive())
+ minWidth = maxWidth = max<int>(minWidth, tableLogicalWidth.value() - m_table->bordersPaddingAndSpacingInRowDirection());
- // This quirk is very similar to one that exists in RenderBlock::calcBlockPrefWidths().
- // Here's the example for this one:
/*
<table style="width:100%; background-color:red"><tr><td>
<table style="background-color:blue"><tr><td>
@@ -211,7 +211,7 @@ void FixedTableLayout::layout()
// FIXME: It is possible to be called without having properly updated our internal representation.
// This means that our preferred logical widths were not recomputed as expected.
if (nEffCols != m_width.size()) {
- calcWidthArray(tableLogicalWidth);
+ calcWidthArray();
// FIXME: Table layout shouldn't modify our table structure (but does due to columns and column-groups).
nEffCols = m_table->numEffCols();
}
diff --git a/Source/WebCore/rendering/FixedTableLayout.h b/Source/WebCore/rendering/FixedTableLayout.h
index 21ed65c51..68ba08468 100644
--- a/Source/WebCore/rendering/FixedTableLayout.h
+++ b/Source/WebCore/rendering/FixedTableLayout.h
@@ -34,11 +34,12 @@ class FixedTableLayout : public TableLayout {
public:
FixedTableLayout(RenderTable*);
- virtual void computePreferredLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth);
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) OVERRIDE;
+ virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE;
virtual void layout();
private:
- int calcWidthArray(int tableWidth);
+ int calcWidthArray();
Vector<Length> m_width;
};
diff --git a/Source/WebCore/rendering/FlowThreadController.cpp b/Source/WebCore/rendering/FlowThreadController.cpp
index 3759a43e1..e0f1c6713 100644
--- a/Source/WebCore/rendering/FlowThreadController.cpp
+++ b/Source/WebCore/rendering/FlowThreadController.cpp
@@ -49,7 +49,7 @@ FlowThreadController::FlowThreadController(RenderView* view)
: m_view(view)
, m_currentRenderFlowThread(0)
, m_isRenderNamedFlowThreadOrderDirty(false)
- , m_autoLogicalHeightRegionsCount(0)
+ , m_flowThreadsWithAutoLogicalHeightRegions(0)
{
}
@@ -74,7 +74,7 @@ RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(cons
// Sanity check for the absence of a named flow in the "CREATED" state with the same name.
ASSERT(!namedFlows->flowByName(name));
- RenderNamedFlowThread* flowRenderer = new (m_view->renderArena()) RenderNamedFlowThread(m_view->document(), namedFlows->ensureFlowWithName(name));
+ RenderNamedFlowThread* flowRenderer = RenderNamedFlowThread::createAnonymous(m_view->document(), namedFlows->ensureFlowWithName(name));
flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style()));
m_renderNamedFlowThreadList->add(flowRenderer);
@@ -97,9 +97,39 @@ void FlowThreadController::styleDidChange()
void FlowThreadController::layoutRenderNamedFlowThreads()
{
- ASSERT(m_renderNamedFlowThreadList);
+ updateFlowThreadsChainIfNecessary();
+
+ for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
+ RenderNamedFlowThread* flowRenderer = *iter;
+ flowRenderer->layoutIfNeeded();
+ }
+}
+
+void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow)
+{
+ ASSERT(contentNode && contentNode->isElementNode());
+ ASSERT(namedFlow);
+ ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode));
+ ASSERT(!namedFlow->hasContentNode(contentNode));
+ m_mapNamedFlowContentNodes.add(contentNode, namedFlow);
+ namedFlow->registerNamedFlowContentNode(contentNode);
+}
+
+void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode)
+{
+ ASSERT(contentNode && contentNode->isElementNode());
+ HashMap<const Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode);
+ ASSERT(it != m_mapNamedFlowContentNodes.end());
+ ASSERT(it->value);
+ ASSERT(it->value->hasContentNode(contentNode));
+ it->value->unregisterNamedFlowContentNode(contentNode);
+ m_mapNamedFlowContentNodes.remove(contentNode);
+}
- ASSERT(isAutoLogicalHeightRegionsFlagConsistent());
+void FlowThreadController::updateFlowThreadsChainIfNecessary()
+{
+ ASSERT(m_renderNamedFlowThreadList);
+ ASSERT(isAutoLogicalHeightRegionsCountConsistent());
// Remove the left-over flow threads.
RenderNamedFlowThreadList toRemoveList;
@@ -131,63 +161,90 @@ void FlowThreadController::layoutRenderNamedFlowThreads()
m_renderNamedFlowThreadList->swap(sortedList);
setIsRenderNamedFlowThreadOrderDirty(false);
}
+}
+
+bool FlowThreadController::updateFlowThreadsNeedingLayout()
+{
+ bool needsTwoPassLayout = false;
for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
RenderNamedFlowThread* flowRenderer = *iter;
- flowRenderer->layoutIfNeeded();
+ ASSERT(!flowRenderer->needsTwoPhasesLayout());
+ flowRenderer->setInConstrainedLayoutPhase(false);
+ if (flowRenderer->needsLayout() && flowRenderer->hasAutoLogicalHeightRegions())
+ needsTwoPassLayout = true;
}
-}
-void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow)
-{
- ASSERT(contentNode && contentNode->isElementNode());
- ASSERT(namedFlow);
- ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode));
- ASSERT(!namedFlow->hasContentNode(contentNode));
- m_mapNamedFlowContentNodes.add(contentNode, namedFlow);
- namedFlow->registerNamedFlowContentNode(contentNode);
+ if (needsTwoPassLayout)
+ resetFlowThreadsWithAutoHeightRegions();
+
+ return needsTwoPassLayout;
}
-void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode)
+bool FlowThreadController::updateFlowThreadsNeedingTwoStepLayout()
{
- ASSERT(contentNode && contentNode->isElementNode());
- HashMap<Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode);
- ASSERT(it != m_mapNamedFlowContentNodes.end());
- ASSERT(it->value);
- ASSERT(it->value->hasContentNode(contentNode));
- it->value->unregisterNamedFlowContentNode(contentNode);
- m_mapNamedFlowContentNodes.remove(contentNode);
+ bool needsTwoPassLayout = false;
+
+ for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
+ RenderNamedFlowThread* flowRenderer = *iter;
+ if (flowRenderer->needsTwoPhasesLayout()) {
+ needsTwoPassLayout = true;
+ break;
+ }
+ }
+
+ if (needsTwoPassLayout)
+ resetFlowThreadsWithAutoHeightRegions();
+
+ return needsTwoPassLayout;
}
-#ifndef NDEBUG
-bool FlowThreadController::isAutoLogicalHeightRegionsFlagConsistent() const
+void FlowThreadController::resetFlowThreadsWithAutoHeightRegions()
{
- if (!hasRenderNamedFlowThreads())
- return !hasAutoLogicalHeightRegions();
-
- // Count the number of auto height regions
- unsigned autoLogicalHeightRegions = 0;
for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
RenderNamedFlowThread* flowRenderer = *iter;
- autoLogicalHeightRegions += flowRenderer->autoLogicalHeightRegionsCount();
+ if (flowRenderer->hasAutoLogicalHeightRegions()) {
+ flowRenderer->markAutoLogicalHeightRegionsForLayout();
+ flowRenderer->invalidateRegions();
+ }
}
+}
- return autoLogicalHeightRegions == m_autoLogicalHeightRegionsCount;
+void FlowThreadController::updateFlowThreadsIntoConstrainedPhase()
+{
+ // Walk the flow chain in reverse order to update the auto-height regions and compute correct sizes for the containing regions. Only after this we can
+ // set the flow in the constrained layout phase.
+ for (RenderNamedFlowThreadList::reverse_iterator iter = m_renderNamedFlowThreadList->rbegin(); iter != m_renderNamedFlowThreadList->rend(); ++iter) {
+ RenderNamedFlowThread* flowRenderer = *iter;
+ ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo());
+ flowRenderer->layoutIfNeeded();
+ if (flowRenderer->hasAutoLogicalHeightRegions()) {
+ ASSERT(flowRenderer->needsTwoPhasesLayout());
+ flowRenderer->markAutoLogicalHeightRegionsForLayout();
+ }
+ flowRenderer->setInConstrainedLayoutPhase(true);
+ flowRenderer->clearNeedsTwoPhasesLayout();
+ }
}
-#endif
-void FlowThreadController::resetRegionsOverrideLogicalContentHeight()
+bool FlowThreadController::isContentNodeRegisteredWithAnyNamedFlow(const Node* contentNode) const
{
- ASSERT(m_view->normalLayoutPhase());
- for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter)
- (*iter)->resetRegionsOverrideLogicalContentHeight();
+ return m_mapNamedFlowContentNodes.contains(contentNode);
}
-void FlowThreadController::markAutoLogicalHeightRegionsForLayout()
+#ifndef NDEBUG
+bool FlowThreadController::isAutoLogicalHeightRegionsCountConsistent() const
{
- ASSERT(m_view->constrainedFlowThreadsLayoutPhase());
- for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter)
- (*iter)->markAutoLogicalHeightRegionsForLayout();
+ if (!hasRenderNamedFlowThreads())
+ return !hasFlowThreadsWithAutoLogicalHeightRegions();
+
+ for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
+ if (!(*iter)->isAutoLogicalHeightRegionsCountConsistent())
+ return false;
+ }
+
+ return true;
}
+#endif
} // namespace WebCore
diff --git a/Source/WebCore/rendering/FlowThreadController.h b/Source/WebCore/rendering/FlowThreadController.h
index 86780d4b1..ec8c74c68 100644
--- a/Source/WebCore/rendering/FlowThreadController.h
+++ b/Source/WebCore/rendering/FlowThreadController.h
@@ -66,29 +66,33 @@ public:
void registerNamedFlowContentNode(Node*, RenderNamedFlowThread*);
void unregisterNamedFlowContentNode(Node*);
+ bool isContentNodeRegisteredWithAnyNamedFlow(const Node*) const;
- bool hasAutoLogicalHeightRegions() const { return m_autoLogicalHeightRegionsCount; }
- void incrementAutoLogicalHeightRegions() { ++m_autoLogicalHeightRegionsCount; }
- void decrementAutoLogicalHeightRegions() { ASSERT(m_autoLogicalHeightRegionsCount > 0); --m_autoLogicalHeightRegionsCount; }
+ bool hasFlowThreadsWithAutoLogicalHeightRegions() const { return m_flowThreadsWithAutoLogicalHeightRegions; }
+ void incrementFlowThreadsWithAutoLogicalHeightRegions() { ++m_flowThreadsWithAutoLogicalHeightRegions; }
+ void decrementFlowThreadsWithAutoLogicalHeightRegions() { ASSERT(m_flowThreadsWithAutoLogicalHeightRegions > 0); --m_flowThreadsWithAutoLogicalHeightRegions; }
+
+ bool updateFlowThreadsNeedingLayout();
+ bool updateFlowThreadsNeedingTwoStepLayout();
+ void updateFlowThreadsIntoConstrainedPhase();
#ifndef NDEBUG
- bool isAutoLogicalHeightRegionsFlagConsistent() const;
+ bool isAutoLogicalHeightRegionsCountConsistent() const;
#endif
- void resetRegionsOverrideLogicalContentHeight();
- void markAutoLogicalHeightRegionsForLayout();
-
protected:
FlowThreadController(RenderView*);
+ void updateFlowThreadsChainIfNecessary();
+ void resetFlowThreadsWithAutoHeightRegions();
private:
RenderView* m_view;
RenderFlowThread* m_currentRenderFlowThread;
bool m_isRenderNamedFlowThreadOrderDirty;
- unsigned m_autoLogicalHeightRegionsCount;
+ unsigned m_flowThreadsWithAutoLogicalHeightRegions;
OwnPtr<RenderNamedFlowThreadList> m_renderNamedFlowThreadList;
// maps a content node to its render flow thread.
- HashMap<Node*, RenderNamedFlowThread*> m_mapNamedFlowContentNodes;
+ HashMap<const Node*, RenderNamedFlowThread*> m_mapNamedFlowContentNodes;
};
}
diff --git a/Source/WebCore/rendering/HitTestLocation.cpp b/Source/WebCore/rendering/HitTestLocation.cpp
new file mode 100644
index 000000000..118a38db2
--- /dev/null
+++ b/Source/WebCore/rendering/HitTestLocation.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2006, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+*/
+
+#include "config.h"
+#include "HitTestLocation.h"
+
+#include "CachedImage.h"
+#include "DocumentMarkerController.h"
+#include "Frame.h"
+#include "FrameSelection.h"
+#include "FrameTree.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
+#include "HTMLPlugInImageElement.h"
+#include "HTMLVideoElement.h"
+#include "RenderBlock.h"
+#include "RenderImage.h"
+#include "RenderInline.h"
+#include "Scrollbar.h"
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#include "XLinkNames.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HitTestLocation::HitTestLocation()
+ : m_region(0)
+ , m_isRectBased(false)
+ , m_isRectilinear(true)
+{
+}
+
+HitTestLocation::HitTestLocation(const LayoutPoint& point)
+ : m_point(point)
+ , m_boundingBox(rectForPoint(point, 0, 0, 0, 0))
+ , m_transformedPoint(point)
+ , m_transformedRect(m_boundingBox)
+ , m_region(0)
+ , m_isRectBased(false)
+ , m_isRectilinear(true)
+{
+}
+
+HitTestLocation::HitTestLocation(const FloatPoint& point)
+ : m_point(flooredLayoutPoint(point))
+ , m_boundingBox(rectForPoint(m_point, 0, 0, 0, 0))
+ , m_transformedPoint(point)
+ , m_transformedRect(m_boundingBox)
+ , m_region(0)
+ , m_isRectBased(false)
+ , m_isRectilinear(true)
+{
+}
+
+HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad)
+ : m_transformedPoint(point)
+ , m_transformedRect(quad)
+ , m_region(0)
+ , m_isRectBased(true)
+{
+ m_point = flooredLayoutPoint(point);
+ m_boundingBox = enclosingIntRect(quad.boundingBox());
+ m_isRectilinear = quad.isRectilinear();
+}
+
+HitTestLocation::HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
+ : m_point(centerPoint)
+ , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding))
+ , m_transformedPoint(centerPoint)
+ , m_region(0)
+ , m_isRectBased(topPadding || rightPadding || bottomPadding || leftPadding)
+ , m_isRectilinear(true)
+{
+ m_transformedRect = FloatQuad(m_boundingBox);
+}
+
+HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset, RenderRegion* region)
+ : m_point(other.m_point)
+ , m_boundingBox(other.m_boundingBox)
+ , m_transformedPoint(other.m_transformedPoint)
+ , m_transformedRect(other.m_transformedRect)
+ , m_region(region ? region : other.m_region)
+ , m_isRectBased(other.m_isRectBased)
+ , m_isRectilinear(other.m_isRectilinear)
+{
+ move(offset);
+}
+
+HitTestLocation::HitTestLocation(const HitTestLocation& other)
+ : m_point(other.m_point)
+ , m_boundingBox(other.m_boundingBox)
+ , m_transformedPoint(other.m_transformedPoint)
+ , m_transformedRect(other.m_transformedRect)
+ , m_region(other.m_region)
+ , m_isRectBased(other.m_isRectBased)
+ , m_isRectilinear(other.m_isRectilinear)
+{
+}
+
+HitTestLocation::~HitTestLocation()
+{
+}
+
+HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other)
+{
+ m_point = other.m_point;
+ m_boundingBox = other.m_boundingBox;
+ m_transformedPoint = other.m_transformedPoint;
+ m_transformedRect = other.m_transformedRect;
+ m_region = other.m_region;
+ m_isRectBased = other.m_isRectBased;
+ m_isRectilinear = other.m_isRectilinear;
+
+ return *this;
+}
+
+void HitTestLocation::move(const LayoutSize& offset)
+{
+ m_point.move(offset);
+ m_transformedPoint.move(offset);
+ m_transformedRect.move(offset);
+ m_boundingBox = enclosingIntRect(m_transformedRect.boundingBox());
+}
+
+template<typename RectType>
+bool HitTestLocation::intersectsRect(const RectType& rect) const
+{
+ // FIXME: When the hit test is not rect based we should use rect.contains(m_point).
+ // That does change some corner case tests though.
+
+ // First check if rect even intersects our bounding box.
+ if (!rect.intersects(m_boundingBox))
+ return false;
+
+ // If the transformed rect is rectilinear the bounding box intersection was accurate.
+ if (m_isRectilinear)
+ return true;
+
+ // If rect fully contains our bounding box, we are also sure of an intersection.
+ if (rect.contains(m_boundingBox))
+ return true;
+
+ // Otherwise we need to do a slower quad based intersection test.
+ return m_transformedRect.intersectsRect(rect);
+}
+
+bool HitTestLocation::intersects(const LayoutRect& rect) const
+{
+ return intersectsRect(rect);
+}
+
+bool HitTestLocation::intersects(const FloatRect& rect) const
+{
+ return intersectsRect(rect);
+}
+
+bool HitTestLocation::intersects(const RoundedRect& rect) const
+{
+ return rect.intersectsQuad(m_transformedRect);
+}
+
+IntRect HitTestLocation::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
+{
+ IntPoint actualPoint(flooredIntPoint(point));
+ actualPoint -= IntSize(leftPadding, topPadding);
+
+ IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding);
+ // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1".
+ // FIXME: Remove this once non-rect based hit-detection stops using IntRect:intersects.
+ actualPadding += IntSize(1, 1);
+
+ return IntRect(actualPoint, actualPadding);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/HitTestLocation.h b/Source/WebCore/rendering/HitTestLocation.h
new file mode 100644
index 000000000..5efe5f77d
--- /dev/null
+++ b/Source/WebCore/rendering/HitTestLocation.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+*/
+
+#ifndef HitTestLocation_h
+#define HitTestLocation_h
+
+#include "FloatQuad.h"
+#include "FloatRect.h"
+#include "HitTestRequest.h"
+#include "LayoutRect.h"
+#include "RoundedRect.h"
+#include "TextDirection.h"
+#include <wtf/Forward.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Element;
+class Frame;
+#if ENABLE(VIDEO)
+class HTMLMediaElement;
+#endif
+class Image;
+class KURL;
+class Node;
+class RenderRegion;
+class Scrollbar;
+
+class HitTestLocation {
+public:
+
+ HitTestLocation();
+ HitTestLocation(const LayoutPoint&);
+ HitTestLocation(const FloatPoint&);
+ HitTestLocation(const FloatPoint&, const FloatQuad&);
+ // Pass non-zero padding values to perform a rect-based hit test.
+ HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
+ // Make a copy the HitTestLocation in a new region by applying given offset to internal point and area.
+ HitTestLocation(const HitTestLocation&, const LayoutSize& offset, RenderRegion* = 0);
+ HitTestLocation(const HitTestLocation&);
+ ~HitTestLocation();
+ HitTestLocation& operator=(const HitTestLocation&);
+
+ const LayoutPoint& point() const { return m_point; }
+ IntPoint roundedPoint() const { return roundedIntPoint(m_point); }
+
+ RenderRegion* region() const { return m_region; }
+
+ // Rect-based hit test related methods.
+ bool isRectBasedTest() const { return m_isRectBased; }
+ bool isRectilinear() const { return m_isRectilinear; }
+ IntRect boundingBox() const { return m_boundingBox; }
+
+ static IntRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
+ int topPadding() const { return roundedPoint().y() - m_boundingBox.y(); }
+ int rightPadding() const { return m_boundingBox.maxX() - roundedPoint().x() - 1; }
+ int bottomPadding() const { return m_boundingBox.maxY() - roundedPoint().y() - 1; }
+ int leftPadding() const { return roundedPoint().x() - m_boundingBox.x(); }
+
+ bool intersects(const LayoutRect&) const;
+ bool intersects(const FloatRect&) const;
+ bool intersects(const RoundedRect&) const;
+
+ const FloatPoint& transformedPoint() const { return m_transformedPoint; }
+ const FloatQuad& transformedRect() const { return m_transformedRect; }
+
+private:
+ template<typename RectType>
+ bool intersectsRect(const RectType&) const;
+ void move(const LayoutSize& offset);
+
+ // This is cached forms of the more accurate point and area below.
+ LayoutPoint m_point;
+ IntRect m_boundingBox;
+
+ FloatPoint m_transformedPoint;
+ FloatQuad m_transformedRect;
+
+ RenderRegion* m_region; // The region we're inside.
+
+ bool m_isRectBased;
+ bool m_isRectilinear;
+};
+
+} // namespace WebCore
+
+#endif // HitTestLocation_h
diff --git a/Source/WebCore/rendering/HitTestRequest.h b/Source/WebCore/rendering/HitTestRequest.h
index d937c2504..40d8d5fe5 100644
--- a/Source/WebCore/rendering/HitTestRequest.h
+++ b/Source/WebCore/rendering/HitTestRequest.h
@@ -35,7 +35,11 @@ public:
IgnoreClipping = 1 << 5,
SVGClipContent = 1 << 6,
TouchEvent = 1 << 7,
- AllowShadowContent = 1 << 8
+ DisallowShadowContent = 1 << 8,
+ AllowFrameScrollbars = 1 << 9,
+ AllowChildFrameContent = 1 << 10,
+ ChildFrameHitTest = 1 << 11,
+ AccessibilityHitTest = 1 << 12
};
typedef unsigned HitTestRequestType;
@@ -53,7 +57,10 @@ public:
bool svgClipContent() const { return m_requestType & SVGClipContent; }
bool touchEvent() const { return m_requestType & TouchEvent; }
bool mouseEvent() const { return !touchEvent(); }
- bool allowsShadowContent() const { return m_requestType & AllowShadowContent; }
+ bool disallowsShadowContent() const { return m_requestType & DisallowShadowContent; }
+ bool allowsFrameScrollbars() const { return m_requestType & AllowFrameScrollbars; }
+ bool allowsChildFrameContent() const { return m_requestType & AllowChildFrameContent; }
+ bool isChildFrameHitTest() const { return m_requestType & ChildFrameHitTest; }
// Convenience functions
bool touchMove() const { return move() && touchEvent(); }
diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp
index 38f1f679f..e0ecdbba0 100644
--- a/Source/WebCore/rendering/HitTestResult.cpp
+++ b/Source/WebCore/rendering/HitTestResult.cpp
@@ -22,24 +22,32 @@
#include "config.h"
#include "HitTestResult.h"
+#include "CachedImage.h"
#include "DocumentMarkerController.h"
+#include "Editor.h"
#include "Frame.h"
#include "FrameSelection.h"
#include "FrameTree.h"
#include "HTMLAnchorElement.h"
-#include "HTMLVideoElement.h"
+#include "HTMLAreaElement.h"
+#include "HTMLAudioElement.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
#include "HTMLPlugInImageElement.h"
+#include "HTMLTextAreaElement.h"
+#include "HTMLVideoElement.h"
+#include "HitTestLocation.h"
#include "RenderBlock.h"
#include "RenderImage.h"
#include "RenderInline.h"
#include "Scrollbar.h"
+#include "UserGestureIndicator.h"
#if ENABLE(SVG)
+#include "SVGImageElement.h"
#include "SVGNames.h"
#include "XLinkNames.h"
#endif
@@ -48,150 +56,6 @@ namespace WebCore {
using namespace HTMLNames;
-HitTestLocation::HitTestLocation()
- : m_region(0)
- , m_isRectBased(false)
- , m_isRectilinear(true)
-{
-}
-
-HitTestLocation::HitTestLocation(const LayoutPoint& point)
- : m_point(point)
- , m_boundingBox(rectForPoint(point, 0, 0, 0, 0))
- , m_transformedPoint(point)
- , m_transformedRect(m_boundingBox)
- , m_region(0)
- , m_isRectBased(false)
- , m_isRectilinear(true)
-{
-}
-
-HitTestLocation::HitTestLocation(const FloatPoint& point)
- : m_point(flooredLayoutPoint(point))
- , m_boundingBox(rectForPoint(m_point, 0, 0, 0, 0))
- , m_transformedPoint(point)
- , m_transformedRect(m_boundingBox)
- , m_region(0)
- , m_isRectBased(false)
- , m_isRectilinear(true)
-{
-}
-
-HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad)
- : m_transformedPoint(point)
- , m_transformedRect(quad)
- , m_region(0)
- , m_isRectBased(true)
-{
- m_point = flooredLayoutPoint(point);
- m_boundingBox = enclosingIntRect(quad.boundingBox());
- m_isRectilinear = quad.isRectilinear();
-}
-
-HitTestLocation::HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
- : m_point(centerPoint)
- , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding))
- , m_transformedPoint(centerPoint)
- , m_region(0)
- , m_isRectBased(topPadding || rightPadding || bottomPadding || leftPadding)
- , m_isRectilinear(true)
-{
- m_transformedRect = FloatQuad(m_boundingBox);
-}
-
-HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset, RenderRegion* region)
- : m_point(other.m_point)
- , m_boundingBox(other.m_boundingBox)
- , m_transformedPoint(other.m_transformedPoint)
- , m_transformedRect(other.m_transformedRect)
- , m_region(region ? region : other.m_region)
- , m_isRectBased(other.m_isRectBased)
- , m_isRectilinear(other.m_isRectilinear)
-{
- move(offset);
-}
-
-HitTestLocation::HitTestLocation(const HitTestLocation& other)
- : m_point(other.m_point)
- , m_boundingBox(other.m_boundingBox)
- , m_transformedPoint(other.m_transformedPoint)
- , m_transformedRect(other.m_transformedRect)
- , m_region(other.m_region)
- , m_isRectBased(other.m_isRectBased)
- , m_isRectilinear(other.m_isRectilinear)
-{
-}
-
-HitTestLocation::~HitTestLocation()
-{
-}
-
-HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other)
-{
- m_point = other.m_point;
- m_boundingBox = other.m_boundingBox;
- m_transformedPoint = other.m_transformedPoint;
- m_transformedRect = other.m_transformedRect;
- m_region = other.m_region;
- m_isRectBased = other.m_isRectBased;
- m_isRectilinear = other.m_isRectilinear;
-
- return *this;
-}
-
-void HitTestLocation::move(const LayoutSize& offset)
-{
- m_point.move(offset);
- m_transformedPoint.move(offset);
- m_transformedRect.move(offset);
- m_boundingBox = enclosingIntRect(m_transformedRect.boundingBox());
-}
-
-template<typename RectType>
-bool HitTestLocation::intersectsRect(const RectType& rect) const
-{
- // FIXME: When the hit test is not rect based we should use rect.contains(m_point).
- // That does change some corner case tests though.
-
- // First check if rect even intersects our bounding box.
- if (!rect.intersects(m_boundingBox))
- return false;
-
- // If the transformed rect is rectilinear the bounding box intersection was accurate.
- if (m_isRectilinear)
- return true;
-
- // If rect fully contains our bounding box, we are also sure of an intersection.
- if (rect.contains(m_boundingBox))
- return true;
-
- // Otherwise we need to do a slower quad based intersection test.
- return m_transformedRect.intersectsRect(rect);
-}
-
-bool HitTestLocation::intersects(const LayoutRect& rect) const
-{
- return intersectsRect(rect);
-}
-
-bool HitTestLocation::intersects(const FloatRect& rect) const
-{
- return intersectsRect(rect);
-}
-
-IntRect HitTestLocation::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
-{
- IntPoint actualPoint(flooredIntPoint(point));
- actualPoint -= IntSize(leftPadding, topPadding);
-
- IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding);
- // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1".
- // FIXME: Remove this once non-rect based hit-detection stops using IntRect:intersects.
- actualPadding += IntSize(1, 1);
-
- return IntRect(actualPoint, actualPadding);
-}
-
HitTestResult::HitTestResult()
: m_isOverWidget(false)
{
@@ -199,21 +63,21 @@ HitTestResult::HitTestResult()
HitTestResult::HitTestResult(const LayoutPoint& point)
: m_hitTestLocation(point)
- , m_pointInMainFrame(point)
+ , m_pointInInnerNodeFrame(point)
, m_isOverWidget(false)
{
}
HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
: m_hitTestLocation(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding)
- , m_pointInMainFrame(centerPoint)
+ , m_pointInInnerNodeFrame(centerPoint)
, m_isOverWidget(false)
{
}
HitTestResult::HitTestResult(const HitTestLocation& other)
: m_hitTestLocation(other)
- , m_pointInMainFrame(m_hitTestLocation.point())
+ , m_pointInInnerNodeFrame(m_hitTestLocation.point())
, m_isOverWidget(false)
{
}
@@ -222,7 +86,7 @@ HitTestResult::HitTestResult(const HitTestResult& other)
: m_hitTestLocation(other.m_hitTestLocation)
, m_innerNode(other.innerNode())
, m_innerNonSharedNode(other.innerNonSharedNode())
- , m_pointInMainFrame(other.m_pointInMainFrame)
+ , m_pointInInnerNodeFrame(other.m_pointInInnerNodeFrame)
, m_localPoint(other.localPoint())
, m_innerURLElement(other.URLElement())
, m_scrollbar(other.scrollbar())
@@ -241,7 +105,7 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other)
m_hitTestLocation = other.m_hitTestLocation;
m_innerNode = other.innerNode();
m_innerNonSharedNode = other.innerNonSharedNode();
- m_pointInMainFrame = other.m_pointInMainFrame;
+ m_pointInInnerNodeFrame = other.m_pointInInnerNodeFrame;
m_localPoint = other.localPoint();
m_innerURLElement = other.URLElement();
m_scrollbar = other.scrollbar();
@@ -257,21 +121,25 @@ void HitTestResult::setToNonShadowAncestor()
{
Node* node = innerNode();
if (node)
- node = node->shadowAncestorNode();
+ node = node->document()->ancestorInThisScope(node);
setInnerNode(node);
node = innerNonSharedNode();
if (node)
- node = node->shadowAncestorNode();
+ node = node->document()->ancestorInThisScope(node);
setInnerNonSharedNode(node);
}
void HitTestResult::setInnerNode(Node* n)
{
+ if (n && n->isPseudoElement())
+ n = n->parentOrShadowHostNode();
m_innerNode = n;
}
void HitTestResult::setInnerNonSharedNode(Node* n)
{
+ if (n && n->isPseudoElement())
+ n = n->parentOrShadowHostNode();
m_innerNonSharedNode = n;
}
@@ -356,7 +224,7 @@ String HitTestResult::title(TextDirection& dir) const
// For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) {
if (titleNode->isElementNode()) {
- String title = static_cast<Element*>(titleNode)->title();
+ String title = toElement(titleNode)->title();
if (!title.isEmpty()) {
if (RenderObject* renderer = titleNode->renderer())
dir = renderer->style()->direction();
@@ -405,13 +273,13 @@ String HitTestResult::altDisplayString() const
if (!m_innerNonSharedNode)
return String();
- if (m_innerNonSharedNode->hasTagName(imgTag)) {
- HTMLImageElement* image = static_cast<HTMLImageElement*>(m_innerNonSharedNode.get());
+ if (isHTMLImageElement(m_innerNonSharedNode.get())) {
+ HTMLImageElement* image = toHTMLImageElement(m_innerNonSharedNode.get());
return displayString(image->getAttribute(altAttr), m_innerNonSharedNode.get());
}
- if (m_innerNonSharedNode->hasTagName(inputTag)) {
- HTMLInputElement* input = static_cast<HTMLInputElement*>(m_innerNonSharedNode.get());
+ if (isHTMLInputElement(m_innerNonSharedNode.get())) {
+ HTMLInputElement* input = toHTMLInputElement(m_innerNonSharedNode.get());
return displayString(input->alt(), m_innerNonSharedNode.get());
}
@@ -450,15 +318,15 @@ KURL HitTestResult::absoluteImageURL() const
AtomicString urlString;
if (m_innerNonSharedNode->hasTagName(embedTag)
- || m_innerNonSharedNode->hasTagName(imgTag)
- || m_innerNonSharedNode->hasTagName(inputTag)
- || m_innerNonSharedNode->hasTagName(objectTag)
+ || isHTMLImageElement(m_innerNonSharedNode.get())
+ || isHTMLInputElement(m_innerNonSharedNode.get())
+ || m_innerNonSharedNode->hasTagName(objectTag)
#if ENABLE(SVG)
- || m_innerNonSharedNode->hasTagName(SVGNames::imageTag)
+ || isSVGImageElement(m_innerNonSharedNode.get())
#endif
) {
- Element* element = static_cast<Element*>(m_innerNonSharedNode.get());
- urlString = element->getAttribute(element->imageSourceAttributeName());
+ Element* element = toElement(m_innerNonSharedNode.get());
+ urlString = element->imageSourceURL();
} else
return KURL();
@@ -473,7 +341,7 @@ KURL HitTestResult::absolutePDFURL() const
if (!m_innerNonSharedNode->hasTagName(embedTag) && !m_innerNonSharedNode->hasTagName(objectTag))
return KURL();
- HTMLPlugInImageElement* element = static_cast<HTMLPlugInImageElement*>(m_innerNonSharedNode.get());
+ HTMLPlugInImageElement* element = toHTMLPlugInImageElement(m_innerNonSharedNode.get());
KURL url = m_innerNonSharedNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(element->url()));
if (!url.isValid())
return KURL();
@@ -513,8 +381,8 @@ HTMLMediaElement* HitTestResult::mediaElement() const
if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isMedia()))
return 0;
- if (m_innerNonSharedNode->hasTagName(HTMLNames::videoTag) || m_innerNonSharedNode->hasTagName(HTMLNames::audioTag))
- return static_cast<HTMLMediaElement*>(m_innerNonSharedNode.get());
+ if (m_innerNonSharedNode->hasTagName(HTMLNames::videoTag) || isHTMLAudioElement(m_innerNonSharedNode.get()))
+ return toHTMLMediaElement(m_innerNonSharedNode.get());
return 0;
}
#endif
@@ -535,14 +403,37 @@ void HitTestResult::toggleMediaLoopPlayback() const
#endif
}
+bool HitTestResult::mediaIsInFullscreen() const
+{
+#if ENABLE(VIDEO)
+ if (HTMLMediaElement* mediaElement = this->mediaElement())
+ return mediaElement->isVideo() && mediaElement->isFullscreen();
+#endif
+ return false;
+}
+
+void HitTestResult::toggleMediaFullscreenState() const
+{
+#if ENABLE(VIDEO)
+ if (HTMLMediaElement* mediaElement = this->mediaElement()) {
+ if (mediaElement->isVideo() && mediaElement->supportsFullscreen()) {
+ UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
+ mediaElement->toggleFullscreenState();
+ }
+ }
+#endif
+}
+
void HitTestResult::enterFullscreenForVideo() const
{
#if ENABLE(VIDEO)
HTMLMediaElement* mediaElt(mediaElement());
if (mediaElt && mediaElt->hasTagName(HTMLNames::videoTag)) {
- HTMLVideoElement* videoElt = static_cast<HTMLVideoElement*>(mediaElt);
- if (!videoElt->isFullscreen() && mediaElt->supportsFullscreen())
+ HTMLVideoElement* videoElt = toHTMLVideoElement(mediaElt);
+ if (!videoElt->isFullscreen() && mediaElt->supportsFullscreen()) {
+ UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
videoElt->enterFullscreen();
+ }
}
#endif
}
@@ -623,7 +514,7 @@ KURL HitTestResult::absoluteLinkURL() const
return KURL();
AtomicString urlString;
- if (m_innerURLElement->hasTagName(aTag) || m_innerURLElement->hasTagName(areaTag) || m_innerURLElement->hasTagName(linkTag))
+ if (isHTMLAnchorElement(m_innerURLElement.get()) || isHTMLAreaElement(m_innerURLElement.get()) || m_innerURLElement->hasTagName(linkTag))
urlString = m_innerURLElement->getAttribute(hrefAttr);
#if ENABLE(SVG)
else if (m_innerURLElement->hasTagName(SVGNames::aTag))
@@ -640,8 +531,8 @@ bool HitTestResult::isLiveLink() const
if (!(m_innerURLElement && m_innerURLElement->document()))
return false;
- if (m_innerURLElement->hasTagName(aTag))
- return static_cast<HTMLAnchorElement*>(m_innerURLElement.get())->isLiveLink();
+ if (isHTMLAnchorElement(m_innerURLElement.get()))
+ return toHTMLAnchorElement(m_innerURLElement.get())->isLiveLink();
#if ENABLE(SVG)
if (m_innerURLElement->hasTagName(SVGNames::aTag))
return m_innerURLElement->isLink();
@@ -650,6 +541,11 @@ bool HitTestResult::isLiveLink() const
return false;
}
+bool HitTestResult::isOverLink() const
+{
+ return m_innerURLElement && m_innerURLElement->isLink();
+}
+
String HitTestResult::titleDisplayString() const
{
if (!m_innerURLElement)
@@ -674,11 +570,11 @@ bool HitTestResult::isContentEditable() const
if (!m_innerNonSharedNode)
return false;
- if (m_innerNonSharedNode->hasTagName(textareaTag))
+ if (isHTMLTextAreaElement(m_innerNonSharedNode.get()))
return true;
- if (m_innerNonSharedNode->hasTagName(inputTag))
- return static_cast<HTMLInputElement*>(m_innerNonSharedNode.get())->isTextField();
+ if (isHTMLInputElement(m_innerNonSharedNode.get()))
+ return toHTMLInputElement(m_innerNonSharedNode.get())->isTextField();
return m_innerNonSharedNode->rendererIsEditable();
}
@@ -694,8 +590,8 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestReques
if (!node)
return true;
- if (!request.allowsShadowContent())
- node = node->shadowAncestorNode();
+ if (request.disallowsShadowContent())
+ node = node->document()->ancestorInThisScope(node);
mutableRectBasedTestResult().add(node);
@@ -714,8 +610,8 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestReques
if (!node)
return true;
- if (!request.allowsShadowContent())
- node = node->shadowAncestorNode();
+ if (request.disallowsShadowContent())
+ node = node->document()->ancestorInThisScope(node);
mutableRectBasedTestResult().add(node);
@@ -731,7 +627,7 @@ void HitTestResult::append(const HitTestResult& other)
m_innerNode = other.innerNode();
m_innerNonSharedNode = other.innerNonSharedNode();
m_localPoint = other.localPoint();
- m_pointInMainFrame = other.m_pointInMainFrame;
+ m_pointInInnerNodeFrame = other.m_pointInInnerNodeFrame;
m_innerURLElement = other.URLElement();
m_scrollbar = other.scrollbar();
m_isOverWidget = other.isOverWidget();
@@ -764,7 +660,7 @@ Vector<String> HitTestResult::dictationAlternatives() const
if (!m_innerNonSharedNode)
return Vector<String>();
- DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(hitTestLocation().point(), DocumentMarker::DictationAlternatives);
+ DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(pointInInnerNodeFrame(), DocumentMarker::DictationAlternatives);
if (!marker)
return Vector<String>();
@@ -772,7 +668,7 @@ Vector<String> HitTestResult::dictationAlternatives() const
if (!frame)
return Vector<String>();
- return frame->editor()->dictationAlternativesForMarker(marker);
+ return frame->editor().dictationAlternativesForMarker(marker);
}
Node* HitTestResult::targetNode() const
@@ -790,4 +686,14 @@ Node* HitTestResult::targetNode() const
return node;
}
+Element* HitTestResult::innerElement() const
+{
+ for (Node* node = m_innerNode.get(); node; node = node->parentNode()) {
+ if (node->isElementNode())
+ return toElement(node);
+ }
+
+ return 0;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h
index 57a41dab5..b6f770345 100644
--- a/Source/WebCore/rendering/HitTestResult.h
+++ b/Source/WebCore/rendering/HitTestResult.h
@@ -24,6 +24,7 @@
#include "FloatQuad.h"
#include "FloatRect.h"
+#include "HitTestLocation.h"
#include "HitTestRequest.h"
#include "LayoutRect.h"
#include "TextDirection.h"
@@ -45,62 +46,6 @@ class Node;
class RenderRegion;
class Scrollbar;
-// FIXME: HitTestLocation should be moved to a separate file.
-class HitTestLocation {
-public:
-
- HitTestLocation();
- HitTestLocation(const LayoutPoint&);
- HitTestLocation(const FloatPoint&);
- HitTestLocation(const FloatPoint&, const FloatQuad&);
- // Pass non-zero padding values to perform a rect-based hit test.
- HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
- // Make a copy the HitTestLocation in a new region by applying given offset to internal point and area.
- HitTestLocation(const HitTestLocation&, const LayoutSize& offset, RenderRegion* = 0);
- HitTestLocation(const HitTestLocation&);
- ~HitTestLocation();
- HitTestLocation& operator=(const HitTestLocation&);
-
- const LayoutPoint& point() const { return m_point; }
- IntPoint roundedPoint() const { return roundedIntPoint(m_point); }
-
- RenderRegion* region() const { return m_region; }
-
- // Rect-based hit test related methods.
- bool isRectBasedTest() const { return m_isRectBased; }
- bool isRectilinear() const { return m_isRectilinear; }
- IntRect boundingBox() const { return m_boundingBox; }
-
- static IntRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
- int topPadding() const { return roundedPoint().y() - m_boundingBox.y(); }
- int rightPadding() const { return m_boundingBox.maxX() - roundedPoint().x() - 1; }
- int bottomPadding() const { return m_boundingBox.maxY() - roundedPoint().y() - 1; }
- int leftPadding() const { return roundedPoint().x() - m_boundingBox.x(); }
-
- bool intersects(const LayoutRect&) const;
- bool intersects(const FloatRect&) const;
-
- const FloatPoint& transformedPoint() const { return m_transformedPoint; }
- const FloatQuad& transformedRect() const { return m_transformedRect; }
-
-private:
- template<typename RectType>
- bool intersectsRect(const RectType&) const;
- void move(const LayoutSize& offset);
-
- // This is cached forms of the more accurate point and area below.
- LayoutPoint m_point;
- IntRect m_boundingBox;
-
- FloatPoint m_transformedPoint;
- FloatQuad m_transformedRect;
-
- RenderRegion* m_region; // The region we're inside.
-
- bool m_isRectBased;
- bool m_isRectilinear;
-};
-
class HitTestResult {
public:
typedef ListHashSet<RefPtr<Node> > NodeSet;
@@ -115,6 +60,7 @@ public:
HitTestResult& operator=(const HitTestResult&);
Node* innerNode() const { return m_innerNode.get(); }
+ Element* innerElement() const;
Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); }
Element* URLElement() const { return m_innerURLElement.get(); }
Scrollbar* scrollbar() const { return m_scrollbar.get(); }
@@ -124,12 +70,11 @@ public:
bool isRectBasedTest() const { return m_hitTestLocation.isRectBasedTest(); }
// The hit-tested point in the coordinates of the main frame.
- const LayoutPoint& pointInMainFrame() const { return m_pointInMainFrame; }
+ const LayoutPoint& pointInMainFrame() const { return m_hitTestLocation.point(); }
IntPoint roundedPointInMainFrame() const { return roundedIntPoint(pointInMainFrame()); }
- void setPointInMainFrame(const LayoutPoint& p) { m_pointInMainFrame = p; }
// The hit-tested point in the coordinates of the innerNode frame, the frame containing innerNode.
- const LayoutPoint& pointInInnerNodeFrame() const { return m_hitTestLocation.point(); }
+ const LayoutPoint& pointInInnerNodeFrame() const { return m_pointInInnerNodeFrame; }
IntPoint roundedPointInInnerNodeFrame() const { return roundedIntPoint(pointInInnerNodeFrame()); }
Frame* innerNodeFrame() const;
@@ -163,9 +108,12 @@ public:
KURL absoluteLinkURL() const;
String textContent() const;
bool isLiveLink() const;
+ bool isOverLink() const;
bool isContentEditable() const;
void toggleMediaControlsDisplay() const;
void toggleMediaLoopPlayback() const;
+ bool mediaIsInFullscreen() const;
+ void toggleMediaFullscreenState() const;
void enterFullscreenForVideo() const;
bool mediaControlsEnabled() const;
bool mediaLoopEnabled() const;
@@ -202,7 +150,7 @@ private:
RefPtr<Node> m_innerNode;
RefPtr<Node> m_innerNonSharedNode;
- LayoutPoint m_pointInMainFrame; // The hit-tested point in main-frame coordinates.
+ LayoutPoint m_pointInInnerNodeFrame; // The hit-tested point in innerNode frame coordinates.
LayoutPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently
// determine where inside the renderer we hit on subsequent operations.
RefPtr<Element> m_innerURLElement;
diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp
index 18079ff0b..883490b37 100644
--- a/Source/WebCore/rendering/InlineBox.cpp
+++ b/Source/WebCore/rendering/InlineBox.cpp
@@ -44,25 +44,23 @@ struct SameSizeAsInlineBox {
FloatPoint b;
float c;
uint32_t d : 32;
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
bool f;
#endif
};
COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
static bool inInlineBoxDetach;
#endif
-#ifndef NDEBUG
-
+#if !ASSERT_DISABLED
InlineBox::~InlineBox()
{
if (!m_hasBadParent && m_parent)
m_parent->setHasBadChildList();
}
-
#endif
void InlineBox::remove()
@@ -73,11 +71,11 @@ void InlineBox::remove()
void InlineBox::destroy(RenderArena* renderArena)
{
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
inInlineBoxDetach = true;
#endif
delete this;
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
inInlineBoxDetach = false;
#endif
@@ -93,7 +91,6 @@ void* InlineBox::operator new(size_t sz, RenderArena* renderArena)
void InlineBox::operator delete(void* ptr, size_t sz)
{
ASSERT(inInlineBoxDetach);
-
// Stash size where destroy can find it.
*(size_t *)ptr = sz;
}
@@ -248,7 +245,11 @@ bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result
// Hit test all phases of replaced elements atomically, as though the replaced element established its
// own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
// specification.)
- return renderer()->hitTest(request, result, locationInContainer, accumulatedOffset);
+ LayoutPoint childPoint = accumulatedOffset;
+ if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
+ childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint);
+
+ return renderer()->hitTest(request, result, locationInContainer, childPoint);
}
const RootInlineBox* InlineBox::root() const
diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h
index e2cf85fdc..2f480c8a9 100644
--- a/Source/WebCore/rendering/InlineBox.h
+++ b/Source/WebCore/rendering/InlineBox.h
@@ -40,7 +40,7 @@ public:
, m_parent(0)
, m_renderer(obj)
, m_logicalWidth(0)
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
, m_hasBadParent(false)
#endif
{
@@ -55,7 +55,7 @@ public:
, m_topLeft(topLeft)
, m_logicalWidth(logicalWidth)
, m_bitfields(firstLine, constructed, dirty, extracted, isHorizontal)
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
, m_hasBadParent(false)
#endif
{
@@ -272,7 +272,7 @@ public:
// visibleLeftEdge, visibleRightEdge are in the parent's coordinate system.
virtual float placeEllipsisBox(bool ltr, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool&);
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
void setHasBadParent();
#endif
@@ -415,19 +415,19 @@ protected:
// For InlineFlowBox and InlineTextBox
bool extracted() const { return m_bitfields.extracted(); }
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
private:
bool m_hasBadParent;
#endif
};
-#ifdef NDEBUG
+#if ASSERT_DISABLED
inline InlineBox::~InlineBox()
{
}
#endif
-#ifndef NDEBUG
+#if !ASSERT_DISABLED
inline void InlineBox::setHasBadParent()
{
m_hasBadParent = true;
diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp
index a0ef3c6c3..654f111b3 100644
--- a/Source/WebCore/rendering/InlineFlowBox.cpp
+++ b/Source/WebCore/rendering/InlineFlowBox.cpp
@@ -20,7 +20,6 @@
#include "config.h"
#include "InlineFlowBox.h"
-#include "CachedImage.h"
#include "CSSPropertyNames.h"
#include "Document.h"
#include "EllipsisBox.h"
@@ -369,15 +368,24 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogically
float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
{
// Set our x position.
- setLogicalLeft(logicalLeft);
-
+ beginPlacingBoxRangesInInlineDirection(logicalLeft);
+
float startLogicalLeft = logicalLeft;
logicalLeft += borderLogicalLeft() + paddingLogicalLeft();
float minLogicalLeft = startLogicalLeft;
float maxLogicalRight = logicalLeft;
- for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ placeBoxRangeInInlineDirection(firstChild(), 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
+
+ logicalLeft += borderLogicalRight() + paddingLogicalRight();
+ endPlacingBoxRangesInInlineDirection(startLogicalLeft, logicalLeft, minLogicalLeft, maxLogicalRight);
+ return logicalLeft;
+}
+
+float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
+{
+ for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) {
if (curr->renderer()->isText()) {
InlineTextBox* text = toInlineTextBox(curr);
RenderText* rt = toRenderText(text->renderer());
@@ -426,14 +434,11 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW
if (knownToHaveNoOverflow())
maxLogicalRight = max(logicalLeft, maxLogicalRight);
logicalLeft += logicalRightMargin;
+ // If we encounter any space after this inline block then ensure it is treated as the space between two words.
+ needsWordSpacing = true;
}
}
}
-
- logicalLeft += borderLogicalRight() + paddingLogicalRight();
- setLogicalWidth(logicalLeft - startLogicalLeft);
- if (knownToHaveNoOverflow() && (minLogicalLeft < startLogicalLeft || maxLogicalRight > logicalLeft))
- clearKnownToHaveNoOverflow();
return logicalLeft;
}
@@ -442,7 +447,7 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo
if (isHorizontal())
return false;
- if (renderer()->style(isFirstLineStyle())->fontDescription().textOrientation() == TextOrientationUpright
+ if (renderer()->style(isFirstLineStyle())->fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright
|| renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs())
return true;
@@ -475,6 +480,13 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo
return false;
}
+static bool verticalAlignApplies(RenderObject* curr)
+{
+ // http://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align - vertical-align
+ // only applies to inline level and table-cell elements
+ return !curr->isText() || curr->parent()->isInline() || curr->parent()->isTableCell();
+}
+
void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom)
{
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
@@ -482,7 +494,8 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, i
// positioned elements
if (curr->renderer()->isOutOfFlowPositioned())
continue; // Positioned placeholders don't affect calculations.
- if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) {
+
+ if ((curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) && verticalAlignApplies(curr->renderer())) {
int lineHeight = curr->lineHeight();
if (curr->verticalAlign() == TOP) {
if (maxAscent + maxDescent < lineHeight)
@@ -565,10 +578,10 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit&
rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
LayoutUnit boxHeight = ascent + descent;
- if (curr->verticalAlign() == TOP) {
+ if (curr->verticalAlign() == TOP && verticalAlignApplies(curr->renderer())) {
if (maxPositionTop < boxHeight)
maxPositionTop = boxHeight;
- } else if (curr->verticalAlign() == BOTTOM) {
+ } else if (curr->verticalAlign() == BOTTOM && verticalAlignApplies(curr->renderer())) {
if (maxPositionBottom < boxHeight)
maxPositionBottom = boxHeight;
} else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())
@@ -614,7 +627,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei
if (descendantsHaveSameLineHeightAndBaseline()) {
adjustmentForChildrenWithSameLineHeightAndBaseline = logicalTop();
if (parent())
- adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderBefore() + boxModelObject()->paddingBefore());
+ adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderAndPaddingBefore());
}
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
@@ -628,9 +641,10 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei
InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0;
bool childAffectsTopBottomPos = true;
- if (curr->verticalAlign() == TOP)
+
+ if (curr->verticalAlign() == TOP && verticalAlignApplies(curr->renderer()))
curr->setLogicalTop(top);
- else if (curr->verticalAlign() == BOTTOM)
+ else if (curr->verticalAlign() == BOTTOM && verticalAlignApplies(curr->renderer()))
curr->setLogicalTop(top + maxHeight - curr->lineHeight());
else {
if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding()
@@ -732,6 +746,25 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei
}
}
+#if ENABLE(CSS3_TEXT)
+void InlineFlowBox::computeMaxLogicalTop(float& maxLogicalTop) const
+{
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->renderer()->isOutOfFlowPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+
+ if (descendantsHaveSameLineHeightAndBaseline())
+ continue;
+
+ maxLogicalTop = max<float>(maxLogicalTop, curr->y());
+ float localMaxLogicalTop = 0;
+ if (curr->isInlineFlowBox())
+ toInlineFlowBox(curr)->computeMaxLogicalTop(localMaxLogicalTop);
+ maxLogicalTop = max<float>(maxLogicalTop, localMaxLogicalTop);
+ }
+}
+#endif // CSS3_TEXT
+
void InlineFlowBox::flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom)
{
// Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop.
@@ -1018,6 +1051,26 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
}
// Now check ourselves. Pixel snap hit testing.
+ if (!visibleToHitTesting())
+ return false;
+
+ // Do not hittest content beyond the ellipsis box.
+ if (isRootInlineBox() && hasEllipsisBox()) {
+ const EllipsisBox* ellipsisBox = root()->ellipsisBox();
+ LayoutRect boundsRect(roundedFrameRect());
+
+ if (isHorizontal())
+ renderer()->style()->isLeftToRightDirection() ? boundsRect.shiftXEdgeTo(ellipsisBox->right()) : boundsRect.setWidth(ellipsisBox->left() - left());
+ else
+ boundsRect.shiftYEdgeTo(ellipsisBox->right());
+
+ flipForWritingMode(boundsRect);
+ boundsRect.moveBy(accumulatedOffset);
+ // We are beyond the ellipsis box.
+ if (locationInContainer.intersects(boundsRect))
+ return false;
+ }
+
LayoutRect frameRect = roundedFrameRect();
LayoutUnit minX = frameRect.x();
LayoutUnit minY = frameRect.y();
@@ -1040,7 +1093,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
flipForWritingMode(rect);
rect.moveBy(accumulatedOffset);
- if (visibleToHitTesting() && locationInContainer.intersects(rect)) {
+ if (locationInContainer.intersects(rect)) {
renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space.
if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect))
return true;
@@ -1108,7 +1161,7 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase;
PaintInfo childInfo(paintInfo);
childInfo.phase = paintPhase;
- childInfo.updatePaintingRootForChildren(renderer());
+ childInfo.updateSubtreePaintRootForChildren(renderer());
// Paint our children.
if (paintPhase != PaintPhaseSelfOutline) {
diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h
index 36d48dc87..d3fdd5ec8 100644
--- a/Source/WebCore/rendering/InlineFlowBox.h
+++ b/Source/WebCore/rendering/InlineFlowBox.h
@@ -80,7 +80,7 @@ public:
InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
- virtual bool isLeaf() const { return false; }
+ virtual bool isLeaf() const FINAL { return false; }
InlineBox* firstLeafChild() const;
InlineBox* lastLeafChild() const;
@@ -88,7 +88,7 @@ public:
typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
- virtual void setConstructed()
+ virtual void setConstructed() FINAL
{
InlineBox::setConstructed();
for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
@@ -96,9 +96,9 @@ public:
}
void addToLine(InlineBox* child);
- virtual void deleteLine(RenderArena*);
- virtual void extractLine();
- virtual void attachLine();
+ virtual void deleteLine(RenderArena*) FINAL;
+ virtual void extractLine() FINAL;
+ virtual void attachLine() FINAL;
virtual void adjustPosition(float dx, float dy);
virtual void extractLineBoxFromRenderObject();
@@ -109,8 +109,8 @@ public:
IntRect roundedFrameRect() const;
- virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
- virtual void paintMask(PaintInfo&, const LayoutPoint&);
+ virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) FINAL;
+ virtual void paintMask(PaintInfo&, const LayoutPoint&) FINAL;
void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
void paintBoxShadow(const PaintInfo&, RenderStyle*, ShadowStyle, const LayoutRect&);
@@ -173,6 +173,15 @@ public:
void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
LayoutUnit getFlowSpacingLogicalWidth();
float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
+ float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
+ void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); }
+ void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight)
+ {
+ setLogicalWidth(logicalRight - logicalLeft);
+ if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
+ clearKnownToHaveNoOverflow();
+ }
+
void computeLogicalBoxHeights(RootInlineBox*, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
@@ -192,7 +201,7 @@ public:
virtual RenderObject::SelectionState selectionState();
- virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const OVERRIDE;
+ virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const OVERRIDE FINAL;
virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) OVERRIDE;
bool hasTextChildren() const { return m_hasTextChildren; }
@@ -210,16 +219,6 @@ public:
{
return m_overflow ? m_overflow->layoutOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
}
- LayoutUnit logicalLeftLayoutOverflow() const
- {
- return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().x() : m_overflow->layoutOverflowRect().y()) :
- static_cast<LayoutUnit>(logicalLeft());
- }
- LayoutUnit logicalRightLayoutOverflow() const
- {
- return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().maxX() : m_overflow->layoutOverflowRect().maxY()) :
- static_cast<LayoutUnit>(ceilf(logicalRight()));
- }
LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const
{
if (m_overflow)
@@ -300,7 +299,7 @@ private:
protected:
OwnPtr<RenderOverflow> m_overflow;
- virtual bool isInlineFlowBox() const { return true; }
+ virtual bool isInlineFlowBox() const FINAL { return true; }
InlineBox* m_firstChild;
InlineBox* m_lastChild;
@@ -308,6 +307,11 @@ protected:
InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
+#if ENABLE(CSS3_TEXT)
+ // Maximum logicalTop among all children of an InlineFlowBox. Used to
+ // calculate the offset for TextUnderlinePositionUnder.
+ void computeMaxLogicalTop(float& maxLogicalTop) const;
+#endif // CSS3_TEXT
private:
unsigned m_includeLogicalLeftEdge : 1;
unsigned m_includeLogicalRightEdge : 1;
@@ -339,13 +343,13 @@ private:
inline InlineFlowBox* toInlineFlowBox(InlineBox* object)
{
- ASSERT(!object || object->isInlineFlowBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox());
return static_cast<InlineFlowBox*>(object);
}
inline const InlineFlowBox* toInlineFlowBox(const InlineBox* object)
{
- ASSERT(!object || object->isInlineFlowBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox());
return static_cast<const InlineFlowBox*>(object);
}
diff --git a/Source/WebCore/rendering/InlineIterator.h b/Source/WebCore/rendering/InlineIterator.h
index bef9a9815..db5843708 100644
--- a/Source/WebCore/rendering/InlineIterator.h
+++ b/Source/WebCore/rendering/InlineIterator.h
@@ -26,7 +26,6 @@
#include "BidiRun.h"
#include "RenderBlock.h"
#include "RenderText.h"
-#include <wtf/AlwaysInline.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
@@ -85,6 +84,7 @@ public:
return (m_obj && m_obj->isBR()) || atTextParagraphSeparator();
}
+ UChar characterAt(unsigned) const;
UChar current() const;
UChar previousInSameNode() const;
ALWAYS_INLINE WTF::Unicode::Direction direction() const;
@@ -175,6 +175,23 @@ enum EmptyInlineBehavior {
IncludeEmptyInlines,
};
+static bool isEmptyInline(RenderObject* object)
+{
+ if (!object->isRenderInline())
+ return false;
+
+ for (RenderObject* curr = object->firstChild(); curr; curr = curr->nextSibling()) {
+ if (curr->isFloatingOrOutOfFlowPositioned())
+ continue;
+ if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace())
+ continue;
+
+ if (!isEmptyInline(curr))
+ return false;
+ }
+ return true;
+}
+
// FIXME: This function is misleadingly named. It has little to do with bidi.
// This function will iterate over inlines within a block, optionally notifying
// a bidi resolver as it enters/exits inlines (so it can push/pop embedding levels).
@@ -224,7 +241,7 @@ static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur
break;
if (isIteratorTarget(next)
- || ((emptyInlineBehavior == IncludeEmptyInlines || !next->firstChild()) // Always return EMPTY inlines.
+ || ((emptyInlineBehavior == IncludeEmptyInlines || isEmptyInline(next)) // Always return EMPTY inlines.
&& next->isRenderInline()))
break;
current = next;
@@ -264,7 +281,7 @@ static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderObject* root, In
if (o->isRenderInline()) {
notifyObserverEnteredObject(resolver, o);
- if (o->firstChild())
+ if (!isEmptyInline(o))
o = bidiNextSkippingEmptyInlines(root, o, resolver);
else {
// Never skip empty inlines.
@@ -352,25 +369,29 @@ inline bool InlineIterator::atEnd() const
return !m_obj;
}
-inline UChar InlineIterator::current() const
+inline UChar InlineIterator::characterAt(unsigned index) const
{
if (!m_obj || !m_obj->isText())
return 0;
RenderText* text = toRenderText(m_obj);
- if (m_pos >= text->textLength())
+ if (index >= text->textLength())
return 0;
- return text->characterAt(m_pos);
+ return text->characterAt(index);
+}
+
+inline UChar InlineIterator::current() const
+{
+ return characterAt(m_pos);
}
inline UChar InlineIterator::previousInSameNode() const
{
- if (!m_obj || !m_obj->isText() || !m_pos)
+ if (!m_pos)
return 0;
- RenderText* text = toRenderText(m_obj);
- return text->characterAt(m_pos - 1);
+ return characterAt(m_pos - 1);
}
ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
@@ -467,6 +488,14 @@ public:
// We don't need to mark the end of the run because this is implicit: it is either endOfLine or the end of the
// isolate, when we call createBidiRunsForLine it will stop at whichever comes first.
addPlaceholderRunForIsolatedInline(resolver, obj, pos);
+ // FIXME: Inline isolates don't work properly with collapsing whitespace, see webkit.org/b/109624
+ // For now, if we enter an isolate between midpoints, we increment our current midpoint or else
+ // we'll leave the isolate and ignore the content that follows.
+ MidpointState<InlineIterator>& midpointState = resolver.midpointState();
+ if (midpointState.betweenMidpoints && midpointState.midpoints[midpointState.currentMidpoint].object() == obj) {
+ midpointState.betweenMidpoints = false;
+ ++midpointState.currentMidpoint;
+ }
}
private:
diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp
index 56ab76cc8..49e2e1dd0 100644
--- a/Source/WebCore/rendering/InlineTextBox.cpp
+++ b/Source/WebCore/rendering/InlineTextBox.cpp
@@ -47,13 +47,20 @@
#include "SVGTextRunRenderingContext.h"
#include "Text.h"
#include "break_lines.h"
-#include <wtf/AlwaysInline.h>
#include <wtf/text/CString.h>
using namespace std;
namespace WebCore {
+struct SameSizeAsInlineTextBox : public InlineBox {
+ unsigned variables[1];
+ unsigned short variables2[2];
+ void* pointers[2];
+};
+
+COMPILE_ASSERT(sizeof(InlineTextBox) == sizeof(SameSizeAsInlineTextBox), InlineTextBox_should_stay_small);
+
typedef WTF::HashMap<const InlineTextBox*, LayoutRect> InlineTextBoxOverflowMap;
static InlineTextBoxOverflowMap* gTextBoxesWithOverflow;
@@ -205,7 +212,12 @@ LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos)
if (respectHyphen)
endPos = textRun.length();
- LayoutRect r = enclosingIntRect(font.selectionRectForText(textRun, FloatPoint(logicalLeft(), selTop), selHeight, sPos, ePos));
+ FloatPoint startingPoint = FloatPoint(logicalLeft(), selTop);
+ LayoutRect r;
+ if (sPos || ePos != static_cast<int>(m_len))
+ r = enclosingIntRect(font.selectionRectForText(textRun, startingPoint, selHeight, sPos, ePos));
+ else // Avoid computing the font width when the entire line box is selected as an optimization.
+ r = enclosingIntRect(FloatRect(startingPoint, FloatSize(m_logicalWidth, selHeight)));
LayoutUnit logicalWidth = r.width();
if (r.x() > logicalRight())
@@ -285,7 +297,7 @@ float InlineTextBox::placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, flo
// and the ellipsis edge.
m_truncation = cFullTruncation;
truncatedWidth += ellipsisWidth;
- return min(ellipsisX, x());
+ return flowIsLTR ? min(ellipsisX, x()) : max(ellipsisX, right() - ellipsisWidth);
}
// Set the truncation index on the text run.
@@ -360,13 +372,29 @@ bool InlineTextBox::isLineBreak() const
bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
+ if (!visibleToHitTesting())
+ return false;
+
if (isLineBreak())
return false;
- FloatPoint boxOrigin = locationIncludingFlipping();
- boxOrigin.moveBy(accumulatedOffset);
- FloatRect rect(boxOrigin, size());
- if (m_truncation != cFullTruncation && visibleToHitTesting() && locationInContainer.intersects(rect)) {
+ if (m_truncation == cFullTruncation)
+ return false;
+
+ FloatRect rect(locationIncludingFlipping(), size());
+ // Make sure truncated text is ignored while hittesting.
+ if (m_truncation != cNoTruncation) {
+ LayoutUnit widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle());
+
+ if (isHorizontal())
+ renderer()->style()->isLeftToRightDirection() ? rect.setWidth(widthOfVisibleText) : rect.shiftXEdgeTo(right() - widthOfVisibleText);
+ else
+ rect.setHeight(widthOfVisibleText);
+ }
+
+ rect.moveBy(accumulatedOffset);
+
+ if (locationInContainer.intersects(rect)) {
renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset)));
if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect))
return true;
@@ -383,21 +411,21 @@ FloatSize InlineTextBox::applyShadowToGraphicsContext(GraphicsContext* context,
int shadowX = horizontal ? shadow->x() : shadow->y();
int shadowY = horizontal ? shadow->y() : -shadow->x();
FloatSize shadowOffset(shadowX, shadowY);
- int shadowBlur = shadow->blur();
+ int shadowRadius = shadow->radius();
const Color& shadowColor = shadow->color();
if (shadow->next() || stroked || !opaque) {
FloatRect shadowRect(textRect);
- shadowRect.inflate(shadowBlur);
+ shadowRect.inflate(shadow->paintingExtent());
shadowRect.move(shadowOffset);
context->save();
context->clip(shadowRect);
- extraOffset = FloatSize(0, 2 * textRect.height() + max(0.0f, shadowOffset.height()) + shadowBlur);
+ extraOffset = FloatSize(0, 2 * textRect.height() + max(0.0f, shadowOffset.height()) + shadowRadius);
shadowOffset -= extraOffset;
}
- context->setShadow(shadowOffset, shadowBlur, shadowColor, context->fillColorSpace());
+ context->setShadow(shadowOffset, shadowRadius, shadowColor, context->fillColorSpace());
return extraOffset;
}
@@ -428,7 +456,8 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con
context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset);
else
context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset), 0, endOffset);
- } if (startOffset < truncationPoint) {
+ }
+ if (startOffset < truncationPoint) {
if (emphasisMark.isEmpty())
context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint);
else
@@ -520,7 +549,6 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
// truncated string i.e. |Hello|CBA| -> |...lo|CBA|
LayoutUnit widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle());
LayoutUnit widthOfHiddenText = m_logicalWidth - widthOfVisibleText;
- // FIXME: The hit testing logic also needs to take this translation into account.
LayoutSize truncationOffset(isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText, 0);
adjustedPaintOffset.move(isHorizontal() ? truncationOffset : truncationOffset.transposedSize());
}
@@ -543,17 +571,17 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
context->concatCTM(rotation(boxRect, Clockwise));
// Determine whether or not we have composition underlines to draw.
- bool containsComposition = renderer()->node() && renderer()->frame()->editor()->compositionNode() == renderer()->node();
- bool useCustomUnderlines = containsComposition && renderer()->frame()->editor()->compositionUsesCustomUnderlines();
+ bool containsComposition = renderer()->node() && renderer()->frame()->editor().compositionNode() == renderer()->node();
+ bool useCustomUnderlines = containsComposition && renderer()->frame()->editor().compositionUsesCustomUnderlines();
// Determine the text colors and selection colors.
Color textFillColor;
Color textStrokeColor;
Color emphasisMarkColor;
float textStrokeWidth = styleToUse->textStrokeWidth();
- const ShadowData* textShadow = paintInfo.forceBlackText ? 0 : styleToUse->textShadow();
+ const ShadowData* textShadow = paintInfo.forceBlackText() ? 0 : styleToUse->textShadow();
- if (paintInfo.forceBlackText) {
+ if (paintInfo.forceBlackText()) {
textFillColor = Color::black;
textStrokeColor = Color::black;
emphasisMarkColor = Color::black;
@@ -595,14 +623,14 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
const ShadowData* selectionShadow = textShadow;
if (haveSelection) {
// Check foreground color first.
- Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor();
+ Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor();
if (foreground.isValid() && foreground != selectionFillColor) {
if (!paintSelectedTextOnly)
paintSelectedTextSeparately = true;
selectionFillColor = foreground;
}
- Color emphasisMarkForeground = paintInfo.forceBlackText ? Color::black : renderer()->selectionEmphasisMarkColor();
+ Color emphasisMarkForeground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionEmphasisMarkColor();
if (emphasisMarkForeground.isValid() && emphasisMarkForeground != selectionEmphasisMarkColor) {
if (!paintSelectedTextOnly)
paintSelectedTextSeparately = true;
@@ -610,7 +638,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
}
if (RenderStyle* pseudoStyle = renderer()->getCachedPseudoStyle(SELECTION)) {
- const ShadowData* shadow = paintInfo.forceBlackText ? 0 : pseudoStyle->textShadow();
+ const ShadowData* shadow = paintInfo.forceBlackText() ? 0 : pseudoStyle->textShadow();
if (shadow != selectionShadow) {
if (!paintSelectedTextOnly)
paintSelectedTextSeparately = true;
@@ -624,7 +652,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
selectionStrokeWidth = strokeWidth;
}
- Color stroke = paintInfo.forceBlackText ? Color::black : pseudoStyle->visitedDependentColor(CSSPropertyWebkitTextStrokeColor);
+ Color stroke = paintInfo.forceBlackText() ? Color::black : pseudoStyle->visitedDependentColor(CSSPropertyWebkitTextStrokeColor);
if (stroke != selectionStrokeColor) {
if (!paintSelectedTextOnly)
paintSelectedTextSeparately = true;
@@ -652,8 +680,8 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
if (containsComposition && !useCustomUnderlines)
paintCompositionBackground(context, boxOrigin, styleToUse, font,
- renderer()->frame()->editor()->compositionStart(),
- renderer()->frame()->editor()->compositionEnd());
+ renderer()->frame()->editor().compositionStart(),
+ renderer()->frame()->editor().compositionEnd());
paintDocumentMarkers(context, boxOrigin, styleToUse, font, true);
@@ -679,7 +707,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
if (!combinedText) {
string = textRenderer()->text();
if (static_cast<unsigned>(length) != string.length() || m_start) {
- ASSERT(static_cast<unsigned>(m_start + length) <= string.length());
+ ASSERT_WITH_SECURITY_IMPLICATION(static_cast<unsigned>(m_start + length) <= string.length());
string = string.substringSharingImpl(m_start, length);
}
maximumLength = textRenderer()->textLength() - m_start;
@@ -766,17 +794,21 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
}
// Paint decorations
- ETextDecoration textDecorations = styleToUse->textDecorationsInEffect();
- if (textDecorations != TDNONE && paintInfo.phase != PaintPhaseSelection) {
+ TextDecoration textDecorations = styleToUse->textDecorationsInEffect();
+ if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSelection) {
updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
+ if (combinedText)
+ context->concatCTM(rotation(boxRect, Clockwise));
paintDecoration(context, boxOrigin, textDecorations, styleToUse->textDecorationStyle(), textShadow);
+ if (combinedText)
+ context->concatCTM(rotation(boxRect, Counterclockwise));
}
if (paintInfo.phase == PaintPhaseForeground) {
paintDocumentMarkers(context, boxOrigin, styleToUse, font, false);
if (useCustomUnderlines) {
- const Vector<CompositionUnderline>& underlines = renderer()->frame()->editor()->customCompositionUnderlines();
+ const Vector<CompositionUnderline>& underlines = renderer()->frame()->editor().customCompositionUnderlines();
size_t numUnderlines = underlines.size();
for (size_t index = 0; index < numUnderlines; ++index) {
@@ -859,7 +891,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b
String string = textRenderer()->text();
if (string.length() != static_cast<unsigned>(length) || m_start) {
- ASSERT(static_cast<unsigned>(m_start + length) <= string.length());
+ ASSERT_WITH_SECURITY_IMPLICATION(static_cast<unsigned>(m_start + length) <= string.length());
string = string.substringSharingImpl(m_start, length);
}
@@ -920,7 +952,7 @@ void InlineTextBox::paintCustomHighlight(const LayoutPoint& paintOffset, const A
FloatRect rootRect(paintOffset.x() + r->x(), paintOffset.y() + selectionTop(), r->logicalWidth(), selectionHeight());
FloatRect textRect(paintOffset.x() + x(), rootRect.y(), logicalWidth(), rootRect.height());
- page->chrome()->client()->paintCustomHighlight(renderer()->node(), type, textRect, rootRect, true, false);
+ page->chrome().client()->paintCustomHighlight(renderer()->node(), type, textRect, rootRect, true, false);
}
#endif
@@ -943,7 +975,6 @@ static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati
strokeStyle = DashedStroke;
break;
case TextDecorationStyleWavy:
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=92868 - Needs platform support.
strokeStyle = WavyStroke;
break;
#endif // CSS3_TEXT
@@ -952,7 +983,158 @@ static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati
return strokeStyle;
}
-void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, ETextDecoration deco, TextDecorationStyle decorationStyle, const ShadowData* shadow)
+#if ENABLE(CSS3_TEXT)
+static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, const InlineTextBox* inlineTextBox, const int textDecorationThickness)
+{
+ // Compute the gap between the font and the underline. Use at least one
+ // pixel gap, if underline is thick then use a bigger gap.
+ const int gap = max<int>(1, ceilf(textDecorationThickness / 2.0));
+
+ // According to the specification TextUnderlinePositionAuto should default to 'alphabetic' for horizontal text
+ // and to 'under Left' for vertical text (e.g. japanese). We support only horizontal text for now.
+ switch (underlinePosition) {
+ case TextUnderlinePositionAlphabetic:
+ case TextUnderlinePositionAuto:
+ return fontMetrics.ascent() + gap; // Position underline near the alphabetic baseline.
+ case TextUnderlinePositionUnder: {
+ // Position underline relative to the under edge of the lowest element's content box.
+ const float offset = inlineTextBox->root()->maxLogicalTop() - inlineTextBox->logicalTop();
+ if (offset > 0)
+ return inlineTextBox->logicalHeight() + gap + offset;
+ return inlineTextBox->logicalHeight() + gap;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return fontMetrics.ascent() + gap;
+}
+#endif // CSS3_TEXT
+
+#if ENABLE(CSS3_TEXT)
+static void adjustStepToDecorationLength(float& step, float& controlPointDistance, float length)
+{
+ ASSERT(step > 0);
+
+ if (length <= 0)
+ return;
+
+ unsigned stepCount = static_cast<unsigned>(length / step);
+
+ // Each Bezier curve starts at the same pixel that the previous one
+ // ended. We need to subtract (stepCount - 1) pixels when calculating the
+ // length covered to account for that.
+ float uncoveredLength = length - (stepCount * step - (stepCount - 1));
+ float adjustment = uncoveredLength / stepCount;
+ step += adjustment;
+ controlPointDistance += adjustment;
+}
+
+/*
+ * Draw one cubic Bezier curve and repeat the same pattern long the the decoration's axis.
+ * The start point (p1), controlPoint1, controlPoint2 and end point (p2) of the Bezier curve
+ * form a diamond shape:
+ *
+ * step
+ * |-----------|
+ *
+ * controlPoint1
+ * +
+ *
+ *
+ * . .
+ * . .
+ * . .
+ * (x1, y1) p1 + . + p2 (x2, y2) - <--- Decoration's axis
+ * . . |
+ * . . |
+ * . . | controlPointDistance
+ * |
+ * |
+ * + -
+ * controlPoint2
+ *
+ * |-----------|
+ * step
+ */
+static void strokeWavyTextDecoration(GraphicsContext* context, FloatPoint& p1, FloatPoint& p2, float strokeThickness)
+{
+ context->adjustLineToPixelBoundaries(p1, p2, strokeThickness, context->strokeStyle());
+
+ Path path;
+ path.moveTo(p1);
+
+ // Distance between decoration's axis and Bezier curve's control points.
+ // The height of the curve is based on this distance. Use a minimum of 6 pixels distance since
+ // the actual curve passes approximately at half of that distance, that is 3 pixels.
+ // The minimum height of the curve is also approximately 3 pixels. Increases the curve's height
+ // as strockThickness increases to make the curve looks better.
+ float controlPointDistance = 3 * max<float>(2, strokeThickness);
+
+ // Increment used to form the diamond shape between start point (p1), control
+ // points and end point (p2) along the axis of the decoration. Makes the
+ // curve wider as strockThickness increases to make the curve looks better.
+ float step = 2 * max<float>(2, strokeThickness);
+
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ if (isVerticalLine) {
+ ASSERT(p1.x() == p2.x());
+
+ float xAxis = p1.x();
+ float y1;
+ float y2;
+
+ if (p1.y() < p2.y()) {
+ y1 = p1.y();
+ y2 = p2.y();
+ } else {
+ y1 = p2.y();
+ y2 = p1.y();
+ }
+
+ adjustStepToDecorationLength(step, controlPointDistance, y2 - y1);
+ FloatPoint controlPoint1(xAxis + controlPointDistance, 0);
+ FloatPoint controlPoint2(xAxis - controlPointDistance, 0);
+
+ for (float y = y1; y + 2 * step <= y2;) {
+ controlPoint1.setY(y + step);
+ controlPoint2.setY(y + step);
+ y += 2 * step;
+ path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(xAxis, y));
+ }
+ } else {
+ ASSERT(p1.y() == p2.y());
+
+ float yAxis = p1.y();
+ float x1;
+ float x2;
+
+ if (p1.x() < p2.x()) {
+ x1 = p1.x();
+ x2 = p2.x();
+ } else {
+ x1 = p2.x();
+ x2 = p1.x();
+ }
+
+ adjustStepToDecorationLength(step, controlPointDistance, x2 - x1);
+ FloatPoint controlPoint1(0, yAxis + controlPointDistance);
+ FloatPoint controlPoint2(0, yAxis - controlPointDistance);
+
+ for (float x = x1; x + 2 * step <= x2;) {
+ controlPoint1.setX(x + step);
+ controlPoint2.setX(x + step);
+ x += 2 * step;
+ path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis));
+ }
+ }
+
+ context->setShouldAntialias(true);
+ context->strokePath(path);
+}
+#endif // CSS3_TEXT
+
+void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, TextDecorationStyle decorationStyle, const ShadowData* shadow)
{
// FIXME: We should improve this rule and not always just assume 1.
const float textDecorationThickness = 1.f;
@@ -979,7 +1161,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
bool isPrinting = textRenderer()->document()->printing();
context->setStrokeThickness(textDecorationThickness);
- bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255);
+ bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.alpha() == 255);
RenderStyle* styleToUse = renderer()->style(isFirstLineStyle());
int baseline = styleToUse->fontMetrics().ascent();
@@ -989,13 +1171,14 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
if (!linesAreOpaque && shadow && shadow->next()) {
FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2));
for (const ShadowData* s = shadow; s; s = s->next()) {
+ int shadowExtent = s->paintingExtent();
FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2));
- shadowRect.inflate(s->blur());
+ shadowRect.inflate(shadowExtent);
int shadowX = isHorizontal() ? s->x() : s->y();
int shadowY = isHorizontal() ? s->y() : -s->x();
shadowRect.move(shadowX, shadowY);
clipRect.unite(shadowRect);
- extraOffset = max(extraOffset, max(0, shadowY) + s->blur());
+ extraOffset = max(extraOffset, max(0, shadowY) + shadowExtent);
}
context->save();
context->clip(clipRect);
@@ -1016,7 +1199,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
}
int shadowX = isHorizontal() ? shadow->x() : shadow->y();
int shadowY = isHorizontal() ? shadow->y() : -shadow->x();
- context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->blur(), shadow->color(), colorSpace);
+ context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->radius(), shadow->color(), colorSpace);
setShadow = true;
shadow = shadow->next();
}
@@ -1026,29 +1209,66 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
float doubleOffset = textDecorationThickness + 1.f;
#endif // CSS3_TEXT
context->setStrokeStyle(textDecorationStyleToStrokeStyle(decorationStyle));
- if (deco & UNDERLINE) {
+ if (deco & TextDecorationUnderline) {
context->setStrokeColor(underline, colorSpace);
+#if ENABLE(CSS3_TEXT)
+ TextUnderlinePosition underlinePosition = styleToUse->textUnderlinePosition();
+ const int underlineOffset = computeUnderlineOffset(underlinePosition, styleToUse->fontMetrics(), this, textDecorationThickness);
+
+ switch (decorationStyle) {
+ case TextDecorationStyleWavy: {
+ FloatPoint start(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset);
+ FloatPoint end(localOrigin.x() + width, localOrigin.y() + underlineOffset + doubleOffset);
+ strokeWavyTextDecoration(context, start, end, textDecorationThickness);
+ break;
+ }
+ default:
+ context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset), width, isPrinting);
+
+ if (decorationStyle == TextDecorationStyleDouble)
+ context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset), width, isPrinting);
+ }
+#else
// Leave one pixel of white between the baseline and the underline.
context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + baseline + 1), width, isPrinting);
-#if ENABLE(CSS3_TEXT)
- if (decorationStyle == TextDecorationStyleDouble)
- context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + baseline + 1 + doubleOffset), width, isPrinting);
#endif // CSS3_TEXT
}
- if (deco & OVERLINE) {
+ if (deco & TextDecorationOverline) {
context->setStrokeColor(overline, colorSpace);
- context->drawLineForText(localOrigin, width, isPrinting);
#if ENABLE(CSS3_TEXT)
- if (decorationStyle == TextDecorationStyleDouble)
- context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting);
+ switch (decorationStyle) {
+ case TextDecorationStyleWavy: {
+ FloatPoint start(localOrigin.x(), localOrigin.y() - doubleOffset);
+ FloatPoint end(localOrigin.x() + width, localOrigin.y() - doubleOffset);
+ strokeWavyTextDecoration(context, start, end, textDecorationThickness);
+ break;
+ }
+ default:
+#endif // CSS3_TEXT
+ context->drawLineForText(localOrigin, width, isPrinting);
+#if ENABLE(CSS3_TEXT)
+ if (decorationStyle == TextDecorationStyleDouble)
+ context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting);
+ }
#endif // CSS3_TEXT
}
- if (deco & LINE_THROUGH) {
+ if (deco & TextDecorationLineThrough) {
context->setStrokeColor(linethrough, colorSpace);
- context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting);
#if ENABLE(CSS3_TEXT)
- if (decorationStyle == TextDecorationStyleDouble)
- context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting);
+ switch (decorationStyle) {
+ case TextDecorationStyleWavy: {
+ FloatPoint start(localOrigin.x(), localOrigin.y() + 2 * baseline / 3);
+ FloatPoint end(localOrigin.x() + width, localOrigin.y() + 2 * baseline / 3);
+ strokeWavyTextDecoration(context, start, end, textDecorationThickness);
+ break;
+ }
+ default:
+#endif // CSS3_TEXT
+ context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting);
+#if ENABLE(CSS3_TEXT)
+ if (decorationStyle == TextDecorationStyleDouble)
+ context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting);
+ }
#endif // CSS3_TEXT
}
} while (shadow);
@@ -1120,7 +1340,7 @@ void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& b
// display a toolTip. We don't do this for misspelling markers.
if (grammar || isDictationMarker) {
markerRect.move(-boxOrigin.x(), -boxOrigin.y());
- markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect), SnapOffsetForTransforms).enclosingBoundingBox();
+ markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
}
}
@@ -1158,11 +1378,11 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint&
// Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(x(), selectionTop()), selHeight, sPos, ePos));
- markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect), SnapOffsetForTransforms).enclosingBoundingBox();
+ markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
// Optionally highlight the text
- if (renderer()->frame()->editor()->markedTextMatchesAreHighlighted()) {
+ if (renderer()->frame()->editor().markedTextMatchesAreHighlighted()) {
Color color = marker->activeMatch() ?
renderer()->theme()->platformActiveTextSearchHighlightColor() :
renderer()->theme()->platformInactiveTextSearchHighlightColor();
@@ -1186,7 +1406,7 @@ void InlineTextBox::computeRectForReplacementMarker(DocumentMarker* marker, Rend
// Compute and store the rect associated with this marker.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos));
- markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect), SnapOffsetForTransforms).enclosingBoundingBox();
+ markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
}
@@ -1200,7 +1420,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint&
// Give any document markers that touch this run a chance to draw before the text has been drawn.
// Note end() points at the last char, not one past it like endOffset and ranges do.
- for ( ; markerIt != markers.end(); markerIt++) {
+ for ( ; markerIt != markers.end(); ++markerIt) {
DocumentMarker* marker = *markerIt;
// Paint either the background markers or the foreground markers, but not both
diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h
index 1f2a63acf..a1c9d930b 100644
--- a/Source/WebCore/rendering/InlineTextBox.h
+++ b/Source/WebCore/rendering/InlineTextBox.h
@@ -57,7 +57,7 @@ public:
{
}
- virtual void destroy(RenderArena*);
+ virtual void destroy(RenderArena*) FINAL;
InlineTextBox* prevTextBox() const { return m_prevTextBox; }
InlineTextBox* nextTextBox() const { return m_nextTextBox; }
@@ -76,7 +76,7 @@ public:
unsigned short truncation() { return m_truncation; }
- virtual void markDirty(bool dirty = true) OVERRIDE;
+ virtual void markDirty(bool dirty = true) OVERRIDE FINAL;
using InlineBox::hasHyphen;
using InlineBox::setHasHyphen;
@@ -85,8 +85,8 @@ public:
static inline bool compareByStart(const InlineTextBox* first, const InlineTextBox* second) { return first->start() < second->start(); }
- virtual int baselinePosition(FontBaseline) const;
- virtual LayoutUnit lineHeight() const;
+ virtual int baselinePosition(FontBaseline) const FINAL;
+ virtual LayoutUnit lineHeight() const FINAL;
bool getEmphasisMarkPosition(RenderStyle*, TextEmphasisPosition&) const;
@@ -101,6 +101,7 @@ public:
virtual void showBox(int = 0) const;
virtual const char* boxName() const;
#endif
+
private:
LayoutUnit selectionTop();
LayoutUnit selectionBottom();
@@ -124,19 +125,19 @@ public:
RenderText* textRenderer() const;
private:
- virtual void deleteLine(RenderArena*);
- virtual void extractLine();
- virtual void attachLine();
+ virtual void deleteLine(RenderArena*) FINAL;
+ virtual void extractLine() FINAL;
+ virtual void attachLine() FINAL;
public:
- virtual RenderObject::SelectionState selectionState();
+ virtual RenderObject::SelectionState selectionState() FINAL;
private:
- virtual void clearTruncation() { m_truncation = cNoTruncation; }
- virtual float placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox) OVERRIDE;
+ virtual void clearTruncation() FINAL { m_truncation = cNoTruncation; }
+ virtual float placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox) OVERRIDE FINAL;
public:
- virtual bool isLineBreak() const;
+ virtual bool isLineBreak() const FINAL;
void setExpansion(int newExpansion)
{
@@ -146,11 +147,11 @@ public:
}
private:
- virtual bool isInlineTextBox() const { return true; }
+ virtual bool isInlineTextBox() const FINAL { return true; }
public:
- virtual int caretMinOffset() const;
- virtual int caretMaxOffset() const;
+ virtual int caretMinOffset() const FINAL;
+ virtual int caretMaxOffset() const FINAL;
private:
float textPos() const; // returns the x position relative to the left start of the text line.
@@ -183,7 +184,7 @@ protected:
#endif
private:
- void paintDecoration(GraphicsContext*, const FloatPoint& boxOrigin, ETextDecoration, TextDecorationStyle, const ShadowData*);
+ void paintDecoration(GraphicsContext*, const FloatPoint& boxOrigin, TextDecoration, TextDecorationStyle, const ShadowData*);
void paintSelection(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, Color textColor);
void paintDocumentMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&, bool grammar);
void paintTextMatchMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&);
@@ -198,13 +199,13 @@ private:
inline InlineTextBox* toInlineTextBox(InlineBox* inlineBox)
{
- ASSERT(!inlineBox || inlineBox->isInlineTextBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!inlineBox || inlineBox->isInlineTextBox());
return static_cast<InlineTextBox*>(inlineBox);
}
inline const InlineTextBox* toInlineTextBox(const InlineBox* inlineBox)
{
- ASSERT(!inlineBox || inlineBox->isInlineTextBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!inlineBox || inlineBox->isInlineTextBox());
return static_cast<const InlineTextBox*>(inlineBox);
}
diff --git a/Source/WebCore/rendering/LayoutState.cpp b/Source/WebCore/rendering/LayoutState.cpp
index 485d91775..28a8ffbea 100644
--- a/Source/WebCore/rendering/LayoutState.cpp
+++ b/Source/WebCore/rendering/LayoutState.cpp
@@ -39,8 +39,8 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz
: m_columnInfo(columnInfo)
, m_lineGrid(0)
, m_next(prev)
-#if ENABLE(CSS_EXCLUSIONS)
- , m_exclusionShapeInsideInfo(0)
+#if ENABLE(CSS_SHAPES)
+ , m_shapeInsideInfo(0)
#endif
#ifndef NDEBUG
, m_renderer(renderer)
@@ -110,11 +110,12 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz
if (!m_columnInfo)
m_columnInfo = m_next->m_columnInfo;
-#if ENABLE(CSS_EXCLUSIONS)
+#if ENABLE(CSS_SHAPES)
if (renderer->isRenderBlock()) {
- m_exclusionShapeInsideInfo = toRenderBlock(renderer)->exclusionShapeInsideInfo();
- if (!m_exclusionShapeInsideInfo)
- m_exclusionShapeInsideInfo = m_next->m_exclusionShapeInsideInfo;
+ const RenderBlock* renderBlock = toRenderBlock(renderer);
+ m_shapeInsideInfo = renderBlock->shapeInsideInfo();
+ if (!m_shapeInsideInfo && m_next->m_shapeInsideInfo && renderBlock->allowsShapeInsideInfoSharing())
+ m_shapeInsideInfo = m_next->m_shapeInsideInfo;
}
#endif
@@ -147,8 +148,8 @@ LayoutState::LayoutState(RenderObject* root)
, m_columnInfo(0)
, m_lineGrid(0)
, m_next(0)
-#if ENABLE(CSS_EXCLUSIONS)
- , m_exclusionShapeInsideInfo(0)
+#if ENABLE(CSS_SHAPES)
+ , m_shapeInsideInfo(0)
#endif
, m_pageLogicalHeight(0)
#ifndef NDEBUG
@@ -156,7 +157,7 @@ LayoutState::LayoutState(RenderObject* root)
#endif
{
RenderObject* container = root->container();
- FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms | SnapOffsetForTransforms);
+ FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms);
m_paintOffset = LayoutSize(absContentPoint.x(), absContentPoint.y());
if (container->hasOverflowClip()) {
diff --git a/Source/WebCore/rendering/LayoutState.h b/Source/WebCore/rendering/LayoutState.h
index 38571f91d..d7749c52c 100644
--- a/Source/WebCore/rendering/LayoutState.h
+++ b/Source/WebCore/rendering/LayoutState.h
@@ -38,8 +38,8 @@ class RenderBlock;
class RenderBox;
class RenderObject;
class RenderFlowThread;
-#if ENABLE(CSS_EXCLUSIONS)
-class ExclusionShapeInsideInfo;
+#if ENABLE(CSS_SHAPES)
+class ShapeInsideInfo;
#endif
class LayoutState {
@@ -56,8 +56,8 @@ public:
, m_columnInfo(0)
, m_lineGrid(0)
, m_next(0)
-#if ENABLE(CSS_EXCLUSIONS)
- , m_exclusionShapeInsideInfo(0)
+#if ENABLE(CSS_SHAPES)
+ , m_shapeInsideInfo(0)
#endif
, m_pageLogicalHeight(0)
#ifndef NDEBUG
@@ -98,8 +98,8 @@ public:
bool needsBlockDirectionLocationSetBeforeLayout() const { return m_lineGrid || (m_isPaginated && m_pageLogicalHeight); }
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo() const { return m_exclusionShapeInsideInfo; }
+#if ENABLE(CSS_SHAPES)
+ ShapeInsideInfo* shapeInsideInfo() const { return m_shapeInsideInfo; }
#endif
private:
// The normal operator new is disallowed.
@@ -125,8 +125,8 @@ public:
// The current line grid that we're snapping to and the offset of the start of the grid.
RenderBlock* m_lineGrid;
LayoutState* m_next;
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo* m_exclusionShapeInsideInfo;
+#if ENABLE(CSS_SHAPES)
+ ShapeInsideInfo* m_shapeInsideInfo;
#endif
// FIXME: Distinguish between the layout clip rect and the paint clip rect which may be larger,
diff --git a/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h
new file mode 100644
index 000000000..3c59fb676
--- /dev/null
+++ b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LogicalSelectionOffsetCaches_h
+#define LogicalSelectionOffsetCaches_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+static inline bool isContainingBlockCandidateForAbsolutelyPositionedObject(RenderObject* object)
+{
+ return object->style()->position() != StaticPosition
+ || (object->hasTransform() && object->isRenderBlock())
+#if ENABLE(SVG)
+ || object->isSVGForeignObject()
+#endif
+ || object->isRenderView();
+}
+
+static inline bool isNonRenderBlockInline(RenderObject* object)
+{
+ return (object->isInline() && !object->isReplaced()) || !object->isRenderBlock();
+}
+
+static inline RenderObject* containingBlockForFixedPosition(RenderObject* parent)
+{
+ RenderObject* object = parent;
+ while (object && !object->canContainFixedPositionObjects())
+ object = object->parent();
+ ASSERT(!object || !object->isAnonymousBlock());
+ return object;
+}
+
+static inline RenderObject* containingBlockForAbsolutePosition(RenderObject* parent)
+{
+ RenderObject* object = parent;
+ while (object && !isContainingBlockCandidateForAbsolutelyPositionedObject(object))
+ object = object->parent();
+
+ // For a relatively positioned inline, return its nearest non-anonymous containing block,
+ // not the inline itself, to avoid having a positioned objects list in all RenderInlines
+ // and use RenderBlock* as RenderObject::containingBlock's return type.
+ // Use RenderBlock::container() to obtain the inline.
+ if (object && object->isRenderInline())
+ object = object->containingBlock();
+
+ while (object && object->isAnonymousBlock())
+ object = object->containingBlock();
+
+ return object;
+}
+
+static inline RenderObject* containingBlockForObjectInFlow(RenderObject* parent)
+{
+ RenderObject* object = parent;
+ while (object && isNonRenderBlockInline(object))
+ object = object->parent();
+ return object;
+}
+
+class LogicalSelectionOffsetCaches {
+public:
+ class ContainingBlockInfo {
+ public:
+ ContainingBlockInfo()
+ : m_block(0)
+ , m_cache(0)
+ , m_hasFloatsOrFlowThreads(false)
+ , m_cachedLogicalLeftSelectionOffset(false)
+ , m_cachedLogicalRightSelectionOffset(false)
+ { }
+
+ void setBlock(RenderBlock* block, const LogicalSelectionOffsetCaches* cache)
+ {
+ m_block = block;
+ m_hasFloatsOrFlowThreads = m_hasFloatsOrFlowThreads || m_block->containsFloats() || m_block->flowThreadContainingBlock();
+ m_cache = cache;
+ m_cachedLogicalLeftSelectionOffset = false;
+ m_cachedLogicalRightSelectionOffset = false;
+ }
+
+ RenderBlock* block() const { return m_block; }
+ const LogicalSelectionOffsetCaches* cache() const { return m_cache; }
+
+ LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) const
+ {
+ ASSERT(m_cache);
+ if (m_hasFloatsOrFlowThreads || !m_cachedLogicalLeftSelectionOffset) {
+ m_cachedLogicalLeftSelectionOffset = true;
+ m_logicalLeftSelectionOffset = m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache);
+ } else
+ ASSERT(m_logicalLeftSelectionOffset == m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache));
+ return m_logicalLeftSelectionOffset;
+ }
+
+ LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) const
+ {
+ ASSERT(m_cache);
+ if (m_hasFloatsOrFlowThreads || !m_cachedLogicalRightSelectionOffset) {
+ m_cachedLogicalRightSelectionOffset = true;
+ m_logicalRightSelectionOffset = m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache);
+ } else
+ ASSERT(m_logicalRightSelectionOffset == m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache));
+ return m_logicalRightSelectionOffset;
+ }
+
+ private:
+ RenderBlock* m_block;
+ const LogicalSelectionOffsetCaches* m_cache;
+ bool m_hasFloatsOrFlowThreads : 1;
+ mutable bool m_cachedLogicalLeftSelectionOffset : 1;
+ mutable bool m_cachedLogicalRightSelectionOffset : 1;
+ mutable LayoutUnit m_logicalLeftSelectionOffset;
+ mutable LayoutUnit m_logicalRightSelectionOffset;
+
+ };
+
+ LogicalSelectionOffsetCaches(RenderBlock* rootBlock)
+ {
+ ASSERT(rootBlock->isSelectionRoot());
+ RenderObject* parent = rootBlock->parent();
+
+ // LogicalSelectionOffsetCaches should not be used on an orphaned tree.
+ m_containingBlockForFixedPosition.setBlock(toRenderBlock(containingBlockForFixedPosition(parent)), 0);
+ m_containingBlockForAbsolutePosition.setBlock(toRenderBlock(containingBlockForAbsolutePosition(parent)), 0);
+ m_containingBlockForInflowPosition.setBlock(toRenderBlock(containingBlockForObjectInFlow(parent)), 0);
+ }
+
+ LogicalSelectionOffsetCaches(RenderBlock* block, const LogicalSelectionOffsetCaches& cache)
+ : m_containingBlockForFixedPosition(cache.m_containingBlockForFixedPosition)
+ , m_containingBlockForAbsolutePosition(cache.m_containingBlockForAbsolutePosition)
+ {
+ if (block->canContainFixedPositionObjects())
+ m_containingBlockForFixedPosition.setBlock(block, &cache);
+
+ if (isContainingBlockCandidateForAbsolutelyPositionedObject(block) && !block->isRenderInline() && !block->isAnonymousBlock())
+ m_containingBlockForFixedPosition.setBlock(block, &cache);
+
+ m_containingBlockForInflowPosition.setBlock(block, &cache);
+ }
+
+ const ContainingBlockInfo& containingBlockInfo(RenderBlock* block) const
+ {
+ EPosition position = block->style()->position();
+ if (position == FixedPosition) {
+ ASSERT(block->containingBlock() == m_containingBlockForFixedPosition.block());
+ return m_containingBlockForFixedPosition;
+ }
+ if (position == AbsolutePosition) {
+ ASSERT(block->containingBlock() == m_containingBlockForAbsolutePosition.block());
+ return m_containingBlockForAbsolutePosition;
+ }
+ ASSERT(block->containingBlock() == m_containingBlockForInflowPosition.block());
+ return m_containingBlockForInflowPosition;
+ }
+
+private:
+ ContainingBlockInfo m_containingBlockForFixedPosition;
+ ContainingBlockInfo m_containingBlockForAbsolutePosition;
+ ContainingBlockInfo m_containingBlockForInflowPosition;
+};
+
+} // namespace WebCore
+
+#endif // LogicalSelectionOffsetCaches_h
diff --git a/Source/WebCore/rendering/PaintInfo.h b/Source/WebCore/rendering/PaintInfo.h
index 2781496e6..417859dd5 100644
--- a/Source/WebCore/rendering/PaintInfo.h
+++ b/Source/WebCore/rendering/PaintInfo.h
@@ -42,6 +42,7 @@ namespace WebCore {
class OverlapTestRequestClient;
class RenderInline;
+class RenderLayerModelObject;
class RenderObject;
class RenderRegion;
@@ -52,37 +53,43 @@ typedef HashMap<OverlapTestRequestClient*, IntRect> OverlapTestRequestMap;
* (tx|ty) is the calculated position of the parent
*/
struct PaintInfo {
- PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, bool newForceBlackText,
- RenderObject* newPaintingRoot, RenderRegion* region, ListHashSet<RenderInline*>* newOutlineObjects,
- OverlapTestRequestMap* overlapTestRequests = 0)
+ PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, PaintBehavior newPaintBehavior,
+ RenderObject* newSubtreePaintRoot = 0, RenderRegion* region = 0, ListHashSet<RenderInline*>* newOutlineObjects = 0,
+ OverlapTestRequestMap* overlapTestRequests = 0, const RenderLayerModelObject* newPaintContainer = 0)
: context(newContext)
, rect(newRect)
, phase(newPhase)
- , forceBlackText(newForceBlackText)
- , paintingRoot(newPaintingRoot)
+ , paintBehavior(newPaintBehavior)
+ , subtreePaintRoot(newSubtreePaintRoot)
, renderRegion(region)
, outlineObjects(newOutlineObjects)
, overlapTestRequests(overlapTestRequests)
+ , paintContainer(newPaintContainer)
{
}
- void updatePaintingRootForChildren(const RenderObject* renderer)
+ void updateSubtreePaintRootForChildren(const RenderObject* renderer)
{
- if (!paintingRoot)
+ if (!subtreePaintRoot)
return;
// If we're the painting root, kids draw normally, and see root of 0.
- if (paintingRoot == renderer) {
- paintingRoot = 0;
+ if (subtreePaintRoot == renderer) {
+ subtreePaintRoot = 0;
return;
}
}
bool shouldPaintWithinRoot(const RenderObject* renderer) const
{
- return !paintingRoot || paintingRoot == renderer;
+ return !subtreePaintRoot || subtreePaintRoot == renderer;
}
+ bool forceBlackText() const { return paintBehavior & PaintBehaviorForceBlackText; }
+
+ bool skipRootBackground() const { return paintBehavior & PaintBehaviorSkipRootBackground; }
+ bool paintRootBackgroundOnly() const { return paintBehavior & PaintBehaviorRootBackgroundOnly; }
+
#if ENABLE(SVG)
void applyTransform(const AffineTransform& localToAncestorTransform)
{
@@ -104,11 +111,12 @@ struct PaintInfo {
GraphicsContext* context;
IntRect rect;
PaintPhase phase;
- bool forceBlackText;
- RenderObject* paintingRoot; // used to draw just one element and its visual kids
+ PaintBehavior paintBehavior;
+ RenderObject* subtreePaintRoot; // used to draw just one element and its visual children
RenderRegion* renderRegion;
ListHashSet<RenderInline*>* outlineObjects; // used to list outlines that should be painted by a block with inline children
OverlapTestRequestMap* overlapTestRequests;
+ const RenderLayerModelObject* paintContainer; // the layer object that originates the current painting
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/PaintPhase.h b/Source/WebCore/rendering/PaintPhase.h
index be4c61be4..af0bd59b9 100644
--- a/Source/WebCore/rendering/PaintPhase.h
+++ b/Source/WebCore/rendering/PaintPhase.h
@@ -57,7 +57,9 @@ enum PaintBehaviorFlags {
PaintBehaviorSelectionOnly = 1 << 0,
PaintBehaviorForceBlackText = 1 << 1,
PaintBehaviorFlattenCompositingLayers = 1 << 2,
- PaintBehaviorRenderingSVGMask = 1 << 3
+ PaintBehaviorRenderingSVGMask = 1 << 3,
+ PaintBehaviorSkipRootBackground = 1 << 4,
+ PaintBehaviorRootBackgroundOnly = 1 << 5
};
typedef unsigned PaintBehavior;
diff --git a/Source/WebCore/rendering/RegionOversetState.h b/Source/WebCore/rendering/RegionOversetState.h
new file mode 100644
index 000000000..e29e370a2
--- /dev/null
+++ b/Source/WebCore/rendering/RegionOversetState.h
@@ -0,0 +1,33 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RegionOversetState_h
+#define RegionOversetState_h
+
+namespace WebCore {
+
+enum RegionOversetState {
+ RegionUndefined,
+ RegionEmpty,
+ RegionFit,
+ RegionOverset
+};
+
+} // namespace WebCore
+
+#endif // RegionOversetState_h
diff --git a/Source/WebCore/rendering/RenderApplet.h b/Source/WebCore/rendering/RenderApplet.h
index 151660066..881e21c0b 100644
--- a/Source/WebCore/rendering/RenderApplet.h
+++ b/Source/WebCore/rendering/RenderApplet.h
@@ -30,7 +30,7 @@ class HTMLAppletElement;
class RenderApplet : public RenderEmbeddedObject {
public:
- RenderApplet(HTMLAppletElement*);
+ explicit RenderApplet(HTMLAppletElement*);
virtual ~RenderApplet();
private:
diff --git a/Source/WebCore/rendering/RenderArena.cpp b/Source/WebCore/rendering/RenderArena.cpp
index cc2362059..c1adee2b1 100644
--- a/Source/WebCore/rendering/RenderArena.cpp
+++ b/Source/WebCore/rendering/RenderArena.cpp
@@ -36,9 +36,11 @@
#include "config.h"
#include "RenderArena.h"
+#include <limits>
#include <stdlib.h>
#include <string.h>
#include <wtf/Assertions.h>
+#include <wtf/CryptographicallyRandomNumber.h>
#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
@@ -89,10 +91,8 @@ RenderArena::RenderArena(unsigned arenaSize)
// should immediately crash on the first invalid vtable access for a stale
// RenderObject pointer.
// See http://download.crowdstrike.com/papers/hes-exploiting-a-coalmine.pdf.
-
- // The bottom bits are predictable because the binary is loaded on a
- // boundary. This just shifts most of those predictable bits out.
- m_mask = ~(reinterpret_cast<uintptr_t>(WTF::fastMalloc) >> 13);
+ WTF::cryptographicallyRandomValues(&m_mask, sizeof(m_mask));
+ m_mask |= (static_cast<uintptr_t>(3) << (std::numeric_limits<uintptr_t>::digits - 2)) | 1;
}
RenderArena::~RenderArena()
diff --git a/Source/WebCore/rendering/RenderArena.h b/Source/WebCore/rendering/RenderArena.h
index 5538effd6..0f003db5c 100644
--- a/Source/WebCore/rendering/RenderArena.h
+++ b/Source/WebCore/rendering/RenderArena.h
@@ -38,15 +38,16 @@
#include "Arena.h"
#include <wtf/FastAllocBase.h>
#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
namespace WebCore {
static const size_t gMaxRecycledSize = 1024;
-class RenderArena {
- WTF_MAKE_NONCOPYABLE(RenderArena); WTF_MAKE_FAST_ALLOCATED;
+class RenderArena : public RefCounted<RenderArena> {
public:
- RenderArena(unsigned arenaSize = 8192);
+ static PassRefPtr<RenderArena> create() { return adoptRef(new RenderArena); }
~RenderArena();
// Memory management functions
@@ -57,6 +58,8 @@ public:
size_t totalRenderArenaAllocatedBytes() const { return m_totalAllocated; }
private:
+ RenderArena(unsigned arenaSize = 8192);
+
// Underlying arena pool
ArenaPool m_pool;
diff --git a/Source/WebCore/rendering/RenderBR.h b/Source/WebCore/rendering/RenderBR.h
index 25e90da8d..91486f29c 100644
--- a/Source/WebCore/rendering/RenderBR.h
+++ b/Source/WebCore/rendering/RenderBR.h
@@ -33,7 +33,7 @@ class Position;
class RenderBR : public RenderText {
public:
- RenderBR(Node*);
+ explicit RenderBR(Node*);
virtual ~RenderBR();
virtual const char* renderName() const { return "RenderBR"; }
@@ -63,13 +63,13 @@ private:
inline RenderBR* toRenderBR(RenderObject* object)
{
- ASSERT(!object || object->isBR());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBR());
return static_cast<RenderBR*>(object);
}
inline const RenderBR* toRenderBR(const RenderObject* object)
{
- ASSERT(!object || object->isBR());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBR());
return static_cast<const RenderBR*>(object);
}
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
index 058e90431..c1b3fe154 100644
--- a/Source/WebCore/rendering/RenderBlock.cpp
+++ b/Source/WebCore/rendering/RenderBlock.cpp
@@ -27,43 +27,47 @@
#include "AXObjectCache.h"
#include "ColumnInfo.h"
#include "Document.h"
+#include "Editor.h"
#include "Element.h"
#include "FloatQuad.h"
#include "Frame.h"
#include "FrameSelection.h"
#include "FrameView.h"
#include "GraphicsContext.h"
-#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
#include "HTMLNames.h"
+#include "HitTestLocation.h"
#include "HitTestResult.h"
#include "InlineIterator.h"
#include "InlineTextBox.h"
#include "LayoutRepainter.h"
+#include "LogicalSelectionOffsetCaches.h"
#include "OverflowEvent.h"
-#include "PODFreeListArena.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderBoxRegionInfo.h"
#include "RenderCombineText.h"
#include "RenderDeprecatedFlexibleBox.h"
-#include "RenderImage.h"
+#include "RenderFlexibleBox.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderMarquee.h"
#include "RenderNamedFlowThread.h"
#include "RenderRegion.h"
-#include "RenderReplica.h"
#include "RenderTableCell.h"
#include "RenderTextFragment.h"
#include "RenderTheme.h"
#include "RenderView.h"
-#include "Settings.h"
#include "SVGTextRunRenderingContext.h"
+#include "Settings.h"
#include "ShadowRoot.h"
#include "TransformState.h"
-#include <wtf/StdLibExtras.h>
-#if ENABLE(CSS_EXCLUSIONS)
-#include "ExclusionShapeInsideInfo.h"
+#include <wtf/StackStats.h>
+#include <wtf/TemporaryChange.h>
+
+#if ENABLE(CSS_SHAPES)
+#include "ShapeInsideInfo.h"
+#include "ShapeOutsideInfo.h"
#endif
using namespace std;
@@ -97,7 +101,7 @@ struct SameSizeAsMarginInfo {
LayoutUnit margins[2];
};
-typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
+typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap;
static ColumnInfoMap* gColumnInfoMap = 0;
static TrackedDescendantsMap* gPositionedDescendantsMap = 0;
@@ -106,12 +110,14 @@ static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0;
static TrackedContainerMap* gPositionedContainerMap = 0;
static TrackedContainerMap* gPercentHeightContainerMap = 0;
-typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
+typedef WTF::HashMap<RenderBlock*, OwnPtr<ListHashSet<RenderInline*> > > ContinuationOutlineTableMap;
typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
static int gDelayUpdateScrollInfo = 0;
static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
+static bool gColumnFlowSplitEnabled = true;
+
bool RenderBlock::s_canPropagateFloatIntoSibling = false;
// This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
@@ -158,16 +164,17 @@ private:
RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
: m_atBeforeSideOfBlock(true)
, m_atAfterSideOfBlock(false)
- , m_marginBeforeQuirk(false)
- , m_marginAfterQuirk(false)
+ , m_hasMarginBeforeQuirk(false)
+ , m_hasMarginAfterQuirk(false)
, m_determinedMarginBeforeQuirk(false)
+ , m_discardMargin(false)
{
RenderStyle* blockStyle = block->style();
ASSERT(block->isRenderView() || block->parent());
m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
&& !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
- && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox() && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth()
- && !blockStyle->columnSpan();
+ && !block->isRenderFlowThread() && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox()
+ && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan();
m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
@@ -178,20 +185,24 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderP
m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
(blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
- m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD
- || blockStyle->marginAfterCollapse() == MDISCARD;
+ m_quirkContainer = block->isTableCell() || block->isBody();
+
+ m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore();
- m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : LayoutUnit();
- m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : LayoutUnit();
+ m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit();
+ m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit();
}
// -------------------------------------------------------------------------------------------------------
-RenderBlock::RenderBlock(Node* node)
- : RenderBox(node)
- , m_lineHeight(-1)
- , m_beingDestroyed(false)
- , m_hasMarkupTruncation(false)
+RenderBlock::RenderBlock(ContainerNode* node)
+ : RenderBox(node)
+ , m_lineHeight(-1)
+ , m_hasMarginBeforeQuirk(false)
+ , m_hasMarginAfterQuirk(false)
+ , m_beingDestroyed(false)
+ , m_hasMarkupTruncation(false)
+ , m_hasBorderOrPaddingLogicalWidthChanged(false)
{
setChildrenInline(true);
COMPILE_ASSERT(sizeof(RenderBlock::FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
@@ -200,21 +211,19 @@ RenderBlock::RenderBlock(Node* node)
static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
{
- if (TrackedRendererListHashSet* descendantSet = descendantMap->take(block)) {
+ if (OwnPtr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) {
TrackedRendererListHashSet::iterator end = descendantSet->end();
for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
- HashSet<RenderBlock*>* containerSet = containerMap->get(*descendant);
- ASSERT(containerSet);
- if (!containerSet)
+ TrackedContainerMap::iterator it = containerMap->find(*descendant);
+ ASSERT(it != containerMap->end());
+ if (it == containerMap->end())
continue;
+ HashSet<RenderBlock*>* containerSet = it->value.get();
ASSERT(containerSet->contains(block));
containerSet->remove(block);
- if (containerSet->isEmpty()) {
- containerMap->remove(*descendant);
- delete containerSet;
- }
+ if (containerSet->isEmpty())
+ containerMap->remove(it);
}
- delete descendantSet;
}
}
@@ -224,7 +233,7 @@ RenderBlock::~RenderBlock()
deleteAllValues(m_floatingObjects->set());
if (hasColumns())
- delete gColumnInfoMap->take(this);
+ gColumnInfoMap->take(this);
if (gPercentHeightDescendantsMap)
removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
@@ -232,11 +241,23 @@ RenderBlock::~RenderBlock()
removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
}
+RenderBlock* RenderBlock::createAnonymous(Document* document)
+{
+ RenderBlock* renderer = new (document->renderArena()) RenderBlock(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
void RenderBlock::willBeDestroyed()
{
// Mark as being destroyed to avoid trouble with merges in removeChild().
m_beingDestroyed = true;
+ if (!documentBeingDestroyed()) {
+ if (firstChild() && firstChild()->isRunIn())
+ moveRunInToOriginalPosition(firstChild());
+ }
+
// Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
// properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
children()->destroyLeftoverChildren();
@@ -277,10 +298,6 @@ void RenderBlock::willBeDestroyed()
if (lineGridBox())
lineGridBox()->destroy(renderArena());
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(this);
-#endif
-
if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
gDelayedUpdateScrollInfoSet->remove(this);
@@ -322,14 +339,28 @@ void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newSt
RenderBox::styleWillChange(diff, newStyle);
}
+static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
+{
+ if (newStyle->isHorizontalWritingMode())
+ return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
+ || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
+ || oldStyle->paddingLeft() != newStyle->paddingLeft()
+ || oldStyle->paddingRight() != newStyle->paddingRight();
+
+ return oldStyle->borderTopWidth() != newStyle->borderTopWidth()
+ || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth()
+ || oldStyle->paddingTop() != newStyle->paddingTop()
+ || oldStyle->paddingBottom() != newStyle->paddingBottom();
+}
+
void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBox::styleDidChange(diff, oldStyle);
-
-#if ENABLE(CSS_EXCLUSIONS)
- // FIXME: Bug 89993: Style changes should affect the ExclusionShapeInsideInfos for other render blocks that
- // share the same ExclusionShapeInsideInfo
- updateExclusionShapeInsideInfoAfterStyleChange(style()->shapeInside(), oldStyle ? oldStyle->shapeInside() : 0);
+
+ RenderStyle* newStyle = style();
+
+#if ENABLE(CSS_SHAPES)
+ updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : 0);
#endif
if (!isAnonymousBlock()) {
@@ -337,7 +368,7 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
RenderBoxModelObject* nextCont = currCont->continuation();
currCont->setContinuation(0);
- currCont->setStyle(style());
+ currCont->setStyle(newStyle);
currCont->setContinuation(nextCont);
}
}
@@ -345,12 +376,6 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
propagateStyleToAnonymousChildren(true);
m_lineHeight = -1;
- // Update pseudos for :before and :after now.
- if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules() && canHaveGeneratedChildren()) {
- updateBeforeAfterContent(BEFORE);
- updateBeforeAfterContent(AFTER);
- }
-
// After our style changed, if we lose our ability to propagate floats into next sibling
// blocks, then we need to find the top most parent containing that overhanging float and
// then mark its descendants with floats for layout and clear all floats from its next
@@ -380,14 +405,10 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
parentBlock->markAllDescendantsWithFloatsForLayout();
parentBlock->markSiblingsWithFloatsForLayout();
}
-}
-
-void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
-{
- // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
- if (parent() && parent()->createsAnonymousWrapper())
- return;
- children()->updateBeforeAfterContent(this, pseudoId);
+
+ // It's possible for our border/padding to change, but for the overall logical width of the block to
+ // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true.
+ m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle);
}
RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
@@ -566,7 +587,7 @@ RenderBlock* RenderBlock::clone() const
// generated content added yet.
cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
}
- cloneBlock->setInRenderFlowThread(inRenderFlowThread());
+ cloneBlock->setFlowThreadState(flowThreadState());
return cloneBlock;
}
@@ -601,15 +622,9 @@ void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
RenderBoxModelObject* currChild = this;
RenderObject* currChildNextSibling = currChild->nextSibling();
- bool documentUsesBeforeAfterRules = document()->styleSheetCollection()->usesBeforeAfterRules();
- // Note: |this| can be destroyed inside this loop if it is an empty anonymous
- // block and we try to call updateBeforeAfterContent inside which removes the
- // generated content and additionally cleans up |this| empty anonymous block.
- // See RenderBlock::removeChild(). DO NOT reference any local variables to |this|
- // after this point.
while (curr && curr != fromBlock) {
- ASSERT(curr->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(curr->isRenderBlock());
RenderBlock* blockCurr = toRenderBlock(curr);
@@ -630,16 +645,6 @@ void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
cloneBlock->setContinuation(oldCont);
}
- // Someone may have indirectly caused a <q> to split. When this happens, the :after content
- // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
- // content gets properly destroyed.
- bool isLastChild = (currChildNextSibling == blockCurr->lastChild());
- if (documentUsesBeforeAfterRules)
- blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
- if (isLastChild && currChildNextSibling != blockCurr->lastChild())
- currChildNextSibling = 0; // We destroyed the last child, so now we need to update
- // the value of currChildNextSibling.
-
// Now we need to take all of the children starting from the first child
// *after* currChild and append them all to the clone.
blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
@@ -798,10 +803,6 @@ RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
{
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild)
- beforeChild = afterPseudoElementRenderer();
-
if (beforeChild && beforeChild->parent() != this) {
RenderObject* beforeChildContainer = beforeChild->parent();
while (beforeChildContainer->parent() != this)
@@ -857,47 +858,33 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild,
beforeChild = beforeChild->nextSibling();
// Check for a spanning element in columns.
- RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
- if (columnsBlockAncestor) {
- // We are placing a column-span element inside a block.
- RenderBlock* newBox = createAnonymousColumnSpanBlock();
+ if (gColumnFlowSplitEnabled) {
+ RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
+ if (columnsBlockAncestor) {
+ TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
+ // We are placing a column-span element inside a block.
+ RenderBlock* newBox = createAnonymousColumnSpanBlock();
- if (columnsBlockAncestor != this) {
- // We are nested inside a multi-column element and are being split by the span. We have to break up
- // our block into continuations.
- RenderBoxModelObject* oldContinuation = continuation();
-
- // When we split an anonymous block, there's no need to do any continuation hookup,
- // since we haven't actually split a real element.
- if (!isAnonymousBlock())
- setContinuation(newBox);
-
- // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
- // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
- // content gets properly destroyed.
- bool isFirstChild = (beforeChild == firstChild());
- bool isLastChild = (beforeChild == lastChild());
- if (document()->styleSheetCollection()->usesBeforeAfterRules())
- children()->updateBeforeAfterContent(this, AFTER);
- if (isLastChild && beforeChild != lastChild()) {
- // We destroyed the last child, so now we need to update our insertion
- // point to be 0. It's just a straight append now.
- beforeChild = 0;
- } else if (isFirstChild && beforeChild != firstChild()) {
- // If beforeChild was the last anonymous block that collapsed,
- // then we need to update its value.
- beforeChild = firstChild();
+ if (columnsBlockAncestor != this && !isRenderFlowThread()) {
+ // We are nested inside a multi-column element and are being split by the span. We have to break up
+ // our block into continuations.
+ RenderBoxModelObject* oldContinuation = continuation();
+
+ // When we split an anonymous block, there's no need to do any continuation hookup,
+ // since we haven't actually split a real element.
+ if (!isAnonymousBlock())
+ setContinuation(newBox);
+
+ splitFlow(beforeChild, newBox, newChild, oldContinuation);
+ return;
}
- splitFlow(beforeChild, newBox, newChild, oldContinuation);
+ // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
+ // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
+ // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
+ makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
return;
}
-
- // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
- // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
- // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
- makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
- return;
}
bool madeBoxesNonInline = false;
@@ -938,7 +925,7 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild,
RenderBox::addChild(newChild, beforeChild);
// Handle placement of run-ins.
- placeRunInIfNeeded(newChild, DoNotPlaceGeneratedRunIn);
+ placeRunInIfNeeded(newChild);
if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
@@ -1013,11 +1000,12 @@ void RenderBlock::deleteLineBoxTree()
}
}
m_lineBoxes.deleteLineBoxTree(renderArena());
- if (UNLIKELY(AXObjectCache::accessibilityEnabled()))
- document()->axObjectCache()->recomputeIsIgnored(this);
+
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->recomputeIsIgnored(this);
}
-RootInlineBox* RenderBlock::createRootInlineBox()
+RootInlineBox* RenderBlock::createRootInlineBox()
{
return new (renderArena()) RootInlineBox(this);
}
@@ -1027,8 +1015,10 @@ RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
RootInlineBox* rootBox = createRootInlineBox();
m_lineBoxes.appendLineBox(rootBox);
- if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox)
- document()->axObjectCache()->recomputeIsIgnored(this);
+ if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) {
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->recomputeIsIgnored(this);
+ }
return rootBox;
}
@@ -1120,12 +1110,16 @@ void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
if (child->nextSibling())
child->nextSibling()->setPreviousSibling(child->previousSibling());
}
+
+ child->children()->setFirstChild(0);
+ child->m_next = 0;
+
+ // Remove all the information in the flow thread associated with the leftover anonymous block.
+ child->removeFromRenderFlowThread();
+
child->setParent(0);
child->setPreviousSibling(0);
child->setNextSibling(0);
-
- child->children()->setFirstChild(0);
- child->m_next = 0;
child->destroy();
}
@@ -1161,7 +1155,7 @@ void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* c
parent->setChildrenInline(child->childrenInline());
RenderObject* nextSibling = child->nextSibling();
- RenderFlowThread* childFlowThread = child->enclosingRenderFlowThread();
+ RenderFlowThread* childFlowThread = child->flowThreadContainingBlock();
CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread);
RenderBlock* anonBlock = toRenderBlock(parent->children()->removeChildNode(parent, child, child->hasLayer()));
@@ -1173,6 +1167,46 @@ void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* c
anonBlock->destroy();
}
+void RenderBlock::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert)
+{
+ moveAllChildrenTo(toBlock, fullRemoveInsert);
+
+ // When a portion of the render tree is being detached, anonymous blocks
+ // will be combined as their children are deleted. In this process, the
+ // anonymous block later in the tree is merged into the one preceeding it.
+ // It can happen that the later block (this) contains floats that the
+ // previous block (toBlock) did not contain, and thus are not in the
+ // floating objects list for toBlock. This can result in toBlock containing
+ // floats that are not in it's floating objects list, but are in the
+ // floating objects lists of siblings and parents. This can cause problems
+ // when the float itself is deleted, since the deletion code assumes that
+ // if a float is not in it's containing block's floating objects list, it
+ // isn't in any floating objects list. In order to preserve this condition
+ // (removing it has serious performance implications), we need to copy the
+ // floating objects from the old block (this) to the new block (toBlock).
+ // The float's metrics will likely all be wrong, but since toBlock is
+ // already marked for layout, this will get fixed before anything gets
+ // displayed.
+ // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
+ if (m_floatingObjects) {
+ if (!toBlock->m_floatingObjects)
+ toBlock->createFloatingObjects();
+
+ const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
+ FloatingObjectSetIterator end = fromFloatingObjectSet.end();
+
+ for (FloatingObjectSetIterator it = fromFloatingObjectSet.begin(); it != end; ++it) {
+ FloatingObject* floatingObject = *it;
+
+ // Don't insert the object again if it's already in the list
+ if (toBlock->containsFloat(floatingObject->renderer()))
+ continue;
+
+ toBlock->m_floatingObjects->add(floatingObject->clone());
+ }
+ }
+}
+
void RenderBlock::removeChild(RenderObject* oldChild)
{
// No need to waste time in merging or removing empty anonymous blocks.
@@ -1182,6 +1216,9 @@ void RenderBlock::removeChild(RenderObject* oldChild)
return;
}
+ // This protects against column split flows when anonymous blocks are getting merged.
+ TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
+
// If this child is a block, and if our previous and next siblings are
// both anonymous blocks with inline content, then we can go ahead and
// fold the inline content back together.
@@ -1222,7 +1259,7 @@ void RenderBlock::removeChild(RenderObject* oldChild)
} else {
// Take all the children out of the |next| block and put them in
// the |prev| block.
- nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
+ nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
// Delete the now-empty block's lines and nuke it.
nextBlock->deleteLineBoxTree();
@@ -1353,6 +1390,7 @@ void RenderBlock::finishDelayUpdateScrollInfo()
RenderBlock* block = *it;
if (block->hasOverflowClip()) {
block->layer()->updateScrollInfoAfterLayout();
+ block->clearLayoutOverflow();
}
}
}
@@ -1391,69 +1429,118 @@ void RenderBlock::layout()
// It's safe to check for control clip here, since controls can never be table cells.
// If we have a lightweight clip, there can never be any overflow from children.
- if (hasControlClip() && m_overflow)
+ if (hasControlClip() && m_overflow && !gDelayUpdateScrollInfo)
clearLayoutOverflow();
+
+ invalidateBackgroundObscurationStatus();
}
-#if ENABLE(CSS_EXCLUSIONS)
-void RenderBlock::updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue* shapeInside, const ExclusionShapeValue* oldShapeInside)
+#if ENABLE(CSS_SHAPES)
+void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
{
// FIXME: A future optimization would do a deep comparison for equality.
if (shapeInside == oldShapeInside)
return;
if (shapeInside) {
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = ExclusionShapeInsideInfo::ensureExclusionShapeInsideInfoForRenderBlock(this);
- exclusionShapeInsideInfo->dirtyShapeSize();
- } else
- ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(this);
+ ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
+ shapeInsideInfo->dirtyShapeSize();
+ } else {
+ setShapeInsideInfo(nullptr);
+ markShapeInsideDescendantsForLayout();
+ }
+}
+
+void RenderBlock::markShapeInsideDescendantsForLayout()
+{
+ if (!everHadLayout())
+ return;
+ if (childrenInline()) {
+ setNeedsLayout(true);
+ return;
+ }
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isRenderBlock())
+ continue;
+ RenderBlock* childBlock = toRenderBlock(child);
+ childBlock->markShapeInsideDescendantsForLayout();
+ }
}
#endif
-void RenderBlock::updateRegionsAndExclusionsLogicalSize()
+static inline bool shapeInfoRequiresRelayout(const RenderBlock* block)
{
-#if ENABLE(CSS_EXCLUSIONS)
- if (!inRenderFlowThread() && !exclusionShapeInsideInfo())
+#if !ENABLE(CSS_SHAPES)
+ return false;
#else
- if (!inRenderFlowThread())
+ ShapeInsideInfo* info = block->shapeInsideInfo();
+ if (info)
+ info->setNeedsLayout(info->shapeSizeDirty());
+ else
+ info = block->layoutShapeInsideInfo();
+ return info && info->needsLayout();
#endif
- return;
+}
+
+bool RenderBlock::updateRegionsAndShapesBeforeChildLayout(RenderFlowThread* flowThread)
+{
+#if ENABLE(CSS_SHAPES)
+ if (!flowThread && !shapeInsideInfo())
+#else
+ if (!flowThread)
+#endif
+ return shapeInfoRequiresRelayout(this);
LayoutUnit oldHeight = logicalHeight();
LayoutUnit oldTop = logicalTop();
// Compute the maximum logical height content may cause this block to expand to
// FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
- setLogicalHeight(LayoutUnit::max() / 2);
+ setLogicalHeight(RenderFlowThread::maxLogicalHeight());
updateLogicalHeight();
-#if ENABLE(CSS_EXCLUSIONS)
- computeExclusionShapeSize();
+#if ENABLE(CSS_SHAPES)
+ computeShapeSize();
#endif
// Set our start and end regions. No regions above or below us will be considered by our children. They are
// effectively clamped to our region range.
- computeRegionRangeForBlock();
+ computeRegionRangeForBlock(flowThread);
setLogicalHeight(oldHeight);
setLogicalTop(oldTop);
+
+ return shapeInfoRequiresRelayout(this);
}
-#if ENABLE(CSS_EXCLUSIONS)
-void RenderBlock::computeExclusionShapeSize()
+#if ENABLE(CSS_SHAPES)
+void RenderBlock::computeShapeSize()
{
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = this->exclusionShapeInsideInfo();
- if (exclusionShapeInsideInfo) {
+ ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
+ if (shapeInsideInfo) {
bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
- exclusionShapeInsideInfo->computeShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
+ shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
}
}
#endif
-void RenderBlock::computeRegionRangeForBlock()
+void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged)
+{
+#if ENABLE(CSS_SHAPES)
+ // A previous sibling has changed dimension, so we need to relayout the shape with the content
+ ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
+ if (heightChanged && shapeInsideInfo)
+ shapeInsideInfo->dirtyShapeSize();
+#else
+ UNUSED_PARAM(heightChanged);
+#endif
+ computeRegionRangeForBlock(flowThread);
+}
+
+void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread)
{
- if (inRenderFlowThread())
- enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
+ if (flowThread)
+ flowThread->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
}
bool RenderBlock::updateLogicalWidthAndColumnWidth()
@@ -1464,7 +1551,10 @@ bool RenderBlock::updateLogicalWidthAndColumnWidth()
updateLogicalWidth();
calcColumnWidth();
- return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth();
+ bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged;
+ m_hasBorderOrPaddingLogicalWidthChanged = false;
+
+ return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
}
void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
@@ -1475,17 +1565,18 @@ void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalH
// We need to go ahead and set our explicit page height if one exists, so that we can
// avoid doing two layout passes.
updateLogicalHeight();
- LayoutUnit columnHeight = contentLogicalHeight();
+ LayoutUnit columnHeight = isRenderView() ? view()->pageOrViewLogicalHeight() : contentLogicalHeight();
if (columnHeight > 0) {
pageLogicalHeight = columnHeight;
hasSpecifiedPageLogicalHeight = true;
}
setLogicalHeight(0);
}
- if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
- colInfo->setColumnHeight(pageLogicalHeight);
+
+ if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout())
pageLogicalHeightChanged = true;
- }
+
+ colInfo->setColumnHeight(pageLogicalHeight);
if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
colInfo->clearForcedBreaks();
@@ -1493,7 +1584,7 @@ void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalH
colInfo->setPaginationUnit(paginationUnit());
} else if (isRenderFlowThread()) {
pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
- pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalHeightChanged();
+ pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged();
}
}
@@ -1512,11 +1603,11 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
if (updateLogicalWidthAndColumnWidth())
relayoutChildren = true;
- m_overflow.clear();
-
clearFloats();
LayoutUnit previousHeight = logicalHeight();
+ // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
+ // for consistency with other render classes?
setLogicalHeight(0);
bool pageLogicalHeightChanged = false;
@@ -1527,12 +1618,12 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
RenderStyle* styleToUse = style();
LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo());
- if (inRenderFlowThread()) {
- // Regions changing widths can force us to relayout our children.
- if (logicalWidthChangedInRegions())
- relayoutChildren = true;
- }
- updateRegionsAndExclusionsLogicalSize();
+ // Regions changing widths can force us to relayout our children.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (logicalWidthChangedInRegions(flowThread))
+ relayoutChildren = true;
+ if (updateRegionsAndShapesBeforeChildLayout(flowThread))
+ relayoutChildren = true;
// We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
// our current maximal positive and negative margins. These values are used when we
@@ -1548,8 +1639,8 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
if (!isCell) {
initMaxMarginValues();
- setMarginBeforeQuirk(styleToUse->marginBefore().quirk());
- setMarginAfterQuirk(styleToUse->marginAfter().quirk());
+ setHasMarginBeforeQuirk(styleToUse->hasMarginBeforeQuirk());
+ setHasMarginAfterQuirk(styleToUse->hasMarginAfterQuirk());
setPaginationStrut(0);
}
@@ -1564,16 +1655,22 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
// Expand our intrinsic height to encompass floats.
- LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
return;
-
+
// Calculate our new height.
LayoutUnit oldHeight = logicalHeight();
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
+
+ // Before updating the final size of the flow thread make sure a forced break is applied after the content.
+ // This ensures the size information is correctly computed for the last auto-height region receiving content.
+ if (isRenderFlowThread())
+ toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge);
+
updateLogicalHeight();
LayoutUnit newHeight = logicalHeight();
if (oldHeight != newHeight) {
@@ -1589,18 +1686,21 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
}
}
- if (previousHeight != newHeight)
+ bool heightChanged = (previousHeight != newHeight);
+ if (heightChanged)
relayoutChildren = true;
layoutPositionedObjects(relayoutChildren || isRoot());
- computeRegionRangeForBlock();
+ updateRegionsAndShapesAfterChildLayout(flowThread, heightChanged);
// Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
computeOverflow(oldClientAfterEdge);
statePusher.pop();
+ fitBorderToLinesIfNeeded();
+
if (renderView->layoutState()->m_pageLogicalHeight)
setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop()));
@@ -1652,7 +1752,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
repaintRectangle(reflectedRect(repaintRect));
}
}
-
+
setNeedsLayout(false);
}
@@ -1676,6 +1776,8 @@ void RenderBlock::addOverflowFromChildren()
void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
{
+ m_overflow.clear();
+
// Add overflow from children.
addOverflowFromChildren();
@@ -1696,16 +1798,39 @@ void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeF
else
rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
addLayoutOverflow(rectToApply);
+ if (hasRenderOverflow())
+ m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
}
+ // Allow our overflow to catch cases where the caret in an empty editable element with negative text indent needs to get painted.
+ LayoutUnit textIndent = textIndentOffset();
+ if (textIndent < 0) {
+ LayoutRect clientRect(clientBoxRect());
+ LayoutRect rectToApply = LayoutRect(clientRect.x() + min<LayoutUnit>(0, textIndent), clientRect.y(), clientRect.width() - min<LayoutUnit>(0, textIndent), clientRect.height());
+ addVisualOverflow(rectToApply);
+ }
+
// Add visual overflow from box-shadow and border-image-outset.
addVisualEffectOverflow();
// Add visual overflow from theme.
addVisualOverflowFromTheme();
- if (isRenderFlowThread())
- enclosingRenderFlowThread()->computeOverflowStateForRegions(oldClientAfterEdge);
+ if (isRenderNamedFlowThread())
+ toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge);
+}
+
+void RenderBlock::clearLayoutOverflow()
+{
+ if (!m_overflow)
+ return;
+
+ if (visualOverflowRect() == borderBoxRect()) {
+ m_overflow.clear();
+ return;
+ }
+
+ m_overflow->setLayoutOverflow(borderBoxRect());
}
void RenderBlock::addOverflowFromBlockChildren()
@@ -1728,7 +1853,6 @@ void RenderBlock::addOverflowFromFloats()
if (r->isDescendant())
addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
}
- return;
}
void RenderBlock::addOverflowFromPositionedObjects()
@@ -1764,7 +1888,7 @@ void RenderBlock::addVisualOverflowFromTheme()
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
- return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
+ return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
|| hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
}
@@ -1774,7 +1898,7 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg
bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
LayoutUnit logicalTop = logicalHeight();
- setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
+ updateStaticInlinePositionForChild(child, logicalTop);
if (!marginInfo.canCollapseWithMarginBefore()) {
// Positioned blocks don't collapse margins, so add the margin provided by
@@ -1813,34 +1937,6 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
setLogicalHeight(logicalHeight() - marginOffset);
}
-bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
-{
- // Handle in the given order
- return handlePositionedChild(child, marginInfo)
- || handleFloatingChild(child, marginInfo);
-}
-
-
-bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
-{
- if (child->isOutOfFlowPositioned()) {
- child->containingBlock()->insertPositionedObject(child);
- adjustPositionedBlock(child, marginInfo);
- return true;
- }
- return false;
-}
-
-bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
-{
- if (child->isFloating()) {
- insertFloatingObject(child);
- adjustFloatingBlock(marginInfo);
- return true;
- }
- return false;
-}
-
static void destroyRunIn(RenderBoxModelObject* runIn)
{
ASSERT(runIn->isRunIn());
@@ -1858,12 +1954,12 @@ static void destroyRunIn(RenderBoxModelObject* runIn)
runIn->destroy();
}
-void RenderBlock::placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunInFlag flag)
+void RenderBlock::placeRunInIfNeeded(RenderObject* newChild)
{
- if (newChild->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
+ if (newChild->isRunIn())
moveRunInUnderSiblingBlockIfNeeded(newChild);
else if (RenderObject* prevSibling = newChild->previousSibling()) {
- if (prevSibling->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
+ if (prevSibling->isRunIn())
moveRunInUnderSiblingBlockIfNeeded(prevSibling);
}
}
@@ -1871,31 +1967,18 @@ void RenderBlock::placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunIn
RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn)
{
ASSERT(runIn->isRunIn());
+ ASSERT(runIn->node());
- // First we destroy any :before/:after content. It will be regenerated by the new run-in.
- // Exception is if the run-in itself is generated.
- if (runIn->style()->styleType() != BEFORE && runIn->style()->styleType() != AFTER) {
- RenderObject* generatedContent;
- if (runIn->getCachedPseudoStyle(BEFORE) && (generatedContent = runIn->beforePseudoElementRenderer()))
- generatedContent->destroy();
- if (runIn->getCachedPseudoStyle(AFTER) && (generatedContent = runIn->afterPseudoElementRenderer()))
- generatedContent->destroy();
- }
-
- bool newRunInShouldBeBlock = !runIn->isRenderBlock();
- Node* runInNode = runIn->node();
RenderBoxModelObject* newRunIn = 0;
- if (newRunInShouldBeBlock)
- newRunIn = new (renderArena()) RenderBlock(runInNode ? runInNode : document());
+ if (!runIn->isRenderBlock())
+ newRunIn = new (renderArena()) RenderBlock(runIn->node());
else
- newRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
+ newRunIn = new (renderArena()) RenderInline(toElement(runIn->node()));
+
+ runIn->node()->setRenderer(newRunIn);
newRunIn->setStyle(runIn->style());
-
- runIn->moveAllChildrenTo(newRunIn, true);
- // If the run-in had an element, we need to set the new renderer.
- if (runInNode)
- runInNode->setRenderer(newRunIn);
+ runIn->moveAllChildrenTo(newRunIn, true);
return newRunIn;
}
@@ -1927,6 +2010,9 @@ void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn)
if (!curr || !curr->isRenderBlock() || !curr->childrenInline())
return;
+ if (toRenderBlock(curr)->beingDestroyed())
+ return;
+
// Per CSS3, "A run-in cannot run in to a block that already starts with a
// run-in or that itself is a run-in".
if (curr->isRunIn() || (curr->firstChild() && curr->firstChild()->isRunIn()))
@@ -1991,6 +2077,13 @@ void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn)
LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
{
+ bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
+ bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
+ bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
+
+ // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
+ childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
+
// Get the four margin values for the child and cache them.
const MarginValues childMargins = marginValuesForChild(child);
@@ -2000,84 +2093,106 @@ LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo
// For self-collapsing blocks, collapse our bottom margins into our
// top to get new posTop and negTop values.
- if (child->isSelfCollapsingBlock()) {
+ if (childIsSelfCollapsing) {
posTop = max(posTop, childMargins.positiveMarginAfter());
negTop = max(negTop, childMargins.negativeMarginAfter());
}
// See if the top margin is quirky. We only care if this child has
// margins that will collapse with us.
- bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
+ bool topQuirk = hasMarginBeforeQuirk(child);
if (marginInfo.canCollapseWithMarginBefore()) {
- // This child is collapsing with the top of the
- // block. If it has larger margin values, then we need to update
- // our own maximal values.
- if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
- setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
-
- // The minute any of the margins involved isn't a quirk, don't
- // collapse it away, even if the margin is smaller (www.webreference.com
- // has an example of this, a <dt> with 0.8em author-specified inside
- // a <dl> inside a <td>.
- if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
- setMarginBeforeQuirk(false);
- marginInfo.setDeterminedMarginBeforeQuirk(true);
- }
-
- if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
- // We have no top margin and our top child has a quirky margin.
- // We will pick up this quirky margin and pass it through.
- // This deals with the <td><div><p> case.
- // Don't do this for a block that split two inlines though. You do
- // still apply margins in this case.
- setMarginBeforeQuirk(true);
+ if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
+ // This child is collapsing with the top of the
+ // block. If it has larger margin values, then we need to update
+ // our own maximal values.
+ if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
+ setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
+
+ // The minute any of the margins involved isn't a quirk, don't
+ // collapse it away, even if the margin is smaller (www.webreference.com
+ // has an example of this, a <dt> with 0.8em author-specified inside
+ // a <dl> inside a <td>.
+ if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
+ setHasMarginBeforeQuirk(false);
+ marginInfo.setDeterminedMarginBeforeQuirk(true);
+ }
+
+ if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
+ // We have no top margin and our top child has a quirky margin.
+ // We will pick up this quirky margin and pass it through.
+ // This deals with the <td><div><p> case.
+ // Don't do this for a block that split two inlines though. You do
+ // still apply margins in this case.
+ setHasMarginBeforeQuirk(true);
+ } else
+ // The before margin of the container will also discard all the margins it is collapsing with.
+ setMustDiscardMarginBefore();
+ }
+
+ // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
+ if (childDiscardMarginBefore) {
+ marginInfo.setDiscardMargin(true);
+ marginInfo.clearMargin();
}
if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
- marginInfo.setMarginBeforeQuirk(topQuirk);
+ marginInfo.setHasMarginBeforeQuirk(topQuirk);
LayoutUnit beforeCollapseLogicalTop = logicalHeight();
LayoutUnit logicalTop = beforeCollapseLogicalTop;
- if (child->isSelfCollapsingBlock()) {
- // This child has no height. We need to compute our
- // position before we collapse the child's margins together,
- // so that we can get an accurate position for the zero-height block.
- LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
- LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
- marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
-
- // Now collapse the child's margins together, which means examining our
- // bottom margin values as well.
- marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
- marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
-
- if (!marginInfo.canCollapseWithMarginBefore())
- // We need to make sure that the position of the self-collapsing block
- // is correct, since it could have overflowing content
- // that needs to be positioned correctly (e.g., a block that
- // had a specified height of 0 but that actually had subcontent).
- logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
- }
- else {
- if (child->style()->marginBeforeCollapse() == MSEPARATE) {
- setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
- logicalTop = logicalHeight();
+ if (childIsSelfCollapsing) {
+ // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
+ // Also, the child's top position equals the logical height of the container.
+ if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
+ // This child has no height. We need to compute our
+ // position before we collapse the child's margins together,
+ // so that we can get an accurate position for the zero-height block.
+ LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
+ LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
+ marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
+
+ // Now collapse the child's margins together, which means examining our
+ // bottom margin values as well.
+ marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
+
+ if (!marginInfo.canCollapseWithMarginBefore())
+ // We need to make sure that the position of the self-collapsing block
+ // is correct, since it could have overflowing content
+ // that needs to be positioned correctly (e.g., a block that
+ // had a specified height of 0 but that actually had subcontent).
+ logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
}
- else if (!marginInfo.atBeforeSideOfBlock() ||
- (!marginInfo.canCollapseMarginBeforeWithChildren()
- && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
+ } else {
+ if (mustSeparateMarginBeforeForChild(child)) {
+ ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
+ // If we are at the before side of the block and we collapse, ignore the computed margin
+ // and just add the child margin to the container height. This will correctly position
+ // the child inside the container.
+ LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0);
+ setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
+ logicalTop = logicalHeight();
+ } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
+ || (!marginInfo.canCollapseMarginBeforeWithChildren()
+ && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
// We're collapsing with a previous sibling's margins and not
// with the top of the block.
setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
logicalTop = logicalHeight();
}
- marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
- marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
+ marginInfo.setDiscardMargin(childDiscardMarginAfter);
+
+ if (!marginInfo.discardMargin()) {
+ marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
+ } else
+ marginInfo.clearMargin();
if (marginInfo.margin())
- marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
+ marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
}
// If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
@@ -2093,12 +2208,15 @@ LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo
// If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
// overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
// or clear it anyway, so don't worry about any floating children it may contain.
+ LayoutUnit oldLogicalHeight = logicalHeight();
+ setLogicalHeight(logicalTop);
RenderObject* prev = child->previousSibling();
if (prev && prev->isBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
RenderBlock* block = toRenderBlock(prev);
if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
addOverhangingFloats(block, false);
}
+ setLogicalHeight(oldLogicalHeight);
return logicalTop;
}
@@ -2110,12 +2228,19 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
return yPos;
if (child->isSelfCollapsingBlock()) {
+ bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
+
// For self-collapsing blocks that clear, they can still collapse their
// margins with following siblings. Reset the current margins to represent
// the self-collapsing block's margins only.
- MarginValues childMargins = marginValuesForChild(child);
- marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
- marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
+ // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
+ if (!childDiscardMargin) {
+ MarginValues childMargins = marginValuesForChild(child);
+ marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
+ marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
+ } else
+ marginInfo.clearMargin();
+ marginInfo.setDiscardMargin(childDiscardMargin);
// CSS2.1 states:
// "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
@@ -2134,7 +2259,8 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
// Move the top of the child box to the bottom of the float ignoring the child's top margin.
LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
setLogicalHeight(child->logicalTop() - collapsedMargin);
- heightIncrease -= collapsedMargin;
+ // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above.
+ heightIncrease -= max(LayoutUnit(), collapsedMargin);
} else
// Increase our height by the amount we had to clear.
setLogicalHeight(logicalHeight() + heightIncrease);
@@ -2147,6 +2273,9 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
// margins involved.
setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
marginInfo.setAtBeforeSideOfBlock(false);
+
+ // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
+ setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
}
LayoutUnit logicalTop = yPos + heightIncrease;
@@ -2158,12 +2287,22 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
return logicalTop;
}
-void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const
+void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
{
- // FIXME: We should deal with the margin-collapse-* style extensions that prevent collapsing and that discard margins.
// Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
- if (document()->inQuirksMode() && child->isMarginBeforeQuirk() && (isTableCell() || isBody()))
+ // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
+ // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
+ if ((document()->inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
+ return;
+
+ // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
+ // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
+ if (child->style()->marginBeforeCollapse() == MDISCARD) {
+ positiveMarginBefore = 0;
+ negativeMarginBefore = 0;
+ discardMarginBefore = true;
return;
+ }
LayoutUnit beforeChildMargin = marginBeforeForChild(child);
positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
@@ -2176,7 +2315,7 @@ void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& pos
if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
return;
- MarginInfo childMarginInfo(childBlock, childBlock->borderBefore() + childBlock->paddingBefore(), childBlock->borderAfter() + childBlock->paddingAfter());
+ MarginInfo childMarginInfo(childBlock, childBlock->borderAndPaddingBefore(), childBlock->borderAndPaddingAfter());
if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
return;
@@ -2193,12 +2332,15 @@ void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& pos
// Make sure to update the block margins now for the grandchild box so that we're looking at current values.
if (grandchildBox->needsLayout()) {
grandchildBox->computeAndSetBlockDirectionMargins(this);
- grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->marginBefore().quirk());
- grandchildBox->setMarginAfterQuirk(grandchildBox->style()->marginAfter().quirk());
+ if (grandchildBox->isRenderBlock()) {
+ RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
+ grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk());
+ grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk());
+ }
}
// Collapse the margin of the grandchild box with our own to produce an estimate.
- childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore);
+ childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
}
LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
@@ -2209,19 +2351,22 @@ LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const Margi
if (!marginInfo.canCollapseWithMarginBefore()) {
LayoutUnit positiveMarginBefore = 0;
LayoutUnit negativeMarginBefore = 0;
+ bool discardMarginBefore = false;
if (child->selfNeedsLayout()) {
// Try to do a basic estimation of how the collapse is going to go.
- marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore);
+ marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
} else {
// Use the cached collapsed margin values from a previous layout. Most of the time they
// will be right.
MarginValues marginValues = marginValuesForChild(child);
positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
+ discardMarginBefore = mustDiscardMarginBeforeForChild(child);
}
// Collapse the result with our current margins.
- logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
+ if (!discardMarginBefore)
+ logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
}
// Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
@@ -2249,10 +2394,9 @@ LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const Margi
return logicalTopEstimate;
}
-LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart,
- RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
+LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* region)
{
- LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
+ LayoutUnit startPosition = startOffsetForContent(region);
// Add in our start margin.
LayoutUnit oldPosition = startPosition + childMarginStart;
@@ -2260,9 +2404,9 @@ LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const Re
LayoutUnit blockOffset = logicalTopForChild(child);
if (region)
- blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage));
+ blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage()));
- LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage, logicalHeightForChild(child));
+ LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, logicalHeightForChild(child));
if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
if (childMarginStart < 0)
@@ -2274,7 +2418,7 @@ LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const Re
return newPosition - oldPosition;
}
-void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
+void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
{
LayoutUnit startPosition = borderStart() + paddingStart();
if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
@@ -2287,27 +2431,34 @@ void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
// Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
// to shift over as necessary to dodge any floats that might get in the way.
- if (child->avoidsFloats() && containsFloats() && !inRenderFlowThread())
+ if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
- setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
+ setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
}
void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
{
if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
+ // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
+ // Don't update the max margin values because we won't need them anyway.
+ if (marginInfo.discardMargin()) {
+ setMustDiscardMarginAfter();
+ return;
+ }
+
// Update our max pos/neg bottom margins, since we collapsed our bottom margins
// with our children.
setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
- if (!marginInfo.marginAfterQuirk())
- setMarginAfterQuirk(false);
+ if (!marginInfo.hasMarginAfterQuirk())
+ setHasMarginAfterQuirk(false);
- if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
+ if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
// We have no bottom margin and our last child has a quirky margin.
// We will pick up this quirky margin and pass it through.
// This deals with the <td><div><p> case.
- setMarginAfterQuirk(true);
+ setHasMarginAfterQuirk(true);
}
}
@@ -2316,11 +2467,8 @@ void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit after
marginInfo.setAtAfterSideOfBlock(true);
// If we can't collapse with children then go ahead and add in the bottom margin.
- // Don't do this for ordinary anonymous blocks as only the enclosing box should add in
- // its margin.
- if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
- && (!isAnonymousBlock() || isAnonymousColumnsBlock() || isAnonymousColumnSpanBlock())
- && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
+ if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
+ && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
setLogicalHeight(logicalHeight() + marginInfo.margin());
// Now add in our bottom border/padding.
@@ -2360,28 +2508,55 @@ void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop,
}
}
-void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
+void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child)
{
- if (gPercentHeightDescendantsMap) {
- if (TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this)) {
- TrackedRendererListHashSet::iterator end = descendants->end();
- for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
- RenderBox* box = *it;
- while (box != this) {
- if (box->normalChildNeedsLayout())
- break;
- box->setChildNeedsLayout(true, MarkOnlyThis);
- box = box->containingBlock();
- ASSERT(box);
- if (!box)
- break;
- }
- }
+ // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
+ // an auto value. Add a method to determine this, so that we can avoid the relayout.
+ if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()) || child->hasViewportPercentageLogicalHeight())
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+
+ // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
+ if (relayoutChildren && child->needsPreferredWidthsRecalculation())
+ child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
+}
+
+void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants()
+{
+ if (!gPercentHeightDescendantsMap)
+ return;
+
+ TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
+ if (!descendants)
+ return;
+
+ TrackedRendererListHashSet::iterator end = descendants->end();
+ for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
+ RenderBox* box = *it;
+ while (box != this) {
+ if (box->normalChildNeedsLayout())
+ break;
+ box->setChildNeedsLayout(true, MarkOnlyThis);
+
+ // If the width of an image is affected by the height of a child (e.g., an image with an aspect ratio),
+ // then we have to dirty preferred widths, since even enclosing blocks can become dirty as a result.
+ // (A horizontal flexbox that contains an inline image wrapped in an anonymous block for example.)
+ if (box->hasAspectRatio())
+ box->setPreferredLogicalWidthsDirty(true);
+
+ box = box->containingBlock();
+ ASSERT(box);
+ if (!box)
+ break;
}
}
+}
+
+void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
+{
+ dirtyForLayoutFromPercentageHeightDescendants();
- LayoutUnit beforeEdge = borderBefore() + paddingBefore();
- LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit beforeEdge = borderAndPaddingBefore();
+ LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
setLogicalHeight(beforeEdge);
@@ -2409,20 +2584,18 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloa
if (childToExclude == child)
continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
- // Make sure we layout children if they need it.
- // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
- // an auto value. Add a method to determine this, so that we can avoid the relayout.
- if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
- child->setChildNeedsLayout(true, MarkOnlyThis);
-
- // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
- if (relayoutChildren && child->needsPreferredWidthsRecalculation())
- child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
+ updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
- // Handle the four types of special elements first. These include positioned content, floating content, compacts and
- // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
- if (handleSpecialChild(child, marginInfo))
+ if (child->isOutOfFlowPositioned()) {
+ child->containingBlock()->insertPositionedObject(child);
+ adjustPositionedBlock(child, marginInfo);
continue;
+ }
+ if (child->isFloating()) {
+ insertFloatingObject(child);
+ adjustFloatingBlock(marginInfo);
+ continue;
+ }
// Lay out the child.
layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
@@ -2441,13 +2614,6 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
// The child is a normal flow object. Compute the margins we will use for collapsing now.
child->computeAndSetBlockDirectionMargins(this);
- // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
- RenderStyle* childStyle = child->style();
- if (childStyle->marginBeforeCollapse() == MSEPARATE) {
- marginInfo.setAtBeforeSideOfBlock(false);
- marginInfo.clearMargin();
- }
-
// Try to guess our correct logical top position. In most cases this guess will
// be correct. Only if we're wrong (when we compute the real logical top position)
// will we have to potentially relayout.
@@ -2468,6 +2634,14 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
bool markDescendantsWithFloats = false;
if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
markDescendantsWithFloats = true;
+#if ENABLE(SUBPIXEL_LAYOUT)
+ else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
+ // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
+ // very large elements. If it does the comparison with oldLogicalTop might yield a
+ // false negative as adding and removing margins, borders etc from a saturated number
+ // might yield incorrect results. If this is the case always mark for layout.
+ markDescendantsWithFloats = true;
+#endif
else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
// If an element might be affected by the presence of floats, then always mark it for
// layout.
@@ -2511,7 +2685,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
// Now we have a final top position. See if it really does end up being different from our estimate.
// clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
// when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
- if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout()) {
+ if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) {
if (child->shrinkToAvoidFloats()) {
// The child's width depends on the line width.
// When the child shifts to clear an item, its width can
@@ -2537,11 +2711,11 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
marginInfo.setAtBeforeSideOfBlock(false);
// Now place the child in the correct left position
- determineLogicalLeftPositionForChild(child);
+ determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
// Update our height now that the child has been placed in the correct position.
setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
- if (childStyle->marginAfterCollapse() == MSEPARATE) {
+ if (mustSeparateMarginAfterForChild(child)) {
setLogicalHeight(logicalHeight() + marginAfterForChild(child));
marginInfo.clearMargin();
}
@@ -2621,16 +2795,23 @@ bool RenderBlock::simplifiedLayout()
simplifiedNormalFlowLayout();
// Lay out our positioned objects if our positioned child bit is set.
- if (posChildNeedsLayout())
- layoutPositionedObjects(false);
+ // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
+ // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
+ // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
+ // are statically positioned and thus need to move with their absolute ancestors.
+ bool canContainFixedPosObjects = canContainFixedPositionObjects();
+ if (posChildNeedsLayout() || canContainFixedPosObjects)
+ layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects);
// Recompute our overflow information.
// FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
// updating our overflow if we either used to have overflow or if the new temporary object has overflow.
// For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
// lowestPosition on every relayout so it's not a regression.
- m_overflow.clear();
- computeOverflow(clientLogicalBottom(), true);
+ // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
+ // simplifiedLayout, we cache the value in m_overflow.
+ LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
+ computeOverflow(oldClientAfterEdge, true);
statePusher.pop();
@@ -2642,7 +2823,38 @@ bool RenderBlock::simplifiedLayout()
return true;
}
-void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
+void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child)
+{
+ if (child->style()->position() != FixedPosition)
+ return;
+
+ bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
+ bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
+ if (!hasStaticBlockPosition && !hasStaticInlinePosition)
+ return;
+
+ RenderObject* o = child->parent();
+ while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition)
+ o = o->parent();
+ if (o->style()->position() != AbsolutePosition)
+ return;
+
+ RenderBox* box = toRenderBox(child);
+ if (hasStaticInlinePosition) {
+ LogicalExtentComputedValues computedValues;
+ box->computeLogicalWidthInRegion(computedValues);
+ LayoutUnit newLeft = computedValues.m_position;
+ if (newLeft != box->logicalLeft())
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ } else if (hasStaticBlockPosition) {
+ LayoutUnit oldTop = box->logicalTop();
+ box->updateLogicalHeight();
+ if (box->logicalTop() != oldTop)
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ }
+}
+
+void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly)
{
TrackedRendererListHashSet* positionedDescendants = positionedObjects();
if (!positionedDescendants)
@@ -2655,6 +2867,16 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
TrackedRendererListHashSet::iterator end = positionedDescendants->end();
for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
r = *it;
+
+ // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
+ // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e.
+ // it has static position.
+ markFixedPositionObjectForLayoutIfNeeded(r);
+ if (fixedPositionObjectsOnly) {
+ r->layoutIfNeeded();
+ continue;
+ }
+
// When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
// non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
// objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
@@ -2718,7 +2940,7 @@ void RenderBlock::markForPaginationRelayoutIfNeeded()
if (needsLayout())
return;
- if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
+ if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()) || shouldBreakAtLineToAvoidWidow())
setChildNeedsLayout(true, MarkOnlyThis);
}
@@ -2741,7 +2963,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
// condition is replaced with being a descendant of us.
if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->shouldPaint()) && !r->m_renderer->hasSelfPaintingLayer()) {
r->m_renderer->repaint();
- r->m_renderer->repaintOverhangingFloats();
+ r->m_renderer->repaintOverhangingFloats(false);
}
}
}
@@ -2772,7 +2994,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
// z-index. We paint after we painted the background/border, so that the scrollbars will
// sit above the background/border.
- if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
+ if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly())
layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
}
@@ -2786,7 +3008,7 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain
EBorderStyle ruleStyle = style()->columnRuleStyle();
LayoutUnit ruleThickness = style()->columnRuleWidth();
LayoutUnit colGap = columnGap();
- bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleThickness <= colGap;
+ bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
if (!renderRule)
return;
@@ -2831,10 +3053,10 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain
bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
LayoutUnit ruleLeft = isHorizontalWritingMode()
? borderLeft() + paddingLeft()
- : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
+ : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderAndPaddingBefore() : borderAndPaddingAfter());
LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
LayoutUnit ruleTop = isHorizontalWritingMode()
- ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
+ ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderAndPaddingBefore() : borderAndPaddingAfter())
: borderStart() + paddingStart();
LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
@@ -2864,6 +3086,36 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain
}
}
+LayoutUnit RenderBlock::initialBlockOffsetForPainting() const
+{
+ ColumnInfo* colInfo = columnInfo();
+ LayoutUnit result = 0;
+ if (colInfo->progressionAxis() == ColumnInfo::BlockAxis && colInfo->progressionIsReversed()) {
+ LayoutRect colRect = columnRectAt(colInfo, 0);
+ result = isHorizontalWritingMode() ? colRect.y() : colRect.x();
+ result -= borderAndPaddingBefore();
+ if (style()->isFlippedBlocksWritingMode())
+ result = -result;
+ }
+ return result;
+}
+
+LayoutUnit RenderBlock::blockDeltaForPaintingNextColumn() const
+{
+ ColumnInfo* colInfo = columnInfo();
+ LayoutUnit blockDelta = -colInfo->columnHeight();
+ LayoutUnit colGap = columnGap();
+ if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
+ if (!colInfo->progressionIsReversed())
+ blockDelta = colGap;
+ else
+ blockDelta -= (colInfo->columnHeight() + colGap);
+ }
+ if (style()->isFlippedBlocksWritingMode())
+ blockDelta = -blockDelta;
+ return blockDelta;
+}
+
void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
{
// We need to do multiple passes, breaking up our child painting into strips.
@@ -2872,20 +3124,16 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p
unsigned colCount = columnCount(colInfo);
if (!colCount)
return;
- LayoutUnit currLogicalTopOffset = 0;
LayoutUnit colGap = columnGap();
+ LayoutUnit currLogicalTopOffset = initialBlockOffsetForPainting();
+ LayoutUnit blockDelta = blockDeltaForPaintingNextColumn();
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
LayoutRect colRect = columnRectAt(colInfo, i);
flipForWritingMode(colRect);
+
LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
- if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
- if (isHorizontalWritingMode())
- offset.expand(0, colRect.y() - borderTop() - paddingTop());
- else
- offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
- }
colRect.moveBy(paintOffset);
PaintInfo info(paintInfo);
info.rect.intersect(pixelSnappedIntRect(colRect));
@@ -2913,12 +3161,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p
else
paintContents(info, adjustedPaintOffset);
}
-
- LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
- if (style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset += blockDelta;
- else
- currLogicalTopOffset -= blockDelta;
+ currLogicalTopOffset += blockDelta;
}
}
@@ -2939,7 +3182,7 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOf
// We don't paint our own background, but we do let the kids paint their backgrounds.
PaintInfo paintInfoForChild(paintInfo);
paintInfoForChild.phase = newPhase;
- paintInfoForChild.updatePaintingRootForChildren(this);
+ paintInfoForChild.updateSubtreePaintRootForChildren(this);
// FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
// NSViews. Do not add any more code for this.
@@ -3026,7 +3269,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
if (hasBoxDecorations())
paintBoxDecorations(paintInfo, paintOffset);
- if (hasColumns())
+ if (hasColumns() && !paintInfo.paintRootBackgroundOnly())
paintColumnRules(paintInfo, paintOffset);
}
@@ -3036,7 +3279,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
}
// We're done. We don't bother painting any children.
- if (paintPhase == PaintPhaseBlockBackground)
+ if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
return;
// Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
@@ -3068,15 +3311,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
// 5. paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
- paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
+ paintOutline(paintInfo, LayoutRect(paintOffset, size()));
// 6. paint continuation outlines.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
RenderInline* inlineCont = inlineElementContinuation();
- // FIXME: For now, do not add continuations for outline painting by our containing block if we are a relative positioned
- // anonymous block (i.e. have our own layer). This is because a block depends on renderers in its continuation table being
- // in the same layer.
- if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE && !hasLayer()) {
+ if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
RenderBlock* cb = containingBlock();
@@ -3088,10 +3328,13 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
}
}
- if (!inlineEnclosedInSelfPaintingLayer)
+ // Do not add continuations for outline painting by our containing block if we are a relative positioned
+ // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being
+ // in the same layer.
+ if (!inlineEnclosedInSelfPaintingLayer && !hasLayer())
cb->addContinuationWithOutline(inlineRenderer);
- else if (!inlineRenderer->firstLineBox())
- inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
+ else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer()))
+ inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
}
paintContinuationOutlines(paintInfo, paintOffset);
}
@@ -3115,7 +3358,7 @@ LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* c
// case.
if (isHorizontalWritingMode())
return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
- return LayoutPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
+ return LayoutPoint(point.x() + width() - child->renderer()->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
}
void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
@@ -3180,7 +3423,7 @@ void RenderBlock::addContinuationWithOutline(RenderInline* flow)
ListHashSet<RenderInline*>* continuations = table->get(this);
if (!continuations) {
continuations = new ListHashSet<RenderInline*>;
- table->set(this, continuations);
+ table->set(this, adoptPtr(continuations));
}
continuations->add(flow);
@@ -3205,7 +3448,7 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint&
if (table->isEmpty())
return;
- ListHashSet<RenderInline*>* continuations = table->get(this);
+ OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this);
if (!continuations)
return;
@@ -3219,12 +3462,8 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint&
for ( ; block && block != this; block = block->containingBlock())
accumulatedPaintOffset.moveBy(block->location());
ASSERT(block);
- flow->paintOutline(info.context, accumulatedPaintOffset);
+ flow->paintOutline(info, accumulatedPaintOffset);
}
-
- // Delete
- delete continuations;
- table->remove(this);
}
bool RenderBlock::shouldPaintSelectionGaps() const
@@ -3234,8 +3473,9 @@ bool RenderBlock::shouldPaintSelectionGaps() const
bool RenderBlock::isSelectionRoot() const
{
- if (!node())
+ if (isPseudoElement())
return false;
+ ASSERT(node() || isAnonymous());
// FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
if (isTable())
@@ -3264,30 +3504,31 @@ GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject*
if (!shouldPaintSelectionGaps())
return GapRects();
- // FIXME: this is broken with transforms
TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
- mapLocalToContainer(repaintContainer, transformState);
+ mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms);
LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
if (hasOverflowClip())
offsetFromRepaintContainer -= scrolledContentOffset();
+ LogicalSelectionOffsetCaches cache(this);
LayoutUnit lastTop = 0;
- LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
- LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
+ LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
+ LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
- return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
+ return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight, cache);
}
void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
+ LogicalSelectionOffsetCaches cache(this);
LayoutUnit lastTop = 0;
- LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
- LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
+ LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
+ LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
GraphicsContextStateSaver stateSaver(*paintInfo.context);
- LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
+ LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, cache, &paintInfo);
if (!gapRectsBounds.isEmpty()) {
if (RenderLayer* layer = enclosingLayer()) {
gapRectsBounds.moveBy(-paintOffset);
@@ -3339,7 +3580,7 @@ LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPh
}
GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
// IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
// Clip out floating and positioned objects when painting selection gaps.
@@ -3376,25 +3617,27 @@ GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& r
if (hasColumns() || hasTransform() || style()->columnSpan()) {
// FIXME: We should learn how to gap fill multiple columns and transforms eventually.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
return result;
}
if (childrenInline())
- result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
+ result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
else
- result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
+ result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
// Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
- if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
- result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
- logicalHeight(), paintInfo));
+ if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) {
+ result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
+ lastLogicalTop, lastLogicalLeft, lastLogicalRight, logicalHeight(), cache, paintInfo));
+ }
+
return result;
}
GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
GapRects result;
@@ -3405,8 +3648,8 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
// Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
// case.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
}
return result;
}
@@ -3422,15 +3665,14 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
if (!containsStart && !lastSelectedLine &&
selectionState() != SelectionStart && selectionState() != SelectionBoth)
- result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
- selTop, paintInfo));
+ result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
|| (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
- result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
+ result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
lastSelectedLine = curr;
}
@@ -3442,20 +3684,25 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
// Go ahead and update our lastY to be the bottom of the last selected line.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
}
return result;
}
GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
GapRects result;
// Go ahead and jump right to the first block child that contains some selected objects.
RenderBox* curr;
for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
+
+ if (!curr)
+ return result;
+
+ LogicalSelectionOffsetCaches childCache(this, cache);
for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
SelectionState childState = curr->selectionState();
@@ -3477,10 +3724,11 @@ GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoi
bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
if (fillBlockGaps) {
// We need to fill the vertical gap above this object.
- if (childState == SelectionEnd || childState == SelectionInside)
+ if (childState == SelectionEnd || childState == SelectionInside) {
// Fill the gap above the object.
- result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
- curr->logicalTop(), paintInfo));
+ result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
+ lastLogicalTop, lastLogicalLeft, lastLogicalRight, curr->logicalTop(), cache, paintInfo));
+ }
// Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past*
// our object. We know this if the selection did not end inside our object.
@@ -3492,26 +3740,27 @@ GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoi
getSelectionGapInfo(childState, leftGap, rightGap);
if (leftGap)
- result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
+ result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
if (rightGap)
- result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
+ result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
// Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
// they can without bumping into floating or positioned objects. Ideally they will go right up
// to the border of the root selection block.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
- } else if (childState != SelectionNone)
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom(), cache);
+ } else if (childState != SelectionNone) {
// We must be a block that has some selected object inside it. Go ahead and recur.
result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
- lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
+ lastLogicalTop, lastLogicalLeft, lastLogicalRight, childCache, paintInfo));
+ }
}
return result;
}
LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
+ LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit logicalTop = lastLogicalTop;
LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
@@ -3519,8 +3768,8 @@ LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPo
return LayoutRect();
// Get the selection offsets for the bottom of the gap
- LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
- LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
+ LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom, cache));
+ LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom, cache));
LayoutUnit logicalWidth = logicalRight - logicalLeft;
if (logicalWidth <= 0)
return LayoutRect();
@@ -3532,11 +3781,12 @@ LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPo
}
LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
+ RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
- LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
- LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
+ LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
+ LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft),
+ min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
if (rootBlockLogicalWidth <= 0)
return LayoutRect();
@@ -3548,11 +3798,12 @@ LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const La
}
LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
+ RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
- LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
- LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
+ LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight),
+ max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
+ LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
if (rootBlockLogicalWidth <= 0)
return LayoutRect();
@@ -3574,37 +3825,45 @@ void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool&
(state == RenderObject::SelectionEnd && !ltr);
}
-LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
+LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
{
LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
if (logicalLeft == logicalLeftOffsetForContent()) {
- if (rootBlock != this)
- // The border can potentially be further extended by our containingBlock().
- return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
+ if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
+ return cache.containingBlockInfo(this).logicalLeftSelectionOffset(rootBlock, position + logicalTop());
return logicalLeft;
} else {
RenderBlock* cb = this;
+ const LogicalSelectionOffsetCaches* currentCache = &cache;
while (cb != rootBlock) {
logicalLeft += cb->logicalLeft();
- cb = cb->containingBlock();
+
+ ASSERT(currentCache);
+ const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
+ cb = info.block();
+ currentCache = info.cache();
}
}
return logicalLeft;
}
-LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
+LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
{
LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
if (logicalRight == logicalRightOffsetForContent()) {
- if (rootBlock != this)
- // The border can potentially be further extended by our containingBlock().
- return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
+ if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
+ return cache.containingBlockInfo(this).logicalRightSelectionOffset(rootBlock, position + logicalTop());
return logicalRight;
} else {
RenderBlock* cb = this;
+ const LogicalSelectionOffsetCaches* currentCache = &cache;
while (cb != rootBlock) {
logicalRight += cb->logicalLeft();
- cb = cb->containingBlock();
+
+ ASSERT(currentCache);
+ const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
+ cb = info.block();
+ currentCache = info.cache();
}
}
return logicalRight;
@@ -3652,7 +3911,7 @@ void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDe
TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
if (!descendantSet) {
descendantSet = new TrackedRendererListHashSet;
- descendantsMap->set(this, descendantSet);
+ descendantsMap->set(this, adoptPtr(descendantSet));
}
bool added = descendantSet->add(descendant).isNewEntry;
if (!added) {
@@ -3664,7 +3923,7 @@ void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDe
HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
if (!containerSet) {
containerSet = new HashSet<RenderBlock*>;
- containerMap->set(descendant, containerSet);
+ containerMap->set(descendant, adoptPtr(containerSet));
}
ASSERT(!containerSet->contains(this));
containerSet->add(this);
@@ -3675,7 +3934,7 @@ void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDe
if (!descendantsMap)
return;
- HashSet<RenderBlock*>* containerSet = containerMap->take(descendant);
+ OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant);
if (!containerSet)
return;
@@ -3688,19 +3947,16 @@ void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDe
// their ancestor chain before being moved. See webkit bug 93766.
// ASSERT(descendant->isDescendantOf(container));
- TrackedRendererListHashSet* descendantSet = descendantsMap->get(container);
- ASSERT(descendantSet);
- if (!descendantSet)
+ TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
+ ASSERT(descendantsMapIterator != descendantsMap->end());
+ if (descendantsMapIterator == descendantsMap->end())
continue;
+ TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get();
ASSERT(descendantSet->contains(descendant));
descendantSet->remove(descendant);
- if (descendantSet->isEmpty()) {
- descendantsMap->remove(container);
- delete descendantSet;
- }
+ if (descendantSet->isEmpty())
+ descendantsMap->remove(descendantsMapIterator);
}
-
- delete containerSet;
}
TrackedRendererListHashSet* RenderBlock::positionedObjects() const
@@ -3774,7 +4030,7 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
// Create the list of special objects if we don't aleady have one
if (!m_floatingObjects)
- m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
+ createFloatingObjects();
else {
// Don't insert the object again if it's already in the list
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
@@ -3800,8 +4056,14 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
o->updateLogicalWidth();
o->computeAndSetBlockDirectionMargins(this);
}
+
setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
+#if ENABLE(CSS_SHAPES)
+ if (ShapeOutsideInfo* shapeOutside = o->shapeOutsideInfo())
+ shapeOutside->setShapeSize(logicalWidthForChild(o), logicalHeightForChild(o));
+#endif
+
newObj->setShouldPaint(!o->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will.
newObj->setIsDescendant(true);
newObj->m_renderer = o;
@@ -3851,7 +4113,7 @@ void RenderBlock::removeFloatingObject(RenderBox* o)
void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
{
- if (!m_floatingObjects)
+ if (!containsFloats())
return;
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
@@ -3869,21 +4131,37 @@ void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logi
LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
{
RenderBox* childBox = floatingObject->renderer();
- LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
+ LayoutUnit logicalRightOffset; // Constant part of right offset.
+#if ENABLE(CSS_SHAPES)
+ // FIXME Bug 102948: This only works for shape outside directly set on this block.
+ ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
+ // FIXME Bug 102846: Take into account the height of the content. The offset should be
+ // equal to the maximum segment length.
+ if (shapeInsideInfo && shapeInsideInfo->hasSegments() && shapeInsideInfo->segments().size() == 1) {
+ // FIXME Bug 102949: Add support for shapes with multipe segments.
+
+ // The segment offsets are relative to the content box.
+ logicalRightOffset = logicalLeftOffset + shapeInsideInfo->segments()[0].logicalRight;
+ logicalLeftOffset += shapeInsideInfo->segments()[0].logicalLeft;
+ } else
+#endif
+ logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset);
+
LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
LayoutUnit floatLogicalLeft;
+ bool insideFlowThread = flowThreadContainingBlock();
+
if (childBox->style()->floating() == LeftFloat) {
LayoutUnit heightRemainingLeft = 1;
LayoutUnit heightRemainingRight = 1;
- floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
- // FIXME: LayoutUnit::epsilon is probably only necessary here due to lost precision elsewhere https://bugs.webkit.org/show_bug.cgi?id=94000
- while (logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft + LayoutUnit::epsilon() < floatLogicalWidth) {
+ floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
+ while (logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
- floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
- if (inRenderFlowThread()) {
+ floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
+ if (insideFlowThread) {
// Have to re-evaluate all of our offsets, since they may have changed.
logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
@@ -3894,12 +4172,11 @@ LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* fl
} else {
LayoutUnit heightRemainingLeft = 1;
LayoutUnit heightRemainingRight = 1;
- floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
- // FIXME: LayoutUnit::epsilon is probably only necessary here due to lost precision elsewhere https://bugs.webkit.org/show_bug.cgi?id=94000
- while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) + LayoutUnit::epsilon() < floatLogicalWidth) {
+ floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
+ while (floatLogicalLeft - logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
- floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
- if (inRenderFlowThread()) {
+ floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
+ if (insideFlowThread) {
// Have to re-evaluate all of our offsets, since they may have changed.
logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
@@ -3971,6 +4248,7 @@ bool RenderBlock::positionNewFloats()
LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
+
setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
@@ -4000,6 +4278,7 @@ bool RenderBlock::positionNewFloats()
floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
+
setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
@@ -4010,6 +4289,7 @@ bool RenderBlock::positionNewFloats()
}
setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
+
setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
m_floatingObjects->addPlacedObject(floatingObject);
@@ -4129,7 +4409,7 @@ inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNe
return;
// All the objects returned from the tree should be already placed.
- ASSERT(r->isPlaced() && rangesIntersect(m_renderer->pixelSnappedLogicalTopForFloat(r), m_renderer->pixelSnappedLogicalBottomForFloat(r), m_lowValue, m_highValue));
+ ASSERT(r->isPlaced() && rangesIntersect(m_renderer->logicalTopForFloat(r), m_renderer->logicalBottomForFloat(r), m_lowValue, m_highValue));
if (FloatTypeValue == FloatingObject::FloatLeft
&& m_renderer->logicalRightForFloat(r) > m_offset) {
@@ -4144,6 +4424,10 @@ inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNe
if (m_heightRemaining)
*m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
}
+
+#if ENABLE(CSS_SHAPES)
+ m_last = r;
+#endif
}
LayoutUnit RenderBlock::textIndentOffset() const
@@ -4157,27 +4441,30 @@ LayoutUnit RenderBlock::textIndentOffset() const
return minimumValueForLength(style()->textIndent(), cw, renderView);
}
-LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const
{
LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
- if (!inRenderFlowThread())
+ if (!region)
return logicalLeftOffset;
- LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
+ LayoutRect boxRect = borderBoxRectInRegion(region);
return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
}
-LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const
{
LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
logicalRightOffset += availableLogicalWidth();
- if (!inRenderFlowThread())
+ if (!region)
return logicalRightOffset;
- LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
+ LayoutRect boxRect = borderBoxRectInRegion(region);
return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
}
-LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
+LayoutUnit RenderBlock::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(offsetMode);
+#endif
LayoutUnit left = fixedOffset;
if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
if (heightRemaining)
@@ -4185,8 +4472,25 @@ LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUn
FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), left, heightRemaining);
m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
+
+#if ENABLE(CSS_SHAPES)
+ const FloatingObject* lastFloat = adapter.lastFloat();
+ if (offsetMode == ShapeOutsideFloatShapeOffset && lastFloat) {
+ if (ShapeOutsideInfo* shapeOutside = lastFloat->renderer()->shapeOutsideInfo()) {
+ shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, logicalTopForFloat(lastFloat), logicalHeight);
+ left += shapeOutside->rightSegmentMarginBoxDelta();
+ }
+ }
+#endif
}
+ return left;
+}
+
+LayoutUnit RenderBlock::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
+{
+ LayoutUnit left = offsetFromFloats;
+
if (applyTextIndent && style()->isLeftToRightDirection())
left += textIndentOffset();
@@ -4223,8 +4527,11 @@ LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUn
return left;
}
-LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
+LayoutUnit RenderBlock::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(offsetMode);
+#endif
LayoutUnit right = fixedOffset;
if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
if (heightRemaining)
@@ -4233,8 +4540,26 @@ LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutU
LayoutUnit rightFloatOffset = fixedOffset;
FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), rightFloatOffset, heightRemaining);
m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
+
+#if ENABLE(CSS_SHAPES)
+ const FloatingObject* lastFloat = adapter.lastFloat();
+ if (offsetMode == ShapeOutsideFloatShapeOffset && lastFloat) {
+ if (ShapeOutsideInfo* shapeOutside = lastFloat->renderer()->shapeOutsideInfo()) {
+ shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, logicalTopForFloat(lastFloat), logicalHeight);
+ rightFloatOffset += shapeOutside->leftSegmentMarginBoxDelta();
+ }
+ }
+#endif
+
right = min(right, rightFloatOffset);
}
+
+ return right;
+}
+
+LayoutUnit RenderBlock::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
+{
+ LayoutUnit right = offsetFromFloats;
if (applyTextIndent && !style()->isLeftToRightDirection())
right -= textIndentOffset();
@@ -4509,8 +4834,7 @@ LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildP
// We create the floating object list lazily.
if (!m_floatingObjects)
- m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
-
+ createFloatingObjects();
m_floatingObjects->add(floatingObj);
}
} else {
@@ -4582,7 +4906,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOf
// We create the floating object list lazily.
if (!m_floatingObjects)
- m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
+ createFloatingObjects();
m_floatingObjects->add(floatingObj);
}
}
@@ -4602,7 +4926,7 @@ bool RenderBlock::containsFloat(RenderBox* renderer) const
void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
{
- if (!everHadLayout())
+ if (!everHadLayout() && !containsFloats())
return;
MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
@@ -4679,7 +5003,7 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
return newLogicalTop - logicalTop;
RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
- LayoutRect borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
+ LayoutRect borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
// FIXME: None of this is right for perpendicular writing-mode children.
@@ -4691,7 +5015,7 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
child->setLogicalTop(newLogicalTop);
child->updateLogicalWidth();
region = regionAtBlockOffset(logicalTopForChild(child));
- borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
+ borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
child->setLogicalTop(childOldLogicalTop);
@@ -4768,7 +5092,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
// Hit test contents if we don't have columns.
if (!hasColumns()) {
if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
- updateHitTestResult(result, locationInContainer.point() - localOffset);
+ updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
return true;
}
if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset)))
@@ -4779,6 +5103,15 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
}
}
+ // Check if the point is outside radii.
+ if (!isRenderView() && style()->hasBorderRadius()) {
+ LayoutRect borderRect = borderBoxRect();
+ borderRect.moveBy(adjustedLocation);
+ RoundedRect border = style()->getRoundedBorderFor(borderRect, view());
+ if (!locationInContainer.intersects(border))
+ return false;
+ }
+
// Now hit test our background
if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
LayoutRect boundsRect(adjustedLocation, size());
@@ -4833,7 +5166,10 @@ public:
{
int colCount = m_colInfo->columnCount();
m_colIndex = colCount - 1;
- m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
+
+ m_currLogicalTopOffset = m_block.initialBlockOffsetForPainting();
+ m_currLogicalTopOffset = colCount * m_block.blockDeltaForPaintingNextColumn();
+
update();
}
@@ -4851,12 +5187,6 @@ public:
{
LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
- if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
- if (m_isHorizontal)
- offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
- else
- offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
- }
}
private:
@@ -4864,10 +5194,9 @@ private:
{
if (m_colIndex < 0)
return;
-
m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
m_block.flipForWritingMode(m_colRect);
- m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
+ m_currLogicalTopOffset -= m_block.blockDeltaForPaintingNextColumn();
}
const RenderBlock& m_block;
@@ -4943,22 +5272,22 @@ Position RenderBlock::positionForBox(InlineBox *box, bool start) const
if (!box)
return Position();
- if (!box->renderer()->node())
- return createLegacyEditingPosition(node(), start ? caretMinOffset() : caretMaxOffset());
+ if (!box->renderer()->nonPseudoNode())
+ return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset());
if (!box->isInlineTextBox())
- return createLegacyEditingPosition(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
+ return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
InlineTextBox* textBox = toInlineTextBox(box);
- return createLegacyEditingPosition(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
+ return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
}
static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
{
- ASSERT(!ancestor || ancestor->node());
- ASSERT(child && child->node());
+ ASSERT(!ancestor || ancestor->nonPseudoNode());
+ ASSERT(child && child->nonPseudoNode());
return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
- || ancestor->node()->rendererIsEditable() == child->node()->rendererIsEditable();
+ || ancestor->nonPseudoNode()->rendererIsEditable() == child->nonPseudoNode()->rendererIsEditable();
}
// FIXME: This function should go on RenderObject as an instance method. Then
@@ -4974,14 +5303,14 @@ static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock*
LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
// If this is an anonymous renderer, we just recur normally
- Node* childNode = child->node();
+ Node* childNode = child->nonPseudoNode();
if (!childNode)
return child->positionForPoint(pointInChildCoordinates);
// Otherwise, first make sure that the editability of the parent and child agree.
// If they don't agree, then we return a visible position just before or after the child
RenderObject* ancestor = parent;
- while (ancestor && !ancestor->node())
+ while (ancestor && !ancestor->nonPseudoNode())
ancestor = ancestor->parent();
// If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
@@ -5039,7 +5368,7 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const LayoutPoin
}
}
- bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
+ bool moveCaretToBoundary = document()->frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
// y coordinate is below last root line box, pretend we hit it
@@ -5218,7 +5547,7 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
bool destroyColumns = !requiresColumns(count);
if (destroyColumns) {
if (hasColumns()) {
- delete gColumnInfoMap->take(this);
+ gColumnInfoMap->take(this);
setHasColumns(false);
}
} else {
@@ -5229,7 +5558,7 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
if (!gColumnInfoMap)
gColumnInfoMap = new ColumnInfoMap;
info = new ColumnInfo;
- gColumnInfoMap->add(this, info);
+ gColumnInfoMap->add(this, adoptPtr(info));
setHasColumns(true);
}
info->setDesiredColumnCount(count);
@@ -5300,9 +5629,9 @@ LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
// Compute the appropriate rect based off our information.
LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
LayoutUnit colLogicalHeight = colInfo->columnHeight();
- LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
+ LayoutUnit colLogicalTop = borderAndPaddingBefore();
LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
- int colGap = columnGap();
+ LayoutUnit colGap = columnGap();
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
colLogicalLeft += index * (colLogicalWidth + colGap);
@@ -5330,7 +5659,7 @@ bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, Layo
addOverflowFromInlineChildren();
else
addOverflowFromBlockChildren();
- LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore();
+ LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderAndPaddingBefore();
// FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
// the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
@@ -5344,7 +5673,7 @@ bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, Layo
// maximum page break distance.
if (!pageLogicalHeight) {
LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(),
- view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset());
+ view()->layoutState()->pageLogicalOffset(this, borderAndPaddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset());
columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
}
} else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) {
@@ -5364,7 +5693,7 @@ bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, Layo
colInfo->setColumnCountAndHeight(ceilf((float)layoutOverflowLogicalBottom / pageLogicalHeight), pageLogicalHeight);
if (columnCount(colInfo)) {
- setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
+ setLogicalHeight(borderAndPaddingBefore() + colInfo->columnHeight() + borderAndPaddingAfter() + scrollbarLogicalHeight());
m_overflow.clear();
} else
m_overflow = savedOverflow.release();
@@ -5476,13 +5805,13 @@ void RenderBlock::adjustRectForColumns(LayoutRect& r) const
LayoutRect result;
bool isHorizontal = isHorizontalWritingMode();
- LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
+ LayoutUnit beforeBorderPadding = borderAndPaddingBefore();
LayoutUnit colHeight = colInfo->columnHeight();
if (!colHeight)
return;
LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
- LayoutUnit endOffset = min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight);
+ LayoutUnit endOffset = max(min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding);
// FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
@@ -5525,7 +5854,7 @@ LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& p
return point;
ColumnInfo* colInfo = columnInfo();
LayoutUnit columnLogicalHeight = colInfo->columnHeight();
- LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit expandedLogicalHeight = borderAndPaddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAndPaddingAfter() + scrollbarLogicalHeight();
if (isHorizontalWritingMode())
return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
@@ -5539,7 +5868,7 @@ void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect
ColumnInfo* colInfo = columnInfo();
LayoutUnit columnLogicalHeight = colInfo->columnHeight();
- LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit expandedLogicalHeight = borderAndPaddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAndPaddingAfter() + scrollbarLogicalHeight();
if (isHorizontalWritingMode())
rect.setY(expandedLogicalHeight - rect.maxY());
@@ -5561,7 +5890,7 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point)
for (unsigned i = 0; i < colCount; ++i) {
// Compute the edges for a given column in the block progression direction.
- LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
+ LayoutRect sliceRect = LayoutRect(logicalLeft, borderAndPaddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
if (!isHorizontalWritingMode())
sliceRect = sliceRect.transposedRect();
@@ -5573,7 +5902,7 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point)
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
else
- offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
+ offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderAndPaddingBefore());
return;
}
} else {
@@ -5581,61 +5910,55 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point)
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
else
- offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
+ offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderAndPaddingBefore(), 0);
return;
}
}
}
}
+void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ if (childrenInline()) {
+ // FIXME: Remove this const_cast.
+ const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
+ } else
+ computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
+
+ maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
+
+ if (!style()->autoWrap() && childrenInline()) {
+ // A horizontal marquee with inline children has no minimum width.
+ if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
+ minLogicalWidth = 0;
+ }
+
+ if (isTableCell()) {
+ Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth();
+ if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
+ maxLogicalWidth = max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
+ }
+
+ int scrollbarWidth = instrinsicScrollbarLogicalWidth();
+ maxLogicalWidth += scrollbarWidth;
+ minLogicalWidth += scrollbarWidth;
+}
+
void RenderBlock::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
updateFirstLetter();
+ m_minPreferredLogicalWidth = 0;
+ m_maxPreferredLogicalWidth = 0;
+
RenderStyle* styleToUse = style();
if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
- && style()->marqueeBehavior() != MALTERNATE && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
+ && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
- else {
- m_minPreferredLogicalWidth = 0;
- m_maxPreferredLogicalWidth = 0;
-
- if (childrenInline())
- computeInlinePreferredLogicalWidths();
- else
- computeBlockPreferredLogicalWidths();
-
- m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
-
- if (!styleToUse->autoWrap() && childrenInline()) {
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
-
- // A horizontal marquee with inline children has no minimum width.
- if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
- m_minPreferredLogicalWidth = 0;
- }
-
- int scrollbarWidth = 0;
- // FIXME: This should only be done for horizontal writing mode.
- // For vertical writing mode, this should check overflowX and use the horizontalScrollbarHeight.
- if (hasOverflowClip() && styleToUse->overflowY() == OSCROLL) {
- layer()->setHasVerticalScrollbar(true);
- scrollbarWidth = verticalScrollbarWidth();
- m_maxPreferredLogicalWidth += scrollbarWidth;
- }
-
- if (isTableCell()) {
- Length w = toRenderTableCell(this)->styleOrColLogicalWidth();
- if (w.isFixed() && w.value() > 0) {
- m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(w.value()));
- scrollbarWidth = 0;
- }
- }
-
- m_minPreferredLogicalWidth += scrollbarWidth;
- }
+ else
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
@@ -5783,7 +6106,7 @@ static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
}
-void RenderBlock::computeInlinePreferredLogicalWidths()
+void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
{
float inlineMax = 0;
float inlineMin = 0;
@@ -5806,7 +6129,12 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
autoWrap = oldAutoWrap = styleToUse->autoWrap();
InlineMinMaxIterator childIterator(this);
- bool addedTextIndent = false; // Only gets added in once.
+
+ // Only gets added to the max preffered width once.
+ bool addedTextIndent = false;
+ // Signals the text indent was more negative than the min preferred width
+ bool hasRemainingNegativeTextIndent = false;
+
LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view());
RenderObject* prevFloat = 0;
bool isPrevChildInlineFlow = false;
@@ -5900,22 +6228,21 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
}
// If we're supposed to clear the previous float, then terminate maxwidth as well.
if (clearPreviousFloat) {
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
inlineMax = 0;
}
// Add in text-indent. This is added in only once.
- LayoutUnit ti = 0;
- if (!addedTextIndent) {
- ti = textIndent;
- childMin += ti.ceilToFloat();
- childMax += ti.ceilToFloat();
+ if (!addedTextIndent && !child->isFloating()) {
+ LayoutUnit ceiledIndent = textIndent.ceilToFloat();
+ childMin += ceiledIndent;
+ childMax += ceiledIndent;
if (childMin < 0)
textIndent = adjustFloatForSubPixelLayout(childMin);
@@ -5928,19 +6255,19 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
if (child->isFloating())
- updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
+ updatePreferredWidth(minLogicalWidth, childMin);
else
inlineMin += childMin;
} else {
// Now check our line.
- updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
+ updatePreferredWidth(minLogicalWidth, childMin);
// Now start a new line.
inlineMin = 0;
}
if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
}
@@ -5955,7 +6282,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
RenderText* t = toRenderText(child);
if (t->isWordBreak()) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
continue;
}
@@ -5979,7 +6306,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
// This text object will not be rendered, but it may still provide a breaking opportunity.
if (!hasBreak && childMax == 0) {
if (autoWrap && (beginWS || endWS)) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
}
continue;
@@ -5992,18 +6319,24 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
// Add in text-indent. This is added in only once.
float ti = 0;
- if (!addedTextIndent) {
+ if (!addedTextIndent || hasRemainingNegativeTextIndent) {
ti = textIndent.ceilToFloat();
-
childMin += ti;
- childMax += ti;
beginMin += ti;
- beginMax += ti;
- if (childMin < 0)
- textIndent = childMin;
- else
+ // It the text indent negative and larger than the child minimum, we re-use the remainder
+ // in future minimum calculations, but using the negative value again on the maximum
+ // will lead to under-counting the max pref width.
+ if (!addedTextIndent) {
+ childMax += ti;
+ beginMax += ti;
addedTextIndent = true;
+ }
+
+ if (childMin < 0) {
+ textIndent = childMin;
+ hasRemainingNegativeTextIndent = true;
+ }
}
// If we have no breakable characters at all,
@@ -6016,10 +6349,10 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
// we start and end with whitespace.
if (beginWS)
// Go ahead and end the current line.
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
else {
inlineMin += beginMin;
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
childMin -= ti;
}
@@ -6028,11 +6361,11 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (endWS) {
// We end in whitespace, which means we can go ahead
// and end our current line.
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
shouldBreakLineAfterText = false;
} else {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = endMin;
shouldBreakLineAfterText = true;
}
@@ -6040,8 +6373,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (hasBreak) {
inlineMax += beginMax;
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
- updatePreferredWidth(m_maxPreferredLogicalWidth, childMax);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
+ updatePreferredWidth(maxLogicalWidth, childMax);
inlineMax = endMax;
addedTextIndent = true;
} else
@@ -6052,8 +6385,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (child->isListMarker())
stripFrontSpaces = true;
} else {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
inlineMin = inlineMax = 0;
stripFrontSpaces = true;
trailingSpaceChild = 0;
@@ -6071,11 +6404,11 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (styleToUse->collapseWhiteSpace())
stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
}
-void RenderBlock::computeBlockPreferredLogicalWidths()
+void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
RenderStyle* styleToUse = style();
bool nowrap = styleToUse->whiteSpace() == NOWRAP;
@@ -6094,11 +6427,11 @@ void RenderBlock::computeBlockPreferredLogicalWidths()
if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
if (childStyle->clear() & CLEFT) {
- m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
floatLeftWidth = 0;
}
if (childStyle->clear() & CRIGHT) {
- m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
floatRightWidth = 0;
}
}
@@ -6129,11 +6462,11 @@ void RenderBlock::computeBlockPreferredLogicalWidths()
}
LayoutUnit w = childMinPreferredLogicalWidth + margin;
- m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth);
+ minLogicalWidth = max(w, minLogicalWidth);
// IE ignores tables for calculation of nowrap. Makes some sense.
if (nowrap && !child->isTable())
- m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(w, maxLogicalWidth);
w = childMaxPreferredLogicalWidth + margin;
@@ -6151,26 +6484,26 @@ void RenderBlock::computeBlockPreferredLogicalWidths()
w = max(w, floatLeftWidth + floatRightWidth);
}
else
- m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
floatLeftWidth = floatRightWidth = 0;
}
if (child->isFloating()) {
- if (styleToUse->floating() == LeftFloat)
+ if (childStyle->floating() == LeftFloat)
floatLeftWidth += w;
else
floatRightWidth += w;
} else
- m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(w, maxLogicalWidth);
child = child->nextSibling();
}
// Always make sure these values are non-negative.
- m_minPreferredLogicalWidth = max<LayoutUnit>(0, m_minPreferredLogicalWidth);
- m_maxPreferredLogicalWidth = max<LayoutUnit>(0, m_maxPreferredLogicalWidth);
+ minLogicalWidth = max<LayoutUnit>(0, minLogicalWidth);
+ maxLogicalWidth = max<LayoutUnit>(0, maxLogicalWidth);
- m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
}
bool RenderBlock::hasLineIfEmpty() const
@@ -6181,7 +6514,7 @@ bool RenderBlock::hasLineIfEmpty() const
if (node()->isRootEditableElement())
return true;
- if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
+ if (node()->isShadowRoot() && isHTMLInputElement(toShadowRoot(node())->host()))
return true;
return false;
@@ -6329,10 +6662,17 @@ RenderBlock* RenderBlock::firstLineBlock() const
if (hasPseudo)
break;
RenderObject* parentBlock = firstLineBlock->parent();
- if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
- !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
+ // We include isRenderButton in this check because buttons are
+ // implemented using flex box but should still support first-line. The
+ // flex box spec requires that flex box does not support first-line,
+ // though.
+ // FIXME: Remove when buttons are implemented with align-items instead
+ // of flexbox.
+ if (firstLineBlock->isReplaced() || firstLineBlock->isFloating()
+ || !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()
+ || (parentBlock->isFlexibleBox() && !parentBlock->isRenderButton()))
break;
- ASSERT(parentBlock->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock());
firstLineBlock = toRenderBlock(parentBlock);
}
@@ -6374,14 +6714,21 @@ static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
{
RenderObject* firstLetterBlock = start;
while (true) {
+ // We include isRenderButton in these two checks because buttons are
+ // implemented using flex box but should still support first-letter.
+ // The flex box spec requires that flex box does not support
+ // first-letter, though.
+ // FIXME: Remove when buttons are implemented with align-items instead
+ // of flexbox.
bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
- && firstLetterBlock->canHaveGeneratedChildren();
+ && firstLetterBlock->canHaveGeneratedChildren()
+ && (!firstLetterBlock->isFlexibleBox() || firstLetterBlock->isRenderButton());
if (canHaveFirstLetterRenderer)
return firstLetterBlock;
RenderObject* parentBlock = firstLetterBlock->parent();
if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
- !parentBlock->isBlockFlow())
+ !parentBlock->isBlockFlow() || (parentBlock->isFlexibleBox() && !parentBlock->isRenderButton()))
return 0;
firstLetterBlock = parentBlock;
}
@@ -6400,9 +6747,9 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO
// The first-letter renderer needs to be replaced. Create a new renderer of the right type.
RenderObject* newFirstLetter;
if (pseudoStyle->display() == INLINE)
- newFirstLetter = new (renderArena()) RenderInline(document());
+ newFirstLetter = RenderInline::createAnonymous(document());
else
- newFirstLetter = new (renderArena()) RenderBlock(document());
+ newFirstLetter = RenderBlock::createAnonymous(document());
newFirstLetter->setStyle(pseudoStyle);
// Move the first letter into the new renderer.
@@ -6446,9 +6793,9 @@ void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend
RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
RenderObject* firstLetter = 0;
if (pseudoStyle->display() == INLINE)
- firstLetter = new (renderArena()) RenderInline(document());
+ firstLetter = RenderInline::createAnonymous(document());
else
- firstLetter = new (renderArena()) RenderBlock(document());
+ firstLetter = RenderBlock::createAnonymous(document());
firstLetter->setStyle(pseudoStyle);
firstLetterContainer->addChild(firstLetter, currentChild);
@@ -6571,28 +6918,6 @@ static bool shouldCheckLines(RenderObject* obj)
&& (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
}
-static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
-{
- if (block->style()->visibility() == VISIBLE) {
- if (block->childrenInline()) {
- for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
- if (count++ == i)
- return box;
- }
- }
- else {
- for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
- if (shouldCheckLines(obj)) {
- RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
- if (box)
- return box;
- }
- }
- }
- }
- return 0;
-}
-
static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
{
if (block->style()->visibility() == VISIBLE) {
@@ -6620,23 +6945,54 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom,
return -1;
}
-RootInlineBox* RenderBlock::lineAtIndex(int i)
+RootInlineBox* RenderBlock::lineAtIndex(int i) const
{
- int count = 0;
- return getLineAtIndex(this, i, count);
+ ASSERT(i >= 0);
+
+ if (style()->visibility() != VISIBLE)
+ return 0;
+
+ if (childrenInline()) {
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
+ if (!i--)
+ return box;
+ } else {
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!shouldCheckLines(child))
+ continue;
+ if (RootInlineBox* box = toRenderBlock(child)->lineAtIndex(i))
+ return box;
+ }
+ }
+
+ return 0;
}
-int RenderBlock::lineCount()
+int RenderBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
{
int count = 0;
+
if (style()->visibility() == VISIBLE) {
if (childrenInline())
- for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
count++;
+ if (box == stopRootInlineBox) {
+ if (found)
+ *found = true;
+ break;
+ }
+ }
else
for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
- if (shouldCheckLines(obj))
- count += toRenderBlock(obj)->lineCount();
+ if (shouldCheckLines(obj)) {
+ bool recursiveFound = false;
+ count += toRenderBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound);
+ if (recursiveFound) {
+ if (found)
+ *found = true;
+ break;
+ }
+ }
}
return count;
}
@@ -6691,32 +7047,30 @@ void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit&
}
}
-void RenderBlock::borderFitAdjust(LayoutRect& rect) const
+void RenderBlock::fitBorderToLinesIfNeeded()
{
- if (style()->borderFit() == BorderFitBorder)
+ if (style()->borderFit() == BorderFitBorder || hasOverrideWidth())
return;
// Walk any normal flow lines to snugly fit.
LayoutUnit left = LayoutUnit::max();
LayoutUnit right = LayoutUnit::min();
- LayoutUnit oldWidth = rect.width();
+ LayoutUnit oldWidth = contentWidth();
adjustForBorderFit(0, left, right);
- if (left != LayoutUnit::max()) {
- left = min(left, oldWidth - (borderRight() + paddingRight()));
-
- left -= (borderLeft() + paddingLeft());
- if (left > 0) {
- rect.move(left, 0);
- rect.expand(-left, 0);
- }
- }
- if (right != LayoutUnit::min()) {
- right = max(right, borderLeft() + paddingLeft());
-
- right += (borderRight() + paddingRight());
- if (right < oldWidth)
- rect.expand(-(oldWidth - right), 0);
- }
+
+ // Clamp to our existing edges. We can never grow. We only shrink.
+ LayoutUnit leftEdge = borderLeft() + paddingLeft();
+ LayoutUnit rightEdge = leftEdge + oldWidth;
+ left = min(rightEdge, max(leftEdge, left));
+ right = max(leftEdge, min(rightEdge, right));
+
+ LayoutUnit newContentWidth = right - left;
+ if (newContentWidth == oldWidth)
+ return;
+
+ setOverrideLogicalContentWidth(newContentWidth);
+ layoutBlock(false);
+ clearOverrideLogicalContentWidth();
}
void RenderBlock::clearTruncation()
@@ -6757,6 +7111,99 @@ void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
m_rareData->m_margins.setNegativeMarginAfter(neg);
}
+void RenderBlock::setMustDiscardMarginBefore(bool value)
+{
+ if (style()->marginBeforeCollapse() == MDISCARD) {
+ ASSERT(value);
+ return;
+ }
+
+ if (!m_rareData && !value)
+ return;
+
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+
+ m_rareData->m_discardMarginBefore = value;
+}
+
+void RenderBlock::setMustDiscardMarginAfter(bool value)
+{
+ if (style()->marginAfterCollapse() == MDISCARD) {
+ ASSERT(value);
+ return;
+ }
+
+ if (!m_rareData && !value)
+ return;
+
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+
+ m_rareData->m_discardMarginAfter = value;
+}
+
+bool RenderBlock::mustDiscardMarginBefore() const
+{
+ return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
+}
+
+bool RenderBlock::mustDiscardMarginAfter() const
+{
+ return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
+}
+
+bool RenderBlock::mustDiscardMarginBeforeForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
+
+ // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
+ // In case the boxes are perpendicular we assume the property is not specified.
+ return false;
+}
+
+bool RenderBlock::mustDiscardMarginAfterForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
+
+ // FIXME: See |mustDiscardMarginBeforeForChild| above.
+ return false;
+}
+
+bool RenderBlock::mustSeparateMarginBeforeForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ const RenderStyle* childStyle = child->style();
+ if (!child->isWritingModeRoot())
+ return childStyle->marginBeforeCollapse() == MSEPARATE;
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return childStyle->marginAfterCollapse() == MSEPARATE;
+
+ // FIXME: See |mustDiscardMarginBeforeForChild| above.
+ return false;
+}
+
+bool RenderBlock::mustSeparateMarginAfterForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ const RenderStyle* childStyle = child->style();
+ if (!child->isWritingModeRoot())
+ return childStyle->marginAfterCollapse() == MSEPARATE;
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return childStyle->marginBeforeCollapse() == MSEPARATE;
+
+ // FIXME: See |mustDiscardMarginBeforeForChild| above.
+ return false;
+}
+
void RenderBlock::setPaginationStrut(LayoutUnit strut)
{
if (!m_rareData) {
@@ -6777,6 +7224,23 @@ void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
m_rareData->m_pageLogicalOffset = logicalOffset;
}
+void RenderBlock::setBreakAtLineToAvoidWidow(RootInlineBox* lineToBreak)
+{
+ ASSERT(lineToBreak);
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+ m_rareData->m_shouldBreakAtLineToAvoidWidow = true;
+ m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
+}
+
+void RenderBlock::clearShouldBreakAtLineToAvoidWidow() const
+{
+ if (!m_rareData)
+ return;
+ m_rareData->m_shouldBreakAtLineToAvoidWidow = false;
+ m_rareData->m_lineBreakToAvoidWidow = 0;
+}
+
void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
{
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
@@ -6863,29 +7327,14 @@ LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, La
LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
- if (extraWidthToEndOfLine) {
- if (isRenderBlock()) {
- *extraWidthToEndOfLine = width() - caretRect.maxX();
- } else {
- // FIXME: This code looks wrong.
- // myRight and containerRight are set up, but then clobbered.
- // So *extraWidthToEndOfLine will always be 0 here.
-
- LayoutUnit myRight = caretRect.maxX();
- // FIXME: why call localToAbsoluteForContent() twice here, too?
- FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
-
- LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
- FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
-
- *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
- }
- }
+ // FIXME: Does this need to adjust for vertical orientation?
+ if (extraWidthToEndOfLine)
+ *extraWidthToEndOfLine = width() - caretRect.maxX();
return caretRect;
}
-void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
+void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
{
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
// inline boxes above and below us (thus getting merged with them to form a single irregular
@@ -6920,16 +7369,16 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& a
FloatPoint pos;
// FIXME: This doesn't work correctly with transforms.
if (box->layer())
- pos = curr->localToAbsolute();
+ pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
else
pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
- box->addFocusRingRects(rects, flooredLayoutPoint(pos));
+ box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer);
}
}
}
if (inlineElementContinuation())
- inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()));
+ inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()), paintContainer);
}
RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
@@ -6945,16 +7394,17 @@ bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBou
{
ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
- if (!inRenderFlowThread())
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread)
return true; // Printing and multi-column both make new pages to accommodate content.
// See if we're in the last region.
LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
- RenderRegion* region = enclosingRenderFlowThread()->regionAtBlockOffset(pageOffset, this);
+ RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this);
if (!region)
return false;
if (region->isLastRegion())
- return region->isRenderRegionSet() || region->style()->regionOverflow() == BreakRegionOverflow
+ return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment
|| (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
return true;
}
@@ -6996,7 +7446,8 @@ LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOff
// FIXME: Add page break checking here when we support printing.
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
- bool checkRegionBreaks = inRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
|| (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
@@ -7004,7 +7455,7 @@ LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOff
view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
if (checkRegionBreaks) {
LayoutUnit offsetBreakAdjustment = 0;
- if (enclosingRenderFlowThread()->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
+ if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
return logicalOffset + offsetBreakAdjustment;
}
return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
@@ -7017,18 +7468,22 @@ LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffs
// FIXME: Add page break checking here when we support printing.
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
- bool checkRegionBreaks = inRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
|| (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
- marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content.
+ LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
+
+ // So our margin doesn't participate in the next collapsing steps.
+ marginInfo.clearMargin();
+
if (checkColumnBreaks)
view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
if (checkRegionBreaks) {
- LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
LayoutUnit offsetBreakAdjustment = 0;
- if (enclosingRenderFlowThread()->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
- return logicalOffset + offsetBreakAdjustment;
+ if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
+ return logicalOffset + marginOffset + offsetBreakAdjustment;
}
return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
}
@@ -7042,21 +7497,23 @@ LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
LayoutUnit cumulativeOffset = offset + blockLogicalTop;
- if (!inRenderFlowThread()) {
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread) {
LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
if (!pageLogicalHeight)
return 0;
return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
}
- return enclosingRenderFlowThread()->pageLogicalTopForOffset(cumulativeOffset);
+ return flowThread->pageLogicalTopForOffset(cumulativeOffset);
}
LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
{
RenderView* renderView = view();
- if (!inRenderFlowThread())
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread)
return renderView->layoutState()->m_pageLogicalHeight;
- return enclosingRenderFlowThread()->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
+ return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
}
LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
@@ -7064,7 +7521,8 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P
RenderView* renderView = view();
offset += offsetFromLogicalTopOfFirstPage();
- if (!inRenderFlowThread()) {
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread) {
LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
if (pageBoundaryRule == IncludePageBoundary) {
@@ -7075,25 +7533,24 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P
return remainingHeight;
}
- return enclosingRenderFlowThread()->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
+ return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
}
LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
{
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
- bool checkRegionBreaks = inRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
|| (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
|| (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
if (!isUnsplittable)
return logicalOffset;
LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
- LayoutState* layoutState = view()->layoutState();
- if (layoutState->m_columnInfo)
- layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
+ bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
+ updateMinimumPageHeight(logicalOffset, childLogicalHeight);
if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
|| !hasNextPage(logicalOffset))
return logicalOffset;
@@ -7121,7 +7578,39 @@ bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment,
return !checkRegion;
}
-void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta)
+void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
+{
+ if (RenderFlowThread* flowThread = flowThreadContainingBlock())
+ flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
+}
+
+void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
+{
+ if (RenderFlowThread* flowThread = flowThreadContainingBlock())
+ flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight);
+ else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo)
+ colInfo->updateMinimumColumnHeight(minHeight);
+}
+
+static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
+{
+ // We may require a certain minimum number of lines per page in order to satisfy
+ // orphans and widows, and that may affect the minimum page height.
+ unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
+ if (lineCount > 1) {
+ RootInlineBox* line = lastLine;
+ for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
+ line = line->prevRootBox();
+
+ // FIXME: Paginating using line overflow isn't all fine. See FIXME in
+ // adjustLinePositionForPagination() for more details.
+ LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
+ lineTop = min(line->lineTopWithLeading(), overflow.y());
+ }
+ return lineBottom - lineTop;
+}
+
+void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread)
{
// FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
// put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
@@ -7144,23 +7633,24 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout
// line and all following lines.
LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
- LayoutUnit lineHeight = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()) - logicalOffset;
- RenderView* renderView = view();
- LayoutState* layoutState = renderView->layoutState();
- if (layoutState->m_columnInfo)
- layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
+ LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
+ LayoutUnit lineHeight = logicalBottom - logicalOffset;
+ updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom));
logicalOffset += delta;
lineBox->setPaginationStrut(0);
lineBox->setIsFirstAfterPageBreak(false);
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
+ bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
// If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
// still going to add a strut, so that the visible overflow fits on a single page.
if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
|| !hasNextPage(logicalOffset))
return;
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
- if (remainingLogicalHeight < lineHeight) {
+
+ if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineBox)) {
+ if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineBox)
+ clearShouldBreakAtLineToAvoidWidow();
// If we have a non-uniform page height, then we have to shift further possibly.
if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
return;
@@ -7170,7 +7660,9 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout
}
LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
- if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isOutOfFlowPositioned() && !isTableCell())
+ setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
+ if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineCount(lineBox)))
+ && !isOutOfFlowPositioned() && !isTableCell())
setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
else {
delta += remainingLogicalHeight;
@@ -7215,6 +7707,21 @@ LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfter
// If the object has a page or column break value of "before", then we should shift to the top of the next page.
LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
+ if (pageLogicalHeightForOffset(result)) {
+ LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
+ LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight;
+ if (spaceShortage > 0) {
+ // If the child crosses a column boundary, report a break, in case nothing inside it has already
+ // done so. The column balancer needs to know how much it has to stretch the columns to make more
+ // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
+ // This should be improved, though, because here we just pretend that the child is
+ // unsplittable. A splittable child, on the other hand, has break opportunities at every position
+ // where there's no child content, border or padding. In other words, we risk stretching more
+ // than necessary.
+ setPageBreak(result, spaceShortage);
+ }
+ }
+
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
@@ -7247,19 +7754,16 @@ LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfter
return result;
}
-bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta) const
+bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const
{
- if (!inRenderFlowThread())
+ if (!flowThread)
return false;
RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta);
- // Just bail if we still don't have a region.
- if (!rootBox->hasContainingRegion() && !currentRegion)
- return false;
// Just bail if the region didn't change.
- if (rootBox->hasContainingRegion() && rootBox->containingRegion() == currentRegion)
+ if (rootBox->containingRegion() == currentRegion)
return false;
- return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion, offsetFromLogicalTopOfFirstPage());
+ return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion);
}
LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
@@ -7267,94 +7771,71 @@ LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
LayoutState* layoutState = view()->layoutState();
if (layoutState && !layoutState->isPaginated())
return 0;
+
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread)
+ return flowThread->offsetFromLogicalTopOfFirstRegion(this);
+
if (layoutState) {
- // FIXME: Sanity check that the renderer in the layout state is ours, since otherwise the computation will be off.
- // Right now this assert gets hit inside computeLogicalHeight for percentage margins, since they're computed using
- // widths which can vary in each region. Until we patch that, we can't have this assert.
- // ASSERT(layoutState->m_renderer == this);
+ ASSERT(layoutState->m_renderer == this);
LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
}
- // FIXME: Right now, this assert is hit outside layout, from logicalLeftSelectionOffset in selectionGapRectsForRepaint (called from FrameSelection::selectAll).
- // ASSERT(inRenderFlowThread());
-
- // FIXME: This is a slower path that doesn't use layout state and relies on getting your logical top inside the enclosing flow thread. It doesn't
- // work with columns or pages currently, but it should once they have been switched over to using flow threads.
- if (!inRenderFlowThread())
- return 0;
-
- const RenderBlock* currentBlock = this;
- LayoutRect blockRect(0, 0, width(), height());
-
- while (currentBlock && !currentBlock->isRenderFlowThread()) {
- RenderBlock* containerBlock = currentBlock->containingBlock();
- ASSERT(containerBlock);
- if (!containerBlock)
- return 0;
- LayoutPoint currentBlockLocation = currentBlock->location();
-
- if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
- // We have to put the block rect in container coordinates
- // and we have to take into account both the container and current block flipping modes
- if (containerBlock->style()->isFlippedBlocksWritingMode()) {
- if (containerBlock->isHorizontalWritingMode())
- blockRect.setY(currentBlock->height() - blockRect.maxY());
- else
- blockRect.setX(currentBlock->width() - blockRect.maxX());
- }
- currentBlock->flipForWritingMode(blockRect);
- }
- blockRect.moveBy(currentBlockLocation);
- currentBlock = containerBlock;
- };
- return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
+
+ ASSERT_NOT_REACHED();
+ return 0;
}
RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
{
- if (!inRenderFlowThread())
- return 0;
-
- RenderFlowThread* flowThread = enclosingRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
if (!flowThread || !flowThread->hasValidRegionInfo())
return 0;
return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
}
+void RenderBlock::updateStaticInlinePositionForChild(RenderBox* child, LayoutUnit logicalTop)
+{
+ if (child->style()->isOriginalDisplayInlineType())
+ setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
+ else
+ setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
+}
+
void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
{
- if (inRenderFlowThread()) {
+ if (flowThreadContainingBlock()) {
// Shift the inline position to exclude the region offset.
inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
}
child->layer()->setStaticInlinePosition(inlinePosition);
}
-bool RenderBlock::logicalWidthChangedInRegions() const
+bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const
{
- if (!inRenderFlowThread())
- return false;
-
- RenderFlowThread* flowThread = enclosingRenderFlowThread();
if (!flowThread || !flowThread->hasValidRegionInfo())
- return 0;
+ return false;
- return flowThread->logicalWidthChangedInRegions(this, offsetFromLogicalTopOfFirstPage());
+ return flowThread->logicalWidthChangedInRegionsForBlock(this);
}
RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
{
- ASSERT(region && inRenderFlowThread());
-
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+
+ ASSERT(isRenderView() || (region && flowThread));
+ if (isRenderView())
+ return region;
+
// We need to clamp to the block, since we want any lines or blocks that overflow out of the
// logical top or logical bottom of the block to size as though the border box in the first and
// last regions extended infinitely. Otherwise the lines are going to size according to the regions
// they overflow into, which makes no sense when this block doesn't exist in |region| at all.
RenderRegion* startRegion;
RenderRegion* endRegion;
- enclosingRenderFlowThread()->getRegionRangeForBox(this, startRegion, endRegion);
+ flowThread->getRegionRangeForBox(this, startRegion, endRegion);
if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
return startRegion;
@@ -7398,6 +7879,40 @@ LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) co
return marginAfterForChild(child);
}
+bool RenderBlock::hasMarginBeforeQuirk(const RenderBox* child) const
+{
+ // If the child has the same directionality as we do, then we can just return its
+ // margin quirk.
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
+
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the opposite edge.
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
+
+ // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
+ // whether or not authors specified quirky ems, since they're an implementation detail.
+ return false;
+}
+
+bool RenderBlock::hasMarginAfterQuirk(const RenderBox* child) const
+{
+ // If the child has the same directionality as we do, then we can just return its
+ // margin quirk.
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
+
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the opposite edge.
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
+
+ // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
+ // whether or not authors specified quirky ems, since they're an implementation detail.
+ return false;
+}
+
RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) const
{
LayoutUnit childBeforePositive = 0;
@@ -7467,23 +7982,40 @@ const char* RenderBlock::renderName() const
return "RenderBlock (floating)";
if (isOutOfFlowPositioned())
return "RenderBlock (positioned)";
- if (isAnonymousColumnsBlock())
+ if (style() && isAnonymousColumnsBlock())
return "RenderBlock (anonymous multi-column)";
- if (isAnonymousColumnSpanBlock())
+ if (style() && isAnonymousColumnSpanBlock())
return "RenderBlock (anonymous multi-column span)";
- if (isAnonymousBlock())
+ if (style() && isAnonymousBlock())
return "RenderBlock (anonymous)";
- else if (isAnonymous())
+ // FIXME: Temporary hack while the new generated content system is being implemented.
+ if (isPseudoElement())
+ return "RenderBlock (generated)";
+ if (isAnonymous())
return "RenderBlock (generated)";
if (isRelPositioned())
return "RenderBlock (relative positioned)";
if (isStickyPositioned())
return "RenderBlock (sticky positioned)";
- if (isRunIn())
+ if (style() && isRunIn())
return "RenderBlock (run-in)";
return "RenderBlock";
}
+inline RenderBlock::FloatingObjects::FloatingObjects(const RenderBlock* renderer, bool horizontalWritingMode)
+ : m_placedFloatsTree(UninitializedTree)
+ , m_leftObjectsCount(0)
+ , m_rightObjectsCount(0)
+ , m_horizontalWritingMode(horizontalWritingMode)
+ , m_renderer(renderer)
+{
+}
+
+void RenderBlock::createFloatingObjects()
+{
+ m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
+}
+
inline void RenderBlock::FloatingObjects::clear()
{
m_set.clear();
@@ -7511,8 +8043,8 @@ inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::T
inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
{
if (m_horizontalWritingMode)
- return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
- return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
+ return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().y(), floatingObject->frameRect().maxY(), floatingObject);
+ return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().x(), floatingObject->frameRect().maxX(), floatingObject);
}
void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
@@ -7660,15 +8192,18 @@ TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, c
RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
{
- // FIXME: Do we need to cover the new flex box here ?
// FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
EDisplay newDisplay;
RenderBlock* newBox = 0;
if (display == BOX || display == INLINE_BOX) {
- newBox = new (parent->renderArena()) RenderDeprecatedFlexibleBox(parent->document() /* anonymous box */);
+ // FIXME: Remove this case once we have eliminated all internal users of old flexbox
+ newBox = RenderDeprecatedFlexibleBox::createAnonymous(parent->document());
newDisplay = BOX;
+ } else if (display == FLEX || display == INLINE_FLEX) {
+ newBox = RenderFlexibleBox::createAnonymous(parent->document());
+ newDisplay = FLEX;
} else {
- newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
+ newBox = RenderBlock::createAnonymous(parent->document());
newDisplay = BLOCK;
}
@@ -7682,7 +8217,7 @@ RenderBlock* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderO
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
newStyle->inheritColumnPropertiesFrom(parent->style());
- RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
+ RenderBlock* newBox = RenderBlock::createAnonymous(parent->document());
newBox->setStyle(newStyle.release());
return newBox;
}
@@ -7692,7 +8227,7 @@ RenderBlock* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const Rend
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
newStyle->setColumnSpan(ColumnSpanAll);
- RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
+ RenderBlock* newBox = RenderBlock::createAnonymous(parent->document());
newBox->setStyle(newStyle.release());
return newBox;
}
@@ -7727,7 +8262,7 @@ String ValueToString<int>::string(const int value)
String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject)
{
- return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
+ return String::format("%p (%ix%i %ix%i)", floatingObject, floatingObject->frameRect().x().toInt(), floatingObject->frameRect().y().toInt(), floatingObject->frameRect().maxX().toInt(), floatingObject->frameRect().maxY().toInt());
}
#endif
diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h
index 9f008477b..de9e9ec6e 100644
--- a/Source/WebCore/rendering/RenderBlock.h
+++ b/Source/WebCore/rendering/RenderBlock.h
@@ -34,9 +34,9 @@
#include <wtf/OwnPtr.h>
#include <wtf/ListHashSet.h>
-#if ENABLE(CSS_EXCLUSIONS)
-#include "ExclusionShapeInsideInfo.h"
-#include "ExclusionShapeValue.h"
+#if ENABLE(CSS_SHAPES)
+#include "ShapeInsideInfo.h"
+#include "ShapeValue.h"
#endif
namespace WebCore {
@@ -46,6 +46,7 @@ class InlineIterator;
class LayoutStateMaintainer;
class LineLayoutState;
class LineWidth;
+class LogicalSelectionOffsetCaches;
class RenderInline;
class RenderText;
@@ -53,6 +54,9 @@ struct BidiRun;
struct PaintInfo;
class LineInfo;
class RenderRubyRun;
+#if ENABLE(CSS_SHAPES)
+class BasicShape;
+#endif
class TextLayout;
class WordMeasurement;
@@ -62,8 +66,8 @@ template <class Iterator> struct MidpointState;
typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver;
typedef MidpointState<InlineIterator> LineMidpointState;
typedef WTF::ListHashSet<RenderBox*, 16> TrackedRendererListHashSet;
-typedef WTF::HashMap<const RenderBlock*, TrackedRendererListHashSet*> TrackedDescendantsMap;
-typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> TrackedContainerMap;
+typedef WTF::HashMap<const RenderBlock*, OwnPtr<TrackedRendererListHashSet> > TrackedDescendantsMap;
+typedef WTF::HashMap<const RenderBox*, OwnPtr<HashSet<RenderBlock*> > > TrackedContainerMap;
typedef Vector<WordMeasurement, 64> WordMeasurements;
enum CaretType { CursorCaret, DragCaret };
@@ -85,9 +89,11 @@ public:
template <class> friend struct ValueToString;
#endif
- RenderBlock(Node*);
+ explicit RenderBlock(ContainerNode*);
virtual ~RenderBlock();
+ static RenderBlock* createAnonymous(Document*);
+
RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); }
RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); }
@@ -137,6 +143,15 @@ public:
void setHasMarkupTruncation(bool b) { m_hasMarkupTruncation = b; }
bool hasMarkupTruncation() const { return m_hasMarkupTruncation; }
+ void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
+ void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }
+
+ bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
+ bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }
+
+ bool hasMarginBeforeQuirk(const RenderBox* child) const;
+ bool hasMarginAfterQuirk(const RenderBox* child) const;
+
RootInlineBox* createAndAppendRootInlineBox();
bool generatesLineBoxesForInlineChild(RenderObject*);
@@ -151,65 +166,66 @@ public:
// Versions that can compute line offsets with the region and page offset passed in. Used for speed to avoid having to
// compute the region all over again when you already know it.
- LayoutUnit availableLogicalWidthForLine(LayoutUnit position, bool firstLine, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, LayoutUnit logicalHeight = 0) const
+ LayoutUnit availableLogicalWidthForLine(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const
{
- return max<LayoutUnit>(0, logicalRightOffsetForLine(position, firstLine, region, offsetFromLogicalTopOfFirstPage, logicalHeight)
- - logicalLeftOffsetForLine(position, firstLine, region, offsetFromLogicalTopOfFirstPage, logicalHeight));
+ return max<LayoutUnit>(0, logicalRightOffsetForLine(position, shouldIndentText, region, logicalHeight)
+ - logicalLeftOffsetForLine(position, shouldIndentText, region, logicalHeight));
}
- LayoutUnit logicalRightOffsetForLine(LayoutUnit position, bool firstLine, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, LayoutUnit logicalHeight = 0) const
+ LayoutUnit logicalRightOffsetForLine(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const
{
- return logicalRightOffsetForLine(position, logicalRightOffsetForContent(region, offsetFromLogicalTopOfFirstPage), firstLine, 0, logicalHeight);
+ return logicalRightOffsetForLine(position, logicalRightOffsetForContent(region), shouldIndentText, 0, logicalHeight);
}
- LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, bool firstLine, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, LayoutUnit logicalHeight = 0) const
+ LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const
{
- return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(region, offsetFromLogicalTopOfFirstPage), firstLine, 0, logicalHeight);
+ return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(region), shouldIndentText, 0, logicalHeight);
}
- LayoutUnit startOffsetForLine(LayoutUnit position, bool firstLine, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, LayoutUnit logicalHeight = 0) const
+ LayoutUnit startOffsetForLine(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const
{
- return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine, region, offsetFromLogicalTopOfFirstPage, logicalHeight)
- : logicalWidth() - logicalRightOffsetForLine(position, firstLine, region, offsetFromLogicalTopOfFirstPage, logicalHeight);
+ return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, region, logicalHeight)
+ : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, region, logicalHeight);
}
- LayoutUnit endOffsetForLine(LayoutUnit position, bool firstLine, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, LayoutUnit logicalHeight = 0) const
+ LayoutUnit endOffsetForLine(LayoutUnit position, bool shouldIndentText, RenderRegion* region, LayoutUnit logicalHeight = 0) const
{
- return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine, region, offsetFromLogicalTopOfFirstPage, logicalHeight)
- : logicalWidth() - logicalRightOffsetForLine(position, firstLine, region, offsetFromLogicalTopOfFirstPage, logicalHeight);
+ return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, region, logicalHeight)
+ : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, region, logicalHeight);
}
- LayoutUnit availableLogicalWidthForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit availableLogicalWidthForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
- return availableLogicalWidthForLine(position, firstLine, regionAtBlockOffset(position), offsetFromLogicalTopOfFirstPage(), logicalHeight);
+ return availableLogicalWidthForLine(position, shouldIndentText, regionAtBlockOffset(position), logicalHeight);
}
- LayoutUnit logicalRightOffsetForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit logicalRightOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
- return logicalRightOffsetForLine(position, logicalRightOffsetForContent(position), firstLine, 0, logicalHeight);
+ return logicalRightOffsetForLine(position, logicalRightOffsetForContent(position), shouldIndentText, 0, logicalHeight);
}
- LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
- return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(position), firstLine, 0, logicalHeight);
+ return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(position), shouldIndentText, 0, logicalHeight);
}
- LayoutUnit pixelSnappedLogicalLeftOffsetForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit pixelSnappedLogicalLeftOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
- return roundToInt(logicalLeftOffsetForLine(position, firstLine, logicalHeight));
+ return roundToInt(logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight));
}
- LayoutUnit pixelSnappedLogicalRightOffsetForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit pixelSnappedLogicalRightOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
// FIXME: Multicolumn layouts break carrying over subpixel values to the logical right offset because the lines may be shifted
// by a subpixel value for all but the first column. This can lead to the actual pixel snapped width of the column being off
// by one pixel when rendered versus layed out, which can result in the line being clipped. For now, we have to floor.
- return floorToInt(logicalRightOffsetForLine(position, firstLine, logicalHeight));
+ // https://bugs.webkit.org/show_bug.cgi?id=105461
+ return floorToInt(logicalRightOffsetForLine(position, shouldIndentText, logicalHeight));
}
- LayoutUnit startOffsetForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit startOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
- return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine, logicalHeight)
- : logicalWidth() - logicalRightOffsetForLine(position, firstLine, logicalHeight);
+ return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight)
+ : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, logicalHeight);
}
- LayoutUnit endOffsetForLine(LayoutUnit position, bool firstLine, LayoutUnit logicalHeight = 0) const
+ LayoutUnit endOffsetForLine(LayoutUnit position, bool shouldIndentText, LayoutUnit logicalHeight = 0) const
{
- return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine, logicalHeight)
- : logicalWidth() - logicalRightOffsetForLine(position, firstLine, logicalHeight);
+ return !style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, shouldIndentText, logicalHeight)
+ : logicalWidth() - logicalRightOffsetForLine(position, shouldIndentText, logicalHeight);
}
- LayoutUnit startAlignedOffsetForLine(LayoutUnit position, bool firstLine);
+ LayoutUnit startAlignedOffsetForLine(LayoutUnit position, bool shouldIndentText);
LayoutUnit textIndentOffset() const;
virtual VisiblePosition positionForPoint(const LayoutPoint&);
@@ -227,17 +243,17 @@ public:
GapRects selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer);
LayoutRect logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo*);
+ RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
LayoutRect logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo*);
+ RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
void getSelectionGapInfo(SelectionState, bool& leftGap, bool& rightGap);
RenderBlock* blockBeforeWithinSelectionRoot(LayoutSize& offset) const;
LayoutRect logicalRectToPhysicalRect(const LayoutPoint& physicalPosition, const LayoutRect& logicalRect);
-
+
// Helper methods for computing line counts and heights for line counts.
- RootInlineBox* lineAtIndex(int);
- int lineCount();
+ RootInlineBox* lineAtIndex(int) const;
+ int lineCount(const RootInlineBox* = 0, bool* = 0) const;
int heightForLineCount(int);
void clearTruncation();
@@ -262,6 +278,7 @@ public:
RenderBlock* createAnonymousBlock(EDisplay display = BLOCK) const { return createAnonymousWithParentRendererAndDisplay(this, display); }
RenderBlock* createAnonymousColumnsBlock() const { return createAnonymousColumnsWithParentRenderer(this); }
RenderBlock* createAnonymousColumnSpanBlock() const { return createAnonymousColumnSpanWithParentRenderer(this); }
+ static void collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* child);
virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE;
@@ -297,13 +314,21 @@ public:
void updateColumnInfoFromStyle(RenderStyle*);
+ LayoutUnit initialBlockOffsetForPainting() const;
+ LayoutUnit blockDeltaForPaintingNextColumn() const;
+
// These two functions take the ColumnInfo* to avoid repeated lookups of the info in the global HashMap.
unsigned columnCount(ColumnInfo*) const;
LayoutRect columnRectAt(ColumnInfo*, unsigned) const;
LayoutUnit paginationStrut() const { return m_rareData ? m_rareData->m_paginationStrut : LayoutUnit(); }
void setPaginationStrut(LayoutUnit);
-
+
+ bool shouldBreakAtLineToAvoidWidow() const { return m_rareData && m_rareData->m_shouldBreakAtLineToAvoidWidow; }
+ void clearShouldBreakAtLineToAvoidWidow() const;
+ RootInlineBox* lineBreakToAvoidWidow() const { return m_rareData ? m_rareData->m_lineBreakToAvoidWidow : 0; }
+ void setBreakAtLineToAvoidWidow(RootInlineBox*);
+
// The page logical offset is the object's offset from the top of the page in the page progression
// direction (so an x-offset in vertical text and a y-offset for horizontal text).
LayoutUnit pageLogicalOffset() const { return m_rareData ? m_rareData->m_pageLogicalOffset : LayoutUnit(); }
@@ -371,41 +396,38 @@ public:
virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { };
- LayoutUnit logicalLeftOffsetForContent(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const;
- LayoutUnit logicalRightOffsetForContent(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const;
- LayoutUnit availableLogicalWidthForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+ LayoutUnit logicalLeftOffsetForContent(RenderRegion*) const;
+ LayoutUnit logicalRightOffsetForContent(RenderRegion*) const;
+ LayoutUnit availableLogicalWidthForContent(RenderRegion* region) const
{
- return max<LayoutUnit>(0, logicalRightOffsetForContent(region, offsetFromLogicalTopOfFirstPage) -
- logicalLeftOffsetForContent(region, offsetFromLogicalTopOfFirstPage)); }
- LayoutUnit startOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+ return max<LayoutUnit>(0, logicalRightOffsetForContent(region) - logicalLeftOffsetForContent(region)); }
+ LayoutUnit startOffsetForContent(RenderRegion* region) const
{
- return style()->isLeftToRightDirection() ? logicalLeftOffsetForContent(region, offsetFromLogicalTopOfFirstPage)
- : logicalWidth() - logicalRightOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
+ return style()->isLeftToRightDirection() ? logicalLeftOffsetForContent(region) : logicalWidth() - logicalRightOffsetForContent(region);
}
- LayoutUnit endOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+ LayoutUnit endOffsetForContent(RenderRegion* region) const
{
- return !style()->isLeftToRightDirection() ? logicalLeftOffsetForContent(region, offsetFromLogicalTopOfFirstPage)
- : logicalWidth() - logicalRightOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
+ return !style()->isLeftToRightDirection() ? logicalLeftOffsetForContent(region) : logicalWidth() - logicalRightOffsetForContent(region);
}
LayoutUnit logicalLeftOffsetForContent(LayoutUnit blockOffset) const
{
- return logicalLeftOffsetForContent(regionAtBlockOffset(blockOffset), offsetFromLogicalTopOfFirstPage());
+ return logicalLeftOffsetForContent(regionAtBlockOffset(blockOffset));
}
LayoutUnit logicalRightOffsetForContent(LayoutUnit blockOffset) const
{
- return logicalRightOffsetForContent(regionAtBlockOffset(blockOffset), offsetFromLogicalTopOfFirstPage());
+ return logicalRightOffsetForContent(regionAtBlockOffset(blockOffset));
}
LayoutUnit availableLogicalWidthForContent(LayoutUnit blockOffset) const
{
- return availableLogicalWidthForContent(regionAtBlockOffset(blockOffset), offsetFromLogicalTopOfFirstPage());
+ return availableLogicalWidthForContent(regionAtBlockOffset(blockOffset));
}
LayoutUnit startOffsetForContent(LayoutUnit blockOffset) const
{
- return startOffsetForContent(regionAtBlockOffset(blockOffset), offsetFromLogicalTopOfFirstPage());
+ return startOffsetForContent(regionAtBlockOffset(blockOffset));
}
LayoutUnit endOffsetForContent(LayoutUnit blockOffset) const
{
- return endOffsetForContent(regionAtBlockOffset(blockOffset), offsetFromLogicalTopOfFirstPage());
+ return endOffsetForContent(regionAtBlockOffset(blockOffset));
}
LayoutUnit logicalLeftOffsetForContent() const { return isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); }
LayoutUnit logicalRightOffsetForContent() const { return logicalLeftOffsetForContent() + availableLogicalWidth(); }
@@ -413,10 +435,11 @@ public:
LayoutUnit endOffsetForContent() const { return !style()->isLeftToRightDirection() ? logicalLeftOffsetForContent() : logicalWidth() - logicalRightOffsetForContent(); }
void setStaticInlinePositionForChild(RenderBox*, LayoutUnit blockOffset, LayoutUnit inlinePosition);
+ void updateStaticInlinePositionForChild(RenderBox*, LayoutUnit logicalTop);
- LayoutUnit computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0);
+ LayoutUnit computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* = 0);
- void placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunInFlag);
+ void placeRunInIfNeeded(RenderObject* newChild);
bool runInIsPlacedIntoSiblingBlock(RenderObject* runIn);
#ifndef NDEBUG
@@ -424,11 +447,29 @@ public:
void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0) const;
#endif
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo() const
+#if ENABLE(CSS_SHAPES)
+ ShapeInsideInfo* ensureShapeInsideInfo()
{
- return style()->shapeInside() && ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock(this) ? ExclusionShapeInsideInfo::exclusionShapeInsideInfoForRenderBlock(this) : 0;
+ if (!m_rareData || !m_rareData->m_shapeInsideInfo)
+ setShapeInsideInfo(ShapeInsideInfo::createInfo(this));
+ return m_rareData->m_shapeInsideInfo.get();
+ }
+
+ ShapeInsideInfo* shapeInsideInfo() const
+ {
+ if (!m_rareData || !m_rareData->m_shapeInsideInfo)
+ return 0;
+ return ShapeInsideInfo::isEnabledFor(this) ? m_rareData->m_shapeInsideInfo.get() : 0;
+ }
+ void setShapeInsideInfo(PassOwnPtr<ShapeInsideInfo> value)
+ {
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+ m_rareData->m_shapeInsideInfo = value;
}
+ void markShapeInsideDescendantsForLayout();
+ ShapeInsideInfo* layoutShapeInsideInfo() const;
+ bool allowsShapeInsideInfoSharing() const { return !isInline() && !isFloating(); }
#endif
protected:
@@ -442,33 +483,64 @@ protected:
void setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg);
void setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg);
+ void setMustDiscardMarginBefore(bool = true);
+ void setMustDiscardMarginAfter(bool = true);
+
+ bool mustDiscardMarginBefore() const;
+ bool mustDiscardMarginAfter() const;
+
+ bool mustDiscardMarginBeforeForChild(const RenderBox*) const;
+ bool mustDiscardMarginAfterForChild(const RenderBox*) const;
+
+ bool mustSeparateMarginBeforeForChild(const RenderBox*) const;
+ bool mustSeparateMarginAfterForChild(const RenderBox*) const;
+
void initMaxMarginValues()
{
if (m_rareData) {
m_rareData->m_margins = MarginValues(RenderBlockRareData::positiveMarginBeforeDefault(this) , RenderBlockRareData::negativeMarginBeforeDefault(this),
RenderBlockRareData::positiveMarginAfterDefault(this), RenderBlockRareData::negativeMarginAfterDefault(this));
m_rareData->m_paginationStrut = 0;
+
+ m_rareData->m_discardMarginBefore = false;
+ m_rareData->m_discardMarginAfter = false;
}
}
virtual void layout();
- void layoutPositionedObjects(bool relayoutChildren);
+ void layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly = false);
+ void markFixedPositionObjectForLayoutIfNeeded(RenderObject* child);
virtual void paint(PaintInfo&, const LayoutPoint&);
virtual void paintObject(PaintInfo&, const LayoutPoint&);
virtual void paintChildren(PaintInfo& forSelf, const LayoutPoint&, PaintInfo& forChild, bool usePrintRect);
bool paintChild(RenderBox*, PaintInfo& forSelf, const LayoutPoint&, PaintInfo& forChild, bool usePrintRect);
- LayoutUnit logicalRightOffsetForLine(LayoutUnit position, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* logicalHeightRemaining = 0, LayoutUnit logicalHeight = 0) const;
- LayoutUnit logicalLeftOffsetForLine(LayoutUnit position, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* logicalHeightRemaining = 0, LayoutUnit logicalHeight = 0) const;
+ LayoutUnit logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining = 0, LayoutUnit logicalHeight = 0) const
+ {
+ return adjustLogicalRightOffsetForLine(logicalRightFloatOffsetForLine(logicalTop, fixedOffset, heightRemaining, logicalHeight, ShapeOutsideFloatShapeOffset), applyTextIndent);
+ }
+ LayoutUnit logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining = 0, LayoutUnit logicalHeight = 0) const
+ {
+ return adjustLogicalLeftOffsetForLine(logicalLeftFloatOffsetForLine(logicalTop, fixedOffset, heightRemaining, logicalHeight, ShapeOutsideFloatShapeOffset), applyTextIndent);
+ }
+ LayoutUnit logicalRightOffsetForLineIgnoringShapeOutside(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining = 0, LayoutUnit logicalHeight = 0) const
+ {
+ return adjustLogicalRightOffsetForLine(logicalRightFloatOffsetForLine(logicalTop, fixedOffset, heightRemaining, logicalHeight, ShapeOutsideFloatMarginBoxOffset), applyTextIndent);
+ }
+ LayoutUnit logicalLeftOffsetForLineIgnoringShapeOutside(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining = 0, LayoutUnit logicalHeight = 0) const
+ {
+ return adjustLogicalLeftOffsetForLine(logicalLeftFloatOffsetForLine(logicalTop, fixedOffset, heightRemaining, logicalHeight, ShapeOutsideFloatMarginBoxOffset), applyTextIndent);
+ }
virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const;
virtual void adjustInlineDirectionLineBounds(int /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { }
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
- virtual void computePreferredLogicalWidths();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual int firstLineBoxBaseline() const;
virtual int inlineBlockBaseline(LineDirectionMode) const OVERRIDE;
@@ -492,11 +564,14 @@ protected:
virtual bool hasLineIfEmpty() const;
bool simplifiedLayout();
- void simplifiedNormalFlowLayout();
+ virtual void simplifiedNormalFlowLayout();
void setDesiredColumnCountAndWidth(int, LayoutUnit);
+public:
void computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats = false);
+ void clearLayoutOverflow();
+protected:
virtual void addOverflowFromChildren();
void addOverflowFromFloats();
void addOverflowFromPositionedObjects();
@@ -504,7 +579,7 @@ protected:
void addOverflowFromInlineChildren();
void addVisualOverflowFromTheme();
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
#if ENABLE(SVG)
// Only used by RenderSVGText, which explicitely overrides RenderBlock::layoutBlock(), do NOT use for anything else.
@@ -517,15 +592,25 @@ protected:
}
#endif
- void updateRegionsAndExclusionsLogicalSize();
- void computeRegionRangeForBlock();
+ bool updateRegionsAndShapesBeforeChildLayout(RenderFlowThread*);
+ void updateRegionsAndShapesAfterChildLayout(RenderFlowThread*, bool heightChanged = false);
+ void computeRegionRangeForBlock(RenderFlowThread*);
+
+ void updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox*);
virtual void checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight);
private:
-#if ENABLE(CSS_EXCLUSIONS)
- void computeExclusionShapeSize();
- void updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue*, const ExclusionShapeValue* oldExclusionShape);
+ enum ShapeOutsideFloatOffsetMode { ShapeOutsideFloatShapeOffset, ShapeOutsideFloatMarginBoxOffset };
+
+ LayoutUnit logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode) const;
+ LayoutUnit logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode) const;
+ LayoutUnit adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const;
+ LayoutUnit adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const;
+
+#if ENABLE(CSS_SHAPES)
+ void computeShapeSize();
+ void updateShapeInsideInfoAfterStyleChange(const ShapeValue*, const ShapeValue* oldShape);
#endif
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
@@ -539,7 +624,7 @@ private:
void makeChildrenNonInline(RenderObject* insertionPoint = 0);
virtual void removeLeftoverAnonymousBlock(RenderBlock* child);
- static void collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* child);
+ void moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert);
virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); }
@@ -554,7 +639,7 @@ private:
virtual LayoutUnit collapsedMarginBefore() const { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); }
virtual LayoutUnit collapsedMarginAfter() const { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); }
- virtual void repaintOverhangingFloats(bool paintAllDescendants);
+ virtual void repaintOverhangingFloats(bool paintAllDescendants) OVERRIDE;
void layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom);
void layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom);
@@ -563,10 +648,6 @@ private:
void insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*&, TrackedContainerMap*&);
static void removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*&, TrackedContainerMap*&);
- virtual void borderFitAdjust(LayoutRect&) const; // Shrink the box in which the border paints if border-fit is set.
-
- virtual void updateBeforeAfterContent(PseudoId);
-
virtual RootInlineBox* createRootInlineBox(); // Subclassed by SVG and Ruby.
// Called to lay out the legend for a fieldset or the ruby text of a ruby run.
@@ -629,6 +710,18 @@ private:
{
}
+ FloatingObject* clone() const
+ {
+ FloatingObject* cloneObject = new FloatingObject(type(), m_frameRect);
+ cloneObject->m_renderer = m_renderer;
+ cloneObject->m_originatingLine = m_originatingLine;
+ cloneObject->m_paginationStrut = m_paginationStrut;
+ cloneObject->m_shouldPaint = m_shouldPaint;
+ cloneObject->m_isDescendant = m_isDescendant;
+ cloneObject->m_isPlaced = m_isPlaced;
+ return cloneObject;
+ }
+
Type type() const { return static_cast<Type>(m_type); }
RenderBox* renderer() const { return m_renderer; }
@@ -763,6 +856,7 @@ private:
private:
void reset();
+ InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&);
@@ -779,10 +873,12 @@ private:
bool checkPaginationAndFloatsAtEndLine(LineLayoutState&);
RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&);
- InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox);
+ InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox, bool startsNewSegment);
void setMarginsForRubyRun(BidiRun*, RenderRubyRun*, RenderObject*, const LineInfo&);
+ BidiRun* computeInlineDirectionPositionsForSegment(RootInlineBox*, const LineInfo&, ETextAlign, float& logicalLeft,
+ float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache&, WordMeasurements&);
void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&, WordMeasurements&);
void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
void deleteEllipsisLineBoxes();
@@ -830,8 +926,9 @@ private:
virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset);
- void computeInlinePreferredLogicalWidths();
- void computeBlockPreferredLogicalWidths();
+ // FIXME: Make this method const so we can remove the const_cast in computeIntrinsicLogicalWidths.
+ void computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth);
+ void computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const;
// Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline
// children.
@@ -851,15 +948,17 @@ private:
virtual bool shouldPaintSelectionGaps() const;
bool isSelectionRoot() const;
GapRects selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* = 0);
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo* = 0);
GapRects inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo*);
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
GapRects blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo*);
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
LayoutRect blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo*);
- LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position);
- LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position);
+ LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const LogicalSelectionOffsetCaches&, const PaintInfo*);
+ LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches&);
+ LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches&);
+
+ friend class LogicalSelectionOffsetCaches;
virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const;
virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const;
@@ -872,6 +971,8 @@ private:
virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0);
void adjustPointToColumnContents(LayoutPoint&) const;
+
+ void fitBorderToLinesIfNeeded(); // Shrink the box in which the border paints if border-fit is set.
void adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const; // Helper function for borderFitAdjust
void markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest = 0);
@@ -917,10 +1018,12 @@ private:
// These variables are used to detect quirky margins that we need to collapse away (in table cells
// and in the body element).
- bool m_marginBeforeQuirk : 1;
- bool m_marginAfterQuirk : 1;
+ bool m_hasMarginBeforeQuirk : 1;
+ bool m_hasMarginAfterQuirk : 1;
bool m_determinedMarginBeforeQuirk : 1;
+ bool m_discardMargin : 1;
+
// These flags track the previous maximal positive and negative margins.
LayoutUnit m_positiveMargin;
LayoutUnit m_negativeMargin;
@@ -935,45 +1038,46 @@ private:
m_positiveMargin = 0;
m_negativeMargin = 0;
}
- void setMarginBeforeQuirk(bool b) { m_marginBeforeQuirk = b; }
- void setMarginAfterQuirk(bool b) { m_marginAfterQuirk = b; }
+ void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
+ void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }
void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
- void setPositiveMargin(LayoutUnit p) { m_positiveMargin = p; }
- void setNegativeMargin(LayoutUnit n) { m_negativeMargin = n; }
+ void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; }
+ void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; }
void setPositiveMarginIfLarger(LayoutUnit p)
{
+ ASSERT(!m_discardMargin);
if (p > m_positiveMargin)
m_positiveMargin = p;
}
void setNegativeMarginIfLarger(LayoutUnit n)
{
+ ASSERT(!m_discardMargin);
if (n > m_negativeMargin)
m_negativeMargin = n;
}
- void setMargin(LayoutUnit p, LayoutUnit n) { m_positiveMargin = p; m_negativeMargin = n; }
+ void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; }
+ void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
+ void setDiscardMargin(bool value) { m_discardMargin = value; }
bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; }
bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; }
bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; }
bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; }
- void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
bool quirkContainer() const { return m_quirkContainer; }
bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; }
- bool marginBeforeQuirk() const { return m_marginBeforeQuirk; }
- bool marginAfterQuirk() const { return m_marginAfterQuirk; }
+ bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
+ bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }
LayoutUnit positiveMargin() const { return m_positiveMargin; }
LayoutUnit negativeMargin() const { return m_negativeMargin; }
+ bool discardMargin() const { return m_discardMargin; }
LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; }
};
void layoutBlockChild(RenderBox* child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom);
void adjustPositionedBlock(RenderBox* child, const MarginInfo&);
void adjustFloatingBlock(const MarginInfo&);
- bool handleSpecialChild(RenderBox* child, const MarginInfo&);
- bool handleFloatingChild(RenderBox* child, const MarginInfo&);
- bool handlePositionedChild(RenderBox* child, const MarginInfo&);
RenderBoxModelObject* createReplacementRunIn(RenderBoxModelObject* runIn);
void moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn);
@@ -982,8 +1086,7 @@ private:
LayoutUnit collapseMargins(RenderBox* child, MarginInfo&);
LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos);
LayoutUnit estimateLogicalTopPosition(RenderBox* child, const MarginInfo&, LayoutUnit& estimateWithoutPagination);
- void marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const;
- void determineLogicalLeftPositionForChild(RenderBox* child);
+ void marginBeforeEstimateForChild(RenderBox*, LayoutUnit&, LayoutUnit&, bool&) const;
void handleAfterSideOfBlock(LayoutUnit top, LayoutUnit bottom, MarginInfo&);
void setCollapsedBottomMargin(const MarginInfo&);
// End helper functions and structs used by layoutBlockChildren.
@@ -992,10 +1095,20 @@ private:
RootInlineBox* createLineBoxesFromBidiRuns(BidiRunList<BidiRun>&, const InlineIterator& end, LineInfo&, VerticalPositionCache&, BidiRun* trailingSpaceRun, WordMeasurements&);
void layoutRunsAndFloats(LineLayoutState&, bool hasInlineChild);
void layoutRunsAndFloatsInRange(LineLayoutState&, InlineBidiResolver&, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines);
+#if ENABLE(CSS_SHAPES)
+ void updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*&, LayoutUnit&, LineLayoutState&);
+ void updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*&, LineLayoutState&);
+ bool adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo*, LayoutUnit, LineLayoutState&, InlineBidiResolver&, FloatingObject*, InlineIterator&, WordMeasurements&);
+#endif
+ const InlineIterator& restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver&, const InlineIterator&);
void linkToEndLineIfNeeded(LineLayoutState&);
static void repaintDirtyFloats(Vector<FloatWithRect>& floats);
protected:
+ void dirtyForLayoutFromPercentageHeightDescendants();
+
+ void determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta);
+
// Pagination routines.
virtual bool relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer&);
@@ -1021,8 +1134,16 @@ public:
protected:
bool pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const;
+ // A page break is required at some offset due to space shortage in the current fragmentainer.
+ void setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage);
+
+ // Update minimum page height required to avoid fragmentation where it shouldn't occur (inside
+ // unbreakable content, between orphans and widows, etc.). This will be used as a hint to the
+ // column balancer to help set a good minimum column height.
+ void updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight);
+
LayoutUnit adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins = false); // If the child is unsplittable and can't fit on the current page, return the top of the next page/column.
- void adjustLinePositionForPagination(RootInlineBox*, LayoutUnit& deltaOffset); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page.
+ void adjustLinePositionForPagination(RootInlineBox*, LayoutUnit& deltaOffset, RenderFlowThread*); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page.
LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock);
// Adjust from painting offsets to the local coords of this renderer
@@ -1031,9 +1152,9 @@ protected:
// This function is called to test a line box that has moved in the block direction to see if it has ended up in a new
// region/page/column that has a different available line width than the old one. Used to know when you have to dirty a
// line, i.e., that it can't be re-used.
- bool lineWidthForPaginatedLineChanged(RootInlineBox*, LayoutUnit lineDelta = 0) const;
+ bool lineWidthForPaginatedLineChanged(RootInlineBox*, LayoutUnit lineDelta, RenderFlowThread*) const;
- bool logicalWidthChangedInRegions() const;
+ bool logicalWidthChangedInRegions(RenderFlowThread*) const;
virtual bool requiresColumns(int desiredColumnCount) const;
@@ -1042,7 +1163,7 @@ protected:
virtual bool canCollapseAnonymousBlockChild() const { return true; }
public:
- LayoutUnit offsetFromLogicalTopOfFirstPage() const;
+ virtual LayoutUnit offsetFromLogicalTopOfFirstPage() const;
RenderRegion* regionAtBlockOffset(LayoutUnit) const;
RenderRegion* clampToStartAndEndRegions(RenderRegion*) const;
@@ -1073,6 +1194,9 @@ protected:
, m_highValue(highValue)
, m_offset(offset)
, m_heightRemaining(heightRemaining)
+#if ENABLE(CSS_SHAPES)
+ , m_last(0)
+#endif
{
}
@@ -1080,25 +1204,39 @@ protected:
inline int highValue() const { return m_highValue; }
void collectIfNeeded(const IntervalType&) const;
+#if ENABLE(CSS_SHAPES)
+ // When computing the offset caused by the floats on a given line, if
+ // the outermost float on that line has a shape-outside, the inline
+ // content that butts up against that float must be positioned using
+ // the contours of the shape, not the margin box of the float.
+ // We save the last float encountered so that the offset can be
+ // computed correctly by the code using this adapter.
+ const FloatingObject* lastFloat() const { return m_last; }
+#endif
+
private:
const RenderBlock* m_renderer;
int m_lowValue;
int m_highValue;
LayoutUnit& m_offset;
LayoutUnit* m_heightRemaining;
+#if ENABLE(CSS_SHAPES)
+ // This member variable is mutable because the collectIfNeeded method
+ // is declared as const, even though it doesn't actually respect that
+ // contract. It modifies other member variables via loopholes in the
+ // const behavior. Instead of using loopholes, I decided it was better
+ // to make the fact that this is modified in a const method explicit.
+ mutable const FloatingObject* m_last;
+#endif
};
+ void createFloatingObjects();
+
+public:
+
class FloatingObjects {
+ WTF_MAKE_NONCOPYABLE(FloatingObjects); WTF_MAKE_FAST_ALLOCATED;
public:
- FloatingObjects(const RenderBlock* renderer, bool horizontalWritingMode)
- : m_placedFloatsTree(UninitializedTree)
- , m_leftObjectsCount(0)
- , m_rightObjectsCount(0)
- , m_horizontalWritingMode(horizontalWritingMode)
- , m_renderer(renderer)
- {
- }
-
void clear();
void add(FloatingObject*);
void remove(FloatingObject*);
@@ -1115,6 +1253,7 @@ protected:
return m_placedFloatsTree;
}
private:
+ FloatingObjects(const RenderBlock*, bool horizontalWritingMode);
void computePlacedFloatsTree();
inline void computePlacedFloatsTreeIfNeeded()
{
@@ -1131,8 +1270,9 @@ protected:
unsigned m_rightObjectsCount;
bool m_horizontalWritingMode;
const RenderBlock* m_renderer;
+
+ friend void RenderBlock::createFloatingObjects();
};
- OwnPtr<FloatingObjects> m_floatingObjects;
// Allocated only when some of these fields have non-default values
struct RenderBlockRareData {
@@ -1143,6 +1283,10 @@ protected:
, m_paginationStrut(0)
, m_pageLogicalOffset(0)
, m_lineGridBox(0)
+ , m_lineBreakToAvoidWidow(0)
+ , m_shouldBreakAtLineToAvoidWidow(false)
+ , m_discardMarginBefore(false)
+ , m_discardMarginAfter(false)
{
}
@@ -1150,7 +1294,6 @@ protected:
{
return std::max<LayoutUnit>(block->marginBefore(), 0);
}
-
static LayoutUnit negativeMarginBeforeDefault(const RenderBlock* block)
{
return std::max<LayoutUnit>(-block->marginBefore(), 0);
@@ -1169,16 +1312,30 @@ protected:
LayoutUnit m_pageLogicalOffset;
RootInlineBox* m_lineGridBox;
+
+ RootInlineBox* m_lineBreakToAvoidWidow;
+#if ENABLE(CSS_SHAPES)
+ OwnPtr<ShapeInsideInfo> m_shapeInsideInfo;
+#endif
+ bool m_shouldBreakAtLineToAvoidWidow : 1;
+ bool m_discardMarginBefore : 1;
+ bool m_discardMarginAfter : 1;
};
+protected:
+
+ OwnPtr<FloatingObjects> m_floatingObjects;
OwnPtr<RenderBlockRareData> m_rareData;
RenderObjectChildList m_children;
RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>.
- mutable signed m_lineHeight : 30;
+ mutable signed m_lineHeight : 27;
+ unsigned m_hasMarginBeforeQuirk : 1; // Note these quirk values can't be put in RenderBlockRareData since they are set too frequently.
+ unsigned m_hasMarginAfterQuirk : 1;
unsigned m_beingDestroyed : 1;
unsigned m_hasMarkupTruncation : 1;
+ unsigned m_hasBorderOrPaddingLogicalWidthChanged : 1;
// RenderRubyBase objects need to be able to split and merge, moving their children around
// (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline).
@@ -1192,13 +1349,13 @@ private:
inline RenderBlock* toRenderBlock(RenderObject* object)
{
- ASSERT(!object || object->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderBlock());
return static_cast<RenderBlock*>(object);
}
inline const RenderBlock* toRenderBlock(const RenderObject* object)
{
- ASSERT(!object || object->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderBlock());
return static_cast<const RenderBlock*>(object);
}
diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
index 970fbc346..8550ca495 100644
--- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved.
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013 ChangSeok Oh <shivamidow@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -29,24 +30,25 @@
#include "Logging.h"
#include "RenderArena.h"
#include "RenderCombineText.h"
+#include "RenderCounter.h"
#include "RenderFlowThread.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderListMarker.h"
+#include "RenderRegion.h"
#include "RenderRubyRun.h"
#include "RenderView.h"
#include "Settings.h"
#include "TrailingFloatsRootInlineBox.h"
#include "VerticalPositionCache.h"
#include "break_lines.h"
-#include <wtf/AlwaysInline.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
#include <wtf/unicode/CharacterNames.h>
-#if ENABLE(CSS_EXCLUSIONS)
-#include "ExclusionShapeInsideInfo.h"
+#if ENABLE(CSS_SHAPES)
+#include "ShapeInsideInfo.h"
#endif
#if ENABLE(SVG)
@@ -63,47 +65,75 @@ namespace WebCore {
// We don't let our line box tree for a single line get any deeper than this.
const unsigned cMaxLineDepth = 200;
-#if ENABLE(CSS_EXCLUSIONS)
-static inline ExclusionShapeInsideInfo* layoutExclusionShapeInsideInfo(const RenderBlock* block)
+static LayoutUnit logicalHeightForLine(const RenderBlock* block, bool isFirstLine, LayoutUnit replacedHeight = 0)
{
- return block->view()->layoutState()->exclusionShapeInsideInfo();
+ if (!block->document()->inNoQuirksMode() && replacedHeight)
+ return replacedHeight;
+
+ if (!(block->style(isFirstLine)->lineBoxContain() & LineBoxContainBlock))
+ return 0;
+
+ return max<LayoutUnit>(replacedHeight, block->lineHeight(isFirstLine, block->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
+}
+
+#if ENABLE(CSS_SHAPES)
+ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
+{
+ ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo();
+
+ if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfoSharing()) {
+ // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ...
+ LayoutUnit offset = logicalHeight() + logicalHeightForLine(this, false) - LayoutUnit(1);
+ RenderRegion* region = regionAtBlockOffset(offset);
+ if (region)
+ shapeInsideInfo = region->shapeInsideInfo();
+ }
+
+ return shapeInsideInfo;
}
#endif
+enum IndentTextOrNot { DoNotIndentText, IndentText };
+
class LineWidth {
public:
- LineWidth(RenderBlock* block, bool isFirstLine)
+ LineWidth(RenderBlock* block, bool isFirstLine, IndentTextOrNot shouldIndentText)
: m_block(block)
, m_uncommittedWidth(0)
, m_committedWidth(0)
, m_overhangWidth(0)
+ , m_trailingWhitespaceWidth(0)
+ , m_trailingCollapsedWhitespaceWidth(0)
, m_left(0)
, m_right(0)
, m_availableWidth(0)
-#if ENABLE(CSS_EXCLUSIONS)
+#if ENABLE(CSS_SHAPES)
, m_segment(0)
#endif
, m_isFirstLine(isFirstLine)
+ , m_shouldIndentText(shouldIndentText)
{
ASSERT(block);
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(m_block);
- // FIXME: Bug 91878: Add support for multiple segments, currently we only support one
- if (exclusionShapeInsideInfo && exclusionShapeInsideInfo->hasSegments())
- m_segment = &exclusionShapeInsideInfo->segments()[0];
+#if ENABLE(CSS_SHAPES)
+ if (ShapeInsideInfo* shapeInsideInfo = m_block->layoutShapeInsideInfo())
+ m_segment = shapeInsideInfo->currentSegment();
#endif
updateAvailableWidth();
}
- bool fitsOnLine() const { return currentWidth() <= m_availableWidth; }
- bool fitsOnLine(float extra) const { return currentWidth() + extra <= m_availableWidth; }
- float currentWidth() const { return m_committedWidth + m_uncommittedWidth; }
+ bool fitsOnLine(bool ignoringTrailingSpace = false)
+ {
+ return ignoringTrailingSpace ? fitsOnLineExcludingTrailingCollapsedWhitespace() : fitsOnLineIncludingExtraWidth(0);
+ }
+ bool fitsOnLineIncludingExtraWidth(float extra) const { return currentWidth() + extra <= m_availableWidth; }
+ bool fitsOnLineExcludingTrailingWhitespace(float extra) const { return currentWidth() - m_trailingWhitespaceWidth + extra <= m_availableWidth; }
+ float currentWidth() const { return m_committedWidth + m_uncommittedWidth; }
// FIXME: We should eventually replace these three functions by ones that work on a higher abstraction.
float uncommittedWidth() const { return m_uncommittedWidth; }
float committedWidth() const { return m_committedWidth; }
float availableWidth() const { return m_availableWidth; }
- void updateAvailableWidth();
+ void updateAvailableWidth(LayoutUnit minimumHeight = 0);
void shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::FloatingObject*);
void addUncommittedWidth(float delta) { m_uncommittedWidth += delta; }
void commit()
@@ -113,49 +143,42 @@ public:
}
void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer);
void fitBelowFloats();
+ void setTrailingWhitespaceWidth(float collapsedWhitespace, float borderPaddingMargin = 0) { m_trailingCollapsedWhitespaceWidth = collapsedWhitespace; m_trailingWhitespaceWidth = collapsedWhitespace + borderPaddingMargin; }
+
+ bool shouldIndentText() const { return m_shouldIndentText == IndentText; }
private:
void computeAvailableWidthFromLeftAndRight()
{
m_availableWidth = max(0.0f, m_right - m_left) + m_overhangWidth;
}
+ bool fitsOnLineExcludingTrailingCollapsedWhitespace() const { return currentWidth() - m_trailingCollapsedWhitespaceWidth <= m_availableWidth; }
private:
RenderBlock* m_block;
float m_uncommittedWidth;
float m_committedWidth;
float m_overhangWidth; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang.
+ float m_trailingWhitespaceWidth;
+ float m_trailingCollapsedWhitespaceWidth;
float m_left;
float m_right;
float m_availableWidth;
-#if ENABLE(CSS_EXCLUSIONS)
+#if ENABLE(CSS_SHAPES)
const LineSegment* m_segment;
#endif
bool m_isFirstLine;
+ IndentTextOrNot m_shouldIndentText;
};
-static LayoutUnit logicalHeightForLine(RenderBlock* block)
-{
- InlineFlowBox* lineBox = block->firstRootBox();
- LayoutUnit logicalHeight = 0;
- if (!lineBox)
- return logicalHeight;
-
- if (lineBox->firstChild() && lineBox->firstChild()->renderer() && lineBox->firstChild()->renderer()->isRenderBlock())
- logicalHeight = toRenderBlock(lineBox->firstChild()->renderer())->logicalHeight();
- else
- logicalHeight = lineBox->height();
- return logicalHeight;
-}
-
-inline void LineWidth::updateAvailableWidth()
+inline void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight)
{
LayoutUnit height = m_block->logicalHeight();
- LayoutUnit logicalHeight = logicalHeightForLine(m_block);
- m_left = m_block->logicalLeftOffsetForLine(height, m_isFirstLine, logicalHeight);
- m_right = m_block->logicalRightOffsetForLine(height, m_isFirstLine, logicalHeight);
+ LayoutUnit logicalHeight = logicalHeightForLine(m_block, m_isFirstLine, replacedHeight);
+ m_left = m_block->logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight);
+ m_right = m_block->logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight);
-#if ENABLE(CSS_EXCLUSIONS)
+#if ENABLE(CSS_SHAPES)
if (m_segment) {
m_left = max<float>(m_segment->logicalLeft, m_left);
m_right = min<float>(m_segment->logicalRight, m_right);
@@ -171,14 +194,55 @@ inline void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::Floa
if (height < m_block->logicalTopForFloat(newFloat) || height >= m_block->logicalBottomForFloat(newFloat))
return;
+#if ENABLE(CSS_SHAPES)
+ // When floats with shape outside are stacked, the floats are positioned based on the margin box of the float,
+ // not the shape's contour. Since we computed the width based on the shape contour when we added the float,
+ // when we add a subsequent float on the same line, we need to undo the shape delta in order to position
+ // based on the margin box. In order to do this, we need to walk back through the floating object list to find
+ // the first previous float that is on the same side as our newFloat.
+ ShapeOutsideInfo* previousShapeOutsideInfo = 0;
+ const RenderBlock::FloatingObjectSet& floatingObjectSet = m_block->m_floatingObjects->set();
+ RenderBlock::FloatingObjectSetIterator it = floatingObjectSet.end();
+ RenderBlock::FloatingObjectSetIterator begin = floatingObjectSet.begin();
+ for (--it; it != begin; --it) {
+ RenderBlock::FloatingObject* previousFloat = *it;
+ if (previousFloat != newFloat && previousFloat->type() == newFloat->type()) {
+ previousShapeOutsideInfo = previousFloat->renderer()->shapeOutsideInfo();
+ if (previousShapeOutsideInfo) {
+ previousShapeOutsideInfo->computeSegmentsForContainingBlockLine(m_block->logicalHeight(), m_block->logicalTopForFloat(previousFloat), logicalHeightForLine(m_block, m_isFirstLine));
+ }
+ break;
+ }
+ }
+
+ ShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer()->shapeOutsideInfo();
+ if (shapeOutsideInfo) {
+ shapeOutsideInfo->computeSegmentsForContainingBlockLine(m_block->logicalHeight(), m_block->logicalTopForFloat(newFloat), logicalHeightForLine(m_block, m_isFirstLine));
+ }
+#endif
+
if (newFloat->type() == RenderBlock::FloatingObject::FloatLeft) {
float newLeft = m_block->logicalRightForFloat(newFloat);
- if (m_isFirstLine && m_block->style()->isLeftToRightDirection())
+#if ENABLE(CSS_SHAPES)
+ if (previousShapeOutsideInfo)
+ newLeft -= previousShapeOutsideInfo->rightSegmentMarginBoxDelta();
+ if (shapeOutsideInfo)
+ newLeft += shapeOutsideInfo->rightSegmentMarginBoxDelta();
+#endif
+
+ if (shouldIndentText() && m_block->style()->isLeftToRightDirection())
newLeft += floorToInt(m_block->textIndentOffset());
m_left = max<float>(m_left, newLeft);
} else {
float newRight = m_block->logicalLeftForFloat(newFloat);
- if (m_isFirstLine && !m_block->style()->isLeftToRightDirection())
+#if ENABLE(CSS_SHAPES)
+ if (previousShapeOutsideInfo)
+ newRight -= previousShapeOutsideInfo->leftSegmentMarginBoxDelta();
+ if (shapeOutsideInfo)
+ newRight += shapeOutsideInfo->leftSegmentMarginBoxDelta();
+#endif
+
+ if (shouldIndentText() && !m_block->style()->isLeftToRightDirection())
newRight -= floorToInt(m_block->textIndentOffset());
m_right = min<float>(m_right, newRight);
}
@@ -215,8 +279,8 @@ void LineWidth::fitBelowFloats()
if (floatLogicalBottom <= lastFloatLogicalBottom)
break;
- newLineLeft = m_block->logicalLeftOffsetForLine(floatLogicalBottom, m_isFirstLine);
- newLineRight = m_block->logicalRightOffsetForLine(floatLogicalBottom, m_isFirstLine);
+ newLineLeft = m_block->logicalLeftOffsetForLine(floatLogicalBottom, shouldIndentText());
+ newLineRight = m_block->logicalRightOffsetForLine(floatLogicalBottom, shouldIndentText());
newLineWidth = max(0.0f, newLineRight - newLineLeft);
lastFloatLogicalBottom = floatLogicalBottom;
if (newLineWidth >= m_uncommittedWidth)
@@ -287,27 +351,37 @@ static inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
return child->marginEnd() + child->paddingEnd() + child->borderEnd();
}
-static bool shouldAddBorderPaddingMargin(RenderObject* child, bool &checkSide)
+static inline bool shouldAddBorderPaddingMargin(RenderObject* child)
{
- if (!child || (child->isText() && !toRenderText(child)->textLength()))
- return true;
- checkSide = false;
- return checkSide;
+ // When deciding whether we're at the edge of an inline, adjacent collapsed whitespace is the same as no sibling at all.
+ return !child || (child->isText() && !toRenderText(child)->textLength());
+}
+
+static RenderObject* previousInFlowSibling(RenderObject* child)
+{
+ child = child->previousSibling();
+ while (child && child->isOutOfFlowPositioned())
+ child = child->previousSibling();
+ return child;
}
-static LayoutUnit inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
+static LayoutUnit inlineLogicalWidth(RenderObject* child, bool checkStartEdge = true, bool checkEndEdge = true)
{
unsigned lineDepth = 1;
LayoutUnit extraWidth = 0;
RenderObject* parent = child->parent();
while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
RenderInline* parentAsRenderInline = toRenderInline(parent);
- if (start && shouldAddBorderPaddingMargin(child->previousSibling(), start))
- extraWidth += borderPaddingMarginStart(parentAsRenderInline);
- if (end && shouldAddBorderPaddingMargin(child->nextSibling(), end))
- extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
- if (!start && !end)
- return extraWidth;
+ if (!isEmptyInline(parentAsRenderInline)) {
+ checkStartEdge = checkStartEdge && shouldAddBorderPaddingMargin(previousInFlowSibling(child));
+ if (checkStartEdge)
+ extraWidth += borderPaddingMarginStart(parentAsRenderInline);
+ checkEndEdge = checkEndEdge && shouldAddBorderPaddingMargin(child->nextSibling());
+ if (checkEndEdge)
+ extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
+ if (!checkStartEdge && !checkEndEdge)
+ return extraWidth;
+ }
child = parent;
parent = child->parent();
}
@@ -355,7 +429,8 @@ static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator&
}
}
-static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
+// Don't call this directly. Use one of the descriptive helper functions below.
+static void deprecatedAddMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
{
if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
@@ -364,6 +439,35 @@ static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterat
midpoints[lineMidpointState.numMidpoints++] = midpoint;
}
+static inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
+{
+ ASSERT(!(lineMidpointState.numMidpoints % 2));
+ deprecatedAddMidpoint(lineMidpointState, midpoint);
+}
+
+static inline void stopIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
+{
+ ASSERT(lineMidpointState.numMidpoints % 2);
+ deprecatedAddMidpoint(lineMidpointState, midpoint);
+}
+
+// When ignoring spaces, this needs to be called for objects that need line boxes such as RenderInlines or
+// hard line breaks to ensure that they're not ignored.
+static inline void ensureLineBoxInsideIgnoredSpaces(LineMidpointState& lineMidpointState, RenderObject* renderer)
+{
+ InlineIterator midpoint(0, renderer, 0);
+ stopIgnoringSpaces(lineMidpointState, midpoint);
+ startIgnoringSpaces(lineMidpointState, midpoint);
+}
+
+// Adding a pair of midpoints before a character will split it out into a new line box.
+static inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, InlineIterator& textParagraphSeparator)
+{
+ InlineIterator midpoint(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos);
+ startIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos - 1));
+ stopIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos));
+}
+
static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
{
return new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir());
@@ -430,11 +534,20 @@ static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRo
return toRenderInline(obj)->createAndAppendInlineFlowBox();
}
+// FIXME: Don't let counters mark themselves as needing pref width recalcs during layout
+// so we don't need this hack.
+static inline void updateCounterIfNeeded(RenderText* o)
+{
+ if (!o->preferredLogicalWidthsDirty() || !o->isCounter())
+ return;
+ toRenderCounter(o)->updateCounter();
+}
+
static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
{
if (o->isText()) {
RenderText* renderText = toRenderText(o);
- renderText->updateTextIfNeeded(); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed.
+ updateCounterIfNeeded(renderText);
renderText->dirtyLineBoxes(fullLayout);
} else
toRenderInline(o)->dirtyLineBoxes(fullLayout);
@@ -450,7 +563,7 @@ static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
return false;
}
-InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
+InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox, bool startNewSegment)
{
// See if we have an unconstructed line box for this object that is also
// the last item on the line.
@@ -459,7 +572,7 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& l
InlineFlowBox* result = 0;
bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
do {
- ASSERT(obj->isRenderInline() || obj == this);
+ ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
@@ -473,12 +586,13 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& l
// the same line (this can happen with very fancy language mixtures).
bool constructedNewBox = false;
bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
- bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
+ bool mustCreateBoxesToRoot = startNewSegment && !(parentBox && parentBox->isRootInlineBox());
+ bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox) && !mustCreateBoxesToRoot;
if (allowedToConstructNewBox && !canUseExistingParentBox) {
// We need to make a new box for this render object. Once
// made, we need to place it at the end of the current line.
InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
- ASSERT(newBox->isInlineFlowBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox());
parentBox = toInlineFlowBox(newBox);
parentBox->setFirstLineStyleBit(lineInfo.isFirstLine());
parentBox->setIsHorizontal(isHorizontalWritingMode());
@@ -570,10 +684,16 @@ RootInlineBox* RenderBlock::constructLine(BidiRunList<BidiRun>& bidiRuns, const
// If we have no parent box yet, or if the run is not simply a sibling,
// then we need to construct inline boxes as necessary to properly enclose the
- // run's inline box.
- if (!parentBox || parentBox->renderer() != r->m_object->parent())
+ // run's inline box. Segments can only be siblings at the root level, as
+ // they are positioned separately.
+#if ENABLE(CSS_SHAPES)
+ bool runStartsSegment = r->m_startsSegment;
+#else
+ bool runStartsSegment = false;
+#endif
+ if (!parentBox || parentBox->renderer() != r->m_object->parent() || runStartsSegment)
// Create new inline boxes all the way back to the appropriate insertion point.
- parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box);
+ parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box, runStartsSegment);
else {
// Append the inline box to this line.
parentBox->addToLine(box);
@@ -692,10 +812,10 @@ void RenderBlock::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, Re
setMarginEndForChild(renderer, -endOverhang);
}
-static inline float measureHyphenWidth(RenderText* renderer, const Font& font)
+static inline float measureHyphenWidth(RenderText* renderer, const Font& font, HashSet<const SimpleFontData*>* fallbackFonts = 0)
{
RenderStyle* style = renderer->style();
- return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphenString().string(), style));
+ return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphenString().string(), style), fallbackFonts);
}
class WordMeasurement {
@@ -716,11 +836,8 @@ public:
};
static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
- GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
+ GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
{
-#if !(PLATFORM(CHROMIUM) && OS(DARWIN))
- UNUSED_PARAM(wordMeasurements);
-#endif
HashSet<const SimpleFontData*> fallbackFonts;
GlyphOverflow glyphOverflow;
@@ -742,29 +859,33 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru
LayoutUnit hyphenWidth = 0;
if (toInlineTextBox(run->m_box)->hasHyphen()) {
const Font& font = renderer->style(lineInfo.isFirstLine())->font();
- hyphenWidth = measureHyphenWidth(renderer, font);
+ hyphenWidth = measureHyphenWidth(renderer, font, &fallbackFonts);
}
float measuredWidth = 0;
-#if !(PLATFORM(CHROMIUM) && OS(DARWIN))
bool kerningIsEnabled = font.typesettingFeatures() & Kerning;
+ bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
// Since we don't cache glyph overflows, we need to re-measure the run if
// the style is linebox-contain: glyph.
- if (!lineBox->fitsToGlyphs() && renderer->canUseSimpleFontCodePath()) {
+ if (!lineBox->fitsToGlyphs() && canUseSimpleFontCodePath) {
int lastEndOffset = run->m_start;
for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
- const WordMeasurement& wordMeasurement = wordMeasurements[i];
- if (wordMeasurement.width <=0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
+ WordMeasurement& wordMeasurement = wordMeasurements[i];
+ if (wordMeasurement.width <= 0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
continue;
if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
continue;
lastEndOffset = wordMeasurement.endOffset;
if (kerningIsEnabled && lastEndOffset == run->m_stop) {
- measuredWidth += renderer->width(wordMeasurement.startOffset, lastEndOffset - wordMeasurement.startOffset, xPos, lineInfo.isFirstLine());
- if (i > 0)
+ int wordLength = lastEndOffset - wordMeasurement.startOffset;
+ GlyphOverflow overflow;
+ measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos + measuredWidth, lineInfo.isFirstLine(),
+ &wordMeasurement.fallbackFonts, &overflow);
+ UChar c = renderer->characterAt(wordMeasurement.startOffset);
+ if (i > 0 && wordLength == 1 && (c == ' ' || c == '\t'))
measuredWidth += renderer->style()->wordSpacing();
} else
measuredWidth += wordMeasurement.width;
@@ -780,7 +901,6 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru
fallbackFonts.clear();
}
}
-#endif
if (!measuredWidth)
measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
@@ -808,6 +928,11 @@ static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun*
size_t i = 0;
for (BidiRun* r = firstRun; r; r = r->next()) {
+#if ENABLE(CSS_SHAPES)
+ // This method is called once per segment, do not move past the current segment.
+ if (r->m_startsSegment)
+ break;
+#endif
if (!r->m_box || r == trailingSpaceRun)
continue;
@@ -874,26 +999,97 @@ void RenderBlock::updateLogicalWidthForAlignment(const ETextAlign& textAlign, Bi
}
}
+static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style)
+{
+ IndentTextOrNot shouldIndentText = DoNotIndentText;
+ if (isFirstLine)
+ shouldIndentText = IndentText;
+#if ENABLE(CSS3_TEXT)
+ else if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine)
+ shouldIndentText = IndentText;
+
+ if (style->textIndentType() == TextIndentHanging)
+ shouldIndentText = shouldIndentText == IndentText ? DoNotIndentText : IndentText;
+#else
+ UNUSED_PARAM(isAfterHardLineBreak);
+ UNUSED_PARAM(style);
+#endif
+ return shouldIndentText;
+}
+
+static void updateLogicalInlinePositions(RenderBlock* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
+{
+ LayoutUnit lineLogicalHeight = logicalHeightForLine(block, firstLine, boxLogicalHeight);
+ lineLogicalLeft = block->pixelSnappedLogicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
+ lineLogicalRight = block->pixelSnappedLogicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
+ availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
+}
+
void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
{
ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
- LayoutUnit lineLogicalHeight = logicalHeightForLine(this);
// CSS 2.1: "'Text-indent' only affects a line if it is the first formatted line of an element. For example, the first line of an anonymous block
// box is only affected if it is the first child of its parent element."
- bool firstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this);
- float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
- float logicalRight = pixelSnappedLogicalRightOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(this);
- if (exclusionShapeInsideInfo && exclusionShapeInsideInfo->hasSegments()) {
- logicalLeft = max<float>(roundToInt(exclusionShapeInsideInfo->segments()[0].logicalLeft), logicalLeft);
- logicalRight = min<float>(floorToInt(exclusionShapeInsideInfo->segments()[0].logicalRight), logicalRight);
+ // CSS3 "text-indent", "-webkit-each-line" affects the first line of the block container as well as each line after a forced line break,
+ // but does not affect lines after a soft wrap break.
+ bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this);
+ bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak();
+ IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, style());
+ float lineLogicalLeft;
+ float lineLogicalRight;
+ float availableLogicalWidth;
+ updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0);
+ bool needsWordSpacing;
+#if ENABLE(CSS_SHAPES)
+ ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
+ if (shapeInsideInfo && shapeInsideInfo->hasSegments()) {
+ BidiRun* segmentStart = firstRun;
+ const SegmentList& segments = shapeInsideInfo->segments();
+ float logicalLeft = max<float>(roundToInt(segments[0].logicalLeft), lineLogicalLeft);
+ float logicalRight = min<float>(floorToInt(segments[0].logicalRight), lineLogicalRight);
+ float startLogicalLeft = logicalLeft;
+ float endLogicalRight = logicalLeft;
+ float minLogicalLeft = logicalLeft;
+ float maxLogicalRight = logicalLeft;
+ lineBox->beginPlacingBoxRangesInInlineDirection(logicalLeft);
+ for (size_t i = 0; i < segments.size(); i++) {
+ if (i) {
+ logicalLeft = max<float>(roundToInt(segments[i].logicalLeft), lineLogicalLeft);
+ logicalRight = min<float>(floorToInt(segments[i].logicalRight), lineLogicalRight);
+ }
+ availableLogicalWidth = logicalRight - logicalLeft;
+ BidiRun* newSegmentStart = computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, logicalLeft, availableLogicalWidth, segmentStart, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
+ needsWordSpacing = false;
+ endLogicalRight = lineBox->placeBoxRangeInInlineDirection(segmentStart->m_box, newSegmentStart ? newSegmentStart->m_box : 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
+ if (!newSegmentStart || !newSegmentStart->next())
+ break;
+ ASSERT(newSegmentStart->m_startsSegment);
+ // Discard the empty segment start marker bidi runs
+ segmentStart = newSegmentStart->next();
+ }
+ lineBox->endPlacingBoxRangesInInlineDirection(startLogicalLeft, endLogicalRight, minLogicalLeft, maxLogicalRight);
+ return;
}
#endif
- float availableLogicalWidth = logicalRight - logicalLeft;
+ if (firstRun && firstRun->m_object->isReplaced()) {
+ RenderBox* renderBox = toRenderBox(firstRun->m_object);
+ updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox->logicalHeight());
+ }
+
+ computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
+ // The widths of all runs are now known. We can now place every inline box (and
+ // compute accurate widths for the inline flow boxes).
+ needsWordSpacing = false;
+ lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing, textBoxDataMap);
+}
+
+BidiRun* RenderBlock::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
+ float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache,
+ WordMeasurements& wordMeasurements)
+{
bool needsWordSpacing = false;
float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
unsigned expansionOpportunityCount = 0;
@@ -901,7 +1097,14 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
Vector<unsigned, 16> expansionOpportunities;
RenderObject* previousObject = 0;
- for (BidiRun* r = firstRun; r; r = r->next()) {
+ BidiRun* r = firstRun;
+ for (; r; r = r->next()) {
+#if ENABLE(CSS_SHAPES)
+ // Once we have reached the start of the next segment, we have finished
+ // computing the positions for this segment's contents.
+ if (r->m_startsSegment)
+ break;
+#endif
if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak())
continue; // Positioned objects are only participating to figure out their
// correct static x position. They have no effect on the width.
@@ -951,10 +1154,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
- // The widths of all runs are now known. We can now place every inline box (and
- // compute accurate widths for the inline flow boxes).
- needsWordSpacing = false;
- lineBox->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
+ return r;
}
void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
@@ -1010,11 +1210,7 @@ static void setStaticPositions(RenderBlock* block, RenderBox* child)
toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(blockHeight, false));
toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
}
-
- if (child->style()->isOriginalDisplayInlineType())
- block->setStaticInlinePositionForChild(child, blockHeight, block->startAlignedOffsetForLine(blockHeight, false));
- else
- block->setStaticInlinePositionForChild(child, blockHeight, block->startOffsetForContent(blockHeight));
+ block->updateStaticInlinePositionForChild(child, blockHeight);
child->layer()->setStaticBlockPosition(blockHeight);
}
@@ -1101,13 +1297,14 @@ static inline BidiStatus statusWithDirection(TextDirection textDirection, bool i
}
// FIXME: BidiResolver should have this logic.
-static inline void constructBidiRuns(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
+static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfRuns, VisualDirectionOverride override, bool previousLineBrokeCleanly)
{
// FIXME: We should pass a BidiRunList into createBidiRunsForLine instead
// of the resolver owning the runs.
ASSERT(&topResolver.runs() == &bidiRuns);
+ ASSERT(topResolver.position() != endOfRuns);
RenderObject* currentRoot = topResolver.position().root();
- topResolver.createBidiRunsForLine(endOfLine, override, previousLineBrokeCleanly);
+ topResolver.createBidiRunsForLine(endOfRuns, override, previousLineBrokeCleanly);
while (!topResolver.isolatedRuns().isEmpty()) {
// It does not matter which order we resolve the runs as long as we resolve them all.
@@ -1147,7 +1344,7 @@ static inline void constructBidiRuns(InlineBidiResolver& topResolver, BidiRunLis
// We stop at the next end of line; we may re-enter this isolate in the next call to constructBidiRuns().
// FIXME: What should end and previousLineBrokeCleanly be?
// rniwa says previousLineBrokeCleanly is just a WinIE hack and could always be false here?
- isolatedResolver.createBidiRunsForLine(endOfLine, NoVisualOverride, previousLineBrokeCleanly);
+ isolatedResolver.createBidiRunsForLine(endOfRuns, NoVisualOverride, previousLineBrokeCleanly);
// Note that we do not delete the runs from the resolver.
// We're not guaranteed to get any BidiRuns in the previous step. If we don't, we allow the placeholder
// itself to be turned into an InlineBox. We can't remove it here without potentially losing track of
@@ -1158,12 +1355,48 @@ static inline void constructBidiRuns(InlineBidiResolver& topResolver, BidiRunLis
// If we encountered any nested isolate runs, just move them
// to the top resolver's list for later processing.
if (!isolatedResolver.isolatedRuns().isEmpty()) {
- topResolver.isolatedRuns().append(isolatedResolver.isolatedRuns());
+ topResolver.isolatedRuns().appendVector(isolatedResolver.isolatedRuns());
isolatedResolver.isolatedRuns().clear();
}
}
}
+static inline void constructBidiRunsForLine(const RenderBlock* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
+{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(block);
+ constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
+#else
+ ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo();
+ if (!shapeInsideInfo || !shapeInsideInfo->hasSegments()) {
+ constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
+ return;
+ }
+
+ const SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges();
+ ASSERT(segmentRanges.size());
+
+ for (size_t i = 0; i < segmentRanges.size(); i++) {
+ LineSegmentIterator iterator = segmentRanges[i].start;
+ InlineIterator segmentStart(iterator.root, iterator.object, iterator.offset);
+ iterator = segmentRanges[i].end;
+ InlineIterator segmentEnd(iterator.root, iterator.object, iterator.offset);
+ if (i) {
+ ASSERT(segmentStart.m_obj);
+ BidiRun* segmentMarker = createRun(segmentStart.m_pos, segmentStart.m_pos, segmentStart.m_obj, topResolver);
+ segmentMarker->m_startsSegment = true;
+ bidiRuns.addRun(segmentMarker);
+ // Do not collapse midpoints between segments
+ topResolver.midpointState().betweenMidpoints = false;
+ }
+ if (segmentStart == segmentEnd)
+ continue;
+ topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart));
+ constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly);
+ }
+#endif
+}
+
// This function constructs line boxes for all of the text runs in the resolver and computes their position.
RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
{
@@ -1221,7 +1454,7 @@ RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bi
// during an entire linebox tree layout pass (aka layoutInlineChildren).
class LineLayoutState {
public:
- LineLayoutState(bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
+ LineLayoutState(bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread)
: m_lastFloat(0)
, m_endLine(0)
, m_floatIndex(0)
@@ -1231,7 +1464,9 @@ public:
, m_isFullLayout(fullLayout)
, m_repaintLogicalTop(repaintLogicalTop)
, m_repaintLogicalBottom(repaintLogicalBottom)
+ , m_adjustedLogicalLineTop(0)
, m_usesRepaintBounds(false)
+ , m_flowThread(flowThread)
{ }
void markForFullLayout() { m_isFullLayout = true; }
@@ -1275,6 +1510,12 @@ public:
unsigned floatIndex() const { return m_floatIndex; }
void setFloatIndex(unsigned floatIndex) { m_floatIndex = floatIndex; }
+ LayoutUnit adjustedLogicalLineTop() const { return m_adjustedLogicalLineTop; }
+ void setAdjustedLogicalLineTop(LayoutUnit value) { m_adjustedLogicalLineTop = value; }
+
+ RenderFlowThread* flowThread() const { return m_flowThread; }
+ void setFlowThread(RenderFlowThread* thread) { m_flowThread = thread; }
+
private:
Vector<RenderBlock::FloatWithRect> m_floats;
RenderBlock::FloatingObject* m_lastFloat;
@@ -1291,7 +1532,11 @@ private:
LayoutUnit& m_repaintLogicalTop;
LayoutUnit& m_repaintLogicalBottom;
+ LayoutUnit m_adjustedLogicalLineTop;
+
bool m_usesRepaintBounds;
+
+ RenderFlowThread* m_flowThread;
};
static void deleteLineRange(LineLayoutState& layoutState, RenderArena* arena, RootInlineBox* startLine, RootInlineBox* stopLine = 0)
@@ -1334,7 +1579,7 @@ void RenderBlock::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInli
}
}
- if (m_floatingObjects && !m_floatingObjects->set().isEmpty())
+ if (containsFloats())
layoutState.setLastFloat(m_floatingObjects->set().last());
// We also find the first clean line and extract these lines. We will add them back
@@ -1381,6 +1626,167 @@ RenderBlock::RenderTextInfo::~RenderTextInfo()
{
}
+// Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
+inline const InlineIterator& RenderBlock::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd)
+{
+ removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
+ setLogicalHeight(newLogicalHeight);
+ resolver.setPositionIgnoringNestedIsolates(oldEnd);
+ return oldEnd;
+}
+
+#if ENABLE(CSS_SHAPES)
+static inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
+{
+ for (size_t i = 0; i < wordMeasurements.size(); ++i) {
+ if (wordMeasurements[i].width > 0)
+ return wordMeasurements[i].width;
+ }
+ return 0;
+}
+
+static inline LayoutUnit adjustLogicalLineTop(ShapeInsideInfo* shapeInsideInfo, InlineIterator start, InlineIterator end, const WordMeasurements& wordMeasurements)
+{
+ if (!shapeInsideInfo || end != start)
+ return 0;
+
+ float minWidth = firstPositiveWidth(wordMeasurements);
+ ASSERT(minWidth || wordMeasurements.isEmpty());
+ if (minWidth > 0 && shapeInsideInfo->adjustLogicalLineTop(minWidth))
+ return shapeInsideInfo->logicalLineTop();
+
+ return shapeInsideInfo->shapeLogicalBottom();
+}
+
+static inline void pushShapeContentOverflowBelowTheContentBox(RenderBlock* block, ShapeInsideInfo* shapeInsideInfo, LayoutUnit lineTop, LayoutUnit lineHeight)
+{
+ ASSERT(shapeInsideInfo);
+
+ LayoutUnit logicalLineBottom = lineTop + lineHeight;
+ LayoutUnit shapeLogicalBottom = shapeInsideInfo->shapeLogicalBottom();
+ LayoutUnit shapeContainingBlockHeight = shapeInsideInfo->shapeContainingBlockHeight();
+
+ bool isOverflowPositionedAlready = (shapeContainingBlockHeight - shapeInsideInfo->owner()->borderAndPaddingAfter() + lineHeight) <= lineTop;
+
+ // If the last line overlaps with the shape, we don't need the segments anymore
+ if (lineTop < shapeLogicalBottom && shapeLogicalBottom < logicalLineBottom)
+ shapeInsideInfo->clearSegments();
+
+ if (logicalLineBottom <= shapeLogicalBottom || !shapeContainingBlockHeight || isOverflowPositionedAlready)
+ return;
+
+ LayoutUnit newLogicalHeight = block->logicalHeight() + (shapeContainingBlockHeight - (lineTop + shapeInsideInfo->owner()->borderAndPaddingAfter()));
+ block->setLogicalHeight(newLogicalHeight);
+}
+
+void RenderBlock::updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*& shapeInsideInfo, LayoutUnit& absoluteLogicalTop, LineLayoutState& layoutState)
+{
+ if (layoutState.flowThread())
+ return updateShapeAndSegmentsForCurrentLineInFlowThread(shapeInsideInfo, layoutState);
+
+ if (!shapeInsideInfo)
+ return;
+
+ LayoutUnit lineTop = logicalHeight() + absoluteLogicalTop;
+ LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+
+ // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which case these segments may be incorrect.
+ shapeInsideInfo->computeSegmentsForLine(lineTop, lineHeight);
+
+ pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
+}
+
+void RenderBlock::updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*& shapeInsideInfo, LineLayoutState& layoutState)
+{
+ ASSERT(layoutState.flowThread());
+
+ LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+
+ RenderRegion* currentRegion = regionAtBlockOffset(logicalHeight());
+ if (!currentRegion)
+ return;
+
+ shapeInsideInfo = currentRegion->shapeInsideInfo();
+
+ LayoutUnit logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage();
+ LayoutUnit logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight;
+ LayoutUnit logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent();
+ LayoutUnit logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter();
+
+ // We only want to deal regions with shapes, so we look up for the next region whether it has a shape
+ if (!shapeInsideInfo && !currentRegion->isLastRegion()) {
+ LayoutUnit deltaToNextRegion = logicalHeight() + logicalRegionBottomInFlowThread - logicalLineTopInFlowThread;
+ RenderRegion* lookupForNextRegion = regionAtBlockOffset(logicalHeight() + deltaToNextRegion);
+ if (!lookupForNextRegion->shapeInsideInfo())
+ return;
+ }
+
+ LayoutUnit shapeBottomInFlowThread = LayoutUnit::max();
+ if (shapeInsideInfo)
+ shapeBottomInFlowThread = shapeInsideInfo->shapeLogicalBottom() + currentRegion->logicalTopForFlowThreadContent();
+
+ // If the line is between two shapes/regions we position the line to the top of the next shape/region
+ RenderRegion* nextRegion = regionAtBlockOffset(logicalHeight() + lineHeight);
+ if ((currentRegion != nextRegion && (logicalLineBottomInFlowThread > logicalRegionBottomInFlowThread)) || (!currentRegion->isLastRegion() && shapeBottomInFlowThread < logicalLineBottomInFlowThread)) {
+ LayoutUnit deltaToNextRegion = logicalRegionBottomInFlowThread - logicalLineTopInFlowThread;
+ nextRegion = regionAtBlockOffset(logicalHeight() + deltaToNextRegion);
+
+ ASSERT(currentRegion != nextRegion);
+
+ shapeInsideInfo = nextRegion->shapeInsideInfo();
+ setLogicalHeight(logicalHeight() + deltaToNextRegion);
+
+ currentRegion = nextRegion;
+
+ logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage();
+ logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight;
+ logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent();
+ logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter();
+ }
+
+ if (!shapeInsideInfo)
+ return;
+
+ // We position the first line to the top of the shape in the region or to the previously adjusted position in the shape
+ if (logicalLineBottomInFlowThread <= (logicalRegionTopInFlowThread + lineHeight) || (logicalLineTopInFlowThread - logicalRegionTopInFlowThread) < (layoutState.adjustedLogicalLineTop() - currentRegion->borderAndPaddingBefore())) {
+ LayoutUnit shapeTopOffset = layoutState.adjustedLogicalLineTop();
+ if (!shapeTopOffset)
+ shapeTopOffset = shapeInsideInfo->shapeLogicalTop();
+
+ LayoutUnit shapePositionInFlowThread = currentRegion->logicalTopForFlowThreadContent() + shapeTopOffset;
+ LayoutUnit shapeTopLineTopDelta = shapePositionInFlowThread - logicalLineTopInFlowThread - currentRegion->borderAndPaddingBefore();
+
+ setLogicalHeight(logicalHeight() + shapeTopLineTopDelta);
+ logicalLineTopInFlowThread += shapeTopLineTopDelta;
+ layoutState.setAdjustedLogicalLineTop(0);
+ }
+
+ LayoutUnit lineTop = logicalLineTopInFlowThread - currentRegion->logicalTopForFlowThreadContent() + currentRegion->borderAndPaddingBefore();
+ shapeInsideInfo->computeSegmentsForLine(lineTop, lineHeight);
+
+ if (currentRegion->isLastRegion())
+ pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
+}
+
+bool RenderBlock::adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo* shapeInsideInfo, LayoutUnit absoluteLogicalTop, LineLayoutState& layoutState, InlineBidiResolver& resolver, FloatingObject* lastFloatFromPreviousLine, InlineIterator& end, WordMeasurements& wordMeasurements)
+{
+ LayoutUnit adjustedLogicalLineTop = adjustLogicalLineTop(shapeInsideInfo, resolver.position(), end, wordMeasurements);
+ if (!adjustedLogicalLineTop)
+ return false;
+
+ LayoutUnit newLogicalHeight = adjustedLogicalLineTop - absoluteLogicalTop;
+
+ if (layoutState.flowThread()) {
+ layoutState.setAdjustedLogicalLineTop(adjustedLogicalLineTop);
+ newLogicalHeight = logicalHeight();
+ }
+
+
+ end = restartLayoutRunsAndFloatsInRange(logicalHeight(), newLogicalHeight, lastFloatFromPreviousLine, resolver, end);
+ return true;
+}
+#endif
+
void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines)
{
RenderStyle* styleToUse = style();
@@ -1393,18 +1799,23 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
LineBreaker lineBreaker(this);
-#if ENABLE(CSS_EXCLUSIONS)
+#if ENABLE(CSS_SHAPES)
LayoutUnit absoluteLogicalTop;
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo(this);
- if (exclusionShapeInsideInfo) {
- if (exclusionShapeInsideInfo != this->exclusionShapeInsideInfo()) {
+ ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
+ if (shapeInsideInfo) {
+ ASSERT(shapeInsideInfo->owner() == this || allowsShapeInsideInfoSharing());
+ if (shapeInsideInfo != this->shapeInsideInfo()) {
// FIXME Bug 100284: If subsequent LayoutStates are pushed, we will have to add
// their offsets from the original shape-inside container.
absoluteLogicalTop = logicalTop();
}
// Begin layout at the logical top of our shape inside.
- if (logicalHeight() + absoluteLogicalTop < exclusionShapeInsideInfo->shapeLogicalTop())
- setLogicalHeight(exclusionShapeInsideInfo->shapeLogicalTop() - absoluteLogicalTop);
+ if (logicalHeight() + absoluteLogicalTop < shapeInsideInfo->shapeLogicalTop()) {
+ LayoutUnit logicalHeight = shapeInsideInfo->shapeLogicalTop() - absoluteLogicalTop;
+ if (layoutState.flowThread())
+ logicalHeight -= shapeInsideInfo->owner()->borderAndPaddingBefore();
+ setLogicalHeight(logicalHeight);
+ }
}
#endif
@@ -1425,17 +1836,14 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
const InlineIterator oldEnd = end;
bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
- FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
-#if ENABLE(CSS_EXCLUSIONS)
- // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which
- // case these segments may be incorrect.
- if (exclusionShapeInsideInfo) {
- LayoutUnit lineTop = logicalHeight() + absoluteLogicalTop;
- exclusionShapeInsideInfo->computeSegmentsForLine(lineTop, lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
- }
+ FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last() : 0;
+
+#if ENABLE(CSS_SHAPES)
+ updateShapeAndSegmentsForCurrentLine(shapeInsideInfo, absoluteLogicalTop, layoutState);
#endif
WordMeasurements wordMeasurements;
end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
+ renderTextInfo.m_lineBreakIterator.resetPriorContext();
if (resolver.position().atEnd()) {
// FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
// Once BidiRunList is separated from BidiResolver this will not be needed.
@@ -1445,6 +1853,11 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
break;
}
+
+#if ENABLE(CSS_SHAPES)
+ if (adjustLogicalLineTopAndLogicalHeightIfNeeded(shapeInsideInfo, absoluteLogicalTop, layoutState, resolver, lastFloatFromPreviousLine, end, wordMeasurements))
+ continue;
+#endif
ASSERT(end != resolver.position());
// This is a short-cut for empty lines.
@@ -1461,7 +1874,7 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
}
// FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
BidiRunList<BidiRun>& bidiRuns = resolver.runs();
- constructBidiRuns(resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
+ constructBidiRunsForLine(this, resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
ASSERT(resolver.position() == end);
BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0;
@@ -1489,7 +1902,7 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
if (paginated) {
LayoutUnit adjustment = 0;
- adjustLinePositionForPagination(lineBox, adjustment);
+ adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread());
if (adjustment) {
LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
lineBox->adjustBlockDirectionPosition(adjustment);
@@ -1499,24 +1912,23 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) {
// We have to delete this line, remove all floats that got added, and let line layout re-run.
lineBox->deleteLine(renderArena());
- removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
- setLogicalHeight(oldLogicalHeight + adjustment);
- resolver.setPositionIgnoringNestedIsolates(oldEnd);
- end = oldEnd;
+ end = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, oldEnd);
continue;
}
setLogicalHeight(lineBox->lineBottomWithLeading());
}
- if (inRenderFlowThread())
+ if (layoutState.flowThread())
lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading()));
}
}
+ }
- for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
- setStaticPositions(this, lineBreaker.positionedObjects()[i]);
+ for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
+ setStaticPositions(this, lineBreaker.positionedObjects()[i]);
+ if (!layoutState.lineInfo().isEmpty()) {
layoutState.lineInfo().setFirstLine(false);
newLine(lineBreaker.clear());
}
@@ -1546,6 +1958,63 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin
lineMidpointState.reset();
resolver.setPosition(end, numberOfIsolateAncestors(end));
}
+
+ if (paginated && !style()->hasAutoWidows()) {
+ // Check the line boxes to make sure we didn't create unacceptable widows.
+ // However, we'll prioritize orphans - so nothing we do here should create
+ // a new orphan.
+
+ RootInlineBox* lineBox = lastRootBox();
+
+ // Count from the end of the block backwards, to see how many hanging
+ // lines we have.
+ RootInlineBox* firstLineInBlock = firstRootBox();
+ int numLinesHanging = 1;
+ while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
+ ++numLinesHanging;
+ lineBox = lineBox->prevRootBox();
+ }
+
+ // If there were no breaks in the block, we didn't create any widows.
+ if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock)
+ return;
+
+ if (numLinesHanging < style()->widows()) {
+ // We have detected a widow. Now we need to work out how many
+ // lines there are on the previous page, and how many we need
+ // to steal.
+ int numLinesNeeded = style()->widows() - numLinesHanging;
+ RootInlineBox* currentFirstLineOfNewPage = lineBox;
+
+ // Count the number of lines in the previous page.
+ lineBox = lineBox->prevRootBox();
+ int numLinesInPreviousPage = 1;
+ while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
+ ++numLinesInPreviousPage;
+ lineBox = lineBox->prevRootBox();
+ }
+
+ // If there was an explicit value for orphans, respect that. If not, we still
+ // shouldn't create a situation where we make an orphan bigger than the initial value.
+ // This means that setting widows implies we also care about orphans, but given
+ // the specification says the initial orphan value is non-zero, this is ok. The
+ // author is always free to set orphans explicitly as well.
+ int orphans = style()->hasAutoOrphans() ? style()->initialOrphans() : style()->orphans();
+ int numLinesAvailable = numLinesInPreviousPage - orphans;
+ if (numLinesAvailable <= 0)
+ return;
+
+ int numLinesToTake = min(numLinesAvailable, numLinesNeeded);
+ // Wind back from our first widowed line.
+ lineBox = currentFirstLineOfNewPage;
+ for (int i = 0; i < numLinesToTake; ++i)
+ lineBox = lineBox->prevRootBox();
+
+ // We now want to break at this line. Remember for next layout and trigger relayout.
+ setBreakAtLineToAvoidWidow(lineBox);
+ markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox);
+ }
+ }
}
void RenderBlock::linkToEndLineIfNeeded(LineLayoutState& layoutState)
@@ -1559,13 +2028,13 @@ void RenderBlock::linkToEndLineIfNeeded(LineLayoutState& layoutState)
line->attachLine();
if (paginated) {
delta -= line->paginationStrut();
- adjustLinePositionForPagination(line, delta);
+ adjustLinePositionForPagination(line, delta, layoutState.flowThread());
}
if (delta) {
layoutState.updateRepaintRangeFromBox(line, delta);
line->adjustBlockDirectionPosition(delta);
}
- if (inRenderFlowThread())
+ if (layoutState.flowThread())
line->setContainingRegion(regionAtBlockOffset(line->lineTopWithLeading()));
if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
Vector<RenderBox*>::iterator end = cleanLineFloats->end();
@@ -1604,7 +2073,7 @@ void RenderBlock::linkToEndLineIfNeeded(LineLayoutState& layoutState)
LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight);
LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight);
trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom());
- if (inRenderFlowThread())
+ if (layoutState.flowThread())
trailingFloatsLineBox->setContainingRegion(regionAtBlockOffset(trailingFloatsLineBox->lineTopWithLeading()));
}
@@ -1640,28 +2109,31 @@ void RenderBlock::repaintDirtyFloats(Vector<FloatWithRect>& floats)
void RenderBlock::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
{
- m_overflow.clear();
-
- setLogicalHeight(borderBefore() + paddingBefore());
+ setLogicalHeight(borderAndPaddingBefore());
// Lay out our hypothetical grid line as though it occurs at the top of the block.
if (view()->layoutState() && view()->layoutState()->lineGrid() == this)
layoutLineGridBox();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions();
+
// Figure out if we should clear out our line boxes.
// FIXME: Handle resize eventually!
- bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren;
- LineLayoutState layoutState(isFullLayout, repaintLogicalTop, repaintLogicalBottom);
+ bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination;
+ LineLayoutState layoutState(isFullLayout, repaintLogicalTop, repaintLogicalBottom, flowThread);
if (isFullLayout)
lineBoxes()->deleteLineBoxes(renderArena());
- // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't
- // clip.
+ // Text truncation kicks in in two cases:
+ // 1) If your overflow isn't visible and your text-overflow-mode isn't clip.
+ // 2) If you're an anonymous block with a block parent that satisfies #1.
// FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
- // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
- // anyway, so we won't worry about following the draft here.
- bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
+ // difficult to figure out in general (especially in the middle of doing layout), so we only handle the
+ // simple case of an anonymous block truncating when it's parent is clipped.
+ bool hasTextOverflow = (style()->textOverflow() && hasOverflowClip())
+ || (isAnonymousBlock() && parent() && parent()->isRenderBlock() && parent()->style()->textOverflow() && parent()->hasOverflowClip());
// Walk all the lines and delete our ellipsis line boxes if they exist.
if (hasTextOverflow)
@@ -1728,7 +2200,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repain
}
// Now add in the bottom border/padding.
- setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
+ setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAndPaddingAfter() + scrollbarLogicalHeight());
if (!firstLineBox() && hasLineIfEmpty())
setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
@@ -1750,7 +2222,7 @@ void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRe
RenderBox* floatingBox = *it;
floatingBox->layoutIfNeeded();
LayoutSize newSize(floatingBox->width() + floatingBox->marginWidth(), floatingBox->height() + floatingBox->marginHeight());
- ASSERT(floatIndex < floats.size());
+ ASSERT_WITH_SECURITY_IMPLICATION(floatIndex < floats.size());
if (floats[floatIndex].object != floatingBox) {
encounteredNewFloat = true;
return;
@@ -1784,12 +2256,12 @@ RootInlineBox* RenderBlock::determineStartPosition(LineLayoutState& layoutState,
size_t floatIndex = 0;
for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
if (paginated) {
- if (lineWidthForPaginatedLineChanged(curr)) {
+ if (lineWidthForPaginatedLineChanged(curr, 0, layoutState.flowThread())) {
curr->markDirty();
break;
}
paginationDelta -= curr->paginationStrut();
- adjustLinePositionForPagination(curr, paginationDelta);
+ adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread());
if (paginationDelta) {
if (containsFloats() || !layoutState.floats().isEmpty()) {
// FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
@@ -1800,7 +2272,7 @@ RootInlineBox* RenderBlock::determineStartPosition(LineLayoutState& layoutState,
layoutState.updateRepaintRangeFromBox(curr, paginationDelta);
curr->adjustBlockDirectionPosition(paginationDelta);
}
- if (inRenderFlowThread())
+ if (layoutState.flowThread())
curr->setContainingRegion(regionAtBlockOffset(curr->lineTopWithLeading()));
}
@@ -1819,16 +2291,9 @@ RootInlineBox* RenderBlock::determineStartPosition(LineLayoutState& layoutState,
}
if (layoutState.isFullLayout()) {
- // FIXME: This should just call deleteLineBoxTree, but that causes
- // crashes for fast/repaint tests.
- RenderArena* arena = renderArena();
- curr = firstRootBox();
- while (curr) {
- // Note: This uses nextRootBox() insted of nextLineBox() like deleteLineBoxTree does.
- RootInlineBox* next = curr->nextRootBox();
- curr->deleteLine(arena);
- curr = next;
- }
+ m_lineBoxes.deleteLineBoxTree(renderArena());
+ curr = 0;
+
ASSERT(!firstLineBox() && !lastLineBox());
} else {
if (curr) {
@@ -1936,7 +2401,7 @@ bool RenderBlock::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState
LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
- if (paginated && inRenderFlowThread()) {
+ if (paginated && layoutState.flowThread()) {
// Check all lines from here to the end, and see if the hypothetical new position for the lines will result
// in a different available line width.
for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) {
@@ -1945,10 +2410,10 @@ bool RenderBlock::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState
// strut yet.
LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
lineDelta -= oldPaginationStrut;
- adjustLinePositionForPagination(lineBox, lineDelta);
+ adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread());
lineBox->setPaginationStrut(oldPaginationStrut);
}
- if (lineWidthForPaginatedLineChanged(lineBox, lineDelta))
+ if (lineWidthForPaginatedLineChanged(lineBox, lineDelta, layoutState.flowThread()))
return false;
}
}
@@ -2050,12 +2515,24 @@ static bool requiresLineBoxForContent(RenderInline* flow, const LineInfo& lineIn
return false;
}
-static bool alwaysRequiresLineBox(RenderInline* flow)
+static bool hasInlineDirectionBordersPaddingOrMargin(RenderInline* flow)
+{
+ // Where an empty inline is split across anonymous blocks we should only give lineboxes to the 'sides' of the
+ // inline that have borders, padding or margin.
+ bool shouldApplyStartBorderPaddingOrMargin = !flow->parent()->isAnonymousBlock() || !flow->isInlineElementContinuation();
+ if (shouldApplyStartBorderPaddingOrMargin && (flow->borderStart() || flow->marginStart() || flow->paddingStart()))
+ return true;
+
+ bool shouldApplyEndBorderPaddingOrMargin = !flow->parent()->isAnonymousBlock() || flow->isInlineElementContinuation() || !flow->inlineElementContinuation();
+ return shouldApplyEndBorderPaddingOrMargin && (flow->borderEnd() || flow->marginEnd() || flow->paddingEnd());
+}
+
+static bool alwaysRequiresLineBox(RenderObject* flow)
{
// FIXME: Right now, we only allow line boxes for inlines that are truly empty.
// We need to fix this, though, because at the very least, inlines containing only
// ignorable whitespace should should also have line boxes.
- return !flow->firstChild() && flow->hasInlineDirectionBordersPaddingOrMargin();
+ return isEmptyInline(flow) && hasInlineDirectionBordersPaddingOrMargin(toRenderInline(flow));
}
static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
@@ -2063,15 +2540,15 @@ static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo =
if (it.m_obj->isFloatingOrOutOfFlowPositioned())
return false;
- if (it.m_obj->isRenderInline() && !alwaysRequiresLineBox(toRenderInline(it.m_obj)) && !requiresLineBoxForContent(toRenderInline(it.m_obj), lineInfo))
+ if (it.m_obj->isRenderInline() && !alwaysRequiresLineBox(it.m_obj) && !requiresLineBoxForContent(toRenderInline(it.m_obj), lineInfo))
return false;
if (!shouldCollapseWhiteSpace(it.m_obj->style(), lineInfo, whitespacePosition) || it.m_obj->isBR())
return true;
UChar current = it.current();
- return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline())
- && !skipNonBreakingSpace(it, lineInfo);
+ bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) && !skipNonBreakingSpace(it, lineInfo);
+ return notJustWhitespace || isEmptyInline(it.m_obj);
}
bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
@@ -2115,9 +2592,15 @@ void RenderBlock::LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolve
resolver.runs().addRun(createRun(0, 1, object, resolver));
lineInfo.incrementRunsFromLeadingWhitespace();
}
- } else if (object->isFloating())
+ } else if (object->isFloating()) {
+ // The top margin edge of a self-collapsing block that clears a float intrudes up into it by the height of the margin,
+ // so in order to place this first child float at the top content edge of the self-collapsing block add the margin back in before placement.
+ LayoutUnit marginOffset = (!object->previousSibling() && m_block->isSelfCollapsingBlock() && m_block->style()->clear() && m_block->getClearDelta(m_block, LayoutUnit())) ? m_block->collapsedMarginBeforeForChild(m_block) : LayoutUnit();
+ LayoutUnit oldLogicalHeight = m_block->logicalHeight();
+ m_block->setLogicalHeight(oldLogicalHeight + marginOffset);
m_block->positionNewFloatOnLine(m_block->insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width);
- else if (object->isText() && object->style()->hasTextCombine() && object->isCombineText() && !toRenderCombineText(object)->isCombined()) {
+ m_block->setLogicalHeight(oldLogicalHeight);
+ } else if (object->isText() && object->style()->hasTextCombine() && object->isCombineText() && !toRenderCombineText(object)->isCombined()) {
toRenderCombineText(object)->combineText();
if (toRenderCombineText(object)->isCombined())
continue;
@@ -2132,11 +2615,14 @@ void RenderBlock::LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolve
static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState)
{
RenderObject* next = bidiNextSkippingEmptyInlines(block, o);
+ while (next && next->isFloatingOrOutOfFlowPositioned())
+ next = bidiNextSkippingEmptyInlines(block, next);
+
if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) {
RenderText* nextText = toRenderText(next);
UChar nextChar = nextText->characterAt(0);
if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
- addMidpoint(lineMidpointState, InlineIterator(0, o, 0));
+ startIgnoringSpaces(lineMidpointState, InlineIterator(0, o, 0));
return true;
}
}
@@ -2144,14 +2630,14 @@ static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObjec
return false;
}
-static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0, TextLayout* layout = 0)
+static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>& fallbackFonts, TextLayout* layout = 0)
{
GlyphOverflow glyphOverflow;
if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
- return text->width(from, len, font, xPos, fallbackFonts, &glyphOverflow);
+ return text->width(from, len, font, xPos, &fallbackFonts, &glyphOverflow);
if (layout)
- return Font::width(*layout, from, len, fallbackFonts);
+ return Font::width(*layout, from, len, &fallbackFonts);
TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, text->style());
run.setCharactersLength(text->textLength() - from);
@@ -2160,7 +2646,7 @@ static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned l
run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
run.setXPos(xPos);
- return font.width(run, fallbackFonts, &glyphOverflow);
+ return font.width(run, &fallbackFonts, &glyphOverflow);
}
static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, unsigned consecutiveHyphenatedLines, int consecutiveHyphenatedLinesLimit, int minimumPrefixLimit, int minimumSuffixLimit, unsigned lastSpace, unsigned pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)
@@ -2219,7 +2705,8 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
ASSERT(pos - lastSpace - prefixLength >= minimumSuffixLength);
#if !ASSERT_DISABLED
- float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
+ HashSet<const SimpleFontData*> fallbackFonts;
+ float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace, fallbackFonts) + lastSpaceWordSpacing;
ASSERT(xPos + prefixWidth <= availableWidth);
#else
UNUSED_PARAM(isFixedPitch);
@@ -2234,7 +2721,7 @@ public:
TrailingObjects();
void setTrailingWhitespace(RenderText*);
void clear();
- void appendBoxIfNeeded(RenderBox*);
+ void appendBoxIfNeeded(RenderBoxModelObject*);
enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace };
@@ -2242,7 +2729,7 @@ public:
private:
RenderText* m_whitespace;
- Vector<RenderBox*, 4> m_boxes;
+ Vector<RenderBoxModelObject*, 4> m_boxes;
};
TrailingObjects::TrailingObjects()
@@ -2259,10 +2746,10 @@ inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)
inline void TrailingObjects::clear()
{
m_whitespace = 0;
- m_boxes.clear();
+ m_boxes.shrink(0); // Use shrink(0) instead of clear() to retain our capacity.
}
-inline void TrailingObjects::appendBoxIfNeeded(RenderBox* box)
+inline void TrailingObjects::appendBoxIfNeeded(RenderBoxModelObject* box)
{
if (m_whitespace)
m_boxes.append(box);
@@ -2289,9 +2776,7 @@ void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMid
for (size_t i = 0; i < m_boxes.size(); ++i) {
if (currentMidpoint >= lineMidpointState.numMidpoints) {
// We don't have a midpoint for this box yet.
- InlineIterator ignoreStart(0, m_boxes[i], 0);
- addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring.
- addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
+ ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
} else {
ASSERT(lineMidpointState.midpoints[currentMidpoint].m_obj == m_boxes[i]);
ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].m_obj == m_boxes[i]);
@@ -2305,11 +2790,9 @@ void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMid
unsigned length = m_whitespace->textLength();
unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
InlineIterator endMid(0, m_whitespace, pos);
- addMidpoint(lineMidpointState, endMid);
+ startIgnoringSpaces(lineMidpointState, endMid);
for (size_t i = 0; i < m_boxes.size(); ++i) {
- InlineIterator ignoreStart(0, m_boxes[i], 0);
- addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
- addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
+ ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
}
}
}
@@ -2323,6 +2806,115 @@ void RenderBlock::LineBreaker::reset()
InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
{
+#if !ENABLE(CSS_SHAPES)
+ return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
+#else
+ ShapeInsideInfo* shapeInsideInfo = m_block->layoutShapeInsideInfo();
+
+ if (!shapeInsideInfo || !shapeInsideInfo->lineOverlapsShapeBounds())
+ return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
+
+ InlineIterator end = resolver.position();
+ InlineIterator oldEnd = end;
+
+ if (!shapeInsideInfo->hasSegments()) {
+ end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
+ resolver.setPositionIgnoringNestedIsolates(oldEnd);
+ return oldEnd;
+ }
+
+ const SegmentList& segments = shapeInsideInfo->segments();
+ SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges();
+
+ for (unsigned i = 0; i < segments.size() && !end.atEnd(); i++) {
+ InlineIterator segmentStart = resolver.position();
+ end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
+
+ ASSERT(segmentRanges.size() == i);
+ if (resolver.position().atEnd()) {
+ segmentRanges.append(LineSegmentRange(segmentStart, end));
+ break;
+ }
+ if (resolver.position() == end) {
+ // Nothing fit this segment
+ end = segmentStart;
+ segmentRanges.append(LineSegmentRange(segmentStart, segmentStart));
+ resolver.setPositionIgnoringNestedIsolates(segmentStart);
+ } else {
+ // Note that resolver.position is already skipping some of the white space at the beginning of the line,
+ // so that's why segmentStart might be different than resolver.position().
+ LineSegmentRange range(resolver.position(), end);
+ segmentRanges.append(range);
+ resolver.setPosition(end, numberOfIsolateAncestors(end));
+
+ if (lineInfo.previousLineBrokeCleanly()) {
+ // If we hit a new line break, just stop adding anything to this line.
+ break;
+ }
+ }
+ }
+ resolver.setPositionIgnoringNestedIsolates(oldEnd);
+ return end;
+#endif
+}
+
+static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer)
+{
+ return iter.m_obj == renderer && iter.m_pos >= renderer->textLength();
+}
+
+static inline void commitLineBreakAtCurrentWidth(LineWidth& width, InlineIterator& lBreak, RenderObject* object, unsigned offset = 0, int nextBreak = -1)
+{
+ width.commit();
+ lBreak.moveTo(object, offset, nextBreak);
+}
+
+static bool textBeginsWithBreakablePosition(RenderObject* next)
+{
+ ASSERT(next->isText());
+ RenderText* nextText = toRenderText(next);
+ if (nextText->isWordBreak())
+ return true;
+ if (!nextText->textLength())
+ return false;
+ UChar c = nextText->characterAt(0);
+ return c == ' ' || c == '\t' || (c == '\n' && !nextText->preservesNewline());
+}
+
+static bool canBreakAtThisPosition(bool autoWrap, LineWidth& width, InlineIterator& lBreak, RenderObject* next, const InlineIterator& current, EWhiteSpace currWS, bool currentCharacterIsSpace, bool autoWrapWasEverTrueOnLine)
+{
+ // If we are no-wrap and have found a line-breaking opportunity already then we should take it.
+ if (width.committedWidth() && !width.fitsOnLine(currentCharacterIsSpace) && currWS == NOWRAP)
+ return true;
+
+ // Avoid breaking before empty inlines.
+ if (next && isEmptyInline(next))
+ return false;
+
+ // Return early if we autowrap and the current character is a space as we will always want to break at such a position.
+ if (autoWrap && currentCharacterIsSpace)
+ return true;
+
+ bool nextIsText = (next && (current.m_obj->isText() || isEmptyInline(current.m_obj)) && next->isText() && !next->isBR() && (autoWrap || next->style()->autoWrap()));
+ if (!nextIsText)
+ return autoWrap;
+
+ bool canBreakHere = !currentCharacterIsSpace && textBeginsWithBreakablePosition(next);
+
+ // See if attempting to fit below floats creates more available width on the line.
+ if (!width.fitsOnLine() && !width.committedWidth())
+ width.fitBelowFloats();
+
+ bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrueOnLine;
+
+ if (canPlaceOnLine && canBreakHere)
+ commitLineBreakAtCurrentWidth(width, lBreak, next);
+
+ return canBreakHere;
+}
+
+InlineIterator RenderBlock::LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
+{
reset();
ASSERT(resolver.position().root() == m_block);
@@ -2331,7 +2923,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
bool includeEndWidth = true;
LineMidpointState& lineMidpointState = resolver.midpointState();
- LineWidth width(m_block, lineInfo.isFirstLine());
+ LineWidth width(m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style()));
skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width);
@@ -2410,10 +3002,8 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// A <br> with clearance always needs a linebox in case the lines below it get dirtied later and
// need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a
// run for this object.
- if (ignoringSpaces && currentStyle->clear() != CNONE) {
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, 0)); // Stop ignoring spaces.
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, 0)); // Start ignoring again.
- }
+ if (ignoringSpaces && currentStyle->clear() != CNONE)
+ ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
if (!lineInfo.isEmpty())
m_clear = currentStyle->clear();
@@ -2437,22 +3027,22 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// If we're ignoring spaces, we have to stop and include this object and
// then start ignoring spaces again.
if (isInlineType || current.m_obj->container()->isRenderInline()) {
- if (ignoringSpaces) {
- ignoreStart.m_obj = current.m_obj;
- ignoreStart.m_pos = 0;
- addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
- addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
- }
+ if (ignoringSpaces)
+ ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
trailingObjects.appendBoxIfNeeded(box);
} else
m_positionedObjects.append(box);
+ width.addUncommittedWidth(inlineLogicalWidth(current.m_obj));
+ // Reset prior line break context characters.
+ renderTextInfo.m_lineBreakIterator.resetPriorContext();
} else if (current.m_obj->isFloating()) {
RenderBox* floatBox = toRenderBox(current.m_obj);
FloatingObject* f = m_block->insertFloatingObject(floatBox);
// check if it fits in the current line.
// If it does, position it now, otherwise, position
// it after moving to next line (in newLine() func)
- if (floatsFitOnLine && width.fitsOnLine(m_block->logicalWidthForFloat(f))) {
+ // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
+ if (floatsFitOnLine && width.fitsOnLineExcludingTrailingWhitespace(m_block->logicalWidthForFloat(f))) {
m_block->positionNewFloatOnLine(f, lastFloatFromPreviousLine, lineInfo, width);
if (lBreak.m_obj == current.m_obj) {
ASSERT(!lBreak.m_pos);
@@ -2460,9 +3050,11 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
}
} else
floatsFitOnLine = false;
+ // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
+ renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
} else if (current.m_obj->isRenderInline()) {
// Right now, we should only encounter empty inlines here.
- ASSERT(!current.m_obj->firstChild());
+ ASSERT(isEmptyInline(current.m_obj));
RenderInline* flowBox = toRenderInline(current.m_obj);
@@ -2470,7 +3062,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// to make sure that we stop to include this object and then start ignoring spaces again.
// If this object is at the start of the line, we need to behave like list markers and
// start ignoring spaces.
- bool requiresLineBox = alwaysRequiresLineBox(flowBox);
+ bool requiresLineBox = alwaysRequiresLineBox(current.m_obj);
if (requiresLineBox || requiresLineBoxForContent(flowBox, lineInfo)) {
// An empty inline that only has line-height, vertical-align or font-metrics will only get a
// line box to affect the height of the line if the rest of the line is not empty.
@@ -2478,8 +3070,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
lineInfo.setEmpty(false, m_block, &width);
if (ignoringSpaces) {
trailingObjects.clear();
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, 0)); // Stop ignoring spaces.
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, 0)); // Start ignoring again.
+ ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
} else if (blockStyle->collapseWhiteSpace() && resolver.position().m_obj == current.m_obj
&& shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) {
// Like with list markers, we start ignoring spaces to make sure that any
@@ -2487,21 +3078,24 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
currentCharacterIsSpace = true;
currentCharacterIsWS = true;
ignoringSpaces = true;
+ } else {
+ trailingObjects.appendBoxIfNeeded(flowBox);
}
}
- width.addUncommittedWidth(borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));
+ width.addUncommittedWidth(inlineLogicalWidth(current.m_obj) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));
} else if (current.m_obj->isReplaced()) {
RenderBox* replacedBox = toRenderBox(current.m_obj);
+ if (atStart)
+ width.updateAvailableWidth(replacedBox->logicalHeight());
+
// Break on replaced elements if either has normal white-space.
- if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!current.m_obj->isImage() || allowImagesToBreak)) {
- width.commit();
- lBreak.moveToStartOf(current.m_obj);
- }
+ if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!current.m_obj->isImage() || allowImagesToBreak))
+ commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj);
if (ignoringSpaces)
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, 0));
+ stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, 0));
lineInfo.setEmpty(false, m_block, &width);
ignoringSpaces = false;
@@ -2526,6 +3120,8 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
width.addUncommittedWidth(replacedLogicalWidth);
if (current.m_obj->isRubyRun())
width.applyOverhang(toRenderRubyRun(current.m_obj), last, next);
+ // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
+ renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
} else if (current.m_obj->isText()) {
if (!current.m_pos)
appliedStartWidth = false;
@@ -2536,8 +3132,21 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
bool isSVGText = t->isSVGInlineText();
#endif
- if (t->style()->hasTextCombine() && current.m_obj->isCombineText() && !toRenderCombineText(current.m_obj)->isCombined())
- toRenderCombineText(current.m_obj)->combineText();
+ // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces
+ // then we need to mark the start of the autowrap inline as a potential linebreak now.
+ if (autoWrap && !RenderStyle::autoWrap(lastWS) && ignoringSpaces)
+ commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj);
+
+ if (t->style()->hasTextCombine() && current.m_obj->isCombineText() && !toRenderCombineText(current.m_obj)->isCombined()) {
+ RenderCombineText* combineRenderer = toRenderCombineText(current.m_obj);
+ combineRenderer->combineText();
+ // The length of the renderer's text may have changed. Increment stale iterator positions
+ if (iteratorIsBeyondEndOfRenderCombineText(lBreak, combineRenderer)) {
+ ASSERT(iteratorIsBeyondEndOfRenderCombineText(resolver.position(), combineRenderer));
+ lBreak.increment();
+ resolver.increment();
+ }
+ }
RenderStyle* style = t->style(lineInfo.isFirstLine());
const Font& f = style->font();
@@ -2558,19 +3167,24 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
bool midWordBreak = false;
bool breakAll = currentStyle->wordBreak() == BreakAllWordBreak && autoWrap;
float hyphenWidth = 0;
+#if ENABLE(SVG)
+ if (isSVGText) {
+ breakWords = false;
+ breakAll = false;
+ }
+#endif
if (t->isWordBreak()) {
- width.commit();
- lBreak.moveToStartOf(current.m_obj);
+ commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj);
ASSERT(current.m_pos == t->textLength());
}
if (renderTextInfo.m_text != t) {
- t->updateTextIfNeeded();
+ updateCounterIfNeeded(t);
renderTextInfo.m_text = t;
renderTextInfo.m_font = &f;
renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
- renderTextInfo.m_lineBreakIterator.reset(t->text(), style->locale());
+ renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(t->text(), style->locale());
} else if (renderTextInfo.m_layout && renderTextInfo.m_font != &f) {
renderTextInfo.m_font = &f;
renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
@@ -2580,8 +3194,11 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
// words with their trailing space, then subtract its width.
- float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) && !textLayout ? f.width(constructTextRun(t, f, &space, 1, style)) + wordSpacing : 0;
+ HashSet<const SimpleFontData*> fallbackFonts;
+ float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) && !textLayout ? f.width(constructTextRun(t, f, &space, 1, style), &fallbackFonts) + wordSpacing : 0;
+ UChar lastCharacter = renderTextInfo.m_lineBreakIterator.lastCharacter();
+ UChar secondToLastCharacter = renderTextInfo.m_lineBreakIterator.secondToLastCharacter();
for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) {
bool previousCharacterIsSpace = currentCharacterIsSpace;
bool previousCharacterIsWS = currentCharacterIsWS;
@@ -2592,7 +3209,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
lineInfo.setEmpty(false, m_block, &width);
if (c == softHyphen && autoWrap && !hyphenWidth && style->hyphens() != HyphensNone) {
- hyphenWidth = measureHyphenWidth(t, f);
+ hyphenWidth = measureHyphenWidth(t, f, &fallbackFonts);
width.addUncommittedWidth(hyphenWidth);
}
@@ -2603,7 +3220,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
if ((breakAll || breakWords) && !midWordBreak) {
wrapW += charWidth;
bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL(t->characters()[current.m_pos + 1]);
- charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, 0, textLayout);
+ charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, fallbackFonts, textLayout);
midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth();
}
@@ -2613,18 +3230,18 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
if (betweenWords || midWordBreak) {
bool stoppedIgnoringSpaces = false;
if (ignoringSpaces) {
+ lastSpaceWordSpacing = 0;
if (!currentCharacterIsSpace) {
// Stop ignoring spaces and begin at this
// new point.
ignoringSpaces = false;
- lastSpaceWordSpacing = 0;
wordSpacingForWordMeasurement = 0;
lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
+ stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
stoppedIgnoringSpaces = true;
} else {
// Just keep ignoring these spaces.
- continue;
+ goto nextCharacter;
}
}
@@ -2635,15 +3252,23 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
wordMeasurement.endOffset = current.m_pos;
wordMeasurement.startOffset = lastSpace;
- float additionalTmpW;
+ float additionalTempWidth;
if (wordTrailingSpaceWidth && c == ' ')
- additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
+ additionalTempWidth = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
else
- additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
+ additionalTempWidth = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
+
+ if (wordMeasurement.fallbackFonts.isEmpty() && !fallbackFonts.isEmpty())
+ wordMeasurement.fallbackFonts.swap(fallbackFonts);
+ fallbackFonts.clear();
+
+ wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement;
+ additionalTempWidth += lastSpaceWordSpacing;
+ width.addUncommittedWidth(additionalTempWidth);
+
+ if (collapseWhiteSpace && previousCharacterIsSpace && currentCharacterIsSpace && additionalTempWidth)
+ width.setTrailingWhitespaceWidth(additionalTempWidth);
- wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement;
- additionalTmpW += lastSpaceWordSpacing;
- width.addUncommittedWidth(additionalTmpW);
if (!appliedStartWidth) {
width.addUncommittedWidth(inlineLogicalWidth(current.m_obj, true, false));
appliedStartWidth = true;
@@ -2659,13 +3284,13 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// as candidate width for this line.
bool lineWasTooWide = false;
if (width.fitsOnLine() && currentCharacterIsWS && currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
- float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
+ float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
// Check if line is too big even without the extra space
// at the end of the line. If it is not, do nothing.
// If the line needs the extra whitespace to be too long,
// then move the line break to the space and skip all
// additional whitespace.
- if (!width.fitsOnLine(charWidth)) {
+ if (!width.fitsOnLineIncludingExtraWidth(charWidth)) {
lineWasTooWide = true;
lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
skipTrailingWhitespace(lBreak, lineInfo);
@@ -2673,16 +3298,13 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
}
if (lineWasTooWide || !width.fitsOnLine()) {
if (canHyphenate && !width.fitsOnLine()) {
- tryHyphenating(t, f, style->locale(), consecutiveHyphenatedLines, blockStyle->hyphenationLimitLines(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTmpW, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
+ tryHyphenating(t, f, style->locale(), consecutiveHyphenatedLines, blockStyle->hyphenationLimitLines(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTempWidth, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
if (m_hyphenated)
goto end;
}
if (lBreak.atTextParagraphSeparator()) {
- if (!stoppedIgnoringSpaces && current.m_pos > 0) {
- // We need to stop right before the newline and then start up again.
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos - 1)); // Stop
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos)); // Start
- }
+ if (!stoppedIgnoringSpaces && current.m_pos > 0)
+ ensureCharacterGetsLineBox(lineMidpointState, current);
lBreak.increment();
lineInfo.setPreviousLineBrokeCleanly(true);
wordMeasurement.endOffset = lBreak.m_pos;
@@ -2695,10 +3317,12 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
wordMeasurement.width = charWidth;
}
}
- goto end; // Didn't fit. Jump to the end.
+ // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.
+ if (ignoringSpaces || !collapseWhiteSpace || !currentCharacterIsSpace || !previousCharacterIsSpace)
+ goto end;
} else {
if (!betweenWords || (midWordBreak && !autoWrap))
- width.addUncommittedWidth(-additionalTmpW);
+ width.addUncommittedWidth(-additionalTempWidth);
if (hyphenWidth) {
// Subtract the width of the soft hyphen out since we fit on a line.
width.addUncommittedWidth(-hyphenWidth);
@@ -2708,11 +3332,8 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
}
if (c == '\n' && preserveNewline) {
- if (!stoppedIgnoringSpaces && current.m_pos > 0) {
- // We need to stop right before the newline and then start up again.
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos - 1)); // Stop
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos)); // Start
- }
+ if (!stoppedIgnoringSpaces && current.m_pos > 0)
+ ensureCharacterGetsLineBox(lineMidpointState, current);
lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
lBreak.increment();
lineInfo.setPreviousLineBrokeCleanly(true);
@@ -2720,9 +3341,8 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
}
if (autoWrap && betweenWords) {
- width.commit();
wrapW = 0;
- lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
+ commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj, current.m_pos, current.m_nextBreakablePosition);
// Auto-wrapping text should not wrap in the middle of a word once it has had an
// opportunity to break after a word.
breakWords = false;
@@ -2751,7 +3371,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// We just entered a mode where we are ignoring
// spaces. Create a midpoint to terminate the run
// before the second space.
- addMidpoint(lineMidpointState, ignoreStart);
+ startIgnoringSpaces(lineMidpointState, ignoreStart);
trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
}
}
@@ -2762,16 +3382,14 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
+ stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
}
#if ENABLE(SVG)
if (isSVGText && current.m_pos > 0) {
// Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).
- if (toRenderSVGInlineText(t)->characterStartsNewTextChunk(current.m_pos)) {
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos - 1));
- addMidpoint(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
- }
+ if (toRenderSVGInlineText(t)->characterStartsNewTextChunk(current.m_pos))
+ ensureCharacterGetsLineBox(lineMidpointState, current);
}
#endif
@@ -2791,24 +3409,39 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
trailingObjects.clear();
atStart = false;
+ nextCharacter:
+ secondToLastCharacter = lastCharacter;
+ lastCharacter = c;
}
+ renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
+
wordMeasurements.grow(wordMeasurements.size() + 1);
WordMeasurement& wordMeasurement = wordMeasurements.last();
wordMeasurement.renderer = t;
// IMPORTANT: current.m_pos is > length here!
- float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
+ float additionalTempWidth = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
wordMeasurement.startOffset = lastSpace;
wordMeasurement.endOffset = current.m_pos;
- wordMeasurement.width = ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement;
- additionalTmpW += lastSpaceWordSpacing;
- width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth));
+ wordMeasurement.width = ignoringSpaces ? 0 : additionalTempWidth + wordSpacingForWordMeasurement;
+ additionalTempWidth += lastSpaceWordSpacing;
+
+ float inlineLogicalTempWidth = inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth);
+ width.addUncommittedWidth(additionalTempWidth + inlineLogicalTempWidth);
+
+ if (wordMeasurement.fallbackFonts.isEmpty() && !fallbackFonts.isEmpty())
+ wordMeasurement.fallbackFonts.swap(fallbackFonts);
+ fallbackFonts.clear();
+
+ if (collapseWhiteSpace && currentCharacterIsSpace && additionalTempWidth)
+ width.setTrailingWhitespaceWidth(additionalTempWidth, inlineLogicalTempWidth);
+
includeEndWidth = false;
if (!width.fitsOnLine()) {
if (canHyphenate)
- tryHyphenating(t, f, style->locale(), consecutiveHyphenatedLines, blockStyle->hyphenationLimitLines(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTmpW, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
+ tryHyphenating(t, f, style->locale(), consecutiveHyphenatedLines, blockStyle->hyphenationLimitLines(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTempWidth, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
if (!m_hyphenated && lBreak.previousInSameNode() == softHyphen && style->hyphens() != HyphensNone)
m_hyphenated = true;
@@ -2819,35 +3452,8 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
} else
ASSERT_NOT_REACHED();
- bool checkForBreak = autoWrap || blockStyle->autoWrap();
- if (width.committedWidth() && !width.fitsOnLine() && lBreak.m_obj && currWS == NOWRAP)
- checkForBreak = true;
- else if (next && current.m_obj->isText() && next->isText() && !next->isBR() && (autoWrap || (next->style()->autoWrap()))) {
- if (currentCharacterIsSpace)
- checkForBreak = true;
- else {
- RenderText* nextText = toRenderText(next);
- if (nextText->textLength()) {
- UChar c = nextText->characterAt(0);
- checkForBreak = (c == ' ' || c == '\t' || (c == '\n' && !next->preservesNewline()));
- // If the next item on the line is text, and if we did not end with
- // a space, then the next text run continues our word (and so it needs to
- // keep adding to |tmpW|. Just update and continue.
- } else if (nextText->isWordBreak())
- checkForBreak = true;
-
- if (!width.fitsOnLine() && !width.committedWidth())
- width.fitBelowFloats();
-
- bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrueOnLine;
- if (canPlaceOnLine && checkForBreak) {
- width.commit();
- lBreak.moveToStartOf(next);
- }
- }
- }
-
- if (checkForBreak && !width.fitsOnLine()) {
+ bool canBreakHere = canBreakAtThisPosition(autoWrap, width, lBreak, next, current, currWS, currentCharacterIsSpace, autoWrapWasEverTrueOnLine);
+ if (canBreakHere && !width.fitsOnLine(ignoringSpaces)) {
// if we have floats, try to get below them.
if (currentCharacterIsSpace && !ignoringSpaces && currentStyle->collapseWhiteSpace())
trailingObjects.clear();
@@ -2860,16 +3466,18 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
// |width| may have been adjusted because we got shoved down past a float (thus
// giving us more room), so we need to retest, and only jump to
// the end label if we still don't fit on the line. -dwh
- if (!width.fitsOnLine())
+ if (!width.fitsOnLine(ignoringSpaces))
goto end;
+ } else if (blockStyle->autoWrap() && !width.fitsOnLine() && !width.committedWidth()) {
+ // If the container autowraps but the current child does not then we still need to ensure that it
+ // wraps and moves below any floats.
+ width.fitBelowFloats();
}
if (!current.m_obj->isFloatingOrOutOfFlowPositioned()) {
last = current.m_obj;
- if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) {
- width.commit();
- lBreak.moveToStartOf(next);
- }
+ if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside()))
+ commitLineBreakAtCurrentWidth(width, lBreak, next);
}
// Clear out our character space bool, since inline <pre>s don't collapse whitespace
@@ -2881,33 +3489,42 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol
atStart = false;
}
- if (width.fitsOnLine() || lastWS == NOWRAP)
+ if (width.fitsOnLine(true) || lastWS == NOWRAP)
lBreak.clear();
end:
- if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR())) {
- // we just add as much as possible
- if (blockStyle->whiteSpace() == PRE) {
- // FIXME: Don't really understand this case.
- if (current.m_pos) {
- // FIXME: This should call moveTo which would clear m_nextBreakablePosition
- // this code as-is is likely wrong.
- lBreak.m_obj = current.m_obj;
- lBreak.m_pos = current.m_pos - 1;
- } else
- lBreak.moveTo(last, last->isText() ? last->length() : 0);
- } else if (lBreak.m_obj) {
- // Don't ever break in the middle of a word if we can help it.
- // There's no room at all. We just have to be on this line,
- // even though we'll spill out.
- lBreak.moveTo(current.m_obj, current.m_pos);
+#if ENABLE(CSS_SHAPES)
+ ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo();
+ bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();
+#else
+ bool segmentAllowsOverflow = true;
+#endif
+
+ if (segmentAllowsOverflow) {
+ if (lBreak == resolver.position()) {
+ if (!lBreak.m_obj || !lBreak.m_obj->isBR()) {
+ // we just add as much as possible
+ if (blockStyle->whiteSpace() == PRE && !current.m_pos) {
+ lBreak.moveTo(last, last->isText() ? last->length() : 0);
+ } else if (lBreak.m_obj) {
+ // Don't ever break in the middle of a word if we can help it.
+ // There's no room at all. We just have to be on this line,
+ // even though we'll spill out.
+ lBreak.moveTo(current.m_obj, current.m_pos);
+ }
+ }
+ // make sure we consume at least one char/object.
+ if (lBreak == resolver.position())
+ lBreak.increment();
+ } else if (!width.committedWidth() && (!current.m_obj || !current.m_obj->isBR()) && !current.m_pos) {
+ // Do not push the current object to the next line, when this line has some content, but it is still considered empty.
+ // Empty inline elements like <span></span> can produce such lines and now we just ignore these break opportunities
+ // at the start of a line, if no width has been committed yet.
+ // Behave as if it was actually empty and consume at least one object.
+ lBreak.increment();
}
}
- // make sure we consume at least one char/object.
- if (lBreak == resolver.position())
- lBreak.increment();
-
// Sanity check our midpoints.
checkMidpoints(lineMidpointState, lBreak);
@@ -2980,9 +3597,11 @@ void RenderBlock::checkLinesForTextOverflow()
ETextAlign textAlign = style()->textAlign();
bool firstLine = true;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
- LayoutUnit blockRightEdge = logicalRightOffsetForLine(curr->lineTop(), firstLine);
- LayoutUnit blockLeftEdge = logicalLeftOffsetForLine(curr->lineTop(), firstLine);
- LayoutUnit lineBoxEdge = ltr ? curr->x() + curr->logicalWidth() : curr->x();
+ // FIXME: Use pixelSnappedLogicalRightOffsetForLine instead of snapping it ourselves once the column workaround in said method has been fixed.
+ // https://bugs.webkit.org/show_bug.cgi?id=105461
+ int blockRightEdge = snapSizeToPixel(logicalRightOffsetForLine(curr->lineTop(), firstLine), curr->x());
+ int blockLeftEdge = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
+ int lineBoxEdge = ltr ? snapSizeToPixel(curr->x() + curr->logicalWidth(), curr->x()) : snapSizeToPixel(curr->x(), 0);
if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
// This line spills out of our box in the appropriate direction. Now we need to see if the line
// can be truncated. In order for truncation to be possible, the line must have sufficient space to
@@ -2994,7 +3613,7 @@ void RenderBlock::checkLinesForTextOverflow()
if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) {
float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width);
- float logicalLeft = 0; // We are only intersted in the delta from the base position.
+ float logicalLeft = 0; // We are only interested in the delta from the base position.
float truncatedWidth = pixelSnappedLogicalRightOffsetForLine(curr->lineTop(), firstLine);
updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, truncatedWidth, 0);
if (ltr)
diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp
index 6c341ddb2..03b81ac9a 100644
--- a/Source/WebCore/rendering/RenderBox.cpp
+++ b/Source/WebCore/rendering/RenderBox.cpp
@@ -25,19 +25,19 @@
#include "config.h"
#include "RenderBox.h"
-#include "CachedImage.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
+#include "FloatQuad.h"
+#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
-#include "HitTestResult.h"
-#include "htmlediting.h"
#include "HTMLElement.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLInputElement.h"
#include "HTMLNames.h"
-#include "ImageBuffer.h"
-#include "FloatQuad.h"
-#include "Frame.h"
+#include "HTMLTextAreaElement.h"
+#include "HitTestResult.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderArena.h"
@@ -47,15 +47,19 @@
#include "RenderGeometryMap.h"
#include "RenderInline.h"
#include "RenderLayer.h"
-#include "RenderPart.h"
#include "RenderRegion.h"
#include "RenderTableCell.h"
#include "RenderTheme.h"
#include "RenderView.h"
-#include "ScrollbarTheme.h"
#include "TransformState.h"
+#include "htmlediting.h"
#include <algorithm>
#include <math.h>
+#include <wtf/StackStats.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerCompositor.h"
+#endif
using namespace std;
@@ -72,9 +76,26 @@ static OverrideSizeMap* gOverrideWidthMap = 0;
static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
+
+// Size of border belt for autoscroll. When mouse pointer in border belt,
+// autoscroll is started.
+static const int autoscrollBeltSize = 20;
+static const unsigned backgroundObscurationTestMaxDepth = 4;
+
bool RenderBox::s_hadOverflowClip = false;
-RenderBox::RenderBox(Node* node)
+static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
+{
+ ASSERT(bodyElementRenderer->isBody());
+ // The <body> only paints its background if the root element has defined a background independent of the body,
+ // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
+ RenderObject* documentElementRenderer = bodyElementRenderer->document()->documentElement()->renderer();
+ return documentElementRenderer
+ && !documentElementRenderer->hasBackground()
+ && (documentElementRenderer == bodyElementRenderer->parent());
+}
+
+RenderBox::RenderBox(ContainerNode* node)
: RenderBoxModelObject(node)
, m_minPreferredLogicalWidth(-1)
, m_maxPreferredLogicalWidth(-1)
@@ -87,13 +108,13 @@ RenderBox::~RenderBox()
{
}
-LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit offsetFromTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const
+LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
{
if (!region)
return borderBoxRect();
// Compute the logical width and placement in this region.
- RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, offsetFromTopOfFirstPage, cacheFlag);
+ RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, cacheFlag);
if (!boxInfo)
return borderBoxRect();
@@ -104,17 +125,15 @@ LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit off
// Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts.
// FIXME: Doesn't work right with perpendicular writing modes.
const RenderBlock* currentBox = containingBlock();
- offsetFromTopOfFirstPage -= logicalTop();
- RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage);
+ RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region);
while (currentBoxInfo && currentBoxInfo->isShifted()) {
if (currentBox->style()->direction() == LTR)
logicalLeft += currentBoxInfo->logicalLeft();
else
logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft();
- offsetFromTopOfFirstPage -= logicalTop();
currentBox = currentBox->containingBlock();
region = currentBox->clampToStartAndEndRegions(region);
- currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage);
+ currentBoxInfo = currentBox->renderBoxRegionInfo(region);
}
if (cacheFlag == DoNotCacheRenderBoxRegionInfo)
@@ -127,11 +146,12 @@ LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit off
void RenderBox::clearRenderBoxRegionInfo()
{
- if (!inRenderFlowThread() || isRenderFlowThread())
+ if (isRenderFlowThread())
return;
- RenderFlowThread* flowThread = enclosingRenderFlowThread();
- flowThread->removeRenderBoxRegionInfo(this);
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread)
+ flowThread->removeRenderBoxRegionInfo(this);
}
void RenderBox::willBeDestroyed()
@@ -141,6 +161,10 @@ void RenderBox::willBeDestroyed()
RenderBlock::removePercentHeightDescendantIfNeeded(this);
+#if ENABLE(CSS_SHAPES)
+ ShapeOutsideInfo::removeInfo(this);
+#endif
+
RenderBoxModelObject::willBeDestroyed();
}
@@ -184,8 +208,14 @@ void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyl
// The background of the root element or the body element could propagate up to
// the canvas. Just dirty the entire canvas when our style changes substantially.
if (diff >= StyleDifferenceRepaint && node() &&
- (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag)))
+ (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag))) {
view()->repaint();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground())
+ view()->compositor()->rootFixedBackgroundsChanged();
+#endif
+ }
// When a layout hint happens and an object's position style changes, we have to do a layout
// to dirty the render tree using the old position value now.
@@ -242,6 +272,15 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
}
}
+ // Our opaqueness might have changed without triggering layout.
+ if (diff >= StyleDifferenceRepaint && diff <= StyleDifferenceRepaintLayer) {
+ RenderObject* parentToInvalidate = parent();
+ for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
+ parentToInvalidate->invalidateBackgroundObscurationStatus();
+ parentToInvalidate = parentToInvalidate->parent();
+ }
+ }
+
bool isBodyRenderer = isBody();
bool isRootRenderer = isRoot();
@@ -253,6 +292,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
// Propagate the new writing mode and direction up to the RenderView.
RenderView* viewRenderer = view();
RenderStyle* viewStyle = viewRenderer->style();
+ bool viewChangedWritingMode = false;
if (viewStyle->direction() != newStyle->direction() && (isRootRenderer || !document()->directionSetOnDocumentElement())) {
viewStyle->setDirection(newStyle->direction());
if (isBodyRenderer)
@@ -262,6 +302,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
if (viewStyle->writingMode() != newStyle->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) {
viewStyle->setWritingMode(newStyle->writingMode());
+ viewChangedWritingMode = true;
viewRenderer->setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
viewRenderer->markAllDescendantsWithFloatsForLayout();
if (isBodyRenderer) {
@@ -272,9 +313,35 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
}
frame()->view()->recalculateScrollbarOverlayStyle();
+
+ const Pagination& pagination = frame()->view()->pagination();
+ if (viewChangedWritingMode && pagination.mode != Pagination::Unpaginated) {
+ viewStyle->setColumnStylesFromPaginationMode(pagination.mode);
+ if (viewRenderer->hasColumns())
+ viewRenderer->updateColumnInfoFromStyle(viewStyle);
+ }
}
+
+#if ENABLE(CSS_SHAPES)
+ updateShapeOutsideInfoAfterStyleChange(style()->shapeOutside(), oldStyle ? oldStyle->shapeOutside() : 0);
+#endif
}
+#if ENABLE(CSS_SHAPES)
+void RenderBox::updateShapeOutsideInfoAfterStyleChange(const ShapeValue* shapeOutside, const ShapeValue* oldShapeOutside)
+{
+ // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
+ if (shapeOutside == oldShapeOutside)
+ return;
+
+ if (shapeOutside) {
+ ShapeOutsideInfo* shapeOutsideInfo = ShapeOutsideInfo::ensureInfo(this);
+ shapeOutsideInfo->dirtyShapeSize();
+ } else
+ ShapeOutsideInfo::removeInfo(this);
+}
+#endif
+
void RenderBox::updateFromStyle()
{
RenderBoxModelObject::updateFromStyle();
@@ -287,7 +354,6 @@ void RenderBox::updateFromStyle()
if (isRootObject || isViewObject)
setHasBoxDecorations(true);
- setPositioned(styleToUse->hasOutOfFlowPosition());
setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
// We also handle <body> and <html>, whose overflow applies to the viewport.
@@ -336,6 +402,7 @@ void RenderBox::layout()
child = child->nextSibling();
}
statePusher.pop();
+ invalidateBackgroundObscurationStatus();
setNeedsLayout(false);
}
@@ -361,6 +428,16 @@ int RenderBox::pixelSnappedClientHeight() const
return snapSizeToPixel(clientHeight(), y() + clientTop());
}
+int RenderBox::pixelSnappedOffsetWidth() const
+{
+ return snapSizeToPixel(offsetWidth(), x() + clientLeft());
+}
+
+int RenderBox::pixelSnappedOffsetHeight() const
+{
+ return snapSizeToPixel(offsetHeight(), y() + clientTop());
+}
+
int RenderBox::scrollWidth() const
{
if (hasOverflowClip())
@@ -420,23 +497,34 @@ void RenderBox::updateLayerTransform()
layer()->updateTransform();
}
-LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region) const
{
RenderStyle* styleToUse = style();
if (!styleToUse->logicalMaxWidth().isUndefined())
- logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, availableWidth, cb, region, offsetFromLogicalTopOfFirstPage));
- return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, availableWidth, cb, region, offsetFromLogicalTopOfFirstPage));
+ logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb, region));
+ return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb, region));
}
LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight) const
{
RenderStyle* styleToUse = style();
if (!styleToUse->logicalMaxHeight().isUndefined()) {
- LayoutUnit maxH = computeLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight());
+ LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight());
if (maxH != -1)
logicalHeight = min(logicalHeight, maxH);
}
- return max(logicalHeight, computeLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight()));
+ return max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight()));
+}
+
+LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight) const
+{
+ RenderStyle* styleToUse = style();
+ if (!styleToUse->logicalMaxHeight().isUndefined()) {
+ LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight());
+ if (maxH != -1)
+ logicalHeight = min(logicalHeight, maxH);
+ }
+ return max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight()));
}
IntRect RenderBox::absoluteContentBox() const
@@ -459,14 +547,16 @@ LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repa
LayoutRect box = borderBoundingBox();
adjustRectForOutlineAndShadow(box);
- FloatQuad containerRelativeQuad;
- if (geometryMap)
- containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
- else
- containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
-
- box = containerRelativeQuad.enclosingBoundingBox();
+ if (repaintContainer != this) {
+ FloatQuad containerRelativeQuad;
+ if (geometryMap)
+ containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
+ else
+ containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
+ box = containerRelativeQuad.enclosingBoundingBox();
+ }
+
// FIXME: layoutDelta needs to be applied in parts before/after transforms and
// repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
box.move(view()->layoutDelta());
@@ -474,7 +564,7 @@ LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repa
return box;
}
-void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
+void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
{
if (!size().isEmpty())
rects.append(pixelSnappedIntRect(additionalOffset, size()));
@@ -565,6 +655,24 @@ int RenderBox::horizontalScrollbarHeight() const
return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
}
+int RenderBox::instrinsicScrollbarLogicalWidth() const
+{
+ if (!hasOverflowClip())
+ return 0;
+
+ if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
+ ASSERT(layer()->hasVerticalScrollbar());
+ return verticalScrollbarWidth();
+ }
+
+ if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
+ ASSERT(layer()->hasHorizontalScrollbar());
+ return horizontalScrollbarHeight();
+ }
+
+ return 0;
+}
+
bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
{
RenderLayer* l = layer();
@@ -628,10 +736,70 @@ bool RenderBox::usesCompositedScrolling() const
return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling();
}
-void RenderBox::autoscroll()
+void RenderBox::autoscroll(const IntPoint& position)
{
if (layer())
- layer()->autoscroll();
+ layer()->autoscroll(position);
+}
+
+// There are two kinds of renderer that can autoscroll.
+bool RenderBox::canAutoscroll() const
+{
+ // Check for a box that can be scrolled in its own right.
+ if (canBeScrolledAndHasScrollableArea())
+ return true;
+
+ // Check for a box that represents the top level of a web page.
+ // This can be scrolled by calling Chrome::scrollRectIntoView.
+ // This only has an effect on the Mac platform in applications
+ // that put web views into scrolling containers, such as Mac OS X Mail.
+ // The code for this is in RenderLayer::scrollRectToVisible.
+ if (node() != document())
+ return false;
+ Frame* frame = this->frame();
+ if (!frame)
+ return false;
+ Page* page = frame->page();
+ return page && page->mainFrame() == frame && frame->view()->isScrollable();
+}
+
+// If specified point is in border belt, returned offset denotes direction of
+// scrolling.
+IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
+{
+ if (!frame())
+ return IntSize();
+
+ FrameView* frameView = frame()->view();
+ if (!frameView)
+ return IntSize();
+
+ IntSize offset;
+ IntPoint point = frameView->windowToContents(windowPoint);
+ IntRect box(absoluteBoundingBoxRect());
+
+ if (point.x() < box.x() + autoscrollBeltSize)
+ point.move(-autoscrollBeltSize, 0);
+ else if (point.x() > box.maxX() - autoscrollBeltSize)
+ point.move(autoscrollBeltSize, 0);
+
+ if (point.y() < box.y() + autoscrollBeltSize)
+ point.move(0, -autoscrollBeltSize);
+ else if (point.y() > box.maxY() - autoscrollBeltSize)
+ point.move(0, autoscrollBeltSize);
+ return frameView->contentsToWindow(point) - windowPoint;
+}
+
+RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
+{
+ while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
+ if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
+ renderer = renderer->document()->ownerElement()->renderer();
+ else
+ renderer = renderer->parent();
+ }
+
+ return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
}
void RenderBox::panScroll(const IntPoint& source)
@@ -661,31 +829,49 @@ LayoutSize RenderBox::cachedSizeForOverflowClip() const
void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const
{
+ flipForWritingMode(paintRect);
paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
// Do not clip scroll layer contents to reduce the number of repaints while scrolling.
- if (usesCompositedScrolling())
+ if (usesCompositedScrolling()) {
+ flipForWritingMode(paintRect);
return;
+ }
// height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
// layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
// anyway if its size does change.
LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip());
paintRect = intersection(paintRect, clipRect);
+ flipForWritingMode(paintRect);
+}
+
+void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
+ maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
}
LayoutUnit RenderBox::minPreferredLogicalWidth() const
{
- if (preferredLogicalWidthsDirty())
+ if (preferredLogicalWidthsDirty()) {
+#ifndef NDEBUG
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
+#endif
const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
+ }
return m_minPreferredLogicalWidth;
}
LayoutUnit RenderBox::maxPreferredLogicalWidth() const
{
- if (preferredLogicalWidthsDirty())
+ if (preferredLogicalWidthsDirty()) {
+#ifndef NDEBUG
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
+#endif
const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
+ }
return m_maxPreferredLogicalWidth;
}
@@ -784,6 +970,11 @@ void RenderBox::clearContainingBlockOverrideSize()
{
if (gOverrideContainingBlockLogicalWidthMap)
gOverrideContainingBlockLogicalWidthMap->remove(this);
+ clearOverrideContainingBlockContentLogicalHeight();
+}
+
+void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
+{
if (gOverrideContainingBlockLogicalHeightMap)
gOverrideContainingBlockLogicalHeightMap->remove(this);
}
@@ -851,13 +1042,16 @@ void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
LayoutPoint adjustedPaintOffset = paintOffset + location();
// default implementation. Just pass paint through to the children
PaintInfo childInfo(paintInfo);
- childInfo.updatePaintingRootForChildren(this);
+ childInfo.updateSubtreePaintRootForChildren(this);
for (RenderObject* child = firstChild(); child; child = child->nextSibling())
child->paint(childInfo, adjustedPaintOffset);
}
void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
{
+ if (paintInfo.skipRootBackground())
+ return;
+
RenderObject* rootBackgroundRenderer = rendererForRootBackground();
const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
@@ -878,9 +1072,24 @@ BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsCo
AffineTransform ctm = context->getCTM();
FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
+
+ // Because RoundedRect uses IntRect internally the inset applied by the
+ // BackgroundBleedShrinkBackground strategy cannot be less than one integer
+ // layout coordinate, even with subpixel layout enabled. To take that into
+ // account, we clamp the contextScaling to 1.0 for the following test so
+ // that borderObscuresBackgroundEdge can only return true if the border
+ // widths are greater than 2 in both layout coordinates and screen
+ // coordinates.
+ // This precaution will become obsolete if RoundedRect is ever promoted to
+ // a sub-pixel representation.
+ if (contextScaling.width() > 1)
+ contextScaling.setWidth(1);
+ if (contextScaling.height() > 1)
+ contextScaling.setHeight(1);
+
if (borderObscuresBackgroundEdge(contextScaling))
return BackgroundBleedShrinkBackground;
- if (!style->hasAppearance() && borderObscuresBackground() && backgroundIsSingleOpaqueLayer())
+ if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
return BackgroundBleedBackgroundOverBorder;
return BackgroundBleedUseTransparencyLayer;
@@ -894,10 +1103,6 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai
LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion);
paintRect.moveBy(paintOffset);
- // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat
- // balloon layout is an example of this).
- borderFitAdjust(paintRect);
-
BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
// FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
@@ -912,7 +1117,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai
// beginning the layer).
RoundedRect border = style()->getRoundedBorderFor(paintRect, view());
stateSaver.save();
- paintInfo.context->addRoundedRectClip(border);
+ paintInfo.context->clipRoundedRect(border);
paintInfo.context->beginTransparencyLayer(1);
}
@@ -941,33 +1146,168 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai
void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
{
- if (isRoot())
+ if (isRoot()) {
paintRootBoxFillLayers(paintInfo);
- else if (!isBody()
- || (document()->documentElement()->renderer() && document()->documentElement()->renderer()->hasBackground())
- || (document()->documentElement()->renderer() != parent())) {
- // The <body> only paints its background if the root element has defined a background independent of the body,
- // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
- if (!backgroundIsObscured())
- paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
+ return;
+ }
+ if (isBody() && skipBodyBackground(this))
+ return;
+ if (backgroundIsKnownToBeObscured() && !boxShadowShouldBeAppliedToBackground(bleedAvoidance))
+ return;
+ paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
+}
+
+bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const
+{
+ ASSERT(hasBackground());
+ LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
+
+ Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
+ if (backgroundColor.isValid() && backgroundColor.alpha()) {
+ paintedExtent = backgroundRect;
+ return true;
+ }
+
+ if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next()) {
+ paintedExtent = backgroundRect;
+ return true;
+ }
+
+ BackgroundImageGeometry geometry;
+ calculateBackgroundImageGeometry(0, style()->backgroundLayers(), backgroundRect, geometry);
+ paintedExtent = geometry.destRect();
+ return !geometry.hasNonLocalGeometry();
+}
+
+bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
+{
+ if (isBody() && skipBodyBackground(this))
+ return false;
+
+ Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
+ if (!backgroundColor.isValid() || backgroundColor.hasAlpha())
+ return false;
+
+ // If the element has appearance, it might be painted by theme.
+ // We cannot be sure if theme paints the background opaque.
+ // In this case it is safe to not assume opaqueness.
+ // FIXME: May be ask theme if it paints opaque.
+ if (style()->hasAppearance())
+ return false;
+ // FIXME: Check the opaqueness of background images.
+
+ // FIXME: Use rounded rect if border radius is present.
+ if (style()->hasBorderRadius())
+ return false;
+ // FIXME: The background color clip is defined by the last layer.
+ if (style()->backgroundLayers()->next())
+ return false;
+ LayoutRect backgroundRect;
+ switch (style()->backgroundClip()) {
+ case BorderFillBox:
+ backgroundRect = borderBoxRect();
+ break;
+ case PaddingFillBox:
+ backgroundRect = paddingBoxRect();
+ break;
+ case ContentFillBox:
+ backgroundRect = contentBoxRect();
+ break;
+ default:
+ break;
+ }
+ return backgroundRect.contains(localRect);
+}
+
+static bool isCandidateForOpaquenessTest(RenderBox* childBox)
+{
+ RenderStyle* childStyle = childBox->style();
+ if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
+ return false;
+ if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
+ return false;
+ if (!childBox->width() || !childBox->height())
+ return false;
+ if (RenderLayer* childLayer = childBox->layer()) {
+#if USE(ACCELERATED_COMPOSITING)
+ if (childLayer->isComposited())
+ return false;
+#endif
+ // FIXME: Deal with z-index.
+ if (!childStyle->hasAutoZIndex())
+ return false;
+ if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
+ return false;
+ }
+ return true;
+}
+
+bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
+{
+ if (!maxDepthToTest)
+ return false;
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isBox())
+ continue;
+ RenderBox* childBox = toRenderBox(child);
+ if (!isCandidateForOpaquenessTest(childBox))
+ continue;
+ LayoutPoint childLocation = childBox->location();
+ if (childBox->isRelPositioned())
+ childLocation.move(childBox->relativePositionOffset());
+ LayoutRect childLocalRect = localRect;
+ childLocalRect.moveBy(-childLocation);
+ if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
+ // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
+ if (childBox->style()->position() == StaticPosition)
+ return false;
+ continue;
+ }
+ if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
+ continue;
+ if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
+ return true;
+ if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
+ return true;
}
+ return false;
}
-bool RenderBox::backgroundIsSingleOpaqueLayer() const
+bool RenderBox::computeBackgroundIsKnownToBeObscured()
+{
+ // Test to see if the children trivially obscure the background.
+ // FIXME: This test can be much more comprehensive.
+ if (!hasBackground())
+ return false;
+ // Table and root background painting is special.
+ if (isTable() || isRoot())
+ return false;
+
+ LayoutRect backgroundRect;
+ if (!getBackgroundPaintedExtent(backgroundRect))
+ return false;
+ return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
+}
+
+bool RenderBox::backgroundHasOpaqueTopLayer() const
{
const FillLayer* fillLayer = style()->backgroundLayers();
- if (!fillLayer || fillLayer->next() || fillLayer->clip() != BorderFillBox || fillLayer->composite() != CompositeSourceOver)
+ if (!fillLayer || fillLayer->clip() != BorderFillBox)
return false;
// Clipped with local scrolling
if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment)
return false;
- Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
- if (bgColor.isValid() && bgColor.alpha() == 255)
+ if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom()))
return true;
-
- // FIXME: return true if a background image is present and is opaque
+
+ // If there is only one layer and no image, check whether the background color is opaque
+ if (!fillLayer->next() && !fillLayer->hasImage()) {
+ Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
+ if (bgColor.isValid() && bgColor.alpha() == 255)
+ return true;
+ }
return false;
}
@@ -978,11 +1318,6 @@ void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
return;
LayoutRect paintRect = LayoutRect(paintOffset, size());
-
- // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat
- // balloon layout is an example of this).
- borderFitAdjust(paintRect);
-
paintMaskImages(paintInfo, paintRect);
}
@@ -1038,7 +1373,8 @@ LayoutRect RenderBox::maskClipRect()
for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
if (maskLayer->image()) {
BackgroundImageGeometry geometry;
- calculateBackgroundImageGeometry(maskLayer, borderBox, geometry);
+ // Masks should never have fixed attachment, so it's OK for paintContainer to be null.
+ calculateBackgroundImageGeometry(0, maskLayer, borderBox, geometry);
result.unite(geometry.destRect());
}
}
@@ -1048,18 +1384,40 @@ LayoutRect RenderBox::maskClipRect()
void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
{
- if (!fillLayer)
- return;
+ Vector<const FillLayer*, 8> layers;
+ const FillLayer* curLayer = fillLayer;
+ bool shouldDrawBackgroundInSeparateBuffer = false;
+ while (curLayer) {
+ layers.append(curLayer);
+ // Stop traversal when an opaque layer is encountered.
+ // FIXME : It would be possible for the following occlusion culling test to be more aggressive
+ // on layers with no repeat by testing whether the image covers the layout rect.
+ // Testing that here would imply duplicating a lot of calculations that are currently done in
+ // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
+ // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
+ // and pass it down.
+
+ if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != BlendModeNormal)
+ shouldDrawBackgroundInSeparateBuffer = true;
+
+ // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
+ if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == BlendModeNormal)
+ break;
+ curLayer = curLayer->next();
+ }
+
+ GraphicsContext* context = paintInfo.context;
+ if (!context)
+ shouldDrawBackgroundInSeparateBuffer = false;
+ if (shouldDrawBackgroundInSeparateBuffer)
+ context->beginTransparencyLayer(1);
- // FIXME : It would be possible for the following occlusion culling test to be more aggressive
- // on layers with no repeat by testing whether the image covers the layout rect.
- // Testing that here would imply duplicating a lot of calculations that are currently done in
- // RenderBoxModelOBject::paintFillLayerExtended. A more efficient solution might be to move
- // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
- // and pass it down.
- if (fillLayer->next() && (!fillLayer->hasOpaqueImage(this) || !fillLayer->image()->canRender(this, style()->effectiveZoom()) || !fillLayer->hasRepeatXY()))
- paintFillLayers(paintInfo, c, fillLayer->next(), rect, bleedAvoidance, op, backgroundObject);
- paintFillLayer(paintInfo, c, fillLayer, rect, bleedAvoidance, op, backgroundObject);
+ Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
+ for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
+ paintFillLayer(paintInfo, c, *it, rect, bleedAvoidance, op, backgroundObject);
+
+ if (shouldDrawBackgroundInSeparateBuffer)
+ context->endTransparencyLayer();
}
void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
@@ -1097,8 +1455,13 @@ void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
#if USE(ACCELERATED_COMPOSITING)
- if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
+ if (!isComposited())
+ return;
+
+ if (layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
layer()->contentChanged(MaskImageChanged);
+ if (layersUseImage(image, style()->backgroundLayers()))
+ layer()->contentChanged(BackgroundImageChanged);
#endif
}
@@ -1109,8 +1472,7 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer
for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) {
- // Now that we know this image is being used, compute the renderer and the rect
- // if we haven't already
+ // Now that we know this image is being used, compute the renderer and the rect if we haven't already.
if (!layerRenderer) {
bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->hasBackground()));
if (drawingRootBackground) {
@@ -1137,7 +1499,14 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer
}
BackgroundImageGeometry geometry;
- layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry);
+ layerRenderer->calculateBackgroundImageGeometry(0, curLayer, rendererRect, geometry);
+ if (geometry.hasNonLocalGeometry()) {
+ // Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds
+ // in order to get the right destRect, just repaint the entire renderer.
+ layerRenderer->repaint();
+ return true;
+ }
+
layerRenderer->repaintRectangle(geometry.destRect());
if (geometry.destRect() == rendererRect)
return true;
@@ -1162,10 +1531,10 @@ void RenderBox::paintCustomHighlight(const LayoutPoint& paintOffset, const Atomi
if (r) {
FloatRect rootRect(paintOffset.x() + r->x(), paintOffset.y() + r->selectionTop(), r->logicalWidth(), r->selectionHeight());
FloatRect imageRect(paintOffset.x() + x(), rootRect.y(), width(), rootRect.height());
- page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
+ page->chrome().client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
} else {
FloatRect imageRect(paintOffset.x() + x(), paintOffset.y() + y(), width(), height());
- page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
+ page->chrome().client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
}
}
@@ -1189,10 +1558,10 @@ bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu
paintObject(paintInfo, accumulatedOffset);
paintInfo.phase = PaintPhaseChildBlockBackgrounds;
}
- IntRect clipRect = pixelSnappedIntRect(isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion));
+ IntRect clipRect = pixelSnappedIntRect(isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion, IgnoreOverlayScrollbarSize, paintInfo.phase));
paintInfo.context->save();
if (style()->hasBorderRadius())
- paintInfo.context->addRoundedRectClip(style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size())));
+ paintInfo.context->clipRoundedRect(style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size())));
paintInfo.context->clip(clipRect);
return true;
}
@@ -1210,7 +1579,7 @@ void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase,
paintInfo.phase = originalPhase;
}
-LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
+LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy, PaintPhase)
{
// FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
// here.
@@ -1258,18 +1627,17 @@ LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region
return clipRect;
}
-LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region) const
{
RenderRegion* containingBlockRegion = 0;
LayoutUnit logicalTopPosition = logicalTop();
- LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop();
if (region) {
- LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage : LayoutUnit();
+ LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
containingBlockRegion = cb->clampToStartAndEndRegions(region);
}
- LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock) - childMarginStart - childMarginEnd;
+ LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion) - childMarginStart - childMarginEnd;
// We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
// then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
@@ -1277,9 +1645,9 @@ LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar
// doesn't fit, we can use the line offset, but we need to grow it by the margin to reflect the fact that the margin was
// "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
if (childMarginStart > 0) {
- LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock);
+ LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion);
LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
- LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock);
+ LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion);
if (startOffset > startContentSideWithMargin)
result += childMarginStart;
else
@@ -1287,9 +1655,9 @@ LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar
}
if (childMarginEnd > 0) {
- LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock);
+ LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion);
LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
- LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock);
+ LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion);
if (endOffset > endContentSideWithMargin)
result += childMarginEnd;
else
@@ -1308,16 +1676,16 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
return cb->availableLogicalWidth();
}
-LayoutUnit RenderBox::containingBlockLogicalHeightForContent() const
+LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
{
if (hasOverrideContainingBlockLogicalHeight())
return overrideContainingBlockContentLogicalHeight();
RenderBlock* cb = containingBlock();
- return cb->availableLogicalHeight();
+ return cb->availableLogicalHeight(heightType);
}
-LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region) const
{
if (!region)
return containingBlockLogicalWidthForContent();
@@ -1327,24 +1695,23 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion
// FIXME: It's unclear if a region's content should use the containing block's override logical width.
// If it should, the following line should call containingBlockLogicalWidthForContent.
LayoutUnit result = cb->availableLogicalWidth();
- RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop());
+ RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
if (!boxInfo)
return result;
return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
}
-LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region) const
{
RenderBlock* cb = containingBlock();
RenderRegion* containingBlockRegion = 0;
LayoutUnit logicalTopPosition = logicalTop();
- LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop();
if (region) {
- LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage : LayoutUnit();
+ LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
containingBlockRegion = cb->clampToStartAndEndRegions(region);
}
- return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock, availableLogicalHeight());
+ return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, availableLogicalHeight(IncludeMarginBorderPadding));
}
LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
@@ -1358,15 +1725,14 @@ LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
RenderStyle* containingBlockStyle = cb->style();
Length logicalHeightLength = containingBlockStyle->logicalHeight();
-
+
// FIXME: For now just support fixed heights. Eventually should support percentage heights as well.
if (!logicalHeightLength.isFixed()) {
- // Rather than making the child be completely unconstrained, WinIE uses the viewport width and height
- // as a constraint. We do that for now as well even though it's likely being unconstrained is what the spec
- // will decide.
- return containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
+ LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
+ LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
+ return min(fillAvailableExtent, fillFallbackExtent);
}
-
+
// Use the content box logical height as specified by the style.
return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value());
}
@@ -1405,8 +1771,6 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain
*wasFixed = mode & IsFixed;
LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
- if (mode & SnapOffsetForTransforms)
- containerOffset = roundedIntSize(containerOffset);
bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
@@ -1425,13 +1789,6 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain
}
mode &= ~ApplyContainerFlip;
- if (o->isRenderFlowThread()) {
- // Transform from render flow coordinates into region coordinates.
- RenderRegion* region = toRenderFlowThread(o)->mapFromFlowToRegion(transformState);
- if (region)
- region->mapLocalToContainer(region->containerForRepaint(), transformState, mode, wasFixed);
- return;
- }
o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
}
@@ -1457,12 +1814,7 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObje
bool offsetDependsOnPoint = false;
LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
- if (geometryMap.mapCoordinatesFlags() & SnapOffsetForTransforms)
- containerOffset = roundedIntSize(containerOffset);
- if (container->isRenderFlowThread())
- offsetDependsOnPoint = true;
-
bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
if (shouldUseTransformFromContainer(container)) {
TransformationMatrix t;
@@ -1494,7 +1846,8 @@ void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState
LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
{
- ASSERT(o == container());
+ // A region "has" boxes inside it without being their container.
+ ASSERT(o == container() || o->isRenderRegion());
LayoutSize offset;
if (isInFlowPositioned())
@@ -1523,6 +1876,9 @@ LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& po
if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
offset += toRenderInline(o)->offsetForInFlowPositionedInline(this);
+ if (offsetDependsOnPoint)
+ *offsetDependsOnPoint |= o->isRenderFlowThread();
+
return offset;
}
@@ -1680,7 +2036,7 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta
if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this);
- else if ((position == RelativePosition || position == StickyPosition) && layer()) {
+ else if (styleToUse->hasInFlowPosition() && layer()) {
// Apply the relative position offset when invalidating a rectangle. The layer
// is translated, but the render box isn't, so we need to do this to get the
// right dirty rect. Since this is called from RenderObject::setStyle, the relative position
@@ -1730,6 +2086,10 @@ void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
}
}
+void RenderBox::repaintOverhangingFloats(bool)
+{
+}
+
void RenderBox::updateLogicalWidth()
{
LogicalExtentComputedValues computedValues;
@@ -1741,7 +2101,7 @@ void RenderBox::updateLogicalWidth()
setMarginEnd(computedValues.m_margins.m_end);
}
-void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
{
computedValues.m_extent = logicalWidth();
computedValues.m_position = logicalLeft();
@@ -1751,7 +2111,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
if (isOutOfFlowPositioned()) {
// FIXME: This calculation is not patched for block-flow yet.
// https://bugs.webkit.org/show_bug.cgi?id=46500
- computePositionedLogicalWidth(computedValues, region, offsetFromLogicalTopOfFirstPage);
+ computePositionedLogicalWidth(computedValues, region);
return;
}
@@ -1763,7 +2123,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
// width. Use the width from the style context.
// FIXME: Account for block-flow in flexible boxes.
// https://bugs.webkit.org/show_bug.cgi?id=46418
- if (hasOverrideWidth() && parent()->isFlexibleBoxIncludingDeprecated()) {
+ if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) {
computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
return;
}
@@ -1778,11 +2138,8 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
RenderBlock* cb = containingBlock();
- LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region, offsetFromLogicalTopOfFirstPage));
+ LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region));
bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
- LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
- if (hasPerpendicularContainingBlock)
- containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
if (isInline() && !isInlineBlockOrInlineTable()) {
// just calculate margins
@@ -1798,14 +2155,13 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
if (treatAsReplaced)
computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
else {
- LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage);
- computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage);
+ LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
+ if (hasPerpendicularContainingBlock)
+ containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
+ LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb, region);
+ computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region);
}
- // Fieldsets are currently the only objects that stretch to their minimum width.
- if (stretchesToMinIntrinsicLogicalWidth())
- computedValues.m_extent = max(computedValues.m_extent, minPreferredLogicalWidth());
-
// Margin calculations.
if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
RenderView* renderView = view();
@@ -1814,7 +2170,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
} else {
LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth;
if (avoidsFloats() && cb->containsFloats())
- containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region, offsetFromLogicalTopOfFirstPage);
+ containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region);
bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent,
hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start,
@@ -1822,7 +2178,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
}
if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
- && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated()) {
+ && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) {
LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this);
bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
if (hasInvertedDirection)
@@ -1832,44 +2188,65 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute
}
}
-LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, LayoutUnit availableLogicalWidth,
- const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
{
- RenderStyle* styleToUse = style();
- Length logicalWidth;
- if (widthType == MainOrPreferredSize)
- logicalWidth = styleToUse->logicalWidth();
- else if (widthType == MinSize)
- logicalWidth = styleToUse->logicalMinWidth();
- else
- logicalWidth = styleToUse->logicalMaxWidth();
+ LayoutUnit marginStart = 0;
+ LayoutUnit marginEnd = 0;
+ return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
+}
- ASSERT(!logicalWidth.isUndefined());
+LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
+{
+ RenderView* renderView = view();
+ marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView);
+ marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView);
+ return availableLogicalWidth - marginStart - marginEnd;
+}
- if (widthType == MinSize && logicalWidth.isAuto())
- return adjustBorderBoxLogicalWidthForBoxSizing(0);
-
+LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
+{
+ if (logicalWidthLength.type() == FillAvailable)
+ return fillAvailableMeasure(availableLogicalWidth);
+
+ LayoutUnit minLogicalWidth = 0;
+ LayoutUnit maxLogicalWidth = 0;
+ computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
+
+ if (logicalWidthLength.type() == MinContent)
+ return minLogicalWidth + borderAndPadding;
+
+ if (logicalWidthLength.type() == MaxContent)
+ return maxLogicalWidth + borderAndPadding;
+
+ if (logicalWidthLength.type() == FitContent) {
+ minLogicalWidth += borderAndPadding;
+ maxLogicalWidth += borderAndPadding;
+ return max(minLogicalWidth, min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth,
+ const RenderBlock* cb, RenderRegion* region) const
+{
if (!logicalWidth.isIntrinsicOrAuto()) {
// FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth, view()));
}
- if (logicalWidth.type() == MinContent)
- return minPreferredLogicalWidth();
- if (logicalWidth.type() == MaxContent)
- return maxPreferredLogicalWidth();
+ if (logicalWidth.isIntrinsic())
+ return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
- RenderView* renderView = view();
- LayoutUnit marginStart = minimumValueForLength(styleToUse->marginStart(), availableLogicalWidth, renderView);
- LayoutUnit marginEnd = minimumValueForLength(styleToUse->marginEnd(), availableLogicalWidth, renderView);
- LayoutUnit logicalWidthResult = availableLogicalWidth - marginStart - marginEnd;
+ LayoutUnit marginStart = 0;
+ LayoutUnit marginEnd = 0;
+ LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
- // shrinkToAvoidFloats() is only true for width: auto so the below code works correctly for
- // width: fill-available since no case matches and it returns the logicalWidthResult from above.
if (shrinkToAvoidFloats() && cb->containsFloats())
- logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region, offsetFromLogicalTopOfFirstPage));
+ logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region));
- if (logicalWidth.type() == FitContent || (logicalWidth.type() != FillAvailable && sizesLogicalWidthToFitContent(widthType)))
+ if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType))
return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult));
return logicalWidthResult;
}
@@ -1938,7 +2315,7 @@ bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
// stretching column flexbox.
// FIXME: Think about block-flow here.
// https://bugs.webkit.org/show_bug.cgi?id=46473
- if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && node() && (node()->hasTagName(inputTag) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || node()->hasTagName(textareaTag) || node()->hasTagName(legendTag)))
+ if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && node() && (isHTMLInputElement(node()) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || isHTMLTextAreaElement(node()) || node()->hasTagName(legendTag)))
return true;
if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
@@ -1995,7 +2372,7 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo
marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView);
}
-RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const
+RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
{
// Make sure nobody is trying to call this with a null region.
if (!region)
@@ -2010,22 +2387,17 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout
// No cached value was found, so we have to compute our insets in this region.
// FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand
// support to cover all boxes.
- if (!inRenderFlowThread() || isFloating() || isReplaced() || isInline() || hasColumns()
- || isTableCell() || !isBlockFlow() || isRenderFlowThread())
- return 0;
-
- RenderFlowThread* flowThread = enclosingRenderFlowThread();
- if (flowThread->style()->writingMode() != style()->writingMode())
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (isRenderFlowThread() || !flowThread || !canHaveBoxInfoInRegion() || flowThread->style()->writingMode() != style()->writingMode())
return 0;
LogicalExtentComputedValues computedValues;
- computeLogicalWidthInRegion(computedValues, region, offsetFromLogicalTopOfFirstPage);
+ computeLogicalWidthInRegion(computedValues, region);
// Now determine the insets based off where this object is supposed to be positioned.
RenderBlock* cb = containingBlock();
RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region);
- RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion,
- offsetFromLogicalTopOfFirstPage - logicalTop());
+ RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion);
LayoutUnit containingBlockLogicalWidth = cb->logicalWidth();
LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth;
@@ -2042,7 +2414,7 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout
LayoutUnit logicalLeftOffset = 0;
if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) {
- LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region, offsetFromLogicalTopOfFirstPage);
+ LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region);
if (cb->style()->isLeftToRightDirection())
logicalLeftDelta += startPositionDelta;
else
@@ -2167,7 +2539,7 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica
LayoutUnit heightResult;
if (checkMinMaxHeight) {
- heightResult = computeLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight());
+ heightResult = computeLogicalHeightUsing(style()->logicalHeight());
if (heightResult == -1)
heightResult = computedValues.m_extent;
heightResult = constrainLogicalHeightByMinMax(heightResult);
@@ -2194,49 +2566,37 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica
// height since we don't set a height in RenderView when we're printing. So without this quirk, the
// height has nothing to be a percentage of, and it ends up being 0. That is bad.
bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
- && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent()));
+ && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline();
if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
- // FIXME: Finish accounting for block flow here.
- // https://bugs.webkit.org/show_bug.cgi?id=46603
LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
- LayoutUnit visHeight;
- if (document()->printing())
- visHeight = static_cast<LayoutUnit>(view()->pageLogicalHeight());
- else {
- if (isHorizontalWritingMode())
- visHeight = view()->viewHeight();
- else
- visHeight = view()->viewWidth();
- }
+ LayoutUnit visibleHeight = view()->pageOrViewLogicalHeight();
if (isRoot())
- computedValues.m_extent = max(computedValues.m_extent, visHeight - margins);
+ computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins);
else {
LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
- computedValues.m_extent = max(computedValues.m_extent, visHeight - marginsBordersPadding);
+ computedValues.m_extent = max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
}
}
}
-LayoutUnit RenderBox::computeLogicalHeightUsing(SizeType heightType, const Length& height) const
+LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height) const
{
- LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(heightType, height);
+ LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height);
if (logicalHeight != -1)
logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
return logicalHeight;
}
-LayoutUnit RenderBox::computeContentLogicalHeight(SizeType heightType, const Length& height)
+LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height) const
{
- LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(heightType, height);
+ LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height);
if (heightIncludingScrollbar == -1)
return -1;
return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
}
-LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(SizeType heightType, const Length& height) const
+LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height) const
{
- if (height.isAuto())
- return heightType == MinSize ? 0 : -1;
if (height.isFixed())
return height.value();
if (height.isPercent())
@@ -2276,9 +2636,7 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
// A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
// explicitly specified that can be used for any percentage computations.
- // FIXME: We can't just check top/bottom here.
- // https://bugs.webkit.org/show_bug.cgi?id=46500
- bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->top().isAuto() && !cbstyle->bottom().isAuto()));
+ bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto()));
bool includeBorderPadding = isTable();
@@ -2308,22 +2666,28 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
includeBorderPadding = true;
}
} else if (cbstyle->logicalHeight().isFixed()) {
- LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
- availableHeight = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight());
+ LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
+ availableHeight = max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight()));
} else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
// We need to recur and compute the percentage height for our containing block.
LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
if (heightWithScrollbar != -1) {
LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
- availableHeight = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight());
+ // We need to adjust for min/max height because this method does not
+ // handle the min/max of the current block, its caller does. So the
+ // return value from the recursive call will not have been adjusted
+ // yet.
+ LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight());
+ availableHeight = max<LayoutUnit>(0, contentBoxHeight);
}
- } else if (cb->isRenderView() || isOutOfFlowPositionedWithSpecifiedHeight) {
+ } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
// Don't allow this to affect the block' height() member variable, since this
// can get called while the block is still laying out its kids.
LogicalExtentComputedValues computedValues;
cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight();
- }
+ } else if (cb->isRenderView())
+ availableHeight = view()->pageOrViewLogicalHeight();
if (availableHeight == -1)
return availableHeight;
@@ -2342,30 +2706,36 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
return result;
}
-LayoutUnit RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const
+LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
{
- return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth()), includeMaxWidth);
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
}
-LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, bool includeMaxWidth) const
+LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
{
- LayoutUnit minLogicalWidth = computeReplacedLogicalWidthUsing(MinSize, style()->logicalMinWidth());
- LayoutUnit maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth());
+ LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
+ LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
}
-LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(SizeType sizeType, Length logicalWidth) const
+LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
{
- if (sizeType == MinSize && logicalWidth.isAuto())
- return adjustContentBoxLogicalWidthForBoxSizing(0);
-
switch (logicalWidth.type()) {
case Fixed:
return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
+ case MinContent:
+ case MaxContent: {
+ // MinContent/MaxContent don't need the availableLogicalWidth argument.
+ LayoutUnit availableLogicalWidth = 0;
+ return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
+ }
case ViewportPercentageWidth:
case ViewportPercentageHeight:
case ViewportPercentageMin:
+ case ViewportPercentageMax:
return adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, 0, view()));
+ case FitContent:
+ case FillAvailable:
case Percent:
case Calculated: {
// FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
@@ -2375,32 +2745,38 @@ LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(SizeType sizeType, Length
Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
// FIXME: Handle cases when containing block width is calculated or viewport percent.
// https://bugs.webkit.org/show_bug.cgi?id=91071
+ if (logicalWidth.isIntrinsic())
+ return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
}
// fall through
- default:
+ case Intrinsic:
+ case MinIntrinsic:
+ case Auto:
+ case Relative:
+ case Undefined:
return intrinsicLogicalWidth();
- }
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
}
LayoutUnit RenderBox::computeReplacedLogicalHeight() const
{
- return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight()));
+ return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
}
LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
{
- LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(MinSize, style()->logicalMinHeight());
- LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(MaxSize, style()->logicalMaxHeight());
+ LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
+ LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
}
-LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Length logicalHeight) const
+LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
{
- if (sizeType == MinSize && logicalHeight.isAuto())
- return adjustContentBoxLogicalHeightForBoxSizing(0);
-
switch (logicalHeight.type()) {
case Fixed:
return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value());
@@ -2416,7 +2792,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt
// FIXME: This calculation is not patched for block-flow yet.
// https://bugs.webkit.org/show_bug.cgi?id=46500
if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
- ASSERT(cb->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
RenderBlock* block = toRenderBlock(cb);
LogicalExtentComputedValues computedValues;
block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
@@ -2432,7 +2808,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt
if (isOutOfFlowPositioned())
availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
else {
- availableHeight = containingBlockLogicalHeightForContent();
+ availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
// It is necessary to use the border-box to match WinIE's broken
// box model. This is essential for sizing inside
// table cells using percentage heights.
@@ -2454,18 +2830,19 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt
case ViewportPercentageWidth:
case ViewportPercentageHeight:
case ViewportPercentageMin:
+ case ViewportPercentageMax:
return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, 0, view()));
default:
return intrinsicLogicalHeight();
}
}
-LayoutUnit RenderBox::availableLogicalHeight() const
+LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
{
- return availableLogicalHeightUsing(style()->logicalHeight());
+ return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType));
}
-LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const
+LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
{
if (isRenderView())
return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
@@ -2479,13 +2856,13 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const
return logicalHeight() - borderAndPaddingLogicalHeight();
}
- if (h.isPercent() && isOutOfFlowPositioned()) {
+ if (h.isPercent() && isOutOfFlowPositioned() && !isRenderFlowThread()) {
// FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
}
- LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(MainOrPreferredSize, h);
+ LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h);
if (heightIncludingScrollbar != -1)
return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
@@ -2500,7 +2877,12 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const
}
// FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
- return containingBlockLogicalHeightForContent();
+ LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
+ if (heightType == ExcludeMarginBorderPadding) {
+ // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
+ availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
+ }
+ return availableHeight;
}
void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const
@@ -2531,8 +2913,7 @@ void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containing
containingBlock->setMarginAfterForChild(this, marginAfter);
}
-LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region,
- LayoutUnit offsetFromLogicalTopOfFirstPage, bool checkForPerpendicularWritingMode) const
+LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, bool checkForPerpendicularWritingMode) const
{
// Container for position:fixed is the frame.
Frame* frame = view() ? view()->frame(): 0;
@@ -2544,29 +2925,28 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxMo
return containingBlockLogicalHeightForPositioned(containingBlock, false);
if (containingBlock->isBox()) {
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread)
+ return toRenderBox(containingBlock)->clientLogicalWidth();
+
const RenderBlock* cb = toRenderBlock(containingBlock);
- LayoutUnit result = cb->clientLogicalWidth();
- if (inRenderFlowThread()) {
- RenderBoxRegionInfo* boxInfo = 0;
- if (!region) {
- if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode)
- return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion();
- if (isWritingModeRoot()) {
- LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop();
- RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
- if (cbRegion) {
- cbRegion = cb->clampToStartAndEndRegions(cbRegion);
- boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
- }
+ RenderBoxRegionInfo* boxInfo = 0;
+ if (!region) {
+ if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode)
+ return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion();
+ if (isWritingModeRoot()) {
+ LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage();
+ RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
+ if (cbRegion) {
+ cbRegion = cb->clampToStartAndEndRegions(cbRegion);
+ boxInfo = cb->renderBoxRegionInfo(cbRegion);
}
- } else if (region && enclosingRenderFlowThread()->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
- RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
- boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop());
}
- if (boxInfo)
- return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
+ } else if (region && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
+ RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
+ boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
}
- return result;
+ return (boxInfo) ? max<LayoutUnit>(0, cb->clientLogicalWidth() - (cb->logicalWidth() - boxInfo->logicalWidth())) : cb->clientLogicalWidth();
}
ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
@@ -2600,12 +2980,13 @@ LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxM
return (view()->isHorizontalWritingMode() ? frameView->visibleHeight() : frameView->visibleWidth()) / frame->frameScaleFactor();
if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
- return containingBlockLogicalWidthForPositioned(containingBlock, 0, 0, false);
+ return containingBlockLogicalWidthForPositioned(containingBlock, 0, false);
if (containingBlock->isBox()) {
const RenderBlock* cb = toRenderBlock(containingBlock);
LayoutUnit result = cb->clientLogicalHeight();
- if (inRenderFlowThread() && containingBlock->isRenderFlowThread() && enclosingRenderFlowThread()->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode())
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread && containingBlock->isRenderFlowThread() && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode())
return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion();
return result;
}
@@ -2644,7 +3025,7 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
if (region && curr->isRenderBlock()) {
const RenderBlock* cb = toRenderBlock(curr);
region = cb->clampToStartAndEndRegions(region);
- RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->logicalTopForFlowThreadContent());
+ RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region);
if (boxInfo)
staticPosition += boxInfo->logicalLeft();
}
@@ -2661,10 +3042,10 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
if (curr == enclosingBox)
staticPosition -= enclosingBox->logicalWidth();
if (region && curr->isRenderBlock()) {
- const RenderBlock* cb = toRenderBlock(curr);
- region = cb->clampToStartAndEndRegions(region);
- RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->logicalTopForFlowThreadContent());
- if (boxInfo) {
+ const RenderBlock* cb = toRenderBlock(curr);
+ region = cb->clampToStartAndEndRegions(region);
+ RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region);
+ if (boxInfo) {
if (curr != containerBlock)
staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth());
if (curr == enclosingBox)
@@ -2679,17 +3060,13 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
}
}
-void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
{
if (isReplaced()) {
- // FIXME: For regions with width auto, we want to compute width using the normal block sizing code.
- // For now, regions are replaced elements and this code can be removed once the RenderRegion
- // will inherit from RenderBlock instead of RenderReplaced.
- // (see https://bugs.webkit.org/show_bug.cgi?id=74132 )
- if (!isRenderRegion() || (isRenderRegion() && shouldComputeSizeAsReplaced())) {
- computePositionedLogicalWidthReplaced(computedValues); // FIXME: Patch for regions when we add replaced element support.
- return;
- }
+ // FIXME: Positioned replaced elements inside a flow thread are not working properly
+ // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ).
+ computePositionedLogicalWidthReplaced(computedValues);
+ return;
}
// QUESTIONS
@@ -2712,7 +3089,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu
// relative positioned inline.
const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
- const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region, offsetFromLogicalTopOfFirstPage);
+ const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region);
// Use the container block's direction except when calculating the static distance
// This conforms with the reference results for abspos-replaced-width-margin-000.htm
@@ -2756,7 +3133,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu
computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region);
// Calculate constraint equation values for 'width' case.
- computePositionedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth(), containerBlock, containerDirection,
+ computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
containerLogicalWidth, bordersPlusPadding,
logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
computedValues);
@@ -2765,7 +3142,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu
if (!style()->logicalMaxWidth().isUndefined()) {
LogicalExtentComputedValues maxValues;
- computePositionedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth(), containerBlock, containerDirection,
+ computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
containerLogicalWidth, bordersPlusPadding,
logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
maxValues);
@@ -2779,10 +3156,10 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu
}
// Calculate constraint equation values for 'min-width' case.
- if (!style()->logicalMinWidth().isZero()) {
+ if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) {
LogicalExtentComputedValues minValues;
- computePositionedLogicalWidthUsing(MinSize, style()->logicalMinWidth(), containerBlock, containerDirection,
+ computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
containerLogicalWidth, bordersPlusPadding,
logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
minValues);
@@ -2795,24 +3172,20 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu
}
}
- if (stretchesToMinIntrinsicLogicalWidth() && computedValues.m_extent < minPreferredLogicalWidth() - bordersPlusPadding) {
- computePositionedLogicalWidthUsing(MainOrPreferredSize, Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
- containerLogicalWidth, bordersPlusPadding,
- logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
- computedValues);
- }
-
computedValues.m_extent += bordersPlusPadding;
// Adjust logicalLeft if we need to for the flipped version of our writing mode in regions.
- if (inRenderFlowThread() && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
+ // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
+ ASSERT(containerBlock->canHaveBoxInfoInRegion());
LayoutUnit logicalLeftPos = computedValues.m_position;
const RenderBlock* cb = toRenderBlock(containerBlock);
- LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop();
+ LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage();
RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
if (cbRegion) {
cbRegion = cb->clampToStartAndEndRegions(cbRegion);
- RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
+ RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion);
if (boxInfo) {
logicalLeftPos += boxInfo->logicalLeft();
computedValues.m_position = logicalLeftPos;
@@ -2832,13 +3205,13 @@ static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const
logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
}
-void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
+void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
LogicalExtentComputedValues& computedValues) const
{
- if (widthSizeType == MinSize && logicalWidth.isAuto())
- logicalWidth = Length(0, Fixed);
+ if (logicalWidth.isIntrinsic())
+ logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
// 'left' and 'right' cannot both be 'auto' because one would of been
// converted to the static position already
@@ -2846,6 +3219,8 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt
LayoutUnit logicalLeftValue = 0;
+ const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
+
bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
bool logicalLeftIsAuto = logicalLeft.isAuto();
bool logicalRightIsAuto = logicalRight.isAuto();
@@ -2893,16 +3268,16 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt
}
} else if (marginLogicalLeft.isAuto()) {
// Solve for left margin
- marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
} else if (marginLogicalRight.isAuto()) {
// Solve for right margin
- marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
+ marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
} else {
// Over-constrained, solve for left if direction is RTL
- marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
- marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
+ marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
// Use the containing block's direction rather than the parent block's
// per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
@@ -2952,8 +3327,8 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt
// because the value is not used for any further calculations.
// Calculate margins, 'auto' margins are ignored.
- marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
- marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
+ marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
@@ -3030,14 +3405,8 @@ static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom
void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const
{
if (isReplaced()) {
- // FIXME: For regions with height auto, we want to compute width using the normal block sizing code.
- // For now, regions are replaced elements and this code can be removed once the RenderRegion
- // will inherit from RenderBlock instead of RenderReplaced.
- // (see https://bugs.webkit.org/show_bug.cgi?id=74132 )
- if (!isRenderRegion() || (isRenderRegion() && shouldComputeSizeAsReplaced())) {
- computePositionedLogicalHeightReplaced(computedValues);
- return;
- }
+ computePositionedLogicalHeightReplaced(computedValues);
+ return;
}
// The following is based off of the W3C Working Draft from April 11, 2006 of
@@ -3082,7 +3451,7 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp
// Calculate constraint equation values for 'height' case.
LayoutUnit logicalHeight = computedValues.m_extent;
- computePositionedLogicalHeightUsing(MainOrPreferredSize, styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
+ computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
computedValues);
@@ -3093,7 +3462,7 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp
if (!styleToUse->logicalMaxHeight().isUndefined()) {
LogicalExtentComputedValues maxValues;
- computePositionedLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
+ computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
maxValues);
@@ -3109,7 +3478,7 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp
if (!styleToUse->logicalMinHeight().isZero()) {
LogicalExtentComputedValues minValues;
- computePositionedLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
+ computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
minValues);
@@ -3125,14 +3494,17 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp
computedValues.m_extent += bordersPlusPadding;
// Adjust logicalTop if we need to for perpendicular writing modes in regions.
- if (inRenderFlowThread() && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode()) {
+ // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
+ ASSERT(containerBlock->canHaveBoxInfoInRegion());
LayoutUnit logicalTopPos = computedValues.m_position;
const RenderBlock* cb = toRenderBlock(containerBlock);
LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft();
RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
if (cbRegion) {
cbRegion = cb->clampToStartAndEndRegions(cbRegion);
- RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
+ RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion);
if (boxInfo) {
logicalTopPos += boxInfo->logicalLeft();
computedValues.m_position = logicalTopPos;
@@ -3163,14 +3535,11 @@ static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const R
}
}
-void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
+void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
LogicalExtentComputedValues& computedValues) const
{
- if (heightSizeType == MinSize && logicalHeightLength.isAuto())
- logicalHeightLength = Length(0, Fixed);
-
// 'top' and 'bottom' cannot both be 'auto' because 'top would of been
// converted to the static position in computePositionedLogicalHeight()
ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
@@ -3178,6 +3547,8 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len
LayoutUnit logicalHeightValue;
LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
+ const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
+
LayoutUnit logicalTopValue = 0;
bool logicalHeightIsAuto = logicalHeightLength.isAuto();
@@ -3216,16 +3587,16 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len
computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences
} else if (marginBefore.isAuto()) {
// Solve for top margin
- computedValues.m_margins.m_after = valueForLength(marginAfter, containerLogicalHeight, renderView);
+ computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after;
} else if (marginAfter.isAuto()) {
// Solve for bottom margin
- computedValues.m_margins.m_before = valueForLength(marginBefore, containerLogicalHeight, renderView);
+ computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before;
} else {
// Over-constrained, (no need solve for bottom)
- computedValues.m_margins.m_before = valueForLength(marginBefore, containerLogicalHeight, renderView);
- computedValues.m_margins.m_after = valueForLength(marginAfter, containerLogicalHeight, renderView);
+ computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
+ computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
}
} else {
/*--------------------------------------------------------------------*\
@@ -3254,8 +3625,8 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len
// because the value is not used for any further calculations.
// Calculate margins, 'auto' margins are ignored.
- computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerLogicalHeight, renderView);
- computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerLogicalHeight, renderView);
+ computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
+ computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
@@ -3302,6 +3673,7 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue
const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
+ const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
// To match WinIE, in quirks mode use the parent's 'direction' property
// instead of the the container block's.
@@ -3386,28 +3758,28 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue
* that value.
\*-----------------------------------------------------------------------*/
} else if (logicalLeft.isAuto()) {
- marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
- marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
+ marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
// Solve for 'left'
logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
} else if (logicalRight.isAuto()) {
- marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
- marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
+ marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
// Solve for 'right'
logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
} else if (marginLogicalLeft.isAuto()) {
- marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
// Solve for 'margin-left'
marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
} else if (marginLogicalRight.isAuto()) {
- marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
+ marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
@@ -3415,8 +3787,8 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue
marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
} else {
// Nothing is 'auto', just calculate the values.
- marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
- marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
+ marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
+ marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
// If the containing block is right-to-left, then push the left position as far to the right as possible
@@ -3470,6 +3842,7 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu
const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
+ const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
// Variables to solve.
Length marginBefore = style()->marginBefore();
@@ -3536,29 +3909,29 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu
* for that value.
\*-----------------------------------------------------------------------*/
} else if (logicalTop.isAuto()) {
- marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
- marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
+ marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
+ marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
// Solve for 'top'
logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
} else if (logicalBottom.isAuto()) {
- marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
- marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
+ marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
+ marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
// Solve for 'bottom'
// NOTE: It is not necessary to solve for 'bottom' because we don't ever
// use the value.
} else if (marginBefore.isAuto()) {
- marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
+ marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
// Solve for 'margin-top'
marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
} else if (marginAfter.isAuto()) {
- marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
+ marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
@@ -3566,8 +3939,8 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu
marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
} else {
// Nothing is 'auto', just calculate the values.
- marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
- marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
+ marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
+ marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
// NOTE: It is not necessary to solve for 'bottom' because we don't ever
// use the value.
@@ -3594,7 +3967,6 @@ LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit
// They never refer to children.
// FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
- // FIXME: What about border and padding?
LayoutRect rect(location(), LayoutSize(caretWidth, height()));
bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
@@ -3626,6 +3998,14 @@ LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit
// Move to local coords
rect.moveBy(-location());
+ // FIXME: Border/padding should be added for all elements but this workaround
+ // is needed because we use offsets inside an "atomic" element to represent
+ // positions before and after the element in deprecated editing offsets.
+ if (node() && !(editingIgnoresContent(node()) || isTableElement(node()))) {
+ rect.setX(rect.x() + borderLeft() + paddingLeft());
+ rect.setY(rect.y() + paddingTop() + borderTop());
+ }
+
if (!isHorizontalWritingMode())
return rect.transposedRect();
@@ -3636,16 +4016,16 @@ VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point)
{
// no children...return this render object's element, if there is one, and offset 0
if (!firstChild())
- return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position());
+ return createVisiblePosition(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position());
- if (isTable() && node()) {
+ if (isTable() && nonPseudoNode()) {
LayoutUnit right = contentWidth() + borderAndPaddingWidth();
LayoutUnit bottom = contentHeight() + borderAndPaddingHeight();
if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) {
if (point.x() <= right / 2)
- return createVisiblePosition(firstPositionInOrBeforeNode(node()));
- return createVisiblePosition(lastPositionInOrAfterNode(node()));
+ return createVisiblePosition(firstPositionInOrBeforeNode(nonPseudoNode()));
+ return createVisiblePosition(lastPositionInOrAfterNode(nonPseudoNode()));
}
}
@@ -3713,7 +4093,7 @@ VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point)
if (closestRenderer)
return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset());
- return createVisiblePosition(firstPositionInOrBeforeNode(node()));
+ return createVisiblePosition(firstPositionInOrBeforeNode(nonPseudoNode()));
}
bool RenderBox::shrinkToAvoidFloats() const
@@ -3728,7 +4108,7 @@ bool RenderBox::shrinkToAvoidFloats() const
bool RenderBox::avoidsFloats() const
{
- return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isDeprecatedFlexItem();
+ return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated();
}
void RenderBox::addVisualEffectOverflow()
@@ -3778,6 +4158,10 @@ void RenderBox::addVisualEffectOverflow()
void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
{
+ // Never allow flow threads to propagate overflow up to a parent.
+ if (child->isRenderFlowThread())
+ return;
+
// Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then
// its overflow is internal to it, and we don't care about it. layoutOverflowRectForPropagation takes care of this
// and just propagates the border box rect instead.
@@ -3810,7 +4194,7 @@ void RenderBox::addLayoutOverflow(const LayoutRect& rect)
bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
if (isFlexibleBox() && style()->isReverseFlexDirection()) {
- RenderFlexibleBox* flexibleBox = static_cast<RenderFlexibleBox*>(this);
+ RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this);
if (flexibleBox->isHorizontalFlow())
hasLeftOverflow = true;
else
@@ -3857,19 +4241,6 @@ void RenderBox::addVisualOverflow(const LayoutRect& rect)
m_overflow->addVisualOverflow(rect);
}
-void RenderBox::clearLayoutOverflow()
-{
- if (!m_overflow)
- return;
-
- if (visualOverflowRect() == borderBoxRect()) {
- m_overflow.clear();
- return;
- }
-
- m_overflow->setLayoutOverflow(borderBoxRect());
-}
-
inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
{
return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned());
@@ -4168,6 +4539,13 @@ bool RenderBox::hasRelativeLogicalHeight() const
|| style()->logicalMaxHeight().isPercent();
}
+bool RenderBox::hasViewportPercentageLogicalHeight() const
+{
+ return style()->logicalHeight().isViewportPercentage()
+ || style()->logicalMinHeight().isViewportPercentage()
+ || style()->logicalMaxHeight().isViewportPercentage();
+}
+
static void markBoxForRelayoutAfterSplit(RenderBox* box)
{
// FIXME: The table code should handle that automatically. If not,
@@ -4218,4 +4596,14 @@ RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChil
return beforeChild;
}
+LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const
+{
+ LayoutState* layoutState = view()->layoutState();
+ if ((layoutState && !layoutState->isPaginated()) || (!layoutState && !flowThreadContainingBlock()))
+ return 0;
+
+ RenderBlock* containerBlock = containingBlock();
+ return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h
index c1de3e736..9756f9e8e 100644
--- a/Source/WebCore/rendering/RenderBox.h
+++ b/Source/WebCore/rendering/RenderBox.h
@@ -26,6 +26,9 @@
#include "RenderBoxModelObject.h"
#include "RenderOverflow.h"
#include "ScrollTypes.h"
+#if ENABLE(CSS_SHAPES)
+#include "ShapeOutsideInfo.h"
+#endif
namespace WebCore {
@@ -34,17 +37,21 @@ class RenderRegion;
struct PaintInfo;
enum SizeType { MainOrPreferredSize, MinSize, MaxSize };
-
+enum AvailableLogicalHeightType { ExcludeMarginBorderPadding, IncludeMarginBorderPadding };
enum OverlayScrollbarSizeRelevancy { IgnoreOverlayScrollbarSize, IncludeOverlayScrollbarSize };
+enum ShouldComputePreferred { ComputeActual, ComputePreferred };
+
class RenderBox : public RenderBoxModelObject {
public:
- RenderBox(Node*);
+ explicit RenderBox(ContainerNode*);
virtual ~RenderBox();
// hasAutoZIndex only returns true if the element is positioned or a flex-item since
// position:static elements that are not flex-items get their z-index coerced to auto.
- virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() || !style()->hasAutoZIndex(); }
+ virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() || !style()->hasAutoZIndex() || isFloatingWithShapeOutside(); }
+
+ virtual bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const OVERRIDE;
// Use this with caution! No type checking is done!
RenderBox* firstChildBox() const;
@@ -75,8 +82,9 @@ public:
LayoutUnit logicalWidth() const { return style()->isHorizontalWritingMode() ? width() : height(); }
LayoutUnit logicalHeight() const { return style()->isHorizontalWritingMode() ? height() : width(); }
- LayoutUnit constrainLogicalWidthInRegionByMinMax(LayoutUnit, LayoutUnit, RenderBlock*, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0) const;
+ LayoutUnit constrainLogicalWidthInRegionByMinMax(LayoutUnit, LayoutUnit, RenderBlock*, RenderRegion* = 0) const;
LayoutUnit constrainLogicalHeightByMinMax(LayoutUnit) const;
+ LayoutUnit constrainContentBoxLogicalHeightByMinMax(LayoutUnit) const;
int pixelSnappedLogicalHeight() const { return style()->isHorizontalWritingMode() ? pixelSnappedHeight() : pixelSnappedWidth(); }
int pixelSnappedLogicalWidth() const { return style()->isHorizontalWritingMode() ? pixelSnappedWidth() : pixelSnappedHeight(); }
@@ -139,6 +147,7 @@ public:
void setFrameRect(const LayoutRect& rect) { m_frameRect = rect; }
LayoutRect borderBoxRect() const { return LayoutRect(LayoutPoint(), size()); }
+ LayoutRect paddingBoxRect() const { return LayoutRect(borderLeft(), borderTop(), contentWidth() + paddingLeft() + paddingRight(), contentHeight() + paddingTop() + paddingBottom()); }
IntRect pixelSnappedBorderBoxRect() const { return IntRect(IntPoint(), m_frameRect.pixelSnappedSize()); }
virtual IntRect borderBoundingBox() const { return pixelSnappedBorderBoxRect(); }
@@ -155,7 +164,7 @@ public:
// Bounds of the outline box in absolute coords. Respects transforms
virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* /*repaintContainer*/, const RenderGeometryMap*) const OVERRIDE;
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
// Use this with caution! No type checking is done!
RenderBox* previousSiblingBox() const;
@@ -167,8 +176,6 @@ public:
// respectively are flipped when compared to their physical counterparts. For example minX is on the left in vertical-lr,
// but it is on the right in vertical-rl.
LayoutRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : clientBoxRect(); }
- IntRect pixelSnappedLayoutOverflowRect() const { return pixelSnappedIntRect(layoutOverflowRect()); }
- LayoutSize maxLayoutOverflow() const { return LayoutSize(layoutOverflowRect().maxX(), layoutOverflowRect().maxY()); }
LayoutUnit logicalLeftLayoutOverflow() const { return style()->isHorizontalWritingMode() ? layoutOverflowRect().x() : layoutOverflowRect().y(); }
LayoutUnit logicalRightLayoutOverflow() const { return style()->isHorizontalWritingMode() ? layoutOverflowRect().maxX() : layoutOverflowRect().maxY(); }
@@ -184,7 +191,6 @@ public:
void addVisualEffectOverflow();
void addOverflowFromChild(RenderBox* child) { addOverflowFromChild(child, child->locationOffset()); }
void addOverflowFromChild(RenderBox* child, const LayoutSize& delta);
- void clearLayoutOverflow();
void updateLayerTransform();
@@ -198,9 +204,8 @@ public:
virtual LayoutUnit offsetWidth() const { return width(); }
virtual LayoutUnit offsetHeight() const { return height(); }
- // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
- virtual int pixelSnappedOffsetWidth() const { return pixelSnappedWidth(); }
- virtual int pixelSnappedOffsetHeight() const { return pixelSnappedHeight(); }
+ virtual int pixelSnappedOffsetWidth() const OVERRIDE;
+ virtual int pixelSnappedOffsetHeight() const OVERRIDE;
// More IE extensions. clientWidth and clientHeight represent the interior of an object
// excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth.
@@ -312,6 +317,7 @@ public:
void setOverrideContainingBlockContentLogicalWidth(LayoutUnit);
void setOverrideContainingBlockContentLogicalHeight(LayoutUnit);
void clearContainingBlockOverrideSize();
+ void clearOverrideContainingBlockContentLogicalHeight();
virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const;
@@ -320,8 +326,6 @@ public:
LayoutUnit adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const;
LayoutUnit adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const;
- virtual void borderFitAdjust(LayoutRect&) const { } // Shrink the box in which the border paints if border-fit is set.
-
struct ComputedMarginValues {
ComputedMarginValues()
: m_before(0)
@@ -355,8 +359,9 @@ public:
void computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock);
enum RenderBoxRegionInfoFlags { CacheRenderBoxRegionInfo, DoNotCacheRenderBoxRegionInfo };
- LayoutRect borderBoxRectInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage = 0, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const;
+ LayoutRect borderBoxRectInRegion(RenderRegion*, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const;
void clearRenderBoxRegionInfo();
+ virtual LayoutUnit offsetFromLogicalTopOfFirstPage() const;
void positionLineBox(InlineBox*);
@@ -372,26 +377,26 @@ public:
virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE;
virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE;
-
- virtual void repaintDuringLayoutIfMoved(const LayoutRect&);
+ void repaintDuringLayoutIfMoved(const LayoutRect&);
+ virtual void repaintOverhangingFloats(bool paintAllDescendants);
virtual LayoutUnit containingBlockLogicalWidthForContent() const;
- LayoutUnit containingBlockLogicalHeightForContent() const;
+ LayoutUnit containingBlockLogicalHeightForContent(AvailableLogicalHeightType) const;
- LayoutUnit containingBlockLogicalWidthForContentInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const;
- LayoutUnit containingBlockAvailableLineWidthInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const;
+ LayoutUnit containingBlockLogicalWidthForContentInRegion(RenderRegion*) const;
+ LayoutUnit containingBlockAvailableLineWidthInRegion(RenderRegion*) const;
LayoutUnit perpendicularContainingBlockLogicalHeight() const;
virtual void updateLogicalWidth();
virtual void updateLogicalHeight();
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const;
- RenderBoxRegionInfo* renderBoxRegionInfo(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const;
- void computeLogicalWidthInRegion(LogicalExtentComputedValues&, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0) const;
+ RenderBoxRegionInfo* renderBoxRegionInfo(RenderRegion*, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const;
+ void computeLogicalWidthInRegion(LogicalExtentComputedValues&, RenderRegion* = 0) const;
bool stretchesToViewport() const
{
- return document()->inQuirksMode() && style()->logicalHeight().isAuto() && !isFloatingOrOutOfFlowPositioned() && (isRoot() || isBody()) && !document()->shouldDisplaySeamlesslyWithParent();
+ return document()->inQuirksMode() && style()->logicalHeight().isAuto() && !isFloatingOrOutOfFlowPositioned() && (isRoot() || isBody()) && !document()->shouldDisplaySeamlesslyWithParent() && !isInline();
}
virtual LayoutSize intrinsicSize() const { return LayoutSize(); }
@@ -401,20 +406,19 @@ public:
// Whether or not the element shrinks to its intrinsic width (rather than filling the width
// of a containing block). HTML4 buttons, <select>s, <input>s, legends, and floating/compact elements do this.
bool sizesLogicalWidthToFitContent(SizeType) const;
- virtual bool stretchesToMinIntrinsicLogicalWidth() const { return false; }
- LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const;
+ LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion*) const;
- LayoutUnit computeLogicalWidthInRegionUsing(SizeType, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const;
- LayoutUnit computeLogicalHeightUsing(SizeType, const Length& height) const;
- LayoutUnit computeContentLogicalHeight(SizeType, const Length& height);
- LayoutUnit computeContentAndScrollbarLogicalHeightUsing(SizeType, const Length& height) const;
- LayoutUnit computeReplacedLogicalWidthUsing(SizeType, Length width) const;
- LayoutUnit computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, bool includeMaxWidth = true) const;
- LayoutUnit computeReplacedLogicalHeightUsing(SizeType, Length height) const;
+ LayoutUnit computeLogicalWidthInRegionUsing(SizeType, Length logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock, RenderRegion*) const;
+ LayoutUnit computeLogicalHeightUsing(const Length& height) const;
+ LayoutUnit computeContentLogicalHeight(const Length& height) const;
+ LayoutUnit computeContentAndScrollbarLogicalHeightUsing(const Length& height) const;
+ LayoutUnit computeReplacedLogicalWidthUsing(Length width) const;
+ LayoutUnit computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred = ComputeActual) const;
+ LayoutUnit computeReplacedLogicalHeightUsing(Length height) const;
LayoutUnit computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const;
- virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const;
virtual LayoutUnit computeReplacedLogicalHeight() const;
static bool percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool outOfFlowPositioned);
@@ -422,24 +426,29 @@ public:
// Block flows subclass availableWidth/Height to handle multi column layout (shrinking the width/height available to children when laying out.)
virtual LayoutUnit availableLogicalWidth() const { return contentLogicalWidth(); }
- virtual LayoutUnit availableLogicalHeight() const;
- LayoutUnit availableLogicalHeightUsing(const Length&) const;
+ virtual LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const;
+ LayoutUnit availableLogicalHeightUsing(const Length&, AvailableLogicalHeightType) const;
// There are a few cases where we need to refer specifically to the available physical width and available physical height.
// Relative positioning is one of those cases, since left/top offsets are physical.
- LayoutUnit availableWidth() const { return style()->isHorizontalWritingMode() ? availableLogicalWidth() : availableLogicalHeight(); }
- LayoutUnit availableHeight() const { return style()->isHorizontalWritingMode() ? availableLogicalHeight() : availableLogicalWidth(); }
+ LayoutUnit availableWidth() const { return style()->isHorizontalWritingMode() ? availableLogicalWidth() : availableLogicalHeight(IncludeMarginBorderPadding); }
+ LayoutUnit availableHeight() const { return style()->isHorizontalWritingMode() ? availableLogicalHeight(IncludeMarginBorderPadding) : availableLogicalWidth(); }
virtual int verticalScrollbarWidth() const;
int horizontalScrollbarHeight() const;
+ int instrinsicScrollbarLogicalWidth() const;
int scrollbarLogicalHeight() const { return style()->isHorizontalWritingMode() ? horizontalScrollbarHeight() : verticalScrollbarWidth(); }
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
bool canBeScrolledAndHasScrollableArea() const;
virtual bool canBeProgramaticallyScrolled() const;
- virtual void autoscroll();
+ virtual void autoscroll(const IntPoint&);
+ bool canAutoscroll() const;
+ IntSize calculateAutoscrollDirection(const IntPoint& windowPoint) const;
+ static RenderBox* findAutoscrollable(RenderObject*);
virtual void stopAutoscroll() { }
virtual void panScroll(const IntPoint&);
+
bool hasAutoVerticalScrollbar() const { return hasOverflowClip() && (style()->overflowY() == OAUTO || style()->overflowY() == OOVERLAY); }
bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); }
bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); }
@@ -452,7 +461,8 @@ public:
virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0);
- virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize);
+ virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, PaintPhase = PaintPhaseBlockBackground);
+ virtual LayoutRect overflowClipRectForChildLayers(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) { return overflowClipRect(location, region, relevancy); }
LayoutRect clipRect(const LayoutPoint& location, RenderRegion*);
virtual bool hasControlClip() const { return false; }
virtual LayoutRect controlClipRect(const LayoutPoint&) const { return LayoutRect(); }
@@ -496,6 +506,7 @@ public:
bool isWritingModeRoot() const { return !parent() || parent()->style()->writingMode() != style()->writingMode(); }
bool isDeprecatedFlexItem() const { return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && parent()->isDeprecatedFlexibleBox(); }
+ bool isFlexItemIncludingDeprecated() const { return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && parent()->isFlexibleBoxIncludingDeprecated(); }
virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE;
@@ -521,7 +532,7 @@ public:
LayoutRect logicalLayoutOverflowRectForPropagation(RenderStyle*) const;
LayoutRect layoutOverflowRectForPropagation(RenderStyle*) const;
- RenderOverflow* hasRenderOverflow() const { return m_overflow.get(); }
+ bool hasRenderOverflow() const { return m_overflow; }
bool hasVisualOverflow() const { return m_overflow && !borderBoxRect().contains(m_overflow->visualOverflowRect()); }
virtual bool needsPreferredWidthsRecalculation() const;
@@ -533,27 +544,26 @@ public:
virtual bool hasRelativeDimensions() const;
virtual bool hasRelativeLogicalHeight() const;
+ virtual bool hasViewportPercentageLogicalHeight() const;
bool hasHorizontalLayoutOverflow() const
{
- if (RenderOverflow* overflow = hasRenderOverflow()) {
- LayoutRect layoutOverflowRect = overflow->layoutOverflowRect();
- flipForWritingMode(layoutOverflowRect);
- return layoutOverflowRect.x() < x() || layoutOverflowRect.maxX() > x() + logicalWidth();
- }
+ if (!m_overflow)
+ return false;
- return false;
+ LayoutRect layoutOverflowRect = m_overflow->layoutOverflowRect();
+ flipForWritingMode(layoutOverflowRect);
+ return layoutOverflowRect.x() < x() || layoutOverflowRect.maxX() > x() + logicalWidth();
}
bool hasVerticalLayoutOverflow() const
{
- if (RenderOverflow* overflow = hasRenderOverflow()) {
- LayoutRect layoutOverflowRect = overflow->layoutOverflowRect();
- flipForWritingMode(layoutOverflowRect);
- return layoutOverflowRect.y() < y() || layoutOverflowRect.maxY() > y() + logicalHeight();
- }
+ if (!m_overflow)
+ return false;
- return false;
+ LayoutRect layoutOverflowRect = m_overflow->layoutOverflowRect();
+ flipForWritingMode(layoutOverflowRect);
+ return layoutOverflowRect.y() < y() || layoutOverflowRect.maxY() > y() + logicalHeight();
}
virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject*) const
@@ -564,6 +574,13 @@ public:
bool hasSameDirectionAs(const RenderBox* object) const { return style()->direction() == object->style()->direction(); }
+#if ENABLE(CSS_SHAPES)
+ ShapeOutsideInfo* shapeOutsideInfo() const
+ {
+ return isFloatingWithShapeOutside() && ShapeOutsideInfo::isEnabledFor(this) ? ShapeOutsideInfo::info(this) : 0;
+ }
+#endif
+
protected:
virtual void willBeDestroyed();
@@ -571,7 +588,11 @@ protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
virtual void updateFromStyle() OVERRIDE;
- virtual bool backgroundIsObscured() const { return false; }
+ // Returns false if it could not cheaply compute the extent (e.g. fixed background), in which case the returned rect may be incorrect.
+ bool getBackgroundPaintedExtent(LayoutRect&) const;
+ virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const;
+ virtual bool computeBackgroundIsKnownToBeObscured() OVERRIDE;
+
void paintBackground(const PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone);
void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance, CompositeOperator, RenderObject* backgroundObject);
@@ -580,17 +601,19 @@ protected:
void paintMaskImages(const PaintInfo&, const LayoutRect&);
BackgroundBleedAvoidance determineBackgroundBleedAvoidance(GraphicsContext*) const;
- bool backgroundIsSingleOpaqueLayer() const;
+ bool backgroundHasOpaqueTopLayer() const;
#if PLATFORM(MAC)
void paintCustomHighlight(const LayoutPoint&, const AtomicString& type, bool behindText);
#endif
- void computePositionedLogicalWidth(LogicalExtentComputedValues&, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0) const;
+ void computePositionedLogicalWidth(LogicalExtentComputedValues&, RenderRegion* = 0) const;
+
+ LayoutUnit computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const;
virtual bool shouldComputeSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); }
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject*, RenderGeometryMap&) const OVERRIDE;
virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const;
@@ -599,6 +622,10 @@ protected:
RenderObject* splitAnonymousBoxesAroundChild(RenderObject* beforeChild);
private:
+#if ENABLE(CSS_SHAPES)
+ void updateShapeOutsideInfoAfterStyleChange(const ShapeValue* shapeOutside, const ShapeValue* oldShapeOutside);
+#endif
+
bool fixedElementLaysOutRelativeToFrame(Frame*, FrameView*) const;
bool includeVerticalScrollbarSize() const;
@@ -609,16 +636,17 @@ private:
bool skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const;
- LayoutUnit containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* = 0,
- LayoutUnit offsetFromLogicalTopOfFirstPage = 0, bool checkForPerpendicularWritingMode = true) const;
+ LayoutUnit containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* = 0, bool checkForPerpendicularWritingMode = true) const;
LayoutUnit containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode = true) const;
+ LayoutUnit viewLogicalHeightForPercentages() const;
+
void computePositionedLogicalHeight(LogicalExtentComputedValues&) const;
- void computePositionedLogicalWidthUsing(SizeType, Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
+ void computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
LogicalExtentComputedValues&) const;
- void computePositionedLogicalHeightUsing(SizeType, Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
+ void computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
Length logicalTop, Length logicalBottom, Length marginLogicalTop, Length marginLogicalBottom,
LogicalExtentComputedValues&) const;
@@ -626,6 +654,11 @@ private:
void computePositionedLogicalHeightReplaced(LogicalExtentComputedValues&) const;
void computePositionedLogicalWidthReplaced(LogicalExtentComputedValues&) const;
+ LayoutUnit fillAvailableMeasure(LayoutUnit availableLogicalWidth) const;
+ LayoutUnit fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const;
+
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const;
+
// This function calculates the minimum and maximum preferred widths for an object.
// These values are used in shrink-to-fit layout systems.
// These include tables, positioned objects, floats and flexible boxes.
@@ -659,13 +692,13 @@ private:
inline RenderBox* toRenderBox(RenderObject* object)
{
- ASSERT(!object || object->isBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBox());
return static_cast<RenderBox*>(object);
}
inline const RenderBox* toRenderBox(const RenderObject* object)
{
- ASSERT(!object || object->isBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBox());
return static_cast<const RenderBox*>(object);
}
diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp
index 6d63169b5..9d156ee37 100644
--- a/Source/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp
@@ -35,11 +35,12 @@
#include "RenderBlock.h"
#include "RenderInline.h"
#include "RenderLayer.h"
+#include "RenderNamedFlowThread.h"
+#include "RenderRegion.h"
#include "RenderView.h"
#include "ScrollingConstraints.h"
#include "Settings.h"
#include "TransformState.h"
-#include <wtf/CurrentTime.h>
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerBacking.h"
@@ -90,11 +91,13 @@ private:
ObjectLayerSizeMap m_objectLayerSizeMap;
Timer<ImageQualityController> m_timer;
bool m_animatedResizeIsActive;
+ bool m_liveResizeOptimizationIsActive;
};
ImageQualityController::ImageQualityController()
: m_timer(this, &ImageQualityController::highQualityRepaintTimerFired)
, m_animatedResizeIsActive(false)
+ , m_liveResizeOptimizationIsActive(false)
{
}
@@ -129,11 +132,22 @@ void ImageQualityController::objectDestroyed(RenderBoxModelObject* object)
void ImageQualityController::highQualityRepaintTimerFired(Timer<ImageQualityController>*)
{
- if (m_animatedResizeIsActive) {
- m_animatedResizeIsActive = false;
- for (ObjectLayerSizeMap::iterator it = m_objectLayerSizeMap.begin(); it != m_objectLayerSizeMap.end(); ++it)
- it->key->repaint();
+ if (!m_animatedResizeIsActive && !m_liveResizeOptimizationIsActive)
+ return;
+ m_animatedResizeIsActive = false;
+
+ for (ObjectLayerSizeMap::iterator it = m_objectLayerSizeMap.begin(); it != m_objectLayerSizeMap.end(); ++it) {
+ if (Frame* frame = it->key->document()->frame()) {
+ // If this renderer's containing FrameView is in live resize, punt the timer and hold back for now.
+ if (frame->view() && frame->view()->inLiveResize()) {
+ restartTimer();
+ return;
+ }
+ }
+ it->key->repaint();
}
+
+ m_liveResizeOptimizationIsActive = false;
}
void ImageQualityController::restartTimer()
@@ -148,9 +162,16 @@ bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, R
if (!image || !image->isBitmapImage() || context->paintingDisabled())
return false;
- if (object->style()->imageRendering() == ImageRenderingOptimizeContrast)
+ switch (object->style()->imageRendering()) {
+ case ImageRenderingOptimizeSpeed:
+ case ImageRenderingCrispEdges:
return true;
-
+ case ImageRenderingOptimizeQuality:
+ return false;
+ case ImageRenderingAuto:
+ break;
+ }
+
// Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
// is actually being scaled.
IntSize imageSize(image->width(), image->height());
@@ -168,6 +189,22 @@ bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, R
}
}
+ // If the containing FrameView is being resized, paint at low quality until resizing is finished.
+ if (Frame* frame = object->document()->frame()) {
+ bool frameViewIsCurrentlyInLiveResize = frame->view() && frame->view()->inLiveResize();
+ if (frameViewIsCurrentlyInLiveResize) {
+ set(object, innerMap, layer, size);
+ restartTimer();
+ m_liveResizeOptimizationIsActive = true;
+ return true;
+ }
+ if (m_liveResizeOptimizationIsActive) {
+ // Live resize has ended, paint in HQ and remove this object from the list.
+ removeLayer(object, innerMap, layer);
+ return false;
+ }
+ }
+
const AffineTransform& currentTransform = context->getCTM();
bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped();
if (!contextIsScaled && size == imageSize) {
@@ -310,7 +347,7 @@ bool RenderBoxModelObject::shouldPaintAtLowQuality(GraphicsContext* context, Ima
return imageQualityController()->shouldPaintAtLowQuality(context, this, image, layer, size);
}
-RenderBoxModelObject::RenderBoxModelObject(Node* node)
+RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node)
: RenderLayerModelObject(node)
{
}
@@ -331,15 +368,6 @@ void RenderBoxModelObject::willBeDestroyed()
// A continuation of this RenderObject should be destroyed at subclasses.
ASSERT(!continuation());
- if (isPositioned()) {
- if (RenderView* view = this->view()) {
- if (FrameView* frameView = view->frameView()) {
- if (style()->hasViewportConstrainedPosition())
- frameView->removeViewportConstrainedObject(this);
- }
- }
- }
-
// If this is a first-letter object with a remaining text fragment then the
// entry needs to be cleared from the map.
if (firstLetterRemainingText())
@@ -357,8 +385,7 @@ void RenderBoxModelObject::updateFromStyle()
RenderStyle* styleToUse = style();
setHasBoxDecorations(hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow());
setInline(styleToUse->isDisplayInlineType());
- setRelPositioned(styleToUse->position() == RelativePosition);
- setStickyPositioned(styleToUse->position() == StickyPosition);
+ setPositionState(styleToUse->position());
setHorizontalWritingMode(styleToUse->isHorizontalWritingMode());
}
@@ -378,6 +405,37 @@ static LayoutSize accumulateInFlowPositionOffsets(const RenderObject* child)
return offset;
}
+bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const
+{
+ Length logicalHeightLength = style()->logicalHeight();
+ if (logicalHeightLength.isAuto())
+ return true;
+
+ // For percentage heights: The percentage is calculated with respect to the height of the generated box's
+ // containing block. If the height of the containing block is not specified explicitly (i.e., it depends
+ // on content height), and this element is not absolutely positioned, the value computes to 'auto'.
+ if (!logicalHeightLength.isPercent() || isOutOfFlowPositioned() || document()->inQuirksMode())
+ return false;
+
+ // Anonymous block boxes are ignored when resolving percentage values that would refer to it:
+ // the closest non-anonymous ancestor box is used instead.
+ RenderBlock* cb = containingBlock();
+ while (cb->isAnonymous())
+ cb = cb->containingBlock();
+
+ // Matching RenderBox::percentageLogicalHeightIsResolvableFromBlock() by
+ // ignoring table cell's attribute value, where it says that table cells violate
+ // what the CSS spec says to do with heights. Basically we
+ // don't care if the cell specified a height or not.
+ if (cb->isTableCell())
+ return false;
+
+ if (!cb->style()->logicalHeight().isAuto() || (!cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto()))
+ return false;
+
+ return true;
+}
+
LayoutSize RenderBoxModelObject::relativePositionOffset() const
{
LayoutSize offset = accumulateInFlowPositionOffsets(this);
@@ -404,13 +462,13 @@ LayoutSize RenderBoxModelObject::relativePositionOffset() const
// calculate the percent offset based on this height.
// See <https://bugs.webkit.org/show_bug.cgi?id=26396>.
if (!style()->top().isAuto()
- && (!containingBlock->style()->height().isAuto()
+ && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
|| !style()->top().isPercent()
|| containingBlock->stretchesToViewport()))
offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight(), view()));
else if (!style()->bottom().isAuto()
- && (!containingBlock->style()->height().isAuto()
+ && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
|| !style()->bottom().isPercent()
|| containingBlock->stretchesToViewport()))
offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight(), view()));
@@ -434,20 +492,31 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L
if (const RenderBoxModelObject* offsetParent = this->offsetParent()) {
if (offsetParent->isBox() && !offsetParent->isBody())
referencePoint.move(-toRenderBox(offsetParent)->borderLeft(), -toRenderBox(offsetParent)->borderTop());
- if (!isOutOfFlowPositioned()) {
+ if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
if (isRelPositioned())
referencePoint.move(relativePositionOffset());
else if (isStickyPositioned())
referencePoint.move(stickyPositionOffset());
- const RenderObject* curr = parent();
- while (curr != offsetParent) {
+
+ // CSS regions specification says that region flows should return the body element as their offsetParent.
+ // Since we will bypass the body’s renderer anyway, just end the loop if we encounter a region flow (named flow thread).
+ // See http://dev.w3.org/csswg/css-regions/#cssomview-offset-attributes
+ RenderObject* curr = parent();
+ while (curr != offsetParent && !curr->isRenderNamedFlowThread()) {
// FIXME: What are we supposed to do inside SVG content?
- if (curr->isBox() && !curr->isTableRow())
- referencePoint.moveBy(toRenderBox(curr)->topLeftLocation());
- referencePoint.move(curr->parent()->offsetForColumns(referencePoint));
+ if (!isOutOfFlowPositioned()) {
+ if (curr->isBox() && !curr->isTableRow())
+ referencePoint.moveBy(toRenderBox(curr)->topLeftLocation());
+ referencePoint.move(curr->parent()->offsetForColumns(referencePoint));
+ }
curr = curr->parent();
}
- if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned())
+
+ // Compute the offset position for elements inside named flow threads for which the offsetParent was the body.
+ // See https://bugs.webkit.org/show_bug.cgi?id=115899
+ if (curr->isRenderNamedFlowThread())
+ referencePoint = toRenderNamedFlowThread(curr)->adjustedPositionRelativeToOffsetParent(*this, referencePoint);
+ else if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned())
referencePoint.moveBy(toRenderBox(offsetParent)->topLeftLocation());
}
}
@@ -455,63 +524,116 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L
return referencePoint;
}
-void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& viewportRect) const
+void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& constrainingRect) const
{
+ constraints.setConstrainingRectAtLastLayout(constrainingRect);
+
RenderBlock* containingBlock = this->containingBlock();
+ RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf);
+ RenderBox* enclosingClippingBox = enclosingClippingLayer ? toRenderBox(enclosingClippingLayer->renderer()) : view();
- LayoutRect containerContentRect = containingBlock->contentBoxRect();
+ LayoutRect containerContentRect;
+ if (!enclosingClippingLayer || (containingBlock != enclosingClippingBox))
+ containerContentRect = containingBlock->contentBoxRect();
+ else {
+ containerContentRect = containingBlock->layoutOverflowRect();
+ LayoutPoint containerLocation = containerContentRect.location() + LayoutPoint(containingBlock->borderLeft() + containingBlock->paddingLeft(),
+ containingBlock->borderTop() + containingBlock->paddingTop());
+ containerContentRect.setLocation(containerLocation);
+ }
+
+ LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
- LayoutUnit minLeftMargin = minimumValueForLength(style()->marginLeft(), containingBlock->availableLogicalWidth(), view());
- LayoutUnit minTopMargin = minimumValueForLength(style()->marginTop(), containingBlock->availableLogicalWidth(), view());
- LayoutUnit minRightMargin = minimumValueForLength(style()->marginRight(), containingBlock->availableLogicalWidth(), view());
- LayoutUnit minBottomMargin = minimumValueForLength(style()->marginBottom(), containingBlock->availableLogicalWidth(), view());
+ // Sticky positioned element ignore any override logical width on the containing block (as they don't call
+ // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine.
+ LayoutBoxExtent minMargin(minimumValueForLength(style()->marginTop(), maxWidth, view()),
+ minimumValueForLength(style()->marginRight(), maxWidth, view()),
+ minimumValueForLength(style()->marginBottom(), maxWidth, view()),
+ minimumValueForLength(style()->marginLeft(), maxWidth, view()));
// Compute the container-relative area within which the sticky element is allowed to move.
- containerContentRect.move(minLeftMargin, minTopMargin);
- containerContentRect.contract(minLeftMargin + minRightMargin, minTopMargin + minBottomMargin);
- constraints.setAbsoluteContainingBlockRect(containingBlock->localToAbsoluteQuad(FloatRect(containerContentRect), SnapOffsetForTransforms).boundingBox());
+ containerContentRect.contract(minMargin);
+ // Finally compute container rect relative to the scrolling ancestor.
+ FloatRect containerRectRelativeToScrollingAncestor = containingBlock->localToContainerQuad(FloatRect(containerContentRect), enclosingClippingBox).boundingBox();
+ if (enclosingClippingLayer) {
+ FloatPoint containerLocationRelativeToScrollingAncestor = containerRectRelativeToScrollingAncestor.location() -
+ FloatSize(enclosingClippingBox->borderLeft() + enclosingClippingBox->paddingLeft(),
+ enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop());
+ if (enclosingClippingBox != containingBlock)
+ containerLocationRelativeToScrollingAncestor += enclosingClippingLayer->scrollOffset();
+ containerRectRelativeToScrollingAncestor.setLocation(containerLocationRelativeToScrollingAncestor);
+ }
+ constraints.setContainingBlockRect(containerRectRelativeToScrollingAncestor);
+
+ // Now compute the sticky box rect, also relative to the scrolling ancestor.
LayoutRect stickyBoxRect = frameRectForStickyPositioning();
LayoutRect flippedStickyBoxRect = stickyBoxRect;
containingBlock->flipForWritingMode(flippedStickyBoxRect);
- LayoutPoint stickyLocation = flippedStickyBoxRect.location();
+ FloatRect stickyBoxRelativeToScrollingAnecstor = flippedStickyBoxRect;
- // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms.
- FloatRect absContainerFrame = containingBlock->localToAbsoluteQuad(FloatRect(FloatPoint(), containingBlock->size()), SnapOffsetForTransforms).boundingBox();
- // We can't call localToAbsolute on |this| because that will recur. FIXME: For now, assume that |this| is not transformed.
- FloatRect absoluteStickyBoxRect(absContainerFrame.location() + stickyLocation, flippedStickyBoxRect.size());
- constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect);
+ // FIXME: sucks to call localToContainerQuad again, but we can't just offset from the previously computed rect if there are transforms.
+ // Map to the view to avoid including page scale factor.
+ FloatPoint stickyLocationRelativeToScrollingAncestor = flippedStickyBoxRect.location() + containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), enclosingClippingBox).boundingBox().location();
+ if (enclosingClippingLayer) {
+ stickyLocationRelativeToScrollingAncestor -= FloatSize(enclosingClippingBox->borderLeft() + enclosingClippingBox->paddingLeft(),
+ enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop());
+ if (enclosingClippingBox != containingBlock)
+ stickyLocationRelativeToScrollingAncestor += enclosingClippingLayer->scrollOffset();
+ }
+ // FIXME: For now, assume that |this| is not transformed.
+ stickyBoxRelativeToScrollingAnecstor.setLocation(stickyLocationRelativeToScrollingAncestor);
+ constraints.setStickyBoxRect(stickyBoxRelativeToScrollingAnecstor);
if (!style()->left().isAuto()) {
- constraints.setLeftOffset(valueForLength(style()->left(), viewportRect.width(), view()));
+ constraints.setLeftOffset(valueForLength(style()->left(), constrainingRect.width(), view()));
constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
}
if (!style()->right().isAuto()) {
- constraints.setRightOffset(valueForLength(style()->right(), viewportRect.width(), view()));
+ constraints.setRightOffset(valueForLength(style()->right(), constrainingRect.width(), view()));
constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight);
}
if (!style()->top().isAuto()) {
- constraints.setTopOffset(valueForLength(style()->top(), viewportRect.height(), view()));
+ constraints.setTopOffset(valueForLength(style()->top(), constrainingRect.height(), view()));
constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
}
if (!style()->bottom().isAuto()) {
- constraints.setBottomOffset(valueForLength(style()->bottom(), viewportRect.height(), view()));
+ constraints.setBottomOffset(valueForLength(style()->bottom(), constrainingRect.height(), view()));
constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom);
}
}
LayoutSize RenderBoxModelObject::stickyPositionOffset() const
{
- LayoutRect viewportRect = view()->frameView()->visibleContentRect();
+ FloatRect constrainingRect;
+ ASSERT(hasLayer());
+ RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf);
+ if (enclosingClippingLayer) {
+ RenderBox* enclosingClippingBox = toRenderBox(enclosingClippingLayer->renderer());
+ LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint(), 0); // FIXME: make this work in regions.
+ constrainingRect = enclosingClippingBox->localToContainerQuad(FloatRect(clipRect), view()).boundingBox();
+
+ FloatPoint scrollOffset = FloatPoint() + enclosingClippingLayer->scrollOffset();
+ constrainingRect.setLocation(scrollOffset);
+ } else {
+ LayoutRect viewportRect = view()->frameView()->viewportConstrainedVisibleContentRect();
+ float scale = 1;
+ if (Frame* frame = view()->frameView()->frame())
+ scale = frame->frameScaleFactor();
+
+ viewportRect.scale(1 / scale);
+ constrainingRect = viewportRect;
+ }
+
StickyPositionViewportConstraints constraints;
- computeStickyPositionConstraints(constraints, viewportRect);
+ computeStickyPositionConstraints(constraints, constrainingRect);
// The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms).
- return LayoutSize(constraints.computeStickyOffset(viewportRect));
+ return LayoutSize(constraints.computeStickyOffset(constrainingRect));
}
LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const
@@ -549,97 +671,12 @@ int RenderBoxModelObject::pixelSnappedOffsetHeight() const
return snapSizeToPixel(offsetHeight(), offsetTop());
}
-LayoutUnit RenderBoxModelObject::computedCSSPaddingTop() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingTop();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingBottom() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingBottom();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingLeft() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingLeft();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingRight() const
+LayoutUnit RenderBoxModelObject::computedCSSPadding(Length padding) const
{
LayoutUnit w = 0;
RenderView* renderView = 0;
- Length padding = style()->paddingRight();
if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingBefore() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingBefore();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingAfter() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingAfter();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingStart() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingStart();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
- else if (padding.isViewportPercentage())
- renderView = view();
- return minimumValueForLength(padding, w, renderView);
-}
-
-LayoutUnit RenderBoxModelObject::computedCSSPaddingEnd() const
-{
- LayoutUnit w = 0;
- RenderView* renderView = 0;
- Length padding = style()->paddingEnd();
- if (padding.isPercent())
- w = containingBlock()->availableLogicalWidth();
+ w = containingBlockLogicalWidthForContent();
else if (padding.isViewportPercentage())
renderView = view();
return minimumValueForLength(padding, w, renderView);
@@ -661,31 +698,31 @@ RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& bor
void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext * context, const LayoutRect& rect, const RoundedRect& clipRect)
{
if (clipRect.isRenderable())
- context->addRoundedRectClip(clipRect);
+ context->clipRoundedRect(clipRect);
else {
// We create a rounded rect for each of the corners and clip it, while making sure we clip opposing corners together.
if (!clipRect.radii().topLeft().isEmpty() || !clipRect.radii().bottomRight().isEmpty()) {
IntRect topCorner(clipRect.rect().x(), clipRect.rect().y(), rect.maxX() - clipRect.rect().x(), rect.maxY() - clipRect.rect().y());
RoundedRect::Radii topCornerRadii;
topCornerRadii.setTopLeft(clipRect.radii().topLeft());
- context->addRoundedRectClip(RoundedRect(topCorner, topCornerRadii));
+ context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii));
IntRect bottomCorner(rect.x(), rect.y(), clipRect.rect().maxX() - rect.x(), clipRect.rect().maxY() - rect.y());
RoundedRect::Radii bottomCornerRadii;
bottomCornerRadii.setBottomRight(clipRect.radii().bottomRight());
- context->addRoundedRectClip(RoundedRect(bottomCorner, bottomCornerRadii));
+ context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii));
}
if (!clipRect.radii().topRight().isEmpty() || !clipRect.radii().bottomLeft().isEmpty()) {
IntRect topCorner(rect.x(), clipRect.rect().y(), clipRect.rect().maxX() - rect.x(), rect.maxY() - clipRect.rect().y());
RoundedRect::Radii topCornerRadii;
topCornerRadii.setTopRight(clipRect.radii().topRight());
- context->addRoundedRectClip(RoundedRect(topCorner, topCornerRadii));
+ context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii));
IntRect bottomCorner(clipRect.rect().x(), rect.y(), rect.maxX() - clipRect.rect().x(), clipRect.rect().maxY() - rect.y());
RoundedRect::Radii bottomCornerRadii;
bottomCornerRadii.setBottomLeft(clipRect.radii().bottomLeft());
- context->addRoundedRectClip(RoundedRect(bottomCorner, bottomCornerRadii));
+ context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii));
}
}
}
@@ -725,9 +762,9 @@ static void applyBoxShadowForBackground(GraphicsContext* context, RenderStyle* s
FloatSize shadowOffset(boxShadow->x(), boxShadow->y());
if (!boxShadow->isWebkitBoxShadow())
- context->setShadow(shadowOffset, boxShadow->blur(), boxShadow->color(), style->colorSpace());
+ context->setShadow(shadowOffset, boxShadow->radius(), boxShadow->color(), style->colorSpace());
else
- context->setLegacyShadow(shadowOffset, boxShadow->blur(), boxShadow->color(), style->colorSpace());
+ context->setLegacyShadow(shadowOffset, boxShadow->radius(), boxShadow->color(), style->colorSpace());
}
void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& color, const FillLayer* bgLayer, const LayoutRect& rect,
@@ -787,10 +824,17 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
if (hasRoundedBorder && bleedAvoidance != BackgroundBleedUseTransparencyLayer) {
RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge);
- context->fillRoundedRect(border, bgColor, style()->colorSpace());
+ if (border.isRenderable())
+ context->fillRoundedRect(border, bgColor, style()->colorSpace());
+ else {
+ context->save();
+ clipRoundedInnerRect(context, rect, border);
+ context->fillRect(border.rect(), bgColor, style()->colorSpace());
+ context->restore();
+ }
} else
context->fillRect(pixelSnappedIntRect(rect), bgColor, style()->colorSpace());
-
+
return;
}
@@ -861,7 +905,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
// Now add the text to the clip. We do this by painting using a special paint phase that signals to
// InlineTextBoxes that they should just add their contents to the clip.
- PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, paintInfo.renderRegion, 0);
+ PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, PaintBehaviorForceBlackText, 0, paintInfo.renderRegion);
if (box) {
RootInlineBox* root = box->root();
box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrolledPaintRect.y() - box->y()), root->lineTop(), root->lineBottom());
@@ -946,7 +990,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
// no progressive loading of the background image
if (shouldPaintBackgroundImage) {
BackgroundImageGeometry geometry;
- calculateBackgroundImageGeometry(bgLayer, scrolledPaintRect, geometry);
+ calculateBackgroundImageGeometry(paintInfo.paintContainer, bgLayer, scrolledPaintRect, geometry, backgroundObject);
geometry.clip(paintInfo.rect);
if (!geometry.destRect().isEmpty()) {
CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
@@ -954,7 +998,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geometry.tileSize());
bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), bgLayer, geometry.tileSize());
context->drawTiledImage(image.get(), style()->colorSpace(), geometry.destRect(), geometry.relativePhase(), geometry.tileSize(),
- compositeOp, useLowQualityScaling);
+ compositeOp, useLowQualityScaling, bgLayer->blendMode());
}
}
@@ -1085,7 +1129,7 @@ IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer,
if (layerWidth.isFixed())
tileSize.setWidth(layerWidth.value());
- else if (layerWidth.isPercent() || layerHeight.isViewportPercentage())
+ else if (layerWidth.isPercent() || layerWidth.isViewportPercentage())
tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width(), renderView));
if (layerHeight.isFixed())
@@ -1165,8 +1209,27 @@ IntPoint RenderBoxModelObject::BackgroundImageGeometry::relativePhase() const
return phase;
}
-void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fillLayer, const LayoutRect& paintRect,
- BackgroundImageGeometry& geometry)
+bool RenderBoxModelObject::fixedBackgroundPaintsInLocalCoordinates() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!isRoot())
+ return false;
+
+ if (view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
+ return false;
+
+ RenderLayer* rootLayer = view()->layer();
+ if (!rootLayer || !rootLayer->isComposited())
+ return false;
+
+ return rootLayer->backing()->backgroundLayerPaintsFixedRootBackground();
+#else
+ return false;
+#endif
+}
+
+void RenderBoxModelObject::calculateBackgroundImageGeometry(const RenderLayerModelObject* paintContainer, const FillLayer* fillLayer, const LayoutRect& paintRect,
+ BackgroundImageGeometry& geometry, RenderObject* backgroundObject) const
{
LayoutUnit left = 0;
LayoutUnit top = 0;
@@ -1175,8 +1238,9 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil
// Determine the background positioning area and set destRect to the background painting area.
// destRect will be adjusted later if the background is non-repeating.
+ // FIXME: transforms spec says that fixed backgrounds behave like scroll inside transforms. https://bugs.webkit.org/show_bug.cgi?id=15679
bool fixedAttachment = fillLayer->attachment() == FixedBackgroundAttachment;
-
+
#if ENABLE(FAST_MOBILE_SCROLLING)
if (view()->frameView() && view()->frameView()->canBlitOnScroll()) {
// As a side effect of an optimization to blit on scroll, we do not honor the CSS
@@ -1216,29 +1280,71 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil
} else
positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutSize(left + right, top + bottom), paintRect.location());
} else {
- geometry.setDestRect(pixelSnappedIntRect(viewRect()));
+ geometry.setHasNonLocalGeometry();
+
+ IntRect viewportRect = pixelSnappedIntRect(viewRect());
+ if (fixedBackgroundPaintsInLocalCoordinates())
+ viewportRect.setLocation(IntPoint());
+ else if (FrameView* frameView = view()->frameView())
+ viewportRect.setLocation(IntPoint(frameView->scrollOffsetForFixedPosition()));
+
+ if (paintContainer) {
+ IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->localToAbsolute(FloatPoint()));
+ viewportRect.moveBy(-absoluteContainerOffset);
+ }
+
+ geometry.setDestRect(pixelSnappedIntRect(viewportRect));
positioningAreaSize = geometry.destRect().size();
}
+ const RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
IntSize fillTileSize = calculateFillTileSize(fillLayer, positioningAreaSize);
- fillLayer->image()->setContainerSizeForRenderer(this, fillTileSize, style()->effectiveZoom());
+ fillLayer->image()->setContainerSizeForRenderer(clientForBackgroundImage, fillTileSize, style()->effectiveZoom());
geometry.setTileSize(fillTileSize);
EFillRepeat backgroundRepeatX = fillLayer->repeatX();
EFillRepeat backgroundRepeatY = fillLayer->repeatY();
RenderView* renderView = view();
+ int availableWidth = positioningAreaSize.width() - geometry.tileSize().width();
+ int availableHeight = positioningAreaSize.height() - geometry.tileSize().height();
+
+ LayoutUnit computedXPosition = minimumValueForLength(fillLayer->xPosition(), availableWidth, renderView, true);
+ if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fillTileSize.width() > 0) {
+ int nrTiles = ceil((double)positioningAreaSize.width() / fillTileSize.width());
+
+ if (fillLayer->size().size.height().isAuto() && backgroundRepeatY != RoundFill)
+ fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.width() / (nrTiles * fillTileSize.width()));
+
+ fillTileSize.setWidth(positioningAreaSize.width() / nrTiles);
+ geometry.setTileSize(fillTileSize);
+ geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
+ }
+
+ LayoutUnit computedYPosition = minimumValueForLength(fillLayer->yPosition(), availableHeight, renderView, true);
+ if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fillTileSize.height() > 0) {
+ int nrTiles = ceil((double)positioningAreaSize.height() / fillTileSize.height());
+
+ if (fillLayer->size().size.width().isAuto() && backgroundRepeatX != RoundFill)
+ fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.height() / (nrTiles * fillTileSize.height()));
+
+ fillTileSize.setHeight(positioningAreaSize.height() / nrTiles);
+ geometry.setTileSize(fillTileSize);
+ geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0);
+ }
- LayoutUnit xPosition = minimumValueForLength(fillLayer->xPosition(), positioningAreaSize.width() - geometry.tileSize().width(), renderView, true);
if (backgroundRepeatX == RepeatFill)
- geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(xPosition + left) % geometry.tileSize().width() : 0);
- else
- geometry.setNoRepeatX(xPosition + left);
+ geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
+ else if (backgroundRepeatX == NoRepeatFill) {
+ int xOffset = fillLayer->backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
+ geometry.setNoRepeatX(left + xOffset);
+ }
- LayoutUnit yPosition = minimumValueForLength(fillLayer->yPosition(), positioningAreaSize.height() - geometry.tileSize().height(), renderView, true);
if (backgroundRepeatY == RepeatFill)
- geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(yPosition + top) % geometry.tileSize().height() : 0);
- else
- geometry.setNoRepeatY(yPosition + top);
+ geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0);
+ else if (backgroundRepeatY == NoRepeatFill) {
+ int yOffset = fillLayer->backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
+ geometry.setNoRepeatY(top + yOffset);
+ }
if (fixedAttachment)
geometry.useFixedAttachment(snappedPaintRect.location());
@@ -1247,6 +1353,16 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil
geometry.setDestOrigin(geometry.destRect().location());
}
+void RenderBoxModelObject::getGeometryForBackgroundImage(const RenderLayerModelObject* paintContainer, IntRect& destRect, IntPoint& phase, IntSize& tileSize) const
+{
+ const FillLayer* backgroundLayer = style()->backgroundLayers();
+ BackgroundImageGeometry geometry;
+ calculateBackgroundImageGeometry(paintContainer, backgroundLayer, destRect, geometry);
+ phase = geometry.phase();
+ tileSize = geometry.tileSize();
+ destRect = geometry.destRect();
+}
+
static LayoutUnit computeBorderImageSide(Length borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent, RenderView* renderView)
{
if (borderSlice.isRelative())
@@ -1795,13 +1911,17 @@ void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, co
void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, const IntPoint& innerBorderAdjustment,
const BorderEdge edges[], BorderEdgeFlags edgesToDraw, BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias)
{
+ // willBeOverdrawn assumes that we draw in order: top, bottom, left, right.
+ // This is different from BoxSide enum order.
+ static BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight };
+
while (edgesToDraw) {
// Find undrawn edges sharing a color.
Color commonColor;
BorderEdgeFlags commonColorEdgeSet = 0;
- for (int i = BSTop; i <= BSLeft; ++i) {
- BoxSide currSide = static_cast<BoxSide>(i);
+ for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i) {
+ BoxSide currSide = paintOrder[i];
if (!includesEdge(edgesToDraw, currSide))
continue;
@@ -1977,7 +2097,7 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect&
if (clipToOuterBorder) {
// Clip to the inner and outer radii rects.
if (bleedAvoidance != BackgroundBleedUseTransparencyLayer)
- graphicsContext->addRoundedRectClip(outerBorder);
+ graphicsContext->clipRoundedRect(outerBorder);
// isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787
// The inside will be clipped out later (in clipBorderSideForComplexInnerPath)
if (innerBorder.isRenderable())
@@ -2074,7 +2194,7 @@ void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext,
innerBorderTopWidth, innerBorderBottomWidth, innerBorderLeftWidth, innerBorderRightWidth,
includeLogicalLeftEdge, includeLogicalRightEdge);
- graphicsContext->addRoundedRectClip(innerClip);
+ graphicsContext->clipRoundedRect(innerClip);
drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
}
@@ -2125,7 +2245,7 @@ void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext,
topWidth, bottomWidth, leftWidth, rightWidth,
includeLogicalLeftEdge, includeLogicalRightEdge);
- graphicsContext->addRoundedRectClip(clipRect);
+ graphicsContext->clipRoundedRect(clipRect);
drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s2, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
return;
}
@@ -2492,11 +2612,11 @@ bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedA
return true;
}
-static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset)
+static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowExtent, int shadowSpread, const IntSize& shadowOffset)
{
IntRect bounds(holeRect);
- bounds.inflate(shadowBlur);
+ bounds.inflate(shadowExtent);
if (shadowSpread < 0)
bounds.inflate(-shadowSpread);
@@ -2525,10 +2645,11 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
continue;
IntSize shadowOffset(shadow->x(), shadow->y());
- int shadowBlur = shadow->blur();
+ int shadowRadius = shadow->radius();
+ int shadowPaintingExtent = shadow->paintingExtent();
int shadowSpread = shadow->spread();
- if (shadowOffset.isZero() && !shadowBlur && !shadowSpread)
+ if (shadowOffset.isZero() && !shadowRadius && !shadowSpread)
continue;
const Color& shadowColor = shadow->color();
@@ -2540,7 +2661,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
continue;
IntRect shadowRect(border.rect());
- shadowRect.inflate(shadowBlur + shadowSpread);
+ shadowRect.inflate(shadowPaintingExtent + shadowSpread);
shadowRect.move(shadowOffset);
GraphicsContextStateSaver stateSaver(*context);
@@ -2548,14 +2669,14 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
// Move the fill just outside the clip, adding 1 pixel separation so that the fill does not
// bleed in (due to antialiasing) if the context is transformed.
- IntSize extraOffset(paintRect.pixelSnappedWidth() + max(0, shadowOffset.width()) + shadowBlur + 2 * shadowSpread + 1, 0);
+ IntSize extraOffset(paintRect.pixelSnappedWidth() + max(0, shadowOffset.width()) + shadowPaintingExtent + 2 * shadowSpread + 1, 0);
shadowOffset -= extraOffset;
fillRect.move(extraOffset);
if (shadow->isWebkitBoxShadow())
- context->setLegacyShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace());
+ context->setLegacyShadow(shadowOffset, shadowRadius, shadowColor, s->colorSpace());
else
- context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace());
+ context->setShadow(shadowOffset, shadowRadius, shadowColor, s->colorSpace());
if (hasBorderRadius) {
RoundedRect rectToClipOut = border;
@@ -2571,7 +2692,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
context->clipOutRoundedRect(rectToClipOut);
RoundedRect influenceRect(shadowRect, border.radii());
- influenceRect.expandRadii(2 * shadowBlur + shadowSpread);
+ influenceRect.expandRadii(2 * shadowPaintingExtent + shadowSpread);
if (allCornersClippedOut(influenceRect, info.rect))
context->fillRect(fillRect.rect(), Color::black, s->colorSpace());
else {
@@ -2614,23 +2735,23 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
if (!includeLogicalLeftEdge) {
if (isHorizontal) {
- holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0);
- holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur);
+ holeRect.move(-max(shadowOffset.width(), 0) - shadowPaintingExtent, 0);
+ holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowPaintingExtent);
} else {
- holeRect.move(0, -max(shadowOffset.height(), 0) - shadowBlur);
- holeRect.setHeight(holeRect.height() + max(shadowOffset.height(), 0) + shadowBlur);
+ holeRect.move(0, -max(shadowOffset.height(), 0) - shadowPaintingExtent);
+ holeRect.setHeight(holeRect.height() + max(shadowOffset.height(), 0) + shadowPaintingExtent);
}
}
if (!includeLogicalRightEdge) {
if (isHorizontal)
- holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur);
+ holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowPaintingExtent);
else
- holeRect.setHeight(holeRect.height() - min(shadowOffset.height(), 0) + shadowBlur);
+ holeRect.setHeight(holeRect.height() - min(shadowOffset.height(), 0) + shadowPaintingExtent);
}
Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255);
- IntRect outerRect = areaCastingShadowInHole(border.rect(), shadowBlur, shadowSpread, shadowOffset);
+ IntRect outerRect = areaCastingShadowInHole(border.rect(), shadowPaintingExtent, shadowSpread, shadowOffset);
RoundedRect roundedHole(holeRect, border.radii());
GraphicsContextStateSaver stateSaver(*context);
@@ -2642,14 +2763,14 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
} else
context->clip(border.rect());
- IntSize extraOffset(2 * paintRect.pixelSnappedWidth() + max(0, shadowOffset.width()) + shadowBlur - 2 * shadowSpread + 1, 0);
+ IntSize extraOffset(2 * paintRect.pixelSnappedWidth() + max(0, shadowOffset.width()) + shadowPaintingExtent - 2 * shadowSpread + 1, 0);
context->translate(extraOffset.width(), extraOffset.height());
shadowOffset -= extraOffset;
if (shadow->isWebkitBoxShadow())
- context->setLegacyShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace());
+ context->setLegacyShadow(shadowOffset, shadowRadius, shadowColor, s->colorSpace());
else
- context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace());
+ context->setShadow(shadowOffset, shadowRadius, shadowColor, s->colorSpace());
context->fillRectWithRoundedHole(outerRect, roundedHole, fillColor, s->colorSpace());
}
@@ -2776,12 +2897,24 @@ void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, Tra
if (!o)
return;
+ // The point inside a box that's inside a region has its coordinates relative to the region,
+ // not the FlowThread that is its container in the RenderObject tree.
+ if (o->isRenderFlowThread() && isRenderBlock()) {
+ // FIXME (CSSREGIONS): switch to Box instead of Block when we'll have range information
+ // for boxes as well, not just for blocks.
+ RenderRegion* startRegion;
+ RenderRegion* endRegion;
+ toRenderFlowThread(o)->getRegionRangeForBox(toRenderBlock(this), startRegion, endRegion);
+ if (startRegion)
+ o = startRegion;
+ }
+
o->mapAbsoluteToLocalPoint(mode, transformState);
LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint());
if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
- RenderBlock* block = static_cast<RenderBlock*>(o);
+ RenderBlock* block = toRenderBlock(o);
LayoutPoint point(roundedLayoutPoint(transformState.mappedPoint()));
point -= containerOffset;
block->adjustForColumnRect(containerOffset, point);
@@ -2819,8 +2952,8 @@ void RenderBoxModelObject::moveChildrenTo(RenderBoxModelObject* toBoxModelObject
// or when fullRemoveInsert is false.
if (fullRemoveInsert && isRenderBlock()) {
RenderBlock* block = toRenderBlock(this);
- if (block->hasPositionedObjects())
- block->removePositionedObjects(0);
+ block->removePositionedObjects(0);
+ block->removeFloatingObjects();
}
ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h
index eea0d6893..8a35a3323 100644
--- a/Source/WebCore/rendering/RenderBoxModelObject.h
+++ b/Source/WebCore/rendering/RenderBoxModelObject.h
@@ -26,7 +26,6 @@
#include "LayoutRect.h"
#include "RenderLayerModelObject.h"
-#include "ShadowData.h"
namespace WebCore {
@@ -45,6 +44,7 @@ enum BackgroundBleedAvoidance {
enum ContentChangeType {
ImageChanged,
MaskImageChanged,
+ BackgroundImageChanged,
CanvasChanged,
CanvasPixelsChanged,
VideoChanged,
@@ -52,6 +52,7 @@ enum ContentChangeType {
};
class KeyframeList;
+class InlineFlowBox;
class StickyPositionViewportConstraints;
// This class is the base for all objects that adhere to the CSS box model as described
@@ -59,7 +60,7 @@ class StickyPositionViewportConstraints;
class RenderBoxModelObject : public RenderLayerModelObject {
public:
- RenderBoxModelObject(Node*);
+ RenderBoxModelObject(ContainerNode*);
virtual ~RenderBoxModelObject();
LayoutSize relativePositionOffset() const;
@@ -80,8 +81,8 @@ public:
int pixelSnappedOffsetLeft() const { return roundToInt(offsetLeft()); }
int pixelSnappedOffsetTop() const { return roundToInt(offsetTop()); }
- int pixelSnappedOffsetWidth() const;
- int pixelSnappedOffsetHeight() const;
+ virtual int pixelSnappedOffsetWidth() const;
+ virtual int pixelSnappedOffsetHeight() const;
virtual void updateFromStyle() OVERRIDE;
@@ -91,14 +92,14 @@ public:
virtual IntRect borderBoundingBox() const = 0;
// These return the CSS computed padding values.
- LayoutUnit computedCSSPaddingTop() const;
- LayoutUnit computedCSSPaddingBottom() const;
- LayoutUnit computedCSSPaddingLeft() const;
- LayoutUnit computedCSSPaddingRight() const;
- LayoutUnit computedCSSPaddingBefore() const;
- LayoutUnit computedCSSPaddingAfter() const;
- LayoutUnit computedCSSPaddingStart() const;
- LayoutUnit computedCSSPaddingEnd() const;
+ LayoutUnit computedCSSPaddingTop() const { return computedCSSPadding(style()->paddingTop()); }
+ LayoutUnit computedCSSPaddingBottom() const { return computedCSSPadding(style()->paddingBottom()); }
+ LayoutUnit computedCSSPaddingLeft() const { return computedCSSPadding(style()->paddingLeft()); }
+ LayoutUnit computedCSSPaddingRight() const { return computedCSSPadding(style()->paddingRight()); }
+ LayoutUnit computedCSSPaddingBefore() const { return computedCSSPadding(style()->paddingBefore()); }
+ LayoutUnit computedCSSPaddingAfter() const { return computedCSSPadding(style()->paddingAfter()); }
+ LayoutUnit computedCSSPaddingStart() const { return computedCSSPadding(style()->paddingStart()); }
+ LayoutUnit computedCSSPaddingEnd() const { return computedCSSPadding(style()->paddingEnd()); }
// These functions are used during layout. Table cells and the MathML
// code override them to include some extra intrinsic padding.
@@ -120,16 +121,22 @@ public:
virtual int borderStart() const { return style()->borderStartWidth(); }
virtual int borderEnd() const { return style()->borderEndWidth(); }
+ LayoutUnit borderAndPaddingStart() const { return borderStart() + paddingStart(); }
+ LayoutUnit borderAndPaddingBefore() const { return borderBefore() + paddingBefore(); }
+ LayoutUnit borderAndPaddingAfter() const { return borderAfter() + paddingAfter(); }
+
LayoutUnit borderAndPaddingHeight() const { return borderTop() + borderBottom() + paddingTop() + paddingBottom(); }
LayoutUnit borderAndPaddingWidth() const { return borderLeft() + borderRight() + paddingLeft() + paddingRight(); }
- LayoutUnit borderAndPaddingLogicalHeight() const { return borderBefore() + borderAfter() + paddingBefore() + paddingAfter(); }
+ LayoutUnit borderAndPaddingLogicalHeight() const { return borderAndPaddingBefore() + borderAndPaddingAfter(); }
LayoutUnit borderAndPaddingLogicalWidth() const { return borderStart() + borderEnd() + paddingStart() + paddingEnd(); }
LayoutUnit borderAndPaddingLogicalLeft() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); }
- LayoutUnit borderAndPaddingStart() const { return borderStart() + paddingStart(); }
LayoutUnit borderLogicalLeft() const { return style()->isHorizontalWritingMode() ? borderLeft() : borderTop(); }
LayoutUnit borderLogicalRight() const { return style()->isHorizontalWritingMode() ? borderRight() : borderBottom(); }
+ LayoutUnit paddingLogicalLeft() const { return style()->isHorizontalWritingMode() ? paddingLeft() : paddingTop(); }
+ LayoutUnit paddingLogicalRight() const { return style()->isHorizontalWritingMode() ? paddingRight() : paddingBottom(); }
+
virtual LayoutUnit marginTop() const = 0;
virtual LayoutUnit marginBottom() const = 0;
virtual LayoutUnit marginLeft() const = 0;
@@ -140,6 +147,8 @@ public:
virtual LayoutUnit marginEnd(const RenderStyle* otherStyle = 0) const = 0;
LayoutUnit marginHeight() const { return marginTop() + marginBottom(); }
LayoutUnit marginWidth() const { return marginLeft() + marginRight(); }
+ LayoutUnit marginLogicalHeight() const { return marginBefore() + marginAfter(); }
+ LayoutUnit marginLogicalWidth() const { return marginStart() + marginEnd(); }
bool hasInlineDirectionBordersPaddingOrMargin() const { return hasInlineDirectionBordersOrPadding() || marginStart()|| marginEnd(); }
bool hasInlineDirectionBordersOrPadding() const { return borderStart() || borderEnd() || paddingStart()|| paddingEnd(); }
@@ -165,6 +174,10 @@ public:
virtual void setSelectionState(SelectionState s);
+ bool canHaveBoxInfoInRegion() const { return !isFloating() && !isReplaced() && !isInline() && !hasColumns() && !isTableCell() && isBlockFlow() && !isRenderSVGBlock(); }
+
+
+ void getGeometryForBackgroundImage(const RenderLayerModelObject* paintContainer, IntRect& destRect, IntPoint& phase, IntSize& tileSize) const;
#if USE(ACCELERATED_COMPOSITING)
void contentChanged(ContentChangeType);
bool hasAcceleratedCompositing() const;
@@ -185,6 +198,9 @@ protected:
class BackgroundImageGeometry {
public:
+ BackgroundImageGeometry()
+ : m_hasNonLocalGeometry(false)
+ { }
IntPoint destOrigin() const { return m_destOrigin; }
void setDestOrigin(const IntPoint& destOrigin)
{
@@ -221,16 +237,21 @@ protected:
void useFixedAttachment(const IntPoint& attachmentPoint);
void clip(const IntRect&);
+
+ void setHasNonLocalGeometry(bool hasNonLocalGeometry = true) { m_hasNonLocalGeometry = hasNonLocalGeometry; }
+ bool hasNonLocalGeometry() const { return m_hasNonLocalGeometry; }
+
private:
IntRect m_destRect;
IntPoint m_destOrigin;
IntPoint m_phase;
IntSize m_tileSize;
+ bool m_hasNonLocalGeometry; // Has background-attachment: fixed. Implies that we can't always cheaply compute destRect.
};
LayoutPoint adjustedPositionRelativeToOffsetParent(const LayoutPoint&) const;
- void calculateBackgroundImageGeometry(const FillLayer*, const LayoutRect& paintRect, BackgroundImageGeometry&);
+ void calculateBackgroundImageGeometry(const RenderLayerModelObject* paintContainer, const FillLayer*, const LayoutRect& paintRect, BackgroundImageGeometry&, RenderObject* = 0) const;
void getBorderEdgeInfo(class BorderEdge[], const RenderStyle*, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const;
bool borderObscuresBackgroundEdge(const FloatSize& contextScale) const;
bool borderObscuresBackground() const;
@@ -248,6 +269,8 @@ protected:
static void clipRoundedInnerRect(GraphicsContext*, const LayoutRect&, const RoundedRect& clipRect);
+ bool hasAutoHeightOrContainingBlockWithAutoHeight() const;
+
public:
// For RenderBlocks and RenderInlines with m_style->styleType() == FIRST_LETTER, this tracks their remaining text fragments
RenderObject* firstLetterRemainingText() const;
@@ -278,6 +301,7 @@ public:
void moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false);
private:
+ LayoutUnit computedCSSPadding(Length) const;
virtual bool isBoxModelObject() const { return true; }
virtual LayoutRect frameRectForStickyPositioning() const = 0;
@@ -289,7 +313,8 @@ private:
RoundedRect getBackgroundRoundedRect(const LayoutRect&, InlineFlowBox*, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight,
bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;
-
+
+ bool fixedBackgroundPaintsInLocalCoordinates() const;
void clipBorderSidePolygon(GraphicsContext*, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
BoxSide, bool firstEdgeMatches, bool secondEdgeMatches);
@@ -309,13 +334,13 @@ private:
inline RenderBoxModelObject* toRenderBoxModelObject(RenderObject* object)
{
- ASSERT(!object || object->isBoxModelObject());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBoxModelObject());
return static_cast<RenderBoxModelObject*>(object);
}
inline const RenderBoxModelObject* toRenderBoxModelObject(const RenderObject* object)
{
- ASSERT(!object || object->isBoxModelObject());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBoxModelObject());
return static_cast<const RenderBoxModelObject*>(object);
}
diff --git a/Source/WebCore/rendering/RenderButton.cpp b/Source/WebCore/rendering/RenderButton.cpp
index 69cef2922..4f655fb43 100644
--- a/Source/WebCore/rendering/RenderButton.cpp
+++ b/Source/WebCore/rendering/RenderButton.cpp
@@ -33,8 +33,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderButton::RenderButton(Node* node)
- : RenderDeprecatedFlexibleBox(node)
+RenderButton::RenderButton(Element* element)
+ : RenderFlexibleBox(element)
, m_buttonText(0)
, m_inner(0)
, m_default(false)
@@ -52,7 +52,7 @@ void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
ASSERT(!firstChild());
m_inner = createAnonymousBlock(style()->display());
setupInnerStyle(m_inner->style());
- RenderDeprecatedFlexibleBox::addChild(m_inner);
+ RenderFlexibleBox::addChild(m_inner);
}
m_inner->addChild(newChild, beforeChild);
@@ -65,7 +65,7 @@ void RenderButton::removeChild(RenderObject* oldChild)
// violated.
if (oldChild == m_inner || !m_inner || oldChild->parent() == this) {
ASSERT(oldChild == m_inner || !m_inner);
- RenderDeprecatedFlexibleBox::removeChild(oldChild);
+ RenderFlexibleBox::removeChild(oldChild);
m_inner = 0;
} else
m_inner->removeChild(oldChild);
@@ -75,10 +75,13 @@ void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle* newS
{
if (m_inner) {
// RenderBlock::setStyle is going to apply a new style to the inner block, which
- // will have the initial box flex value, 0. The current value is 1, because we set
+ // will have the initial flex value, 0. The current value is 1, because we set
// it right below. Here we change it back to 0 to avoid getting a spurious layout hint
- // because of the difference.
- m_inner->style()->setBoxFlex(0);
+ // because of the difference. Same goes for the other properties.
+ // FIXME: Make this hack unnecessary.
+ m_inner->style()->setFlexGrow(newStyle->initialFlexGrow());
+ m_inner->style()->setMarginTop(newStyle->initialMargin());
+ m_inner->style()->setMarginBottom(newStyle->initialMargin());
}
RenderBlock::styleWillChange(diff, newStyle);
}
@@ -108,15 +111,19 @@ void RenderButton::setupInnerStyle(RenderStyle* innerStyle)
ASSERT(innerStyle->refCount() == 1);
// RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
// safe to modify.
- innerStyle->setBoxFlex(1.0f);
- innerStyle->setBoxOrient(style()->boxOrient());
+ innerStyle->setFlexGrow(1.0f);
+ // Use margin:auto instead of align-items:center to get safe centering, i.e.
+ // when the content overflows, treat it the same as align-items: flex-start.
+ innerStyle->setMarginTop(Length());
+ innerStyle->setMarginBottom(Length());
+ innerStyle->setFlexDirection(style()->flexDirection());
}
void RenderButton::updateFromElement()
{
// If we're an input element, we may need to change our button text.
- if (node()->hasTagName(inputTag)) {
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ if (isHTMLInputElement(node())) {
+ HTMLInputElement* input = toHTMLInputElement(node());
String value = input->valueWithDefault();
setText(value);
}
@@ -150,15 +157,7 @@ bool RenderButton::canHaveGeneratedChildren() const
// Input elements can't have generated children, but button elements can. We'll
// write the code assuming any other button types that might emerge in the future
// can also have children.
- return !node()->hasTagName(inputTag);
-}
-
-void RenderButton::updateBeforeAfterContent(PseudoId type)
-{
- if (m_inner)
- m_inner->children()->updateBeforeAfterContent(m_inner, type, this);
- else
- children()->updateBeforeAfterContent(this, type);
+ return !isHTMLInputElement(node());
}
LayoutRect RenderButton::controlClipRect(const LayoutPoint& additionalOffset) const
diff --git a/Source/WebCore/rendering/RenderButton.h b/Source/WebCore/rendering/RenderButton.h
index 5be62b012..9bdc48751 100644
--- a/Source/WebCore/rendering/RenderButton.h
+++ b/Source/WebCore/rendering/RenderButton.h
@@ -21,7 +21,7 @@
#ifndef RenderButton_h
#define RenderButton_h
-#include "RenderDeprecatedFlexibleBox.h"
+#include "RenderFlexibleBox.h"
#include "Timer.h"
#include <wtf/OwnPtr.h>
@@ -32,9 +32,9 @@ class RenderTextFragment;
// RenderButtons are just like normal flexboxes except that they will generate an anonymous block child.
// For inputs, they will also generate an anonymous RenderText and keep its style and content up
// to date as the button changes.
-class RenderButton : public RenderDeprecatedFlexibleBox {
+class RenderButton : public RenderFlexibleBox {
public:
- explicit RenderButton(Node*);
+ explicit RenderButton(Element*);
virtual ~RenderButton();
virtual const char* renderName() const { return "RenderButton"; }
@@ -50,8 +50,6 @@ public:
void setupInnerStyle(RenderStyle*);
virtual void updateFromElement();
- virtual void updateBeforeAfterContent(PseudoId);
-
virtual bool canHaveGeneratedChildren() const OVERRIDE;
virtual bool hasControlClip() const { return true; }
virtual LayoutRect controlClipRect(const LayoutPoint&) const;
@@ -63,7 +61,7 @@ private:
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
- virtual bool hasLineIfEmpty() const { return true; }
+ virtual bool hasLineIfEmpty() const { return node() && node()->toInputElement(); }
virtual bool requiresForcedStyleRecalcPropagation() const { return true; }
@@ -78,13 +76,13 @@ private:
inline RenderButton* toRenderButton(RenderObject* object)
{
- ASSERT(!object || object->isRenderButton());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderButton());
return static_cast<RenderButton*>(object);
}
inline const RenderButton* toRenderButton(const RenderObject* object)
{
- ASSERT(!object || object->isRenderButton());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderButton());
return static_cast<const RenderButton*>(object);
}
diff --git a/Source/WebCore/rendering/RenderCombineText.cpp b/Source/WebCore/rendering/RenderCombineText.cpp
index ce316b6b9..39070b49c 100644
--- a/Source/WebCore/rendering/RenderCombineText.cpp
+++ b/Source/WebCore/rendering/RenderCombineText.cpp
@@ -26,7 +26,7 @@
namespace WebCore {
-const float textCombineMargin = 1.1f; // Allow em + 10% margin
+const float textCombineMargin = 1.15f; // Allow em + 15% margin
RenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> string)
: RenderText(node, string)
diff --git a/Source/WebCore/rendering/RenderCombineText.h b/Source/WebCore/rendering/RenderCombineText.h
index 26021c7f9..6ee9ff27f 100644
--- a/Source/WebCore/rendering/RenderCombineText.h
+++ b/Source/WebCore/rendering/RenderCombineText.h
@@ -51,13 +51,13 @@ private:
inline RenderCombineText* toRenderCombineText(RenderObject* object)
{
- ASSERT(!object || object->isCombineText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isCombineText());
return static_cast<RenderCombineText*>(object);
}
inline const RenderCombineText* toRenderCombineText(const RenderObject* object)
{
- ASSERT(!object || object->isCombineText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isCombineText());
return static_cast<const RenderCombineText*>(object);
}
diff --git a/Source/WebCore/rendering/RenderCounter.cpp b/Source/WebCore/rendering/RenderCounter.cpp
index 24c863304..d72199ecf 100644
--- a/Source/WebCore/rendering/RenderCounter.cpp
+++ b/Source/WebCore/rendering/RenderCounter.cpp
@@ -27,6 +27,7 @@
#include "Element.h"
#include "HTMLNames.h"
#include "HTMLOListElement.h"
+#include "NodeTraversal.h"
#include "RenderListItem.h"
#include "RenderListMarker.h"
#include "RenderStyle.h"
@@ -52,111 +53,34 @@ static CounterMaps& counterMaps()
return staticCounterMaps;
}
-static RenderObject* rendererOfAfterPseudoElement(RenderObject* renderer)
-{
- RenderObject* lastContinuation = renderer;
- while (RenderObject* continuation = lastContinuation->virtualContinuation())
- lastContinuation = continuation;
- return lastContinuation->afterPseudoElementRenderer();
-}
-
// This function processes the renderer tree in the order of the DOM tree
// including pseudo elements as defined in CSS 2.1.
-// Anonymous renderers are skipped except for those representing pseudo elements.
static RenderObject* previousInPreOrder(const RenderObject* object)
{
- Element* parent;
- Element* sibling;
- switch (object->style()->styleType()) {
- case NOPSEUDO:
- ASSERT(!object->isAnonymous());
- parent = toElement(object->node());
- sibling = parent->previousElementSibling();
- parent = parent->parentElement();
- break;
- case BEFORE:
- return object->generatingNode()->renderer(); // It is always the generating node's renderer
- case AFTER:
- parent = toElement(object->generatingNode());
- sibling = parent->lastElementChild();
- break;
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
- while (sibling) {
- if (RenderObject* renderer = sibling->renderer()) {
- if (RenderObject* after = rendererOfAfterPseudoElement(renderer))
- return after;
- parent = sibling;
- sibling = sibling->lastElementChild();
- if (!sibling) {
- if (RenderObject* before = renderer->beforePseudoElementRenderer())
- return before;
- return renderer;
- }
- } else
- sibling = sibling->previousElementSibling();
- }
- if (!parent)
- return 0;
- RenderObject* renderer = parent->renderer(); // Should never be null
- if (RenderObject* before = renderer->beforePseudoElementRenderer())
- return before;
- return renderer;
+ Element* self = toElement(object->node());
+ Element* previous = ElementTraversal::previousIncludingPseudo(self);
+ while (previous && !previous->renderer())
+ previous = ElementTraversal::previousIncludingPseudo(previous);
+ return previous ? previous->renderer() : 0;
}
// This function processes the renderer tree in the order of the DOM tree
// including pseudo elements as defined in CSS 2.1.
-// Anonymous renderers are skipped except for those representing pseudo elements.
static RenderObject* previousSiblingOrParent(const RenderObject* object)
{
- Element* parent;
- Element* sibling;
- switch (object->style()->styleType()) {
- case NOPSEUDO:
- ASSERT(!object->isAnonymous());
- parent = toElement(object->node());
- sibling = parent->previousElementSibling();
- parent = parent->parentElement();
- break;
- case BEFORE:
- return object->generatingNode()->renderer(); // It is always the generating node's renderer
- case AFTER:
- parent = toElement(object->generatingNode());
- sibling = parent->lastElementChild();
- break;
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
- while (sibling) {
- if (RenderObject* renderer = sibling->renderer()) // This skips invisible nodes
- return renderer;
- sibling = sibling->previousElementSibling();
- }
- if (parent) {
- RenderObject* renderer = parent->renderer();
- if (RenderObject* before = renderer->virtualChildren()->beforePseudoElementRenderer(renderer))
- return before;
- return renderer;
- }
- return 0;
+ Element* self = toElement(object->node());
+ Element* previous = ElementTraversal::pseudoAwarePreviousSibling(self);
+ while (previous && !previous->renderer())
+ previous = ElementTraversal::pseudoAwarePreviousSibling(previous);
+ if (previous)
+ return previous->renderer();
+ previous = self->parentElement();
+ return previous ? previous->renderer() : 0;
}
-static Element* parentElement(RenderObject* object)
+static inline Element* parentElement(RenderObject* object)
{
- switch (object->style()->styleType()) {
- case NOPSEUDO:
- ASSERT(!object->isAnonymous());
- return toElement(object->node())->parentElement();
- case BEFORE:
- case AFTER:
- return toElement(object->generatingNode());
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return toElement(object->node())->parentElement();
}
static inline bool areRenderersElementsSiblings(RenderObject* first, RenderObject* second)
@@ -166,51 +90,13 @@ static inline bool areRenderersElementsSiblings(RenderObject* first, RenderObjec
// This function processes the renderer tree in the order of the DOM tree
// including pseudo elements as defined in CSS 2.1.
-// Anonymous renderers are skipped except for those representing pseudo elements.
static RenderObject* nextInPreOrder(const RenderObject* object, const Element* stayWithin, bool skipDescendants = false)
{
- Element* self;
- Element* child;
- RenderObject* result;
- self = toElement(object->generatingNode());
- if (skipDescendants)
- goto nextsibling;
- switch (object->style()->styleType()) {
- case NOPSEUDO:
- ASSERT(!object->isAnonymous());
- result = object->beforePseudoElementRenderer();
- if (result)
- return result;
- break;
- case BEFORE:
- break;
- case AFTER:
- goto nextsibling;
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
- child = self->firstElementChild();
- while (true) {
- while (child) {
- result = child->renderer();
- if (result)
- return result;
- child = child->nextElementSibling();
- }
- result = rendererOfAfterPseudoElement(self->renderer());
- if (result)
- return result;
-nextsibling:
- if (self == stayWithin)
- return 0;
- child = self->nextElementSibling();
- self = self->parentElement();
- if (!self) {
- ASSERT(!child); // We can only reach this if we are searching beyond the root element
- return 0; // which cannot have siblings
- }
- }
+ Element* self = toElement(object->node());
+ Element* next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(self, stayWithin) : ElementTraversal::nextIncludingPseudo(self, stayWithin);
+ while (next && !next->renderer())
+ next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(next, stayWithin) : ElementTraversal::nextIncludingPseudo(next, stayWithin);
+ return next ? next->renderer() : 0;
}
static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value)
@@ -412,7 +298,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
if (object->hasCounterNodeMap()) {
if (CounterMap* nodeMap = counterMaps().get(object)) {
- if (CounterNode* node = nodeMap->get(identifier).get())
+ if (CounterNode* node = nodeMap->get(identifier))
return node;
}
}
@@ -447,7 +333,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id
skipDescendants = false;
if (!currentRenderer->hasCounterNodeMap())
continue;
- CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier).get();
+ CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier);
if (!currentCounter)
continue;
skipDescendants = true;
@@ -501,7 +387,7 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const
while (true) {
if (!beforeAfterContainer)
return 0;
- if (!beforeAfterContainer->isAnonymous())
+ if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement())
return 0; // RenderCounters are restricted to before and after pseudo elements
PseudoId containerStyle = beforeAfterContainer->style()->styleType();
if ((containerStyle == BEFORE) || (containerStyle == AFTER))
@@ -529,14 +415,24 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const
return text.impl();
}
-void RenderCounter::updateText()
+void RenderCounter::updateCounter()
{
computePreferredLogicalWidths(0);
}
void RenderCounter::computePreferredLogicalWidths(float lead)
{
+#ifndef NDEBUG
+ // FIXME: We shouldn't be modifying the tree in computePreferredLogicalWidths.
+ // Instead, we should properly hook the appropriate changes in the DOM and modify
+ // the render tree then. When that's done, we also won't need to override
+ // computePreferredLogicalWidths at all.
+ // https://bugs.webkit.org/show_bug.cgi?id=104829
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(this, false);
+#endif
+
setTextInternal(originalText());
+
RenderText::computePreferredLogicalWidths(lead);
}
@@ -731,7 +627,7 @@ void showCounterRendererTree(const WebCore::RenderObject* renderer, const char*
fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n",
current, current->node(), current->parent(), current->previousSibling(),
current->nextSibling(), current->hasCounterNodeMap() ?
- counterName ? WebCore::counterMaps().get(current)->get(identifier).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0);
+ counterName ? WebCore::counterMaps().get(current)->get(identifier) : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0);
}
fflush(stderr);
}
diff --git a/Source/WebCore/rendering/RenderCounter.h b/Source/WebCore/rendering/RenderCounter.h
index 548828647..ed2fdf5cf 100644
--- a/Source/WebCore/rendering/RenderCounter.h
+++ b/Source/WebCore/rendering/RenderCounter.h
@@ -40,6 +40,8 @@ public:
static void rendererRemovedFromTree(RenderObject*);
static void rendererStyleChanged(RenderObject*, const RenderStyle* oldStyle, const RenderStyle* newStyle);
+ void updateCounter();
+
protected:
virtual void willBeDestroyed();
@@ -48,8 +50,7 @@ private:
virtual bool isCounter() const;
virtual PassRefPtr<StringImpl> originalText() const;
- virtual void updateText() OVERRIDE;
- virtual void computePreferredLogicalWidths(float leadWidth);
+ virtual void computePreferredLogicalWidths(float leadWidth) OVERRIDE;
// Removes the reference to the CounterNode associated with this renderer.
// This is used to cause a counter display update when the CounterNode tree changes.
@@ -63,7 +64,7 @@ private:
inline RenderCounter* toRenderCounter(RenderObject* object)
{
- ASSERT(!object || object->isCounter());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isCounter());
return static_cast<RenderCounter*>(object);
}
diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
index 3323986c9..3106fc9a2 100644
--- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
+++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
@@ -25,6 +25,7 @@
#include "config.h"
#include "RenderDeprecatedFlexibleBox.h"
+#include "FeatureObserver.h"
#include "Font.h"
#include "LayoutRepainter.h"
#include "RenderLayer.h"
@@ -119,17 +120,33 @@ private:
int m_ordinalIteration;
};
-RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Node* node)
- : RenderBlock(node)
+RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Element* element)
+ : RenderBlock(element)
{
setChildrenInline(false); // All of our children must be block-level
m_stretchingChildren = false;
+ if (!isAnonymous()) {
+ const KURL& url = document()->url();
+ if (url.protocolIs("chrome"))
+ FeatureObserver::observe(document(), FeatureObserver::DeprecatedFlexboxChrome);
+ else if (url.protocolIs("chrome-extension"))
+ FeatureObserver::observe(document(), FeatureObserver::DeprecatedFlexboxChromeExtension);
+ else
+ FeatureObserver::observe(document(), FeatureObserver::DeprecatedFlexboxWebContent);
+ }
}
RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
{
}
+RenderDeprecatedFlexibleBox* RenderDeprecatedFlexibleBox::createAnonymous(Document* document)
+{
+ RenderDeprecatedFlexibleBox* renderer = new (document->renderArena()) RenderDeprecatedFlexibleBox(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
static LayoutUnit marginWidthForChild(RenderBox* child)
{
// A margin basically has three types: fixed, percentage, and auto (variable).
@@ -174,56 +191,47 @@ void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const Re
RenderBlock::styleWillChange(diff, newStyle);
}
-void RenderDeprecatedFlexibleBox::calcHorizontalPrefWidths()
+void RenderDeprecatedFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
- for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- if (childDoesNotAffectWidthOrFlexing(child))
- continue;
-
- LayoutUnit margin = marginWidthForChild(child);
- m_minPreferredLogicalWidth += child->minPreferredLogicalWidth() + margin;
- m_maxPreferredLogicalWidth += child->maxPreferredLogicalWidth() + margin;
- }
-}
+ if (hasMultipleLines() || isVertical()) {
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (childDoesNotAffectWidthOrFlexing(child))
+ continue;
-void RenderDeprecatedFlexibleBox::calcVerticalPrefWidths()
-{
- for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- if (childDoesNotAffectWidthOrFlexing(child))
- continue;
+ LayoutUnit margin = marginWidthForChild(child);
+ LayoutUnit width = child->minPreferredLogicalWidth() + margin;
+ minLogicalWidth = max(width, minLogicalWidth);
- LayoutUnit margin = marginWidthForChild(child);
- LayoutUnit width = child->minPreferredLogicalWidth() + margin;
- m_minPreferredLogicalWidth = max(width, m_minPreferredLogicalWidth);
+ width = child->maxPreferredLogicalWidth() + margin;
+ maxLogicalWidth = max(width, maxLogicalWidth);
+ }
+ } else {
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (childDoesNotAffectWidthOrFlexing(child))
+ continue;
- width = child->maxPreferredLogicalWidth() + margin;
- m_maxPreferredLogicalWidth = max(width, m_maxPreferredLogicalWidth);
+ LayoutUnit margin = marginWidthForChild(child);
+ minLogicalWidth += child->minPreferredLogicalWidth() + margin;
+ maxLogicalWidth += child->maxPreferredLogicalWidth() + margin;
+ }
}
+
+ maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
+
+ LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
+ maxLogicalWidth += scrollbarWidth;
+ minLogicalWidth += scrollbarWidth;
}
void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
if (style()->width().isFixed() && style()->width().value() > 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
- else {
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
-
- if (hasMultipleLines() || isVertical())
- calcVerticalPrefWidths();
- else
- calcHorizontalPrefWidths();
-
- m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
- }
-
- if (hasOverflowClip() && style()->overflowY() == OSCROLL) {
- layer()->setHasVerticalScrollbar(true);
- LayoutUnit scrollbarWidth = verticalScrollbarWidth();
- m_maxPreferredLogicalWidth += scrollbarWidth;
- m_minPreferredLogicalWidth += scrollbarWidth;
- }
+ else
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
@@ -242,6 +250,47 @@ void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
setPreferredLogicalWidthsDirty(false);
}
+// Use an inline capacity of 8, since flexbox containers usually have less than 8 children.
+typedef Vector<LayoutRect, 8> ChildFrameRects;
+typedef Vector<LayoutSize, 8> ChildLayoutDeltas;
+
+static void appendChildFrameRects(RenderDeprecatedFlexibleBox* box, ChildFrameRects& childFrameRects)
+{
+ FlexBoxIterator iterator(box);
+ for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+ if (!child->isOutOfFlowPositioned())
+ childFrameRects.append(child->frameRect());
+ }
+}
+
+static void appendChildLayoutDeltas(RenderDeprecatedFlexibleBox* box, ChildLayoutDeltas& childLayoutDeltas)
+{
+ FlexBoxIterator iterator(box);
+ for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+ if (!child->isOutOfFlowPositioned())
+ childLayoutDeltas.append(LayoutSize());
+ }
+}
+
+static void repaintChildrenDuringLayoutIfMoved(RenderDeprecatedFlexibleBox* box, const ChildFrameRects& oldChildRects)
+{
+ size_t childIndex = 0;
+ FlexBoxIterator iterator(box);
+ for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+ if (child->isOutOfFlowPositioned())
+ continue;
+
+ // If the child moved, we have to repaint it as well as any floating/positioned
+ // descendants. An exception is if we need a layout. In this case, we know we're going to
+ // repaint ourselves (and the child) anyway.
+ if (!box->selfNeedsLayout() && child->checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
+
+ ++childIndex;
+ }
+ ASSERT(childIndex == oldChildRects.size());
+}
+
void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
{
ASSERT(needsLayout());
@@ -252,20 +301,18 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- if (inRenderFlowThread()) {
- // Regions changing widths can force us to relayout our children.
- if (logicalWidthChangedInRegions())
- relayoutChildren = true;
- }
- updateRegionsAndExclusionsLogicalSize();
+ // Regions changing widths can force us to relayout our children.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (logicalWidthChangedInRegions(flowThread))
+ relayoutChildren = true;
+ if (updateRegionsAndShapesBeforeChildLayout(flowThread))
+ relayoutChildren = true;
LayoutSize previousSize = size();
updateLogicalWidth();
updateLogicalHeight();
- m_overflow.clear();
-
if (previousSize != size()
|| (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
&& parent()->style()->boxAlign() == BSTRETCH))
@@ -277,11 +324,23 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
initMaxMarginValues();
+#if !ASSERT_DISABLED
+ LayoutSize oldLayoutDelta = view()->layoutDelta();
+#endif
+
+ ChildFrameRects oldChildRects;
+ appendChildFrameRects(this, oldChildRects);
+
+ dirtyForLayoutFromPercentageHeightDescendants();
+
if (isHorizontal())
layoutHorizontalBox(relayoutChildren);
else
layoutVerticalBox(relayoutChildren);
+ repaintChildrenDuringLayoutIfMoved(this, oldChildRects);
+ ASSERT(view()->layoutDeltaMatches(oldLayoutDelta));
+
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
updateLogicalHeight();
@@ -290,7 +349,7 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
layoutPositionedObjects(relayoutChildren || isRoot());
- computeRegionRangeForBlock();
+ updateRegionsAndShapesAfterChildLayout(flowThread);
if (!isFloatingOrOutOfFlowPositioned() && height() == 0) {
// We are a block with no border and padding and a computed height
@@ -321,8 +380,7 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
// Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
- if (hasOverflowClip())
- layer()->updateScrollInfoAfterLayout();
+ updateScrollInfoAfterLayout();
// Repaint with our new bounds if they are different from our old bounds.
repainter.repaintAfterLayout();
@@ -353,6 +411,16 @@ static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChild
}
}
+static void layoutChildIfNeededApplyingDelta(RenderBox* child, const LayoutSize& layoutDelta)
+{
+ if (!child->needsLayout())
+ return;
+
+ child->view()->addLayoutDelta(layoutDelta);
+ child->layoutIfNeeded();
+ child->view()->addLayoutDelta(-layoutDelta);
+}
+
void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
{
LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
@@ -363,43 +431,52 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
LayoutUnit remainingSpace = 0;
-
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
- bool haveFlex = false, flexingChildren = false;
+ bool haveFlex = false, flexingChildren = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
RenderBlock::startDelayUpdateScrollInfo();
+ ChildLayoutDeltas childLayoutDeltas;
+ appendChildLayoutDeltas(this, childLayoutDeltas);
+
// We do 2 passes. The first pass is simply to lay everyone out at
- // their preferred widths. The second pass handles flexing the children.
+ // their preferred widths. The subsequent passes handle flexing the children.
+ // The first pass skips flexible objects completely.
do {
// Reset our height.
setHeight(yPos);
xPos = borderLeft() + paddingLeft();
+ size_t childIndex = 0;
+
// Our first pass is done without flexing. We simply lay the children
// out within the box. We have to do a layout first in order to determine
// our box's intrinsic height.
LayoutUnit maxAscent = 0, maxDescent = 0;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
- // make sure we relayout children if we need it.
- if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
+ if (relayoutChildren)
child->setChildNeedsLayout(true, MarkOnlyThis);
if (child->isOutOfFlowPositioned())
continue;
-
+
+ LayoutSize& childLayoutDelta = childLayoutDeltas[childIndex++];
+
// Compute the child's vertical margins.
child->computeAndSetBlockDirectionMargins(this);
if (!child->needsLayout())
child->markForPaginationRelayoutIfNeeded();
-
+
+ // Apply the child's current layout delta.
+ layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
+
// Now do the layout.
- child->layoutIfNeeded();
+ layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
// Update our height and overflow height.
if (style()->boxAlign() == BBASELINE) {
@@ -421,6 +498,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
else
setHeight(max(height(), yPos + child->height() + child->marginHeight()));
}
+ ASSERT(childIndex == childLayoutDeltas.size());
if (!iterator.first() && hasLineIfEmpty())
setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
@@ -435,6 +513,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
heightSpecified = true;
// Now that our height is actually known, we can place our boxes.
+ childIndex = 0;
m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (child->isOutOfFlowPositioned()) {
@@ -449,14 +528,15 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
continue;
}
+ LayoutSize& childLayoutDelta = childLayoutDeltas[childIndex++];
+
if (child->style()->visibility() == COLLAPSE) {
// visibility: collapsed children do not participate in our positioning.
- // But we need to lay them down.
- child->layoutIfNeeded();
+ // But we need to lay them out.
+ layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
continue;
}
-
// We need to see if this child's height has changed, since we make block elements
// fill the height of a containing box by default.
// Now do a layout.
@@ -468,7 +548,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
if (!child->needsLayout())
child->markForPaginationRelayoutIfNeeded();
- child->layoutIfNeeded();
+ layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
// We can place the child now, using our value of box-align.
xPos += child->marginLeft();
@@ -493,10 +573,11 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
break;
}
- placeChild(child, LayoutPoint(xPos, childY));
+ placeChild(child, LayoutPoint(xPos, childY), &childLayoutDelta);
xPos += child->width() + child->marginRight();
}
+ ASSERT(childIndex == childLayoutDeltas.size());
remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
@@ -654,7 +735,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
- bool haveFlex = false, flexingChildren = false;
+ bool haveFlex = false, flexingChildren = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
// We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
@@ -665,6 +746,9 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
RenderBlock::startDelayUpdateScrollInfo();
+ ChildLayoutDeltas childLayoutDeltas;
+ appendChildLayoutDeltas(this, childLayoutDeltas);
+
// We do 2 passes. The first pass is simply to lay everyone out at
// their preferred widths. The second pass handles flexing the children.
// Our first pass is done without flexing. We simply lay the children
@@ -673,9 +757,10 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
setHeight(borderTop() + paddingTop());
LayoutUnit minHeight = height() + toAdd;
+ size_t childIndex = 0;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
// Make sure we relayout children if we need it.
- if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
+ if (!haveLineClamp && relayoutChildren)
child->setChildNeedsLayout(true, MarkOnlyThis);
if (child->isOutOfFlowPositioned()) {
@@ -690,10 +775,12 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
continue;
}
+ LayoutSize& childLayoutDelta = childLayoutDeltas[childIndex++];
+
if (child->style()->visibility() == COLLAPSE) {
// visibility: collapsed children do not participate in our positioning.
// But we need to lay them down.
- child->layoutIfNeeded();
+ layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
continue;
}
@@ -707,7 +794,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
child->markForPaginationRelayoutIfNeeded();
// Now do a layout.
- child->layoutIfNeeded();
+ layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
// We can place the child now, using our value of box-align.
LayoutUnit childX = borderLeft() + paddingLeft();
@@ -731,9 +818,10 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
}
// Place the child.
- placeChild(child, LayoutPoint(childX, height()));
+ placeChild(child, LayoutPoint(childX, height()), &childLayoutDelta);
setHeight(height() + child->height() + child->marginBottom());
}
+ ASSERT(childIndex == childLayoutDeltas.size());
yPos = height();
@@ -1010,18 +1098,12 @@ void RenderDeprecatedFlexibleBox::clearLineClamp()
}
}
-void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
+void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location, LayoutSize* childLayoutDelta)
{
- LayoutRect oldRect = child->frameRect();
-
- // Place the child.
+ // Place the child and track the layout delta so we can apply it if we do another layout.
+ if (childLayoutDelta)
+ *childLayoutDelta += LayoutSize(child->x() - location.x(), child->y() - location.y());
child->setLocation(location);
-
- // If the child moved, we have to repaint it as well as any floating/positioned
- // descendants. An exception is if we need a layout. In this case, we know we're going to
- // repaint ourselves (and the child) anyway.
- if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
- child->repaintDuringLayoutIfMoved(oldRect);
}
LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
@@ -1083,12 +1165,15 @@ LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool
return 0;
}
-const char *RenderDeprecatedFlexibleBox::renderName() const
+const char* RenderDeprecatedFlexibleBox::renderName() const
{
if (isFloating())
return "RenderDeprecatedFlexibleBox (floating)";
if (isOutOfFlowPositioned())
return "RenderDeprecatedFlexibleBox (positioned)";
+ // FIXME: Temporary hack while the new generated content system is being implemented.
+ if (isPseudoElement())
+ return "RenderDeprecatedFlexibleBox (generated)";
if (isAnonymous())
return "RenderDeprecatedFlexibleBox (generated)";
if (isRelPositioned())
diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h
index 851fbe464..5f223cd4b 100644
--- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h
+++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h
@@ -31,14 +31,12 @@ class FlexBoxIterator;
class RenderDeprecatedFlexibleBox : public RenderBlock {
public:
- RenderDeprecatedFlexibleBox(Node*);
+ RenderDeprecatedFlexibleBox(Element*);
virtual ~RenderDeprecatedFlexibleBox();
- virtual const char* renderName() const;
+ static RenderDeprecatedFlexibleBox* createAnonymous(Document*);
- virtual void computePreferredLogicalWidths();
- void calcHorizontalPrefWidths();
- void calcVerticalPrefWidths();
+ virtual const char* renderName() const;
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle) OVERRIDE;
@@ -51,9 +49,12 @@ public:
virtual bool isStretchingChildren() const { return m_stretchingChildren; }
virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return false; }
- void placeChild(RenderBox* child, const LayoutPoint& location);
+ void placeChild(RenderBox* child, const LayoutPoint& location, LayoutSize* childLayoutDelta = 0);
protected:
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
+
LayoutUnit allowedChildFlex(RenderBox* child, bool expanding, unsigned group);
bool hasMultipleLines() const { return style()->boxLines() == MULTIPLE; }
diff --git a/Source/WebCore/rendering/RenderDetailsMarker.cpp b/Source/WebCore/rendering/RenderDetailsMarker.cpp
index 345c1389e..2ae332f3c 100644
--- a/Source/WebCore/rendering/RenderDetailsMarker.cpp
+++ b/Source/WebCore/rendering/RenderDetailsMarker.cpp
@@ -19,11 +19,12 @@
*/
#include "config.h"
+#if ENABLE(DETAILS_ELEMENT)
#include "RenderDetailsMarker.h"
-#if ENABLE(DETAILS_ELEMENT) || ENABLE(INPUT_MULTIPLE_FIELDS_UI)
#include "Element.h"
#include "GraphicsContext.h"
+#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "PaintInfo.h"
@@ -31,8 +32,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderDetailsMarker::RenderDetailsMarker(Node* node)
- : RenderBlock(node)
+RenderDetailsMarker::RenderDetailsMarker(Element* element)
+ : RenderBlock(element)
{
}
@@ -144,7 +145,7 @@ bool RenderDetailsMarker::isOpen() const
continue;
if (renderer->node()->hasTagName(detailsTag))
return !toElement(renderer->node())->getAttribute(openAttr).isNull();
- if (renderer->node()->hasTagName(inputTag))
+ if (isHTMLInputElement(renderer->node()))
return true;
}
diff --git a/Source/WebCore/rendering/RenderDetailsMarker.h b/Source/WebCore/rendering/RenderDetailsMarker.h
index f60b3cb48..db7d29d70 100644
--- a/Source/WebCore/rendering/RenderDetailsMarker.h
+++ b/Source/WebCore/rendering/RenderDetailsMarker.h
@@ -21,14 +21,14 @@
#ifndef RenderDetailsMarker_h
#define RenderDetailsMarker_h
-#if ENABLE(DETAILS_ELEMENT) || ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#if ENABLE(DETAILS_ELEMENT)
#include "RenderBlock.h"
namespace WebCore {
class RenderDetailsMarker : public RenderBlock {
public:
- RenderDetailsMarker(Node*);
+ RenderDetailsMarker(Element*);
enum Orientation { Up, Down, Left, Right };
@@ -46,13 +46,13 @@ private:
inline RenderDetailsMarker* toRenderDetailsMarker(RenderObject* object)
{
- ASSERT(!object || object->isDetailsMarker());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isDetailsMarker());
return static_cast<RenderDetailsMarker*>(object);
}
inline const RenderDetailsMarker* toRenderDetailsMarker(const RenderObject* object)
{
- ASSERT(!object || object->isDetailsMarker());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isDetailsMarker());
return static_cast<const RenderDetailsMarker*>(object);
}
diff --git a/Source/WebCore/rendering/RenderDialog.cpp b/Source/WebCore/rendering/RenderDialog.cpp
index b2498ae4c..b8f3d1985 100644
--- a/Source/WebCore/rendering/RenderDialog.cpp
+++ b/Source/WebCore/rendering/RenderDialog.cpp
@@ -53,7 +53,7 @@ void RenderDialog::layout()
FrameView* frameView = document()->view();
int scrollTop = frameView->scrollOffset().height();
FloatPoint absolutePoint(0, scrollTop);
- int visibleHeight = frameView->visibleContentRect(true).height();
+ int visibleHeight = frameView->visibleContentRect(ScrollableArea::IncludeScrollbars).height();
if (height() < visibleHeight)
absolutePoint.move(0, (visibleHeight - height()) / 2);
FloatPoint localPoint = containingBlock()->absoluteToLocal(absolutePoint);
diff --git a/Source/WebCore/rendering/RenderDialog.h b/Source/WebCore/rendering/RenderDialog.h
index ea669469e..a672c06b8 100644
--- a/Source/WebCore/rendering/RenderDialog.h
+++ b/Source/WebCore/rendering/RenderDialog.h
@@ -36,8 +36,8 @@ class HTMLDialogElement;
class RenderDialog : public RenderBlock {
public:
- explicit RenderDialog(Node* node)
- : RenderBlock(node)
+ explicit RenderDialog(Element* element)
+ : RenderBlock(element)
{ }
virtual ~RenderDialog() { }
diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp
index e964855d7..69e2fd495 100644
--- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp
+++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp
@@ -24,10 +24,11 @@
#include "config.h"
#include "RenderEmbeddedObject.h"
+#include "CSSValueKeywords.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "Cursor.h"
-#include "CSSValueKeywords.h"
+#include "EventHandler.h"
#include "Font.h"
#include "FontSelector.h"
#include "Frame.h"
@@ -38,6 +39,7 @@
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTMLParamElement.h"
+#include "HTMLPlugInElement.h"
#include "HitTestResult.h"
#include "LocalizedStrings.h"
#include "MIMETypeRegistry.h"
@@ -45,13 +47,16 @@
#include "Page.h"
#include "PaintInfo.h"
#include "Path.h"
+#include "PlatformMouseEvent.h"
#include "PluginViewBase.h"
+#include "RenderLayer.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "RenderWidgetProtector.h"
#include "Settings.h"
#include "Text.h"
#include "TextRun.h"
+#include <wtf/StackStats.h>
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
#include "HTMLMediaElement.h"
@@ -60,29 +65,43 @@
namespace WebCore {
using namespace HTMLNames;
-
+
static const float replacementTextRoundedRectHeight = 18;
static const float replacementTextRoundedRectLeftRightTextMargin = 6;
-static const float replacementTextRoundedRectOpacity = 0.20f;
-static const float replacementTextPressedRoundedRectOpacity = 0.65f;
+static const float replacementTextRoundedRectBottomTextPadding = 1;
+static const float replacementTextRoundedRectOpacity = 0.8f;
static const float replacementTextRoundedRectRadius = 5;
-static const float replacementTextTextOpacity = 0.55f;
-static const float replacementTextPressedTextOpacity = 0.65f;
+static const float replacementArrowLeftMargin = 5;
+static const float replacementArrowPadding = 4;
static const Color& replacementTextRoundedRectPressedColor()
{
- static const Color lightGray(205, 205, 205);
- return lightGray;
+ static const Color pressed(205, 205, 205);
+ return pressed;
}
-
+
+static const Color& replacementTextRoundedRectColor()
+{
+ static const Color standard(221, 221, 221);
+ return standard;
+}
+
+static const Color& replacementTextColor()
+{
+ static const Color standard(102, 102, 102);
+ return standard;
+}
+
RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
: RenderPart(element)
, m_hasFallbackContent(false)
- , m_showsUnavailablePluginIndicator(false)
+ , m_isPluginUnavailable(false)
+ , m_isUnavailablePluginIndicatorHidden(false)
, m_unavailablePluginIndicatorIsPressed(false)
, m_mouseDownWasInUnavailablePluginIndicator(false)
{
- view()->frameView()->setIsVisuallyNonEmpty();
+ // Actual size is not known yet, report the default intrinsic size.
+ view()->frameView()->incrementVisuallyNonEmptyPixelCount(roundedIntSize(intrinsicSize()));
}
RenderEmbeddedObject::~RenderEmbeddedObject()
@@ -102,7 +121,7 @@ bool RenderEmbeddedObject::requiresLayer() const
bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
{
- return widget() && widget()->isPluginViewBase() && static_cast<PluginViewBase*>(widget())->platformLayer();
+ return widget() && widget()->isPluginViewBase() && toPluginViewBase(widget())->platformLayer();
}
#endif
@@ -117,44 +136,94 @@ static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnava
return blockedPluginByContentSecurityPolicyText();
case RenderEmbeddedObject::InsecurePluginVersion:
return insecurePluginVersionText();
- case RenderEmbeddedObject::PluginInactive:
- return inactivePluginText();
}
ASSERT_NOT_REACHED();
return String();
}
-void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason)
+static bool shouldUnavailablePluginMessageBeButton(Document* document, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
{
- ASSERT(!m_showsUnavailablePluginIndicator);
- m_showsUnavailablePluginIndicator = true;
- m_pluginUnavailabilityReason = pluginUnavailabilityReason;
+ Page* page = document->page();
+ return page && page->chrome().client()->shouldUnavailablePluginMessageBeButton(pluginUnavailabilityReason);
+}
- m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason);
+void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason)
+{
+ setPluginUnavailabilityReasonWithDescription(pluginUnavailabilityReason, unavailablePluginReplacementText(pluginUnavailabilityReason));
}
-bool RenderEmbeddedObject::showsUnavailablePluginIndicator() const
+void RenderEmbeddedObject::setPluginUnavailabilityReasonWithDescription(PluginUnavailabilityReason pluginUnavailabilityReason, const String& description)
{
- return m_showsUnavailablePluginIndicator;
+ ASSERT(!m_isPluginUnavailable);
+ m_isPluginUnavailable = true;
+ m_pluginUnavailabilityReason = pluginUnavailabilityReason;
+
+ if (description.isEmpty())
+ m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason);
+ else
+ m_unavailablePluginReplacementText = description;
}
void RenderEmbeddedObject::setUnavailablePluginIndicatorIsPressed(bool pressed)
{
if (m_unavailablePluginIndicatorIsPressed == pressed)
return;
-
+
m_unavailablePluginIndicatorIsPressed = pressed;
repaint();
}
+void RenderEmbeddedObject::paintSnapshotImage(PaintInfo& paintInfo, const LayoutPoint& paintOffset, Image* image)
+{
+ LayoutUnit cWidth = contentWidth();
+ LayoutUnit cHeight = contentHeight();
+ if (!cWidth || !cHeight)
+ return;
+
+ GraphicsContext* context = paintInfo.context;
+ LayoutSize contentSize(cWidth, cHeight);
+ LayoutPoint contentLocation = location() + paintOffset;
+ contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
+
+ LayoutRect rect(contentLocation, contentSize);
+ IntRect alignedRect = pixelSnappedIntRect(rect);
+ if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
+ return;
+
+ bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size());
+ context->drawImage(image, style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling);
+}
+
+void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ Element* element = toElement(node());
+ if (!element || !element->isPluginElement())
+ return;
+
+ HTMLPlugInElement* plugInElement = toHTMLPlugInElement(element);
+
+ if (plugInElement->displayState() > HTMLPlugInElement::DisplayingSnapshot) {
+ RenderPart::paintContents(paintInfo, paintOffset);
+ if (!plugInElement->isRestartedPlugin())
+ return;
+ }
+
+ if (!plugInElement->isPlugInImageElement())
+ return;
+
+ Image* snapshot = toHTMLPlugInImageElement(plugInElement)->snapshotImage();
+ if (snapshot)
+ paintSnapshotImage(paintInfo, paintOffset, snapshot);
+}
+
void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
Page* page = 0;
if (Frame* frame = this->frame())
page = frame->page();
- if (showsUnavailablePluginIndicator()) {
+ if (isPluginUnavailable()) {
if (page && paintInfo.phase == PaintPhaseForeground)
page->addRelevantUnpaintedObject(this, visualOverflowRect());
RenderReplaced::paint(paintInfo, paintOffset);
@@ -174,39 +243,66 @@ void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint
if (paintInfo.phase == PaintPhaseSelection)
return;
-
+
GraphicsContext* context = paintInfo.context;
if (context->paintingDisabled())
return;
-
+
FloatRect contentRect;
Path path;
FloatRect replacementTextRect;
+ FloatRect arrowRect;
Font font;
TextRun run("");
float textWidth;
- if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, font, run, textWidth))
+ if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, arrowRect, font, run, textWidth))
return;
-
+
GraphicsContextStateSaver stateSaver(*context);
context->clip(contentRect);
- context->setAlpha(m_unavailablePluginIndicatorIsPressed ? replacementTextPressedRoundedRectOpacity : replacementTextRoundedRectOpacity);
- context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : Color::white, style()->colorSpace());
+ context->setAlpha(replacementTextRoundedRectOpacity);
+ context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor(), style()->colorSpace());
context->fillPath(path);
const FontMetrics& fontMetrics = font.fontMetrics();
float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent());
- context->setAlpha(m_unavailablePluginIndicatorIsPressed ? replacementTextPressedTextOpacity : replacementTextTextOpacity);
- context->setFillColor(Color::black, style()->colorSpace());
+ context->setFillColor(replacementTextColor(), style()->colorSpace());
context->drawBidiText(font, run, FloatPoint(labelX, labelY));
}
-bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, Font& font, TextRun& run, float& textWidth) const
+void RenderEmbeddedObject::setUnavailablePluginIndicatorIsHidden(bool hidden)
+{
+ m_isUnavailablePluginIndicatorHidden = hidden;
+
+ repaint();
+}
+
+static void addReplacementArrowPath(Path& path, const FloatRect& insideRect)
+{
+ FloatRect rect(insideRect);
+ rect.inflate(-replacementArrowPadding);
+
+ FloatPoint center = rect.center();
+ FloatSize arrowEdge(rect.width() / 2, rect.height() / 3);
+ FloatSize arrowHorizontalEdge(arrowEdge.width(), 0);
+ FloatSize arrowVerticalEdge(0, arrowEdge.height());
+
+ path.moveTo(FloatPoint(floorf(center.x()), floorf(rect.y())));
+ path.addLineTo(FloatPoint(floorf(center.x()), floorf(rect.y() + arrowEdge.height())));
+ path.addLineTo(FloatPoint(ceilf(center.x() - arrowEdge.width()), floorf(rect.y() + arrowEdge.height())));
+ path.addLineTo(FloatPoint(ceilf(center.x() - arrowEdge.width()), ceilf(rect.y() + arrowEdge.height() + arrowEdge.height())));
+ path.addLineTo(FloatPoint(floorf(center.x()), ceilf(rect.y() + arrowEdge.height() + arrowEdge.height())));
+ path.addLineTo(FloatPoint(floorf(center.x()), ceilf(rect.y() + arrowEdge.height() + arrowEdge.height() + arrowEdge.height())));
+ path.addLineTo(FloatPoint(ceilf(center.x() + arrowEdge.width()), center.y()));
+ path.closeSubpath();
+}
+
+bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, FloatRect& arrowRect, Font& font, TextRun& run, float& textWidth) const
{
contentRect = contentBoxRect();
contentRect.moveBy(roundedIntPoint(accumulatedOffset));
-
+
FontDescription fontDescription;
RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription);
fontDescription.setWeight(FontWeightBold);
@@ -221,25 +317,115 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumul
run = TextRun(m_unavailablePluginReplacementText);
textWidth = font.width(run);
-
+
replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
replacementTextRect.setLocation(FloatPoint(x, y));
-
+
+ replacementTextRect.setHeight(replacementTextRect.height() + replacementTextRoundedRectBottomTextPadding);
+
path.addRoundedRect(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
+ if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) {
+ arrowRect = path.boundingRect();
+ arrowRect.setX(ceilf(arrowRect.maxX() + replacementArrowLeftMargin));
+ arrowRect.setWidth(arrowRect.height());
+ arrowRect.inflate(-0.5);
+ path.addEllipse(arrowRect);
+ addReplacementArrowPath(path, arrowRect);
+ }
+
return true;
}
+LayoutRect RenderEmbeddedObject::unavailablePluginIndicatorBounds(const LayoutPoint& accumulatedOffset) const
+{
+ FloatRect contentRect;
+ Path path;
+ FloatRect replacementTextRect;
+ FloatRect arrowRect;
+ Font font;
+ TextRun run("", 0);
+ float textWidth;
+ if (getReplacementTextGeometry(accumulatedOffset, contentRect, path, replacementTextRect, arrowRect, font, run, textWidth))
+ return LayoutRect(path.boundingRect());
+
+ return LayoutRect();
+}
+
+bool RenderEmbeddedObject::isReplacementObscured() const
+{
+ // Return whether or not the replacement content for blocked plugins is accessible to the user.
+
+ // Check the opacity of each layer containing the element or its ancestors.
+ float opacity = 1.0;
+ for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) {
+ RenderLayerModelObject* renderer = layer->renderer();
+ RenderStyle* style = renderer->style();
+ opacity *= style->opacity();
+ if (opacity < 0.1)
+ return true;
+ }
+
+ // Calculate the absolute rect for the blocked plugin replacement text.
+ IntRect absoluteBoundingBox = absoluteBoundingBoxRect();
+ LayoutPoint absoluteLocation(absoluteBoundingBox.location());
+ LayoutRect rect = unavailablePluginIndicatorBounds(absoluteLocation);
+ if (rect.isEmpty())
+ return true;
+
+ RenderView* docRenderer = document()->renderView();
+ ASSERT(docRenderer);
+ if (!docRenderer)
+ return true;
+
+ HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
+ HitTestResult result;
+ HitTestLocation location;
+
+ LayoutUnit x = rect.x();
+ LayoutUnit y = rect.y();
+ LayoutUnit width = rect.width();
+ LayoutUnit height = rect.height();
+
+ // Hit test the center and near the corners of the replacement text to ensure
+ // it is visible and is not masked by other elements.
+ bool hit = false;
+ location = LayoutPoint(x + width / 2, y + height / 2);
+ hit = docRenderer->hitTest(request, location, result);
+ if (!hit || result.innerNode() != node())
+ return true;
+
+ location = LayoutPoint(x, y);
+ hit = docRenderer->hitTest(request, location, result);
+ if (!hit || result.innerNode() != node())
+ return true;
+
+ location = LayoutPoint(x + width, y);
+ hit = docRenderer->hitTest(request, location, result);
+ if (!hit || result.innerNode() != node())
+ return true;
+
+ location = LayoutPoint(x + width, y + height);
+ hit = docRenderer->hitTest(request, location, result);
+ if (!hit || result.innerNode() != node())
+ return true;
+
+ location = LayoutPoint(x, y + height);
+ hit = docRenderer->hitTest(request, location, result);
+ if (!hit || result.innerNode() != node())
+ return true;
+
+ return false;
+}
+
void RenderEmbeddedObject::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
ASSERT(needsLayout());
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
LayoutSize oldSize = contentBoxRect().size();
-#endif
updateLogicalWidth();
updateLogicalHeight();
@@ -251,19 +437,42 @@ void RenderEmbeddedObject::layout()
updateLayerTransform();
- if (!widget() && frameView())
+ bool wasMissingWidget = false;
+ if (!widget() && frameView() && canHaveWidget()) {
+ wasMissingWidget = true;
frameView()->addWidgetToUpdate(this);
+ }
setNeedsLayout(false);
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ LayoutSize newSize = contentBoxRect().size();
+
+ if (!wasMissingWidget && newSize.width() >= oldSize.width() && newSize.height() >= oldSize.height()) {
+ Element* element = toElement(node());
+ if (element && element->isPluginElement() && toHTMLPlugInElement(element)->isPlugInImageElement()) {
+ HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(element);
+ if (plugInImageElement->displayState() > HTMLPlugInElement::DisplayingSnapshot && plugInImageElement->snapshotDecision() == HTMLPlugInImageElement::MaySnapshotWhenResized && document()->view()) {
+ plugInImageElement->setNeedsCheckForSizeChange();
+ document()->view()->addWidgetToUpdate(this);
+ }
+ }
+ }
+
+ if (!canHaveChildren())
+ return;
+
// This code copied from RenderMedia::layout().
- RenderBox* controlsRenderer = toRenderBox(m_children.firstChild());
- if (!controlsRenderer)
+ RenderObject* child = m_children.firstChild();
+
+ if (!child)
return;
-
- LayoutSize newSize = contentBoxRect().size();
- if (newSize == oldSize && !controlsRenderer->needsLayout())
+
+ RenderBox* childBox = toRenderBox(child);
+
+ if (!childBox)
+ return;
+
+ if (newSize == oldSize && !childBox->needsLayout())
return;
// When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or
@@ -271,26 +480,25 @@ void RenderEmbeddedObject::layout()
// and this method will be called many times per second during playback, use a LayoutStateMaintainer:
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- controlsRenderer->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop()));
- controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed));
- controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed));
- controlsRenderer->setNeedsLayout(true, MarkOnlyThis);
- controlsRenderer->layout();
+ childBox->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop()));
+ childBox->style()->setHeight(Length(newSize.height(), Fixed));
+ childBox->style()->setWidth(Length(newSize.width(), Fixed));
+ childBox->setNeedsLayout(true, MarkOnlyThis);
+ childBox->layout();
setChildNeedsLayout(false);
statePusher.pop();
-#endif
}
void RenderEmbeddedObject::viewCleared()
{
// This is required for <object> elements whose contents are rendered by WebCore (e.g. src="foo.html").
if (node() && widget() && widget()->isFrameView()) {
- FrameView* view = static_cast<FrameView*>(widget());
+ FrameView* view = toFrameView(widget());
int marginWidth = -1;
int marginHeight = -1;
if (node()->hasTagName(iframeTag)) {
- HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node());
+ HTMLIFrameElement* frame = toHTMLIFrameElement(node());
marginWidth = frame->marginWidth();
marginHeight = frame->marginHeight();
}
@@ -309,7 +517,7 @@ bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestRes
if (!widget() || !widget()->isPluginViewBase())
return true;
- PluginViewBase* view = static_cast<PluginViewBase*>(widget());
+ PluginViewBase* view = toPluginViewBase(widget());
IntPoint roundedPoint = locationInContainer.roundedPoint();
if (Scrollbar* horizontalScrollbar = view->horizontalScrollbar()) {
@@ -334,7 +542,7 @@ bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity g
if (!widget() || !widget()->isPluginViewBase())
return false;
- return static_cast<PluginViewBase*>(widget())->scroll(direction, granularity);
+ return toPluginViewBase(widget())->scroll(direction, granularity);
}
bool RenderEmbeddedObject::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
@@ -349,34 +557,29 @@ bool RenderEmbeddedObject::isInUnavailablePluginIndicator(const LayoutPoint& poi
FloatRect contentRect;
Path path;
FloatRect replacementTextRect;
+ FloatRect arrowRect;
Font font;
TextRun run("");
float textWidth;
- return getReplacementTextGeometry(IntPoint(), contentRect, path, replacementTextRect, font, run, textWidth)
- && path.contains(point);
+ return getReplacementTextGeometry(IntPoint(), contentRect, path, replacementTextRect, arrowRect, font, run, textWidth)
+ && (path.contains(point) || arrowRect.contains(point));
}
bool RenderEmbeddedObject::isInUnavailablePluginIndicator(MouseEvent* event) const
{
- return isInUnavailablePluginIndicator(roundedLayoutPoint(absoluteToLocal(event->absoluteLocation(), UseTransforms | SnapOffsetForTransforms)));
-}
-
-static bool shouldUnavailablePluginMessageBeButton(Document* document, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
-{
- Page* page = document->page();
- return page && page->chrome()->client()->shouldUnavailablePluginMessageBeButton(pluginUnavailabilityReason);
+ return isInUnavailablePluginIndicator(roundedLayoutPoint(absoluteToLocal(event->absoluteLocation(), UseTransforms)));
}
void RenderEmbeddedObject::handleUnavailablePluginIndicatorEvent(Event* event)
{
if (!shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason))
return;
-
+
if (!event->isMouseEvent())
return;
-
+
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
- HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(node());
+ HTMLPlugInElement* element = toHTMLPlugInElement(node());
if (event->type() == eventNames().mousedownEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
m_mouseDownWasInUnavailablePluginIndicator = isInUnavailablePluginIndicator(mouseEvent);
if (m_mouseDownWasInUnavailablePluginIndicator) {
@@ -387,7 +590,7 @@ void RenderEmbeddedObject::handleUnavailablePluginIndicatorEvent(Event* event)
setUnavailablePluginIndicatorIsPressed(true);
}
event->setDefaultHandled();
- }
+ }
if (event->type() == eventNames().mouseupEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
if (m_unavailablePluginIndicatorIsPressed) {
if (Frame* frame = document()->frame()) {
@@ -398,7 +601,7 @@ void RenderEmbeddedObject::handleUnavailablePluginIndicatorEvent(Event* event)
}
if (m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent)) {
if (Page* page = document()->page())
- page->chrome()->client()->unavailablePluginButtonClicked(element, m_pluginUnavailabilityReason);
+ page->chrome().client()->unavailablePluginButtonClicked(element, m_pluginUnavailabilityReason);
}
m_mouseDownWasInUnavailablePluginIndicator = false;
event->setDefaultHandled();
@@ -418,4 +621,20 @@ CursorDirective RenderEmbeddedObject::getCursor(const LayoutPoint& point, Cursor
return RenderPart::getCursor(point, cursor);
}
+bool RenderEmbeddedObject::canHaveChildren() const
+{
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ if (!node())
+ return false;
+
+ if (toElement(node())->isMediaElement())
+ return true;
+#endif
+
+ if (isSnapshottedPlugIn())
+ return true;
+
+ return false;
+}
+
}
diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.h b/Source/WebCore/rendering/RenderEmbeddedObject.h
index ef09ebb4d..af3b901a8 100644
--- a/Source/WebCore/rendering/RenderEmbeddedObject.h
+++ b/Source/WebCore/rendering/RenderEmbeddedObject.h
@@ -42,10 +42,14 @@ public:
PluginCrashed,
PluginBlockedByContentSecurityPolicy,
InsecurePluginVersion,
- PluginInactive,
};
void setPluginUnavailabilityReason(PluginUnavailabilityReason);
- bool showsUnavailablePluginIndicator() const;
+ void setPluginUnavailabilityReasonWithDescription(PluginUnavailabilityReason, const String& description);
+
+ bool isPluginUnavailable() const { return m_isPluginUnavailable; }
+ bool showsUnavailablePluginIndicator() const { return isPluginUnavailable() && !m_isUnavailablePluginIndicatorHidden; }
+
+ void setUnavailablePluginIndicatorIsHidden(bool);
// FIXME: This belongs on HTMLObjectElement.
bool hasFallbackContent() const { return m_hasFallbackContent; }
@@ -53,6 +57,8 @@ public:
void handleUnavailablePluginIndicatorEvent(Event*);
+ bool isReplacementObscured() const;
+
#if USE(ACCELERATED_COMPOSITING)
virtual bool allowsAcceleratedCompositing() const;
#endif
@@ -63,10 +69,8 @@ protected:
virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const;
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
-#endif
protected:
virtual void layout() OVERRIDE;
@@ -75,6 +79,9 @@ private:
virtual const char* renderName() const { return "RenderEmbeddedObject"; }
virtual bool isEmbeddedObject() const { return true; }
+ void paintSnapshotImage(PaintInfo&, const LayoutPoint&, Image*);
+ virtual void paintContents(PaintInfo&, const LayoutPoint&) OVERRIDE;
+
#if USE(ACCELERATED_COMPOSITING)
virtual bool requiresLayer() const;
#endif
@@ -89,29 +96,30 @@ private:
void setUnavailablePluginIndicatorIsPressed(bool);
bool isInUnavailablePluginIndicator(MouseEvent*) const;
bool isInUnavailablePluginIndicator(const LayoutPoint&) const;
- bool getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path&, FloatRect& replacementTextRect, Font&, TextRun&, float& textWidth) const;
+ bool getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path&, FloatRect& replacementTextRect, FloatRect& arrowRect, Font&, TextRun&, float& textWidth) const;
+ LayoutRect unavailablePluginIndicatorBounds(const LayoutPoint&) const;
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- virtual bool canHaveChildren() const { return node() && toElement(node())->isMediaElement(); }
+ virtual bool canHaveChildren() const;
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
-#endif
+
+ virtual bool canHaveWidget() const { return true; }
bool m_hasFallbackContent; // FIXME: This belongs on HTMLObjectElement.
- bool m_showsUnavailablePluginIndicator;
+ bool m_isPluginUnavailable;
+ bool m_isUnavailablePluginIndicatorHidden;
PluginUnavailabilityReason m_pluginUnavailabilityReason;
String m_unavailablePluginReplacementText;
bool m_unavailablePluginIndicatorIsPressed;
bool m_mouseDownWasInUnavailablePluginIndicator;
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
RenderObjectChildList m_children;
-#endif
+ String m_unavailabilityDescription;
};
inline RenderEmbeddedObject* toRenderEmbeddedObject(RenderObject* object)
{
- ASSERT(!object || object->isEmbeddedObject());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isEmbeddedObject());
return static_cast<RenderEmbeddedObject*>(object);
}
diff --git a/Source/WebCore/rendering/RenderFieldset.cpp b/Source/WebCore/rendering/RenderFieldset.cpp
index 1ebae53d5..3216999cc 100644
--- a/Source/WebCore/rendering/RenderFieldset.cpp
+++ b/Source/WebCore/rendering/RenderFieldset.cpp
@@ -36,7 +36,7 @@ namespace WebCore {
using namespace HTMLNames;
-RenderFieldset::RenderFieldset(Node* element)
+RenderFieldset::RenderFieldset(Element* element)
: RenderBlock(element)
{
}
@@ -212,13 +212,4 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOff
paintMaskImages(paintInfo, paintRect);
}
-bool RenderFieldset::stretchesToMinIntrinsicLogicalWidth() const
-{
- // If width is explicitly specified then Fieldsets should not stretch
- if (style()->width().isPercent())
- return false;
-
- return true;
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderFieldset.h b/Source/WebCore/rendering/RenderFieldset.h
index 74ad92b6e..3481c87aa 100644
--- a/Source/WebCore/rendering/RenderFieldset.h
+++ b/Source/WebCore/rendering/RenderFieldset.h
@@ -30,7 +30,7 @@ namespace WebCore {
class RenderFieldset : public RenderBlock {
public:
- explicit RenderFieldset(Node*);
+ explicit RenderFieldset(Element*);
enum FindLegendOption { IgnoreFloatingOrOutOfFlow, IncludeFloatingOrOutOfFlow };
RenderBox* findLegend(FindLegendOption = IgnoreFloatingOrOutOfFlow) const;
@@ -43,7 +43,6 @@ private:
virtual void computePreferredLogicalWidths();
virtual bool avoidsFloats() const { return true; }
- virtual bool stretchesToMinIntrinsicLogicalWidth() const OVERRIDE;
virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
virtual void paintMask(PaintInfo&, const LayoutPoint&);
@@ -51,7 +50,7 @@ private:
inline RenderFieldset* toRenderFieldset(RenderObject* object)
{
- ASSERT(!object || object->isFieldset());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFieldset());
return static_cast<RenderFieldset*>(object);
}
diff --git a/Source/WebCore/rendering/RenderFileUploadControl.cpp b/Source/WebCore/rendering/RenderFileUploadControl.cpp
index ce6f278b5..6113cef0c 100644
--- a/Source/WebCore/rendering/RenderFileUploadControl.cpp
+++ b/Source/WebCore/rendering/RenderFileUploadControl.cpp
@@ -68,18 +68,10 @@ bool RenderFileUploadControl::canBeReplacedWithInlineRunIn() const
void RenderFileUploadControl::updateFromElement()
{
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ HTMLInputElement* input = toHTMLInputElement(node());
ASSERT(input->isFileUpload());
if (HTMLInputElement* button = uploadButton()) {
- bool newDisabled = !theme()->isEnabled(this);
- // We should avoid to call HTMLFormControlElement::setDisabled() as
- // possible because setAttribute() in setDisabled() can cause style
- // recalculation, and HTMLFormControlElement::recalcStyle() calls
- // updateFromElement() eventually.
- if (button->disabled() != newDisabled)
- button->setDisabled(newDisabled);
-
bool newCanReceiveDroppedFilesState = input->canReceiveDroppedFiles();
if (m_canReceiveDroppedFiles != newCanReceiveDroppedFilesState) {
m_canReceiveDroppedFiles = newCanReceiveDroppedFilesState;
@@ -97,12 +89,12 @@ void RenderFileUploadControl::updateFromElement()
static int nodeWidth(Node* node)
{
- return node ? node->renderBox()->pixelSnappedWidth() : 0;
+ return (node && node->renderBox()) ? node->renderBox()->pixelSnappedWidth() : 0;
}
int RenderFileUploadControl::maxFilenameWidth() const
{
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ HTMLInputElement* input = toHTMLInputElement(node());
return max(0, contentBoxRect().pixelSnappedWidth() - nodeWidth(uploadButton()) - afterButtonSpacing
- (input->icon() ? iconWidth + iconFilenameSpacing : 0));
}
@@ -135,7 +127,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin
if (!button)
return;
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ HTMLInputElement* input = toHTMLInputElement(node());
LayoutUnit buttonWidth = nodeWidth(button);
LayoutUnit buttonAndIconWidth = buttonWidth + afterButtonSpacing
+ (input->icon() ? iconWidth + iconFilenameSpacing : 0);
@@ -144,10 +136,14 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin
textX = contentLeft + buttonAndIconWidth;
else
textX = contentLeft + contentWidth() - buttonAndIconWidth - font.width(textRun);
+
+ LayoutUnit textY = 0;
// We want to match the button's baseline
- RenderButton* buttonRenderer = toRenderButton(button->renderer());
// FIXME: Make this work with transforms.
- LayoutUnit textY = paintOffset.y() + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
+ if (RenderButton* buttonRenderer = toRenderButton(button->renderer()))
+ textY = paintOffset.y() + borderTop() + paddingTop() + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
+ else
+ textY = baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine);
paintInfo.context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace());
@@ -172,6 +168,28 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin
RenderBlock::paintObject(paintInfo, paintOffset);
}
+void RenderFileUploadControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ // Figure out how big the filename space needs to be for a given number of characters
+ // (using "0" as the nominal character).
+ const UChar character = '0';
+ const String characterAsString = String(&character, 1);
+ const Font& font = style()->font();
+ // FIXME: Remove the need for this const_cast by making constructTextRun take a const RenderObject*.
+ RenderFileUploadControl* renderer = const_cast<RenderFileUploadControl*>(this);
+ float minDefaultLabelWidth = defaultWidthNumChars * font.width(constructTextRun(renderer, font, characterAsString, style(), TextRun::AllowTrailingExpansion));
+
+ const String label = theme()->fileListDefaultLabel(node()->toInputElement()->multiple());
+ float defaultLabelWidth = font.width(constructTextRun(renderer, font, label, style(), TextRun::AllowTrailingExpansion));
+ if (HTMLInputElement* button = uploadButton())
+ if (RenderObject* buttonRenderer = button->renderer())
+ defaultLabelWidth += buttonRenderer->maxPreferredLogicalWidth() + afterButtonSpacing;
+ maxLogicalWidth = static_cast<int>(ceilf(max(minDefaultLabelWidth, defaultLabelWidth)));
+
+ if (!style()->width().isPercent())
+ minLogicalWidth = maxLogicalWidth;
+}
+
void RenderFileUploadControl::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
@@ -179,38 +197,19 @@ void RenderFileUploadControl::computePreferredLogicalWidths()
m_minPreferredLogicalWidth = 0;
m_maxPreferredLogicalWidth = 0;
- RenderStyle* style = this->style();
- ASSERT(style);
-
- const Font& font = style->font();
- if (style->width().isFixed() && style->width().value() > 0)
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style->width().value());
- else {
- // Figure out how big the filename space needs to be for a given number of characters
- // (using "0" as the nominal character).
- const UChar character = '0';
- const String characterAsString = String(&character, 1);
- float minDefaultLabelWidth = defaultWidthNumChars * font.width(constructTextRun(this, font, characterAsString, style, TextRun::AllowTrailingExpansion));
-
- const String label = theme()->fileListDefaultLabel(node()->toInputElement()->multiple());
- float defaultLabelWidth = font.width(constructTextRun(this, font, label, style, TextRun::AllowTrailingExpansion));
- if (HTMLInputElement* button = uploadButton())
- if (RenderObject* buttonRenderer = button->renderer())
- defaultLabelWidth += buttonRenderer->maxPreferredLogicalWidth() + afterButtonSpacing;
- m_maxPreferredLogicalWidth = static_cast<int>(ceilf(max(minDefaultLabelWidth, defaultLabelWidth)));
- }
-
- if (style->minWidth().isFixed() && style->minWidth().value() > 0) {
- m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style->minWidth().value()));
- m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style->minWidth().value()));
- } else if (style->width().isPercent() || (style->width().isAuto() && style->height().isPercent()))
- m_minPreferredLogicalWidth = 0;
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
else
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
+ m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
+ }
- if (style->maxWidth().isFixed()) {
- m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style->maxWidth().value()));
- m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style->maxWidth().value()));
+ if (style()->maxWidth().isFixed()) {
+ m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
+ m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
}
int toAdd = borderAndPaddingWidth();
@@ -227,12 +226,12 @@ VisiblePosition RenderFileUploadControl::positionForPoint(const LayoutPoint&)
HTMLInputElement* RenderFileUploadControl::uploadButton() const
{
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ HTMLInputElement* input = toHTMLInputElement(node());
ASSERT(input->shadow());
- Node* buttonNode = input->shadow()->oldestShadowRoot()->firstChild();
- return buttonNode && buttonNode->isHTMLElement() && buttonNode->hasTagName(inputTag) ? static_cast<HTMLInputElement*>(buttonNode) : 0;
+ Node* buttonNode = input->shadow()->shadowRoot()->firstChild();
+ return buttonNode && buttonNode->isHTMLElement() && isHTMLInputElement(buttonNode) ? toHTMLInputElement(buttonNode) : 0;
}
String RenderFileUploadControl::buttonValue()
@@ -245,7 +244,7 @@ String RenderFileUploadControl::buttonValue()
String RenderFileUploadControl::fileTextValue() const
{
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ HTMLInputElement* input = toHTMLInputElement(node());
ASSERT(input->files());
return theme()->fileListNameForWidth(input->files(), style()->font(), maxFilenameWidth(), input->multiple());
}
diff --git a/Source/WebCore/rendering/RenderFileUploadControl.h b/Source/WebCore/rendering/RenderFileUploadControl.h
index 2ce4ca6f2..34d160422 100644
--- a/Source/WebCore/rendering/RenderFileUploadControl.h
+++ b/Source/WebCore/rendering/RenderFileUploadControl.h
@@ -46,6 +46,7 @@ private:
virtual bool canBeReplacedWithInlineRunIn() const OVERRIDE;
virtual void updateFromElement();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
virtual void computePreferredLogicalWidths();
virtual void paintObject(PaintInfo&, const LayoutPoint&);
@@ -62,13 +63,13 @@ private:
inline RenderFileUploadControl* toRenderFileUploadControl(RenderObject* object)
{
- ASSERT(!object || object->isFileUploadControl());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFileUploadControl());
return static_cast<RenderFileUploadControl*>(object);
}
inline const RenderFileUploadControl* toRenderFileUploadControl(const RenderObject* object)
{
- ASSERT(!object || object->isFileUploadControl());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFileUploadControl());
return static_cast<const RenderFileUploadControl*>(object);
}
diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp
index e11d865f1..c95e37e2d 100644
--- a/Source/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp
@@ -49,59 +49,52 @@ struct RenderFlexibleBox::OrderHashTraits : WTF::GenericHashTraits<int> {
static bool isDeletedValue(int value) { return value == std::numeric_limits<int>::min() + 1; }
};
-class RenderFlexibleBox::OrderIterator {
-public:
- OrderIterator(RenderFlexibleBox* flexibleBox, const OrderHashSet& orderValues)
- : m_flexibleBox(flexibleBox)
- , m_currentChild(0)
- , m_orderValuesIterator(0)
- {
- copyToVector(orderValues, m_orderValues);
- std::sort(m_orderValues.begin(), m_orderValues.end());
- first();
- }
+RenderFlexibleBox::OrderIterator::OrderIterator(const RenderFlexibleBox* flexibleBox)
+ : m_flexibleBox(flexibleBox)
+ , m_currentChild(0)
+ , m_orderValuesIterator(0)
+{
+}
- RenderBox* currentChild() { return m_currentChild; }
+void RenderFlexibleBox::OrderIterator::setOrderValues(const OrderHashSet& orderValues)
+{
+ reset();
+ copyToVector(orderValues, m_orderValues);
+ std::sort(m_orderValues.begin(), m_orderValues.end());
+}
- RenderBox* first()
- {
- reset();
- return next();
- }
+RenderBox* RenderFlexibleBox::OrderIterator::first()
+{
+ reset();
+ return next();
+}
- RenderBox* next()
- {
- do {
- if (!m_currentChild) {
+RenderBox* RenderFlexibleBox::OrderIterator::next()
+{
+ do {
+ if (!m_currentChild) {
+ if (m_orderValuesIterator == m_orderValues.end())
+ return 0;
+ if (m_orderValuesIterator) {
+ ++m_orderValuesIterator;
if (m_orderValuesIterator == m_orderValues.end())
return 0;
- if (m_orderValuesIterator) {
- ++m_orderValuesIterator;
- if (m_orderValuesIterator == m_orderValues.end())
- return 0;
- } else
- m_orderValuesIterator = m_orderValues.begin();
-
- m_currentChild = m_flexibleBox->firstChildBox();
} else
- m_currentChild = m_currentChild->nextSiblingBox();
- } while (!m_currentChild || m_currentChild->style()->order() != *m_orderValuesIterator);
+ m_orderValuesIterator = m_orderValues.begin();
- return m_currentChild;
- }
+ m_currentChild = m_flexibleBox->firstChildBox();
+ } else
+ m_currentChild = m_currentChild->nextSiblingBox();
+ } while (!m_currentChild || m_currentChild->style()->order() != *m_orderValuesIterator);
- void reset()
- {
- m_currentChild = 0;
- m_orderValuesIterator = 0;
- }
+ return m_currentChild;
+}
-private:
- RenderFlexibleBox* m_flexibleBox;
- RenderBox* m_currentChild;
- Vector<int> m_orderValues;
- Vector<int>::const_iterator m_orderValuesIterator;
-};
+void RenderFlexibleBox::OrderIterator::reset()
+{
+ m_currentChild = 0;
+ m_orderValuesIterator = 0;
+}
struct RenderFlexibleBox::LineContext {
LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
@@ -130,8 +123,9 @@ struct RenderFlexibleBox::Violation {
};
-RenderFlexibleBox::RenderFlexibleBox(Node* node)
- : RenderBlock(node)
+RenderFlexibleBox::RenderFlexibleBox(Element* element)
+ : RenderBlock(element)
+ , m_orderIterator(this)
, m_numberOfInFlowChildrenOnFirstLine(-1)
{
setChildrenInline(false); // All of our children must be block-level.
@@ -141,6 +135,13 @@ RenderFlexibleBox::~RenderFlexibleBox()
{
}
+RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
+{
+ RenderFlexibleBox* renderer = new (document->renderArena()) RenderFlexibleBox(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
const char* RenderFlexibleBox::renderName() const
{
return "RenderFlexibleBox";
@@ -161,60 +162,57 @@ static LayoutUnit marginLogicalWidthForChild(RenderBox* child, RenderStyle* pare
return margin;
}
+void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
+ // the flex shorthand stops setting it to 0.
+ // See https://bugs.webkit.org/show_bug.cgi?id=116117,
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (child->isOutOfFlowPositioned())
+ continue;
+
+ LayoutUnit margin = marginLogicalWidthForChild(child, style());
+ bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
+ LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
+ LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
+ minPreferredLogicalWidth += margin;
+ maxPreferredLogicalWidth += margin;
+ if (!isColumnFlow()) {
+ maxLogicalWidth += maxPreferredLogicalWidth;
+ if (isMultiline()) {
+ // For multiline, the min preferred width is if you put a break between each item.
+ minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
+ } else
+ minLogicalWidth += minPreferredLogicalWidth;
+ } else {
+ minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
+ if (isMultiline()) {
+ // For multiline, the max preferred width is if you never break between items.
+ maxLogicalWidth += maxPreferredLogicalWidth;
+ } else
+ maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
+ }
+ }
+
+ maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
+
+ LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
+ maxLogicalWidth += scrollbarWidth;
+ minLogicalWidth += scrollbarWidth;
+}
+
void RenderFlexibleBox::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
+
RenderStyle* styleToUse = style();
// FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for width.
if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
- else {
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
-
- for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- if (child->isOutOfFlowPositioned())
- continue;
-
- LayoutUnit margin = marginLogicalWidthForChild(child, style());
- bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
- LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
- LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
- minPreferredLogicalWidth += margin;
- maxPreferredLogicalWidth += margin;
- if (!isColumnFlow()) {
- m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
- if (isMultiline()) {
- // For multiline, the min preferred width is if you put a break between each item.
- m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, minPreferredLogicalWidth);
- } else
- m_minPreferredLogicalWidth += minPreferredLogicalWidth;
- } else {
- m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth);
- if (isMultiline()) {
- // For multiline, the max preferred width is if you put a break between each item.
- m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
- } else
- m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
- }
- }
-
- m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
- }
-
- LayoutUnit scrollbarWidth = 0;
- if (hasOverflowClip()) {
- if (isHorizontalWritingMode() && styleToUse->overflowY() == OSCROLL) {
- ASSERT(layer()->hasVerticalScrollbar());
- scrollbarWidth = verticalScrollbarWidth();
- } else if (!isHorizontalWritingMode() && styleToUse->overflowX() == OSCROLL) {
- ASSERT(layer()->hasHorizontalScrollbar());
- scrollbarWidth = horizontalScrollbarHeight();
- }
- }
-
- m_maxPreferredLogicalWidth += scrollbarWidth;
- m_minPreferredLogicalWidth += scrollbarWidth;
+ else
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
// FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
@@ -252,13 +250,11 @@ int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode di
int RenderFlexibleBox::firstLineBoxBaseline() const
{
- ASSERT(m_orderIterator);
-
if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
return -1;
RenderBox* baselineChild = 0;
int childNumber = 0;
- for (RenderBox* child = m_orderIterator->first(); child; child = m_orderIterator->next()) {
+ for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
if (child->isOutOfFlowPositioned())
continue;
if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
@@ -302,6 +298,29 @@ int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
return synthesizedBaselineFromContentBox(this, direction) + marginAscent;
}
+static EAlignItems resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
+{
+ EAlignItems align = childStyle->alignSelf();
+ if (align == AlignAuto)
+ align = parentStyle->alignItems();
+ return align;
+}
+
+void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ if (oldStyle && oldStyle->alignItems() == AlignStretch && diff == StyleDifferenceLayout) {
+ // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
+ // This is only necessary for stretching since other alignment values don't change the size of the box.
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ EAlignItems previousAlignment = resolveAlignment(oldStyle, child->style());
+ if (previousAlignment == AlignStretch && previousAlignment != resolveAlignment(style(), child->style()))
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ }
+ }
+}
+
void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
{
ASSERT(needsLayout());
@@ -310,47 +329,52 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
return;
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
- LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- if (inRenderFlowThread()) {
- // Regions changing widths can force us to relayout our children.
- if (logicalWidthChangedInRegions())
- relayoutChildren = true;
- }
- updateRegionsAndExclusionsLogicalSize();
+ if (updateLogicalWidthAndColumnWidth())
+ relayoutChildren = true;
- LayoutSize previousSize = size();
+ LayoutUnit previousHeight = logicalHeight();
+ setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
+
+ LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- setLogicalHeight(0);
- updateLogicalWidth();
+ // Regions changing widths can force us to relayout our children.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (logicalWidthChangedInRegions(flowThread))
+ relayoutChildren = true;
+ if (updateRegionsAndShapesBeforeChildLayout(flowThread))
+ relayoutChildren = true;
m_numberOfInFlowChildrenOnFirstLine = -1;
- m_overflow.clear();
RenderBlock::startDelayUpdateScrollInfo();
- WTF::Vector<LineContext> lineContexts;
+ dirtyForLayoutFromPercentageHeightDescendants();
+
+ Vector<LineContext> lineContexts;
OrderHashSet orderValues;
- computeMainAxisPreferredSizes(relayoutChildren, orderValues);
- m_orderIterator = adoptPtr(new OrderIterator(this, orderValues));
- layoutFlexItems(*m_orderIterator, lineContexts);
+ computeMainAxisPreferredSizes(orderValues);
+ m_orderIterator.setOrderValues(orderValues);
+
+ ChildFrameRects oldChildRects;
+ appendChildFrameRects(oldChildRects);
+ layoutFlexItems(relayoutChildren, lineContexts);
- LayoutUnit oldClientAfterEdge = clientLogicalBottom();
updateLogicalHeight();
- repositionLogicalHeightDependentFlexItems(*m_orderIterator, lineContexts, oldClientAfterEdge);
+ repositionLogicalHeightDependentFlexItems(lineContexts);
RenderBlock::finishDelayUpdateScrollInfo();
- if (size() != previousSize)
+ if (logicalHeight() != previousHeight)
relayoutChildren = true;
layoutPositionedObjects(relayoutChildren || isRoot());
- computeRegionRangeForBlock();
- clearChildOverrideSizes();
+ updateRegionsAndShapesAfterChildLayout(flowThread);
+ repaintChildrenDuringLayoutIfMoved(oldChildRects);
// FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
- computeOverflow(oldClientAfterEdge);
+ computeOverflow(clientLogicalBottomAfterRepositioning());
statePusher.pop();
updateLayerTransform();
@@ -364,41 +388,67 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
setNeedsLayout(false);
}
-void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
+void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
{
- ASSERT(m_orderIterator);
+ for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
+ if (!child->isOutOfFlowPositioned())
+ childFrameRects.append(child->frameRect());
+ }
+}
- for (RenderBox* child = m_orderIterator->first(); child; child = m_orderIterator->next()) {
+void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
+{
+ size_t childIndex = 0;
+ for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
+ if (child->isOutOfFlowPositioned())
+ continue;
+
+ // If the child moved, we have to repaint it as well as any floating/positioned
+ // descendants. An exception is if we need a layout. In this case, we know we're going to
+ // repaint ourselves (and the child) anyway.
+ if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
+ ++childIndex;
+ }
+ ASSERT(childIndex == oldChildRects.size());
+}
+
+void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
+{
+ for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
return;
}
}
-void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts, LayoutUnit& oldClientAfterEdge)
+void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
{
LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
- alignFlexLines(iterator, lineContexts);
+ alignFlexLines(lineContexts);
// If we have a single line flexbox, the line height is all the available space.
// For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
if (!isMultiline() && lineContexts.size() == 1)
lineContexts[0].crossAxisExtent = crossAxisContentExtent();
- alignChildren(iterator, lineContexts);
+ alignChildren(lineContexts);
- if (style()->flexWrap() == FlexWrapReverse) {
- if (isHorizontalFlow())
- oldClientAfterEdge = clientLogicalBottom();
- flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge);
- }
+ if (style()->flexWrap() == FlexWrapReverse)
+ flipForWrapReverse(lineContexts, crossAxisStartEdge);
// direction:rtl + flex-direction:column means the cross-axis direction is flipped.
- flipForRightToLeftColumn(iterator);
+ flipForRightToLeftColumn();
}
-void RenderFlexibleBox::clearChildOverrideSizes()
+LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
{
- for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox())
- child->clearOverrideSize();
+ LayoutUnit maxChildLogicalBottom = 0;
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (child->isOutOfFlowPositioned())
+ continue;
+ LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
+ maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
+ }
+ return std::max(clientLogicalBottom(), maxChildLogicalBottom);
}
bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
@@ -476,8 +526,14 @@ LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHei
{
if (isColumnFlow()) {
LogicalExtentComputedValues computedValues;
- computeLogicalHeight(contentLogicalHeight, logicalTop(), computedValues);
- return std::max(LayoutUnit(0), computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight());
+ LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
+ if (contentLogicalHeight > LayoutUnit::max() - borderPaddingAndScrollbar)
+ contentLogicalHeight -= borderPaddingAndScrollbar;
+ LayoutUnit borderBoxLogicalHeight = contentLogicalHeight + borderPaddingAndScrollbar;
+ computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
+ if (computedValues.m_extent == LayoutUnit::max())
+ return computedValues.m_extent;
+ return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
}
return contentLogicalWidth();
}
@@ -486,9 +542,14 @@ LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, Si
{
// FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
// to figure out the logical height/width.
+ // FIXME: This is wrong if the height is set to an intrinsic keyword value. computeContentLogicalHeight will return -1.
+ // Instead, we need to layout the child an get the appropriate height value.
+ // https://bugs.webkit.org/show_bug.cgi?id=113610
if (isColumnFlow())
- return child->computeContentLogicalHeight(sizeType, size);
- return child->adjustContentBoxLogicalWidthForBoxSizing(valueForLength(size, contentLogicalWidth(), view()));
+ return child->computeContentLogicalHeight(size);
+ // FIXME: Figure out how this should work for regions and pass in the appropriate values.
+ RenderRegion* region = 0;
+ return child->computeLogicalWidthInRegionUsing(sizeType, size, contentLogicalWidth(), this, region) - child->borderAndPaddingLogicalWidth();
}
WritingMode RenderFlexibleBox::transformedWritingMode() const
@@ -664,21 +725,10 @@ LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
{
- LayoutRect oldFrameRect = child->frameRect();
-
if (isHorizontalFlow())
child->setLocation(location);
else
child->setLocation(location.transposedPoint());
-
- // If the child moved, we have to repaint it as well as any floating/positioned
- // descendants. An exception is if we need a layout. In this case, we know we're going to
- // repaint ourselves (and the child) anyway.
- // FIXME: In some cases, we might overpaint as we move a child multiple times. We could reduce
- // overpainting by keeping track of the original position of a child and running this check on
- // the final position.
- if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
- child->repaintDuringLayoutIfMoved(oldFrameRect);
}
LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
@@ -691,10 +741,19 @@ LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child)
return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
}
-LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child)
+LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength)
{
+ bool hasOverrideSize = child->hasOverrideWidth() || child->hasOverrideHeight();
+ if (hasOverrideSize)
+ child->clearOverrideSize();
+
Length flexBasis = flexBasisForChild(child);
- if (flexBasis.isAuto()) {
+ if (flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength)) {
+ if (hasOrthogonalFlow(child)) {
+ if (hasOverrideSize)
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ child->layoutIfNeeded();
+ }
LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
@@ -702,7 +761,7 @@ LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox*
return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
}
-void RenderFlexibleBox::layoutFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
+void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren, Vector<LineContext>& lineContexts)
{
OrderedFlexItemList orderedChildren;
LayoutUnit preferredMainAxisExtent;
@@ -710,18 +769,31 @@ void RenderFlexibleBox::layoutFlexItems(OrderIterator& iterator, WTF::Vector<Lin
double totalWeightedFlexShrink;
LayoutUnit minMaxAppliedMainAxisExtent;
+ m_orderIterator.first();
LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
- while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent)) {
+ bool hasInfiniteLineLength = false;
+ while (computeNextFlexLine(orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent, hasInfiniteLineLength)) {
LayoutUnit availableFreeSpace = mainAxisContentExtent(preferredMainAxisExtent) - preferredMainAxisExtent;
FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
InflexibleFlexItemSize inflexibleItems;
- WTF::Vector<LayoutUnit> childSizes;
- while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes)) {
+ Vector<LayoutUnit> childSizes;
+ while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
ASSERT(inflexibleItems.size() > 0);
}
- layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts);
+ layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts);
+ }
+ if (hasLineIfEmpty()) {
+ // Even if computeNextFlexLine returns true, the flexbox might not have
+ // a line because all our children might be out of flow positioned.
+ // Instead of just checking if we have a line, make sure the flexbox
+ // has at least a line's worth of height to cover this case.
+ LayoutUnit minHeight = borderAndPaddingLogicalHeight()
+ + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
+ + scrollbarLogicalHeight();
+ if (height() < minHeight)
+ setLogicalHeight(minHeight);
}
}
@@ -758,6 +830,8 @@ LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemLi
void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
{
+ ASSERT(autoMarginOffset >= 0);
+
if (isHorizontalFlow()) {
if (child->style()->marginLeft().isAuto())
child->setMarginLeft(autoMarginOffset);
@@ -788,6 +862,7 @@ LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCro
bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
{
ASSERT(!child->isOutOfFlowPositioned());
+ ASSERT(availableAlignmentSpace >= 0);
bool isHorizontal = isHorizontalFlow();
Length start = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
@@ -837,7 +912,7 @@ LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin, RenderView*
return minimumValueForLength(margin, availableSize, view);
}
-void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, OrderHashSet& orderValues)
+void RenderFlexibleBox::computeMainAxisPreferredSizes(OrderHashSet& orderValues)
{
RenderView* renderView = view();
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
@@ -846,14 +921,6 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, Ord
if (child->isOutOfFlowPositioned())
continue;
- // Only need to layout here if we will need to get the logicalHeight of the child in computeNextFlexLine.
- Length childMainAxisMin = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
- if (hasOrthogonalFlow(child) && (flexBasisForChild(child).isAuto() || childMainAxisMin.isAuto())) {
- if (!relayoutChildren)
- child->setChildNeedsLayout(true, MarkOnlyThis);
- child->layoutIfNeeded();
- }
-
// Before running the flex algorithm, 'auto' has a margin of 0.
// Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
if (isHorizontalFlow()) {
@@ -868,9 +935,8 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, Ord
LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
{
- // FIXME: Support intrinsic min/max lengths.
Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
- if (max.isSpecified()) {
+ if (max.isSpecifiedOrIntrinsic()) {
LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
if (maxExtent != -1 && childSize > maxExtent)
childSize = maxExtent;
@@ -878,35 +944,33 @@ LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, Layo
Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
LayoutUnit minExtent = 0;
- if (min.isSpecified())
+ if (min.isSpecifiedOrIntrinsic())
minExtent = computeMainAxisExtentForChild(child, MinSize, min);
- else if (min.isAuto()) {
- minExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->minPreferredLogicalWidth();
- minExtent -= mainAxisBorderAndPaddingExtentForChild(child);
- }
return std::max(childSize, minExtent);
}
-bool RenderFlexibleBox::computeNextFlexLine(OrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent)
+bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength)
{
orderedChildren.clear();
preferredMainAxisExtent = 0;
totalFlexGrow = totalWeightedFlexShrink = 0;
minMaxAppliedMainAxisExtent = 0;
- if (!iterator.currentChild())
+ if (!m_orderIterator.currentChild())
return false;
LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
+ hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
+
bool lineHasInFlowItem = false;
- for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
+ for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
if (child->isOutOfFlowPositioned()) {
orderedChildren.append(child);
continue;
}
- LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
+ LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
@@ -924,12 +988,12 @@ bool RenderFlexibleBox::computeNextFlexLine(OrderIterator& iterator, OrderedFlex
return true;
}
-void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems)
+void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
{
for (size_t i = 0; i < violations.size(); ++i) {
RenderBox* child = violations[i].child;
LayoutUnit childSize = violations[i].childSize;
- LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
+ LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
availableFreeSpace -= childSize - preferredChildSize;
totalFlexGrow -= child->style()->flexGrow();
totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
@@ -938,13 +1002,13 @@ void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violation
}
// Returns true if we successfully ran the algorithm and sized the flex items.
-bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
+bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength)
{
childSizes.clear();
LayoutUnit totalViolation = 0;
LayoutUnit usedFreeSpace = 0;
- WTF::Vector<Violation> minViolations;
- WTF::Vector<Violation> maxViolations;
+ Vector<Violation> minViolations;
+ Vector<Violation> maxViolations;
for (size_t i = 0; i < children.size(); ++i) {
RenderBox* child = children[i];
if (child->isOutOfFlowPositioned()) {
@@ -955,12 +1019,15 @@ bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedF
if (inflexibleItems.contains(child))
childSizes.append(inflexibleItems.get(child));
else {
- LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
+ LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
LayoutUnit childSize = preferredChildSize;
- if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && isfinite(totalFlexGrow))
- childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexGrow() / totalFlexGrow);
- else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && isfinite(totalWeightedFlexShrink))
- childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink);
+ double extraSpace = 0;
+ if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
+ extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
+ else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
+ extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
+ if (std::isfinite(extraSpace))
+ childSize += roundedLayoutUnit(extraSpace);
LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
childSizes.append(adjustedChildSize);
@@ -976,7 +1043,7 @@ bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedF
}
if (totalViolation)
- freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems);
+ freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
else
availableFreeSpace -= usedFreeSpace;
@@ -1037,9 +1104,7 @@ void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, Layout
EAlignItems RenderFlexibleBox::alignmentForChild(RenderBox* child) const
{
- EAlignItems align = child->style()->alignSelf();
- if (align == AlignAuto)
- align = style()->alignItems();
+ EAlignItems align = resolveAlignment(style(), child->style());
if (align == AlignBaseline && hasOrthogonalFlow(child))
align = AlignFlexStart;
@@ -1065,7 +1130,22 @@ size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItem
return count;
}
-void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts)
+bool RenderFlexibleBox::needToStretchChild(RenderBox* child)
+{
+ if (alignmentForChild(child) != AlignStretch)
+ return false;
+
+ Length crossAxisLength = isHorizontalFlow() ? child->style()->height() : child->style()->width();
+ return crossAxisLength.isAuto();
+}
+
+void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child)
+{
+ if (hasAutoMarginsInCrossAxis(child))
+ child->updateLogicalHeight();
+}
+
+void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts)
{
ASSERT(childSizes.size() == children.size());
@@ -1087,10 +1167,17 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
continue;
}
+
LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
setLogicalOverrideSize(child, childPreferredSize);
// FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
- child->setChildNeedsLayout(true, MarkOnlyThis);
+ if (needToStretchChild(child) || childPreferredSize != mainAxisExtentForChild(child))
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ else {
+ // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
+ resetAutoMarginsAndLogicalTopInCrossAxis(child);
+ }
+ updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
child->layoutIfNeeded();
updateAutoMarginsInMainAxis(child, autoMarginOffset);
@@ -1106,7 +1193,7 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
} else
childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
- if (!isColumnFlow() && style()->logicalHeight().isAuto())
+ if (!isColumnFlow())
setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
@@ -1196,7 +1283,7 @@ static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace
return 0;
}
-void RenderFlexibleBox::alignFlexLines(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
+void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
{
if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
return;
@@ -1205,11 +1292,11 @@ void RenderFlexibleBox::alignFlexLines(OrderIterator& iterator, WTF::Vector<Line
for (size_t i = 0; i < lineContexts.size(); ++i)
availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
- RenderBox* child = iterator.first();
+ RenderBox* child = m_orderIterator.first();
LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
lineContexts[lineNumber].crossAxisOffset += lineOffset;
- for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next())
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
adjustAlignmentForChild(child, lineOffset);
if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
@@ -1234,18 +1321,18 @@ void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit del
setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
}
-void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts)
+void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
{
// Keep track of the space between the baseline edge and the after edge of the box for each line.
- WTF::Vector<LayoutUnit> minMarginAfterBaselines;
+ Vector<LayoutUnit> minMarginAfterBaselines;
- RenderBox* child = iterator.first();
+ RenderBox* child = m_orderIterator.first();
for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
- for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
ASSERT(child);
if (child->isOutOfFlowPositioned()) {
if (style()->flexWrap() == FlexWrapReverse)
@@ -1253,7 +1340,7 @@ void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector
continue;
}
- if (updateAutoMarginsInCrossAxis(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)))
+ if (updateAutoMarginsInCrossAxis(child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, child))))
continue;
switch (alignmentForChild(child)) {
@@ -1296,10 +1383,10 @@ void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector
// wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
// need to align the after edge of baseline elements with the after edge of the flex line.
- child = iterator.first();
+ child = m_orderIterator.first();
for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
- for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
ASSERT(child);
if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
adjustAlignmentForChild(child, minMarginAfterBaseline);
@@ -1320,7 +1407,7 @@ void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUni
child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
child->setLogicalHeight(0);
child->setChildNeedsLayout(true, MarkOnlyThis);
- child->layoutIfNeeded();
+ child->layout();
}
}
} else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
@@ -1332,19 +1419,19 @@ void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUni
if (childWidth != child->logicalWidth()) {
child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth());
child->setChildNeedsLayout(true, MarkOnlyThis);
- child->layoutIfNeeded();
+ child->layout();
}
}
}
}
-void RenderFlexibleBox::flipForRightToLeftColumn(OrderIterator& iterator)
+void RenderFlexibleBox::flipForRightToLeftColumn()
{
if (style()->isLeftToRightDirection() || !isColumnFlow())
return;
LayoutUnit crossExtent = crossAxisExtent();
- for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+ for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
if (child->isOutOfFlowPositioned())
continue;
LayoutPoint location = flowAwareLocationForChild(child);
@@ -1353,12 +1440,12 @@ void RenderFlexibleBox::flipForRightToLeftColumn(OrderIterator& iterator)
}
}
-void RenderFlexibleBox::flipForWrapReverse(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
+void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
{
LayoutUnit contentExtent = crossAxisContentExtent();
- RenderBox* child = iterator.first();
+ RenderBox* child = m_orderIterator.first();
for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
- for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
ASSERT(child);
LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
diff --git a/Source/WebCore/rendering/RenderFlexibleBox.h b/Source/WebCore/rendering/RenderFlexibleBox.h
index 98eafca7c..ad7707585 100644
--- a/Source/WebCore/rendering/RenderFlexibleBox.h
+++ b/Source/WebCore/rendering/RenderFlexibleBox.h
@@ -32,21 +32,21 @@
#define RenderFlexibleBox_h
#include "RenderBlock.h"
-#include <wtf/OwnPtr.h>
namespace WebCore {
class RenderFlexibleBox : public RenderBlock {
public:
- RenderFlexibleBox(Node*);
+ RenderFlexibleBox(Element*);
virtual ~RenderFlexibleBox();
+ static RenderFlexibleBox* createAnonymous(Document*);
+
virtual const char* renderName() const OVERRIDE;
virtual bool isFlexibleBox() const OVERRIDE { return true; }
virtual bool avoidsFloats() const OVERRIDE { return true; }
virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return false; }
- virtual void computePreferredLogicalWidths() OVERRIDE;
virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE;
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE;
@@ -57,6 +57,12 @@ public:
bool isHorizontalFlow() const;
+protected:
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
+
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
private:
enum FlexSign {
PositiveFlexibility,
@@ -71,13 +77,32 @@ private:
struct OrderHashTraits;
typedef HashSet<int, DefaultHash<int>::Hash, OrderHashTraits> OrderHashSet;
- class OrderIterator;
- typedef WTF::HashMap<const RenderBox*, LayoutUnit> InflexibleFlexItemSize;
- typedef WTF::Vector<RenderBox*> OrderedFlexItemList;
+ class OrderIterator {
+ WTF_MAKE_NONCOPYABLE(OrderIterator);
+ public:
+ OrderIterator(const RenderFlexibleBox*);
+ void setOrderValues(const OrderHashSet&);
+ RenderBox* currentChild() const { return m_currentChild; }
+ RenderBox* first();
+ RenderBox* next();
+ void reset();
+
+ private:
+ const RenderFlexibleBox* m_flexibleBox;
+ RenderBox* m_currentChild;
+ Vector<int> m_orderValues;
+ Vector<int>::const_iterator m_orderValuesIterator;
+ };
+
+ typedef HashMap<const RenderBox*, LayoutUnit> InflexibleFlexItemSize;
+ typedef Vector<RenderBox*> OrderedFlexItemList;
struct LineContext;
struct Violation;
+ // Use an inline capacity of 8, since flexbox containers usually have less than 8 children.
+ typedef Vector<LayoutRect, 8> ChildFrameRects;
+
bool hasOrthogonalFlow(RenderBox* child) const;
bool isColumnFlow() const;
bool isLeftToRightFlow() const;
@@ -113,42 +138,61 @@ private:
EAlignItems alignmentForChild(RenderBox* child) const;
LayoutUnit mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const;
LayoutUnit mainAxisScrollbarExtentForChild(RenderBox* child) const;
- LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child);
+ LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength);
- void layoutFlexItems(OrderIterator&, WTF::Vector<LineContext>&);
+ void layoutFlexItems(bool relayoutChildren, Vector<LineContext>&);
LayoutUnit autoMarginOffsetInMainAxis(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace);
void updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset);
bool hasAutoMarginsInCrossAxis(RenderBox* child) const;
bool updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace);
- void repositionLogicalHeightDependentFlexItems(OrderIterator&, WTF::Vector<LineContext>&, LayoutUnit& oldClientAfterEdge);
- void clearChildOverrideSizes();
+ void repositionLogicalHeightDependentFlexItems(Vector<LineContext>&);
+ LayoutUnit clientLogicalBottomAfterRepositioning();
+ void appendChildFrameRects(ChildFrameRects&);
+ void repaintChildrenDuringLayoutIfMoved(const ChildFrameRects&);
LayoutUnit availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox*);
LayoutUnit marginBoxAscentForChild(RenderBox*);
LayoutUnit computeChildMarginValue(Length margin, RenderView*);
- void computeMainAxisPreferredSizes(bool relayoutChildren, OrderHashSet&);
+ void computeMainAxisPreferredSizes(OrderHashSet&);
LayoutUnit adjustChildSizeForMinAndMax(RenderBox*, LayoutUnit childSize);
- bool computeNextFlexLine(OrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent);
+ bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength);
- bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, WTF::Vector<LayoutUnit>& childSizes);
- void freezeViolations(const WTF::Vector<Violation>&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&);
+ bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength);
+ void freezeViolations(const Vector<Violation>&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, bool hasInfiniteLineLength);
+ void resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox*);
+ bool needToStretchChild(RenderBox*);
void setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize);
void prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode);
size_t numberOfInFlowPositionedChildren(const OrderedFlexItemList&) const;
- void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>&);
+ void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>&);
void layoutColumnReverse(const OrderedFlexItemList&, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace);
- void alignFlexLines(OrderIterator&, WTF::Vector<LineContext>&);
- void alignChildren(OrderIterator&, const WTF::Vector<LineContext>&);
+ void alignFlexLines(Vector<LineContext>&);
+ void alignChildren(const Vector<LineContext>&);
void applyStretchAlignmentToChild(RenderBox*, LayoutUnit lineCrossAxisExtent);
- void flipForRightToLeftColumn(OrderIterator&);
- void flipForWrapReverse(OrderIterator&, const WTF::Vector<LineContext>&, LayoutUnit crossAxisStartEdge);
+ void flipForRightToLeftColumn();
+ void flipForWrapReverse(const Vector<LineContext>&, LayoutUnit crossAxisStartEdge);
- OwnPtr<OrderIterator> m_orderIterator;
+ mutable OrderIterator m_orderIterator;
int m_numberOfInFlowChildrenOnFirstLine;
};
+inline RenderFlexibleBox* toRenderFlexibleBox(RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFlexibleBox());
+ return static_cast<RenderFlexibleBox*>(object);
+}
+
+inline const RenderFlexibleBox* toRenderFlexibleBox(const RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFlexibleBox());
+ return static_cast<const RenderFlexibleBox*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderFlexibleBox(const RenderFlexibleBox*);
+
} // namespace WebCore
#endif // RenderFlexibleBox_h
diff --git a/Source/WebCore/rendering/RenderFlowThread.cpp b/Source/WebCore/rendering/RenderFlowThread.cpp
index 4aa170a2c..f898d7257 100644
--- a/Source/WebCore/rendering/RenderFlowThread.cpp
+++ b/Source/WebCore/rendering/RenderFlowThread.cpp
@@ -35,29 +35,34 @@
#include "HitTestRequest.h"
#include "HitTestResult.h"
#include "Node.h"
+#include "PODIntervalTree.h"
#include "PaintInfo.h"
#include "RenderBoxRegionInfo.h"
+#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderRegion.h"
#include "RenderView.h"
#include "TransformState.h"
#include "WebKitNamedFlow.h"
+#include <wtf/StackStats.h>
namespace WebCore {
-RenderFlowThread::RenderFlowThread(Node* node)
- : RenderBlock(node)
+RenderFlowThread::RenderFlowThread()
+ : RenderBlock(0)
+ , m_previousRegionCount(0)
+ , m_autoLogicalHeightRegionsCount(0)
, m_regionsInvalidated(false)
, m_regionsHaveUniformLogicalWidth(true)
, m_regionsHaveUniformLogicalHeight(true)
- , m_overset(true)
, m_hasRegionsWithStyling(false)
, m_dispatchRegionLayoutUpdateEvent(false)
- , m_pageLogicalHeightChanged(false)
+ , m_dispatchRegionOversetChangeEvent(false)
+ , m_pageLogicalSizeChanged(false)
+ , m_inConstrainedLayoutPhase(false)
+ , m_needsTwoPhasesLayout(false)
{
- ASSERT(node->document()->cssRegionsEnabled());
- setIsAnonymous(false);
- setInRenderFlowThread();
+ setFlowThreadState(InsideOutOfFlowThread);
}
PassRefPtr<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* parentStyle)
@@ -96,17 +101,27 @@ void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion)
ASSERT(renderRegion);
m_regionList.add(renderRegion);
renderRegion->setIsValid(true);
- invalidateRegions();
- checkRegionsWithStyling();
}
void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
{
ASSERT(renderRegion);
- m_regionRangeMap.clear();
m_regionList.remove(renderRegion);
- invalidateRegions();
- checkRegionsWithStyling();
+}
+
+void RenderFlowThread::invalidateRegions()
+{
+ if (m_regionsInvalidated) {
+ ASSERT(selfNeedsLayout());
+ return;
+ }
+
+ m_regionRangeMap.clear();
+ m_breakBeforeToRegionMap.clear();
+ m_breakAfterToRegionMap.clear();
+ setNeedsLayout(true);
+
+ m_regionsInvalidated = true;
}
class CurrentRenderFlowThreadDisabler {
@@ -130,29 +145,33 @@ private:
RenderFlowThread* m_renderFlowThread;
};
-void RenderFlowThread::layout()
+void RenderFlowThread::validateRegions()
{
- StackStats::LayoutCheckPoint layoutCheckPoint;
-
- m_pageLogicalHeightChanged = m_regionsInvalidated && everHadLayout();
if (m_regionsInvalidated) {
m_regionsInvalidated = false;
m_regionsHaveUniformLogicalWidth = true;
m_regionsHaveUniformLogicalHeight = true;
- m_regionRangeMap.clear();
- m_breakBeforeToRegionMap.clear();
- m_breakAfterToRegionMap.clear();
- LayoutUnit previousRegionLogicalWidth = 0;
- LayoutUnit previousRegionLogicalHeight = 0;
- bool firstRegionVisited = false;
if (hasRegions()) {
+ LayoutUnit previousRegionLogicalWidth = 0;
+ LayoutUnit previousRegionLogicalHeight = 0;
+ bool firstRegionVisited = false;
+
for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
- ASSERT(!region->needsLayout());
-
+ ASSERT(!region->needsLayout() || region->isRenderRegionSet());
+
region->deleteAllRenderBoxRegionInfo();
+ // In the normal layout phase we need to initialize the computedAutoHeight for auto-height regions.
+ // See initializeRegionsComputedAutoHeight for the explanation.
+ // Also, if we have auto-height regions we can't assume m_regionsHaveUniformLogicalHeight to be true in the first phase
+ // because the auto-height regions don't have their height computed yet.
+ if (!inConstrainedLayoutPhase() && region->hasAutoLogicalHeight()) {
+ region->setComputedAutoHeight(region->maxPageLogicalHeight());
+ m_regionsHaveUniformLogicalHeight = false;
+ }
+
LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
LayoutUnit regionLogicalHeight = region->pageLogicalHeight();
@@ -167,30 +186,51 @@ void RenderFlowThread::layout()
previousRegionLogicalWidth = regionLogicalWidth;
}
-
- updateLogicalWidth(); // Called to get the maximum logical width for the region.
- updateRegionsFlowThreadPortionRect();
}
}
+ updateLogicalWidth(); // Called to get the maximum logical width for the region.
+ updateRegionsFlowThreadPortionRect();
+}
+
+void RenderFlowThread::layout()
+{
+ StackStats::LayoutCheckPoint layoutCheckPoint;
+
+ m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout();
+
+ // In case this is the second pass of the normal phase we need to update the auto-height regions to their initial value.
+ // If the region chain was invalidated this will happen anyway.
+ if (!m_regionsInvalidated && !inConstrainedLayoutPhase())
+ initializeRegionsComputedAutoHeight();
+
+ validateRegions();
+
+ // This is the first phase of the layout and because we have auto-height regions we'll need a second
+ // pass to update the flow with the computed auto-height regions.
+ m_needsTwoPhasesLayout = !inConstrainedLayoutPhase() && hasAutoLogicalHeightRegions();
+
CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this);
RenderBlock::layout();
- m_pageLogicalHeightChanged = false;
+ m_pageLogicalSizeChanged = false;
if (lastRegion())
lastRegion()->expandToEncompassFlowThreadContentsIfNeeded();
if (shouldDispatchRegionLayoutUpdateEvent())
dispatchRegionLayoutUpdateEvent();
+
+ if (shouldDispatchRegionOversetChangeEvent())
+ dispatchRegionOversetChangeEvent();
}
void RenderFlowThread::updateLogicalWidth()
{
- LayoutUnit logicalWidth = 0;
+ LayoutUnit logicalWidth = initialLogicalWidth();
for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
- ASSERT(!region->needsLayout());
+ ASSERT(!region->needsLayout() || region->isRenderRegionSet());
logicalWidth = max(region->pageLogicalWidth(), logicalWidth);
}
setLogicalWidth(logicalWidth);
@@ -211,62 +251,90 @@ void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, L
computedValues.m_position = logicalTop;
computedValues.m_extent = 0;
+ const LayoutUnit maxFlowSize = RenderFlowThread::maxLogicalHeight();
for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
- ASSERT(!region->needsLayout());
+ ASSERT(!region->needsLayout() || region->isRenderRegionSet());
- if (region->needsOverrideLogicalContentHeightComputation()) {
- // If we have an auto logical height region for which we did not compute a height yet,
- // then we cannot compute and update the height of this flow.
- return;
- }
+ LayoutUnit distanceToMaxSize = maxFlowSize - computedValues.m_extent;
+ computedValues.m_extent += std::min(distanceToMaxSize, region->logicalHeightOfAllFlowThreadContent());
- computedValues.m_extent += region->logicalHeightOfAllFlowThreadContent();
+ // If we reached the maximum size there's no point in going further.
+ if (computedValues.m_extent == maxFlowSize)
+ return;
}
}
-void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const
+LayoutRect RenderFlowThread::computeRegionClippingRect(const LayoutPoint& offset, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect) const
+{
+ LayoutRect regionClippingRect(offset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size());
+ if (style()->isFlippedBlocksWritingMode())
+ regionClippingRect.move(flowThreadPortionRect.size() - flowThreadPortionOverflowRect.size());
+ return regionClippingRect;
+}
+
+void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const
{
GraphicsContext* context = paintInfo.context;
if (!context)
return;
- // Adjust the clipping rect for the region.
- // paintOffset contains the offset where the painting should occur
- // adjusted with the region padding and border.
- LayoutRect regionClippingRect(paintOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size());
+ // RenderFlowThread should start painting its content in a position that is offset
+ // from the region rect's current position. The amount of offset is equal to the location of
+ // the flow thread portion in the flow thread's local coordinates.
+ // Note that we have to pixel snap the location at which we're going to paint, since this is necessary
+ // to minimize the amount of incorrect snapping that would otherwise occur.
+ // If we tried to paint by applying a non-integral translation, then all the
+ // layout code that attempted to pixel snap would be incorrect.
+ IntPoint adjustedPaintOffset;
+ LayoutPoint portionLocation;
+ if (style()->isFlippedBlocksWritingMode()) {
+ LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
+ flipForWritingMode(flippedFlowThreadPortionRect);
+ portionLocation = flippedFlowThreadPortionRect.location();
+ } else
+ portionLocation = flowThreadPortionRect.location();
+ adjustedPaintOffset = roundedIntPoint(paintOffset - portionLocation);
+
+ // The clipping rect for the region is set up by assuming the flowThreadPortionRect is going to paint offset from adjustedPaintOffset.
+ // Remember that we pixel snapped and moved the paintOffset and stored the snapped result in adjustedPaintOffset. Now we add back in
+ // the flowThreadPortionRect's location to get the spot where we expect the portion to actually paint. This can be non-integral and
+ // that's ok. We then pixel snap the resulting clipping rect to account for snapping that will occur when the flow thread paints.
+ IntRect regionClippingRect = pixelSnappedIntRect(computeRegionClippingRect(adjustedPaintOffset + portionLocation, flowThreadPortionRect, flowThreadPortionOverflowRect));
PaintInfo info(paintInfo);
- info.rect.intersect(pixelSnappedIntRect(regionClippingRect));
+ info.rect.intersect(regionClippingRect);
if (!info.rect.isEmpty()) {
context->save();
context->clip(regionClippingRect);
- // RenderFlowThread should start painting its content in a position that is offset
- // from the region rect's current position. The amount of offset is equal to the location of
- // the flow thread portion in the flow thread's local coordinates.
- IntPoint renderFlowThreadOffset;
- if (style()->isFlippedBlocksWritingMode()) {
- LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
- flipForWritingMode(flippedFlowThreadPortionRect);
- renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedFlowThreadPortionRect.location());
- } else
- renderFlowThreadOffset = roundedIntPoint(paintOffset - flowThreadPortionRect.location());
-
- context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y());
- info.rect.moveBy(-renderFlowThreadOffset);
+ context->translate(adjustedPaintOffset.x(), adjustedPaintOffset.y());
+ info.rect.moveBy(-adjustedPaintOffset);
- layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects);
+ PaintBehavior paintBehavior = 0;
+ if (info.phase == PaintPhaseTextClip)
+ paintBehavior |= PaintBehaviorForceBlackText;
+ else if (info.phase == PaintPhaseSelection)
+ paintBehavior |= PaintBehaviorSelectionOnly;
+
+ layer()->paint(context, info.rect, paintBehavior, 0, region, RenderLayer::PaintLayerTemporaryClipRects);
context->restore();
}
}
-bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
+bool RenderFlowThread::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
{
- LayoutRect regionClippingRect(accumulatedOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size());
+ if (hitTestAction == HitTestBlockBackground)
+ return false;
+ return RenderBlock::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction);
+}
+
+bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
+{
+ LayoutRect regionClippingRect = computeRegionClippingRect(accumulatedOffset, flowThreadPortionRect, flowThreadPortionOverflowRect);
if (!regionClippingRect.contains(locationInContainer.point()))
return false;
@@ -279,7 +347,7 @@ bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, La
renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.location();
// Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView.
- HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping);
+ HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
// Make a new temporary HitTestLocation in the new region.
HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOffset, region);
@@ -318,76 +386,134 @@ void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect,
}
}
-RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool extendLastRegion) const
+RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool extendLastRegion, RegionAutoGenerationPolicy autoGenerationPolicy)
{
ASSERT(!m_regionsInvalidated);
- // If no region matches the position and extendLastRegion is true, it will return
- // the last valid region. It is similar to auto extending the size of the last region.
- RenderRegion* lastValidRegion = 0;
-
- LayoutUnit accumulatedLogicalHeight = 0;
-
- // FIXME: The regions are always in order, optimize this search.
- for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
- RenderRegion* region = *iter;
+ if (autoGenerationPolicy == AllowRegionAutoGeneration)
+ autoGenerateRegionsToBlockOffset(offset);
- if (offset <= 0)
- return region;
+ if (offset <= 0)
+ return m_regionList.isEmpty() ? 0 : m_regionList.first();
- if (extendLastRegion || region->isRenderRegionSet())
- lastValidRegion = region;
+ RegionSearchAdapter adapter(offset);
+ m_regionIntervalTree.allOverlapsWithAdapter<RegionSearchAdapter>(adapter);
- // If we did not compute the region's height, we should consider this region
- // tall enough to accomodate all content.
- if (region->needsOverrideLogicalContentHeightComputation())
- return region;
+ // If no region was found, the offset is in the flow thread overflow.
+ // The last region will contain the offset if extendLastRegion is set or if the last region is a set.
+ if (!adapter.result() && !m_regionList.isEmpty() && (extendLastRegion || m_regionList.last()->isRenderRegionSet()))
+ return m_regionList.last();
- if (region->hasOverrideHeight() && view()->normalLayoutPhase()) {
- accumulatedLogicalHeight += region->overrideLogicalContentHeight();
- if (offset < accumulatedLogicalHeight)
- return region;
- continue;
+ return adapter.result();
+}
+
+LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint)
+{
+ LayoutPoint referencePoint = startPoint;
+
+ // FIXME: This needs to be adapted for different writing modes inside the flow thread.
+ RenderRegion* startRegion = regionAtBlockOffset(referencePoint.y());
+ if (startRegion) {
+ // Take into account the offset coordinates of the region.
+ RenderBoxModelObject* currObject = startRegion;
+ RenderBoxModelObject* currOffsetParent;
+ while ((currOffsetParent = currObject->offsetParent())) {
+ referencePoint.move(currObject->offsetLeft(), currObject->offsetTop());
+
+ // Since we're looking for the offset relative to the body, we must also
+ // take into consideration the borders of the region's offsetParent.
+ if (currOffsetParent->isBox() && !currOffsetParent->isBody())
+ referencePoint.move(toRenderBox(currOffsetParent)->borderLeft(), toRenderBox(currOffsetParent)->borderTop());
+
+ currObject = currOffsetParent;
}
-
- LayoutRect regionRect = region->flowThreadPortionRect();
- accumulatedLogicalHeight += isHorizontalWritingMode() ? regionRect.height() : regionRect.width();
- if (offset < accumulatedLogicalHeight)
- return region;
+
+ // We need to check if any of this box's containing blocks start in a different region
+ // and if so, drop the object's top position (which was computed relative to its containing block
+ // and is no longer valid) and recompute it using the region in which it flows as reference.
+ bool wasComputedRelativeToOtherRegion = false;
+ const RenderBlock* objContainingBlock = boxModelObject.containingBlock();
+ while (objContainingBlock && !objContainingBlock->isRenderNamedFlowThread()) {
+ // Check if this object is in a different region.
+ RenderRegion* parentStartRegion = 0;
+ RenderRegion* parentEndRegion = 0;
+ getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEndRegion);
+ if (parentStartRegion && parentStartRegion != startRegion) {
+ wasComputedRelativeToOtherRegion = true;
+ break;
+ }
+ objContainingBlock = objContainingBlock->containingBlock();
+ }
+
+ if (wasComputedRelativeToOtherRegion) {
+ if (boxModelObject.isBox()) {
+ // Use borderBoxRectInRegion to account for variations such as percentage margins.
+ LayoutRect borderBoxRect = toRenderBox(&boxModelObject)->borderBoxRectInRegion(startRegion, RenderBox::DoNotCacheRenderBoxRegionInfo);
+ referencePoint.move(borderBoxRect.location().x(), 0);
+ }
+
+ // Get the logical top coordinate of the current object.
+ LayoutUnit top = 0;
+ if (boxModelObject.isRenderBlock())
+ top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirstPage();
+ else {
+ if (boxModelObject.containingBlock())
+ top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage();
+
+ if (boxModelObject.isBox())
+ top += toRenderBox(&boxModelObject)->topLeftLocation().y();
+ else if (boxModelObject.isRenderInline())
+ top -= toRenderInline(&boxModelObject)->borderTop();
+ }
+
+ // Get the logical top of the region this object starts in
+ // and compute the object's top, relative to the region's top.
+ LayoutUnit regionLogicalTop = startRegion->pageLogicalTopForOffset(top);
+ LayoutUnit topRelativeToRegion = top - regionLogicalTop;
+ referencePoint.setY(startRegion->offsetTop() + topRelativeToRegion);
+
+ // Since the top has been overriden, check if the
+ // relative/sticky positioning must be reconsidered.
+ if (boxModelObject.isRelPositioned())
+ referencePoint.move(0, boxModelObject.relativePositionOffset().height());
+ else if (boxModelObject.isStickyPositioned())
+ referencePoint.move(0, boxModelObject.stickyPositionOffset().height());
+ }
+
+ // Since we're looking for the offset relative to the body, we must also
+ // take into consideration the borders of the region.
+ referencePoint.move(startRegion->borderLeft(), startRegion->borderTop());
}
-
- return lastValidRegion;
+
+ return referencePoint;
}
-LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset) const
+LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset)
{
RenderRegion* region = regionAtBlockOffset(offset);
return region ? region->pageLogicalTopForOffset(offset) : LayoutUnit();
}
-LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset) const
+LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset)
{
RenderRegion* region = regionAtBlockOffset(offset, true);
return region ? region->pageLogicalWidth() : contentLogicalWidth();
}
-LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset) const
+LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset)
{
RenderRegion* region = regionAtBlockOffset(offset);
if (!region)
return 0;
- if (region->needsOverrideLogicalContentHeightComputation())
- return LayoutUnit::max() / 2;
+
return region->pageLogicalHeight();
}
-LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
+LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule)
{
RenderRegion* region = regionAtBlockOffset(offset);
if (!region)
return 0;
- if (region->needsOverrideLogicalContentHeightComputation())
- return LayoutUnit::max() / 2;
LayoutUnit pageLogicalTop = region->pageLogicalTopForOffset(offset);
LayoutUnit pageLogicalHeight = region->pageLogicalHeight();
@@ -414,7 +540,7 @@ RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformSta
// Note: Using the center in order to avoid rounding errors.
LayoutPoint center = boxRect.center();
- RenderRegion* renderRegion = regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true);
+ RenderRegion* renderRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true, DisallowRegionAutoGeneration);
if (!renderRegion)
return 0;
@@ -431,6 +557,12 @@ void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box)
if (!hasRegions())
return;
+ // If the region chain was invalidated the next layout will clear the box information from all the regions.
+ if (m_regionsInvalidated) {
+ ASSERT(selfNeedsLayout());
+ return;
+ }
+
RenderRegion* startRegion;
RenderRegion* endRegion;
getRegionRangeForBox(box, startRegion, endRegion);
@@ -453,25 +585,33 @@ void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box)
m_regionRangeMap.remove(box);
}
-bool RenderFlowThread::logicalWidthChangedInRegions(const RenderBlock* block, LayoutUnit offsetFromLogicalTopOfFirstPage)
+bool RenderFlowThread::logicalWidthChangedInRegionsForBlock(const RenderBlock* block)
{
- if (!hasRegions() || block == this) // Not necessary, since if any region changes, we do a full pagination relayout anyway.
+ if (!hasRegions())
return false;
RenderRegion* startRegion;
RenderRegion* endRegion;
getRegionRangeForBox(block, startRegion, endRegion);
+ // When the region chain is invalidated the box information is discarded so we must assume the width has changed.
+ if (m_pageLogicalSizeChanged && !startRegion)
+ return true;
+
+ // Not necessary for the flow thread, since we already computed the correct info for it.
+ if (block == this)
+ return false;
+
for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
- ASSERT(!region->needsLayout());
+ ASSERT(!region->needsLayout() || region->isRenderRegionSet());
OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block);
if (!oldInfo)
continue;
LayoutUnit oldLogicalWidth = oldInfo->logicalWidth();
- RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region, offsetFromLogicalTopOfFirstPage);
+ RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region);
if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth)
return true;
@@ -551,6 +691,8 @@ void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit off
if (!hasRegions())
return;
+ ASSERT(box->logicalHeight() >= 0);
+
// FIXME: Not right for differing writing-modes.
RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage, true);
RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight(), true);
@@ -598,47 +740,11 @@ void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*&
ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion));
}
-void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge)
+void RenderFlowThread::applyBreakAfterContent(LayoutUnit clientHeight)
{
- LayoutUnit height = oldClientAfterEdge;
-
// Simulate a region break at height. If it points inside an auto logical height region,
- // then it may determine the region override logical content height.
- addForcedRegionBreak(height, this, false);
-
- // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread)
- // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow
- // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height).
- // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region)
- if (hasRenderOverflow()
- && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY())
- || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX())))
- height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX();
-
- RenderRegion* lastReg = lastRegion();
- for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
- RenderRegion* region = *iter;
- LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x());
- LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX());
- RenderRegion::RegionState previousState = region->regionState();
- RenderRegion::RegionState state = RenderRegion::RegionFit;
- if (flowMin <= 0)
- state = RenderRegion::RegionEmpty;
- if (flowMax > 0 && region == lastReg)
- state = RenderRegion::RegionOverset;
- region->setRegionState(state);
- // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event
- // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually
- // changed, so it just assumes that the NamedFlow should dispatch the event
- if (previousState != state
- || state == RenderRegion::RegionFit
- || state == RenderRegion::RegionOverset)
- setDispatchRegionLayoutUpdateEvent(true);
- }
-
- // With the regions overflow state computed we can also set the overset flag for the named flow.
- // If there are no valid regions in the chain, overset is true.
- m_overset = lastReg ? lastReg->regionState() == RenderRegion::RegionOverset : true;
+ // then it may determine the region computed autoheight.
+ addForcedRegionBreak(clientHeight, this, false);
}
bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const
@@ -675,9 +781,8 @@ bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend
ASSERT(object);
ASSERT(region);
- if (!object->inRenderFlowThread())
- return false;
- if (object->enclosingRenderFlowThread() != this)
+ RenderFlowThread* flowThread = object->flowThreadContainingBlock();
+ if (flowThread != this)
return false;
if (!m_regionList.contains(const_cast<RenderRegion*>(region)))
return false;
@@ -717,7 +822,7 @@ bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend
}
#ifndef NDEBUG
-unsigned RenderFlowThread::autoLogicalHeightRegionsCount() const
+bool RenderFlowThread::isAutoLogicalHeightRegionsCountConsistent() const
{
unsigned autoLogicalHeightRegions = 0;
for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
@@ -726,45 +831,30 @@ unsigned RenderFlowThread::autoLogicalHeightRegionsCount() const
autoLogicalHeightRegions++;
}
- return autoLogicalHeightRegions;
+ return autoLogicalHeightRegions == m_autoLogicalHeightRegionsCount;
}
#endif
-void RenderFlowThread::resetRegionsOverrideLogicalContentHeight()
+// During the normal layout phase of the named flow the regions are initialized with a height equal to their max-height.
+// This way unforced breaks are automatically placed when a region is full and the content height/position correctly estimated.
+// Also, the region where a forced break falls is exactly the region found at the forced break offset inside the flow content.
+void RenderFlowThread::initializeRegionsComputedAutoHeight(RenderRegion* startRegion)
{
- ASSERT(view()->layoutState());
- ASSERT(view()->normalLayoutPhase());
-
- // We need to reset the override logical content height for regions with auto logical height
- // only if the flow thread content needs layout.
- if (!needsLayout())
+ ASSERT(!inConstrainedLayoutPhase());
+ if (!hasAutoLogicalHeightRegions())
return;
- // FIXME: optimize this to iterate the region chain only if the flow thread has auto logical height
- // region.
-
- for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
- RenderRegion* region = *iter;
- if (!region->hasAutoLogicalHeight())
- continue;
-
- region->clearOverrideLogicalContentHeight();
- // FIXME: We need to find a way to avoid marking all the regions ancestors for layout
- // as we are already inside layout.
- region->setNeedsLayout(true);
+ RenderRegionList::iterator regionIter = startRegion ? m_regionList.find(startRegion) : m_regionList.begin();
+ for (; regionIter != m_regionList.end(); ++regionIter) {
+ RenderRegion* region = *regionIter;
+ if (region->hasAutoLogicalHeight())
+ region->setComputedAutoHeight(region->maxPageLogicalHeight());
}
- // Make sure we don't skip any region breaks when we do the layout again.
- // Using m_regionsInvalidated to force all the RenderFlowThread children do the layout again.
- m_regionsInvalidated = true;
}
void RenderFlowThread::markAutoLogicalHeightRegionsForLayout()
{
- ASSERT(view()->layoutState());
- ASSERT(view()->constrainedFlowThreadsLayoutPhase());
-
- // FIXME: optimize this to iterate the region chain only if the flow thread has auto logical height
- // region.
+ ASSERT(hasAutoLogicalHeightRegions());
for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
@@ -775,46 +865,40 @@ void RenderFlowThread::markAutoLogicalHeightRegionsForLayout()
// as we are already inside layout.
region->setNeedsLayout(true);
}
-
- m_regionsInvalidated = true;
- setNeedsLayout(true);
}
-void RenderFlowThread::updateRegionsFlowThreadPortionRect()
+void RenderFlowThread::updateRegionsFlowThreadPortionRect(const RenderRegion* lastRegionWithContent)
{
+ ASSERT(!lastRegionWithContent || (!inConstrainedLayoutPhase() && hasAutoLogicalHeightRegions()));
LayoutUnit logicalHeight = 0;
+ bool emptyRegionsSegment = false;
+ // FIXME: Optimize not to clear the interval all the time. This implies manually managing the tree nodes lifecycle.
+ m_regionIntervalTree.clear();
+ m_regionIntervalTree.initIfNeeded();
for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
+ // If we find an empty auto-height region, clear the computedAutoHeight value.
+ if (emptyRegionsSegment && region->hasAutoLogicalHeight())
+ region->clearComputedAutoHeight();
+
LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
- LayoutUnit regionLogicalHeight = region->logicalHeightOfAllFlowThreadContent();
+ LayoutUnit regionLogicalHeight = std::min<LayoutUnit>(RenderFlowThread::maxLogicalHeight() - logicalHeight, region->logicalHeightOfAllFlowThreadContent());
LayoutRect regionRect(style()->direction() == LTR ? LayoutUnit() : logicalWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogicalHeight);
- // When a flow thread has more than one auto logical height region,
- // we have to take into account the override logical content height value,
- // if computed for an auto logical height region, and use it to set the height
- // for the region rect. This way, the regions in the chain following the auto
- // logical height region, will be able to fragment the right part of their
- // associated flow thread content (and compute their overrideComputedLogicalHeight properly).
- if (region->hasOverrideHeight() && view()->normalLayoutPhase()) {
- regionLogicalHeight = region->overrideLogicalContentHeight();
- regionRect.setHeight(regionLogicalHeight);
- }
-
region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect());
+
+ m_regionIntervalTree.add(RegionIntervalTree::createInterval(logicalHeight, logicalHeight + regionLogicalHeight, region));
+
logicalHeight += regionLogicalHeight;
- }
-}
-void RenderFlowThread::clearOverrideLogicalContentHeightInRegions(RenderRegion* startRegion)
-{
- RenderRegionList::iterator regionIter = startRegion ? m_regionList.find(startRegion) : m_regionList.begin();
- for (; regionIter != m_regionList.end(); ++regionIter) {
- RenderRegion* region = *regionIter;
- if (region->hasAutoLogicalHeight())
- region->clearOverrideLogicalContentHeight();
+ // Once we find the last region with content the next regions are considered empty.
+ if (lastRegionWithContent == region)
+ emptyRegionsSegment = true;
}
+
+ ASSERT(!lastRegionWithContent || emptyRegionsSegment);
}
// Even if we require the break to occur at offsetBreakInFlowThread, because regions may have min/max-height values,
@@ -824,9 +908,9 @@ bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread,
{
// We take breaks into account for height computation for auto logical height regions
// only in the layout phase in which we lay out the flows threads unconstrained
- // and we use the content breaks to determine the overrideContentLogicalHeight for
+ // and we use the content breaks to determine the computed auto height for
// auto logical height regions.
- if (view()->constrainedFlowThreadsLayoutPhase())
+ if (inConstrainedLayoutPhase())
return false;
// Breaks can come before or after some objects. We need to track these objects, so that if we get
@@ -838,7 +922,7 @@ bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread,
RenderRegionList::iterator regionIter = m_regionList.find(iter->value);
ASSERT(regionIter != m_regionList.end());
ASSERT((*regionIter)->hasAutoLogicalHeight());
- clearOverrideLogicalContentHeightInRegions(*regionIter);
+ initializeRegionsComputedAutoHeight(*regionIter);
// We need to update the regions flow thread portion rect because we are going to process
// a break on these regions.
@@ -846,63 +930,224 @@ bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread,
}
// Simulate a region break at offsetBreakInFlowThread. If it points inside an auto logical height region,
- // then it determines the region override logical content height.
+ // then it determines the region computed auto height.
RenderRegion* region = regionAtBlockOffset(offsetBreakInFlowThread);
if (!region)
return false;
- // We want to distribute the offsetBreakInFlowThread content among the regions starting with the found region.
- bool overrideLogicalContentHeightComputed = false;
+ bool lastBreakAfterContent = breakChild == this;
+ bool hasComputedAutoHeight = false;
LayoutUnit currentRegionOffsetInFlowThread = isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x();
LayoutUnit offsetBreakInCurrentRegion = offsetBreakInFlowThread - currentRegionOffsetInFlowThread;
- RenderRegionList::iterator regionIter = m_regionList.find(region);
- ASSERT(regionIter != m_regionList.end());
- for (; regionIter != m_regionList.end(); ++regionIter) {
- RenderRegion* region = *regionIter;
- if (region->needsOverrideLogicalContentHeightComputation()) {
- mapToUse.set(breakChild, region);
+ if (region->hasAutoLogicalHeight()) {
+ // A forced break can appear only in an auto-height region that didn't have a forced break before.
+ // This ASSERT is a good-enough heuristic to verify the above condition.
+ ASSERT(region->maxPageLogicalHeight() == region->computedAutoHeight());
- overrideLogicalContentHeightComputed = true;
+ mapToUse.set(breakChild, region);
- // Compute the region height pretending that the offsetBreakInCurrentRegion is the logicalHeight for the auto-height region.
- LayoutUnit regionOverrideLogicalContentHeight = region->computeReplacedLogicalHeightRespectingMinMaxHeight(offsetBreakInCurrentRegion);
- region->setOverrideLogicalContentHeight(regionOverrideLogicalContentHeight);
+ hasComputedAutoHeight = true;
- offsetBreakInCurrentRegion -= regionOverrideLogicalContentHeight;
- currentRegionOffsetInFlowThread += regionOverrideLogicalContentHeight;
- } else
- currentRegionOffsetInFlowThread += isHorizontalWritingMode() ? region->flowThreadPortionRect().height() : region->flowThreadPortionRect().width();
+ // Compute the region height pretending that the offsetBreakInCurrentRegion is the logicalHeight for the auto-height region.
+ LayoutUnit regionComputedAutoHeight = region->constrainContentBoxLogicalHeightByMinMax(offsetBreakInCurrentRegion);
- // If the current offset if greater than the break offset, bail out and skip the current region.
- if (currentRegionOffsetInFlowThread >= offsetBreakInFlowThread) {
- ++regionIter;
- break;
- }
- }
+ // The new height of this region needs to be smaller than the initial value, the max height. A forced break is the only way to change the initial
+ // height of an auto-height region besides content ending.
+ ASSERT(regionComputedAutoHeight <= region->maxPageLogicalHeight());
- // The remaining auto logical height regions in the chain that were unable to receive content
- // and set their overrideLogicalContentHeight should have their associated values cleared.
- if (regionIter != m_regionList.end())
- clearOverrideLogicalContentHeightInRegions(*regionIter);
+ region->setComputedAutoHeight(regionComputedAutoHeight);
+
+ currentRegionOffsetInFlowThread += regionComputedAutoHeight;
+ } else
+ currentRegionOffsetInFlowThread += isHorizontalWritingMode() ? region->flowThreadPortionRect().height() : region->flowThreadPortionRect().width();
- if (overrideLogicalContentHeightComputed)
+ // If the break was found inside an auto-height region its size changed so we need to recompute the flow thread portion rectangles.
+ // Also, if this is the last break after the content we need to clear the computedAutoHeight value on the last empty regions.
+ if (hasAutoLogicalHeightRegions() && lastBreakAfterContent)
+ updateRegionsFlowThreadPortionRect(region);
+ else if (hasComputedAutoHeight)
updateRegionsFlowThreadPortionRect();
if (offsetBreakAdjustment)
*offsetBreakAdjustment = max<LayoutUnit>(0, currentRegionOffsetInFlowThread - offsetBreakInFlowThread);
- return overrideLogicalContentHeightComputed;
+ return hasComputedAutoHeight;
+}
+
+void RenderFlowThread::incrementAutoLogicalHeightRegions()
+{
+ if (!m_autoLogicalHeightRegionsCount)
+ view()->flowThreadController()->incrementFlowThreadsWithAutoLogicalHeightRegions();
+ ++m_autoLogicalHeightRegionsCount;
+}
+
+void RenderFlowThread::decrementAutoLogicalHeightRegions()
+{
+ ASSERT(m_autoLogicalHeightRegionsCount > 0);
+ --m_autoLogicalHeightRegionsCount;
+ if (!m_autoLogicalHeightRegionsCount)
+ view()->flowThreadController()->decrementFlowThreadsWithAutoLogicalHeightRegions();
+}
+
+void RenderFlowThread::collectLayerFragments(LayerFragments& layerFragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
+{
+ ASSERT(!m_regionsInvalidated);
+
+ for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
+ RenderRegion* region = *iter;
+ region->collectLayerFragments(layerFragments, layerBoundingBox, dirtyRect);
+ }
+}
+
+LayoutRect RenderFlowThread::fragmentsBoundingBox(const LayoutRect& layerBoundingBox)
+{
+ ASSERT(!m_regionsInvalidated);
+
+ LayoutRect result;
+ for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
+ RenderRegion* region = *iter;
+ LayerFragments fragments;
+ region->collectLayerFragments(fragments, layerBoundingBox, PaintInfo::infiniteRect());
+ for (size_t i = 0; i < fragments.size(); ++i) {
+ const LayerFragment& fragment = fragments.at(i);
+ LayoutRect fragmentRect(layerBoundingBox);
+ fragmentRect.intersect(fragment.paginationClip);
+ fragmentRect.moveBy(fragment.paginationOffset);
+ result.unite(fragmentRect);
+ }
+ }
+
+ return result;
+}
+
+bool RenderFlowThread::hasCachedOffsetFromLogicalTopOfFirstRegion(const RenderBox* box) const
+{
+ return m_boxesToOffsetMap.contains(box);
+}
+
+LayoutUnit RenderFlowThread::cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox* box) const
+{
+ return m_boxesToOffsetMap.get(box);
+}
+
+void RenderFlowThread::setOffsetFromLogicalTopOfFirstRegion(const RenderBox* box, LayoutUnit offset)
+{
+ m_boxesToOffsetMap.set(box, offset);
+}
+
+void RenderFlowThread::clearOffsetFromLogicalTopOfFirstRegion(const RenderBox* box)
+{
+ ASSERT(m_boxesToOffsetMap.contains(box));
+ m_boxesToOffsetMap.remove(box);
+}
+
+const RenderBox* RenderFlowThread::currentActiveRenderBox() const
+{
+ if (m_activeObjectsStack.isEmpty())
+ return 0;
+
+ const RenderObject* currentObject = m_activeObjectsStack.last();
+ return currentObject->isBox() ? toRenderBox(currentObject) : 0;
+}
+
+void RenderFlowThread::pushFlowThreadLayoutState(const RenderObject* object)
+{
+ if (const RenderBox* currentBoxDescendant = currentActiveRenderBox()) {
+ LayoutState* layoutState = currentBoxDescendant->view()->layoutState();
+ if (layoutState && layoutState->isPaginated()) {
+ ASSERT(layoutState->m_renderer == currentBoxDescendant);
+ LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
+ setOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant, currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width());
+ }
+ }
+
+ m_activeObjectsStack.add(object);
+}
+
+void RenderFlowThread::popFlowThreadLayoutState()
+{
+ m_activeObjectsStack.removeLast();
+
+ if (const RenderBox* currentBoxDescendant = currentActiveRenderBox()) {
+ LayoutState* layoutState = currentBoxDescendant->view()->layoutState();
+ if (layoutState && layoutState->isPaginated())
+ clearOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant);
+ }
+}
+
+LayoutUnit RenderFlowThread::offsetFromLogicalTopOfFirstRegion(const RenderBlock* currentBlock) const
+{
+ // First check if we cached the offset for the block if it's an ancestor containing block of the box
+ // being currently laid out.
+ if (hasCachedOffsetFromLogicalTopOfFirstRegion(currentBlock))
+ return cachedOffsetFromLogicalTopOfFirstRegion(currentBlock);
+
+ // If it's the current box being laid out, use the layout state.
+ const RenderBox* currentBoxDescendant = currentActiveRenderBox();
+ if (currentBlock == currentBoxDescendant) {
+ LayoutState* layoutState = view()->layoutState();
+ ASSERT(layoutState->m_renderer == currentBlock);
+ ASSERT(layoutState && layoutState->isPaginated());
+ LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
+ return currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
+ }
+
+ // As a last resort, take the slow path.
+ LayoutRect blockRect(0, 0, currentBlock->width(), currentBlock->height());
+ while (currentBlock && !currentBlock->isRenderFlowThread()) {
+ RenderBlock* containerBlock = currentBlock->containingBlock();
+ ASSERT(containerBlock);
+ if (!containerBlock)
+ return 0;
+ LayoutPoint currentBlockLocation = currentBlock->location();
+
+ if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
+ // We have to put the block rect in container coordinates
+ // and we have to take into account both the container and current block flipping modes
+ if (containerBlock->style()->isFlippedBlocksWritingMode()) {
+ if (containerBlock->isHorizontalWritingMode())
+ blockRect.setY(currentBlock->height() - blockRect.maxY());
+ else
+ blockRect.setX(currentBlock->width() - blockRect.maxX());
+ }
+ currentBlock->flipForWritingMode(blockRect);
+ }
+ blockRect.moveBy(currentBlockLocation);
+ currentBlock = containerBlock;
+ }
+
+ return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
+}
+
+void RenderFlowThread::RegionSearchAdapter::collectIfNeeded(const RegionInterval& interval)
+{
+ if (m_result)
+ return;
+ if (interval.low() <= m_offset && interval.high() > m_offset)
+ m_result = interval.data();
+}
+
+void RenderFlowThread::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
+{
+ if (this == repaintContainer)
+ return;
+
+ if (RenderRegion* region = mapFromFlowToRegion(transformState))
+ // FIXME: The cast below is probably not the best solution, we may need to find a better way.
+ static_cast<const RenderObject*>(region)->mapLocalToContainer(region->containerForRepaint(), transformState, mode, wasFixed);
}
CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowThread* renderFlowThread)
: m_renderFlowThread(renderFlowThread)
+ , m_previousRenderFlowThread(0)
{
if (!m_renderFlowThread)
return;
RenderView* view = m_renderFlowThread->view();
- ASSERT(!view->flowThreadController()->currentRenderFlowThread());
+ m_previousRenderFlowThread = view->flowThreadController()->currentRenderFlowThread();
+ ASSERT(!m_previousRenderFlowThread || !renderFlowThread->isRenderNamedFlowThread());
view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread);
}
@@ -912,7 +1157,7 @@ CurrentRenderFlowThreadMaintainer::~CurrentRenderFlowThreadMaintainer()
return;
RenderView* view = m_renderFlowThread->view();
ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFlowThread);
- view->flowThreadController()->setCurrentRenderFlowThread(0);
+ view->flowThreadController()->setCurrentRenderFlowThread(m_previousRenderFlowThread);
}
diff --git a/Source/WebCore/rendering/RenderFlowThread.h b/Source/WebCore/rendering/RenderFlowThread.h
index c39874c64..ffd42bc16 100644
--- a/Source/WebCore/rendering/RenderFlowThread.h
+++ b/Source/WebCore/rendering/RenderFlowThread.h
@@ -35,10 +35,11 @@
#include <wtf/HashCountedSet.h>
#include <wtf/ListHashSet.h>
#include <wtf/PassRefPtr.h>
-#include <wtf/UnusedParam.h>
namespace WebCore {
+struct LayerFragment;
+typedef Vector<LayerFragment, 1> LayerFragments;
class RenderFlowThread;
class RenderStyle;
class RenderRegion;
@@ -53,7 +54,7 @@ typedef ListHashSet<RenderRegion*> RenderRegionList;
class RenderFlowThread: public RenderBlock {
public:
- RenderFlowThread(Node*);
+ RenderFlowThread();
virtual ~RenderFlowThread() { };
virtual bool isRenderFlowThread() const { return true; }
@@ -76,15 +77,17 @@ public:
virtual void updateLogicalWidth() OVERRIDE;
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
- void paintFlowThreadPortionInRegion(PaintInfo&, RenderRegion*, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint&) const;
- bool hitTestFlowThreadPortionInRegion(RenderRegion*, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
+ void paintFlowThreadPortionInRegion(PaintInfo&, RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint&) const;
+ bool hitTestFlowThreadPortionInRegion(RenderRegion*, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
bool hasRegions() const { return m_regionList.size(); }
// Check if the content is flown into at least a region with region styling rules.
bool hasRegionsWithStyling() const { return m_hasRegionsWithStyling; }
void checkRegionsWithStyling();
- void invalidateRegions() { m_regionsInvalidated = true; setNeedsLayout(true); }
+ void validateRegions();
+ void invalidateRegions();
bool hasValidRegionInfo() const { return !m_regionsInvalidated && !m_regionList.isEmpty(); }
static PassRefPtr<RenderStyle> createFlowThreadStyle(RenderStyle* parentStyle);
@@ -92,12 +95,22 @@ public:
void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
void repaintRectangleInRegions(const LayoutRect&, bool immediate) const;
+
+ LayoutPoint adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject&, const LayoutPoint&);
+
+ LayoutUnit pageLogicalTopForOffset(LayoutUnit);
+ LayoutUnit pageLogicalWidthForOffset(LayoutUnit);
+ LayoutUnit pageLogicalHeightForOffset(LayoutUnit);
+ LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary);
+
+ virtual void setPageBreak(LayoutUnit /*offset*/, LayoutUnit /*spaceShortage*/) { }
+ virtual void updateMinimumPageHeight(LayoutUnit /*offset*/, LayoutUnit /*minHeight*/) { }
- LayoutUnit pageLogicalTopForOffset(LayoutUnit) const;
- LayoutUnit pageLogicalWidthForOffset(LayoutUnit) const;
- LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const;
- LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary) const;
- RenderRegion* regionAtBlockOffset(LayoutUnit, bool extendLastRegion = false) const;
+ enum RegionAutoGenerationPolicy {
+ AllowRegionAutoGeneration,
+ DisallowRegionAutoGeneration,
+ };
+ RenderRegion* regionAtBlockOffset(LayoutUnit, bool extendLastRegion = false, RegionAutoGenerationPolicy = AllowRegionAutoGeneration);
bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; }
bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; }
@@ -105,7 +118,7 @@ public:
RenderRegion* mapFromFlowToRegion(TransformState&) const;
void removeRenderBoxRegionInfo(RenderBox*);
- bool logicalWidthChangedInRegions(const RenderBlock*, LayoutUnit offsetFromLogicalTopOfFirstPage);
+ bool logicalWidthChangedInRegionsForBlock(const RenderBlock*);
LayoutUnit contentLogicalWidthOfFirstRegion() const;
LayoutUnit contentLogicalHeightOfFirstRegion() const;
@@ -114,47 +127,88 @@ public:
RenderRegion* firstRegion() const;
RenderRegion* lastRegion() const;
+ bool previousRegionCountChanged() const { return m_previousRegionCount != m_regionList.size(); };
+ void updatePreviousRegionCount() { m_previousRegionCount = m_regionList.size(); };
+
void setRegionRangeForBox(const RenderBox*, LayoutUnit offsetFromLogicalTopOfFirstPage);
void getRegionRangeForBox(const RenderBox*, RenderRegion*& startRegion, RenderRegion*& endRegion) const;
void clearRenderObjectCustomStyle(const RenderObject*,
const RenderRegion* oldStartRegion = 0, const RenderRegion* oldEndRegion = 0,
const RenderRegion* newStartRegion = 0, const RenderRegion* newEndRegion = 0);
-
- void computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge);
-
- bool overset() const { return m_overset; }
// Check if the object is in region and the region is part of this flow thread.
bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const;
- void resetRegionsOverrideLogicalContentHeight();
void markAutoLogicalHeightRegionsForLayout();
bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
+ void applyBreakAfterContent(LayoutUnit);
+
+ bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; }
- bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; }
+ bool hasAutoLogicalHeightRegions() const { ASSERT(isAutoLogicalHeightRegionsCountConsistent()); return m_autoLogicalHeightRegionsCount; }
+ void incrementAutoLogicalHeightRegions();
+ void decrementAutoLogicalHeightRegions();
#ifndef NDEBUG
- unsigned autoLogicalHeightRegionsCount() const;
+ bool isAutoLogicalHeightRegionsCountConsistent() const;
#endif
+ void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect);
+ LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox);
+
+ void setInConstrainedLayoutPhase(bool value) { m_inConstrainedLayoutPhase = value; }
+ bool inConstrainedLayoutPhase() const { return m_inConstrainedLayoutPhase; }
+
+ bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; }
+ void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; }
+
+ void pushFlowThreadLayoutState(const RenderObject*);
+ void popFlowThreadLayoutState();
+ LayoutUnit offsetFromLogicalTopOfFirstRegion(const RenderBlock*) const;
+
+ // Used to estimate the maximum height of the flow thread.
+ static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; }
+
protected:
virtual const char* renderName() const = 0;
- void updateRegionsFlowThreadPortionRect();
+ // Overridden by columns/pages to set up an initial logical width of the page width even when
+ // no regions have been generated yet.
+ virtual LayoutUnit initialLogicalWidth() const { return 0; };
+
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
+
+ void updateRegionsFlowThreadPortionRect(const RenderRegion* = 0);
bool shouldRepaint(const LayoutRect&) const;
bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const;
-
+
+ LayoutRect computeRegionClippingRect(const LayoutPoint&, const LayoutRect&, const LayoutRect&) const;
+
void setDispatchRegionLayoutUpdateEvent(bool value) { m_dispatchRegionLayoutUpdateEvent = value; }
bool shouldDispatchRegionLayoutUpdateEvent() { return m_dispatchRegionLayoutUpdateEvent; }
+ void setDispatchRegionOversetChangeEvent(bool value) { m_dispatchRegionOversetChangeEvent = value; }
+ bool shouldDispatchRegionOversetChangeEvent() const { return m_dispatchRegionOversetChangeEvent; }
+
// Override if the flow thread implementation supports dispatching events when the flow layout is updated (e.g. for named flows)
virtual void dispatchRegionLayoutUpdateEvent() { m_dispatchRegionLayoutUpdateEvent = false; }
+ virtual void dispatchRegionOversetChangeEvent() { m_dispatchRegionOversetChangeEvent = false; }
+
+ void initializeRegionsComputedAutoHeight(RenderRegion* = 0);
+
+ virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) { };
- void clearOverrideLogicalContentHeightInRegions(RenderRegion* startRegion = 0);
+ inline bool hasCachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const;
+ inline LayoutUnit cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox*) const;
+ inline void setOffsetFromLogicalTopOfFirstRegion(const RenderBox*, LayoutUnit);
+ inline void clearOffsetFromLogicalTopOfFirstRegion(const RenderBox*);
+
+ inline const RenderBox* currentActiveRenderBox() const;
RenderRegionList m_regionList;
+ unsigned short m_previousRegionCount;
class RenderRegionRange {
public:
@@ -182,6 +236,28 @@ protected:
RenderRegion* m_endRegion;
};
+ typedef PODInterval<LayoutUnit, RenderRegion*> RegionInterval;
+ typedef PODIntervalTree<LayoutUnit, RenderRegion*> RegionIntervalTree;
+
+ class RegionSearchAdapter {
+ public:
+ RegionSearchAdapter(LayoutUnit offset)
+ : m_offset(offset)
+ , m_result(0)
+ {
+ }
+
+ const LayoutUnit& lowValue() const { return m_offset; }
+ const LayoutUnit& highValue() const { return m_offset; }
+ void collectIfNeeded(const RegionInterval&);
+
+ RenderRegion* result() const { return m_result; }
+
+ private:
+ LayoutUnit m_offset;
+ RenderRegion* m_result;
+ };
+
// A maps from RenderBox
typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap;
RenderRegionRangeMap m_regionRangeMap;
@@ -190,24 +266,35 @@ protected:
RenderObjectToRegionMap m_breakBeforeToRegionMap;
RenderObjectToRegionMap m_breakAfterToRegionMap;
+ typedef ListHashSet<const RenderObject*> RenderObjectStack;
+ RenderObjectStack m_activeObjectsStack;
+ typedef HashMap<const RenderBox*, LayoutUnit> RenderBoxToOffsetMap;
+ RenderBoxToOffsetMap m_boxesToOffsetMap;
+
+ unsigned m_autoLogicalHeightRegionsCount;
+
+ RegionIntervalTree m_regionIntervalTree;
+
bool m_regionsInvalidated : 1;
bool m_regionsHaveUniformLogicalWidth : 1;
bool m_regionsHaveUniformLogicalHeight : 1;
- bool m_overset : 1;
bool m_hasRegionsWithStyling : 1;
bool m_dispatchRegionLayoutUpdateEvent : 1;
- bool m_pageLogicalHeightChanged : 1;
+ bool m_dispatchRegionOversetChangeEvent : 1;
+ bool m_pageLogicalSizeChanged : 1;
+ bool m_inConstrainedLayoutPhase : 1;
+ bool m_needsTwoPhasesLayout : 1;
};
inline RenderFlowThread* toRenderFlowThread(RenderObject* object)
{
- ASSERT(!object || object->isRenderFlowThread());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderFlowThread());
return static_cast<RenderFlowThread*>(object);
}
inline const RenderFlowThread* toRenderFlowThread(const RenderObject* object)
{
- ASSERT(!object || object->isRenderFlowThread());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderFlowThread());
return static_cast<const RenderFlowThread*>(object);
}
@@ -221,8 +308,20 @@ public:
~CurrentRenderFlowThreadMaintainer();
private:
RenderFlowThread* m_renderFlowThread;
+ RenderFlowThread* m_previousRenderFlowThread;
+};
+
+// These structures are used by PODIntervalTree for debugging.
+#ifndef NDEBUG
+template <> struct ValueToString<LayoutUnit> {
+ static String string(const LayoutUnit value) { return String::number(value.toFloat()); }
};
+template <> struct ValueToString<RenderRegion*> {
+ static String string(const RenderRegion* value) { return String::format("%p", value); }
+};
+#endif
+
} // namespace WebCore
#endif // RenderFlowThread_h
diff --git a/Source/WebCore/rendering/RenderFrame.cpp b/Source/WebCore/rendering/RenderFrame.cpp
index f4c3cb6b6..9bd7c1654 100644
--- a/Source/WebCore/rendering/RenderFrame.cpp
+++ b/Source/WebCore/rendering/RenderFrame.cpp
@@ -54,7 +54,7 @@ void RenderFrame::viewCleared()
if (!element || !widget() || !widget()->isFrameView())
return;
- FrameView* view = static_cast<FrameView*>(widget());
+ FrameView* view = toFrameView(widget());
int marginWidth = element->marginWidth();
int marginHeight = element->marginHeight();
diff --git a/Source/WebCore/rendering/RenderFrame.h b/Source/WebCore/rendering/RenderFrame.h
index 6f48e2679..9eadb9393 100644
--- a/Source/WebCore/rendering/RenderFrame.h
+++ b/Source/WebCore/rendering/RenderFrame.h
@@ -47,7 +47,7 @@ private:
inline RenderFrame* toRenderFrame(RenderObject* object)
{
- ASSERT(!object || object->isFrame());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFrame());
return static_cast<RenderFrame*>(object);
}
diff --git a/Source/WebCore/rendering/RenderFrameBase.cpp b/Source/WebCore/rendering/RenderFrameBase.cpp
index aa82870d4..94c09002c 100644
--- a/Source/WebCore/rendering/RenderFrameBase.cpp
+++ b/Source/WebCore/rendering/RenderFrameBase.cpp
@@ -54,8 +54,8 @@ inline bool shouldExpandFrame(LayoutUnit width, LayoutUnit height, bool hasFixed
void RenderFrameBase::layoutWithFlattening(bool hasFixedWidth, bool hasFixedHeight)
{
- FrameView* childFrameView = static_cast<FrameView*>(widget());
- RenderView* childRoot = childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0;
+ FrameView* childFrameView = toFrameView(widget());
+ RenderView* childRoot = childFrameView ? childFrameView->frame()->contentRenderer() : 0;
if (!childRoot || !shouldExpandFrame(width(), height(), hasFixedWidth, hasFixedHeight)) {
updateWidgetPosition();
@@ -67,15 +67,12 @@ void RenderFrameBase::layoutWithFlattening(bool hasFixedWidth, bool hasFixedHeig
// need to update to calculate min/max correctly
updateWidgetPosition();
- if (childRoot->preferredLogicalWidthsDirty())
- childRoot->computePreferredLogicalWidths();
// if scrollbars are off, and the width or height are fixed
// we obey them and do not expand. With frame flattening
// no subframe much ever become scrollable.
- HTMLFrameElementBase* element = static_cast<HTMLFrameElementBase*>(node());
- bool isScrollable = element->scrollingMode() != ScrollbarAlwaysOff;
+ bool isScrollable = toHTMLFrameElementBase(node())->scrollingMode() != ScrollbarAlwaysOff;
// consider iframe inset border
int hBorder = borderLeft() + borderRight();
diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp
index e4e7e24bb..308204547 100644
--- a/Source/WebCore/rendering/RenderFrameSet.cpp
+++ b/Source/WebCore/rendering/RenderFrameSet.cpp
@@ -40,6 +40,7 @@
#include "RenderLayer.h"
#include "RenderView.h"
#include "Settings.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -157,24 +158,6 @@ void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
}
}
-bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
- const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
-{
- if (action != HitTestForeground)
- return false;
-
- bool inside = RenderBox::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action)
- || m_isResizing;
-
- if (inside && frameSet()->noResize()
- && !request.readOnly() && !result.innerNode() && !request.touchMove()) {
- result.setInnerNode(node());
- result.setInnerNonSharedNode(node());
- }
-
- return inside || m_isChildResizing;
-}
-
void RenderFrameSet::GridAxis::resize(int size)
{
m_sizes.resize(size);
@@ -420,10 +403,10 @@ void RenderFrameSet::computeEdgeInfo()
if (!child)
return;
- int rows = frameSet()->totalRows();
- int cols = frameSet()->totalCols();
- for (int r = 0; r < rows; ++r) {
- for (int c = 0; c < cols; ++c) {
+ size_t rows = m_rows.m_sizes.size();
+ size_t cols = m_cols.m_sizes.size();
+ for (size_t r = 0; r < rows; ++r) {
+ for (size_t c = 0; c < cols; ++c) {
FrameEdgeInfo edgeInfo;
if (child->isFrameSet())
edgeInfo = toRenderFrameSet(child)->edgeInfo();
@@ -464,8 +447,11 @@ void RenderFrameSet::layout()
bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
LayoutRect oldBounds;
- if (doFullRepaint)
- oldBounds = absoluteClippedOverflowRect();
+ RenderLayerModelObject* repaintContainer = 0;
+ if (doFullRepaint) {
+ repaintContainer = containerForRepaint();
+ oldBounds = clippedOverflowRectForRepaint(repaintContainer);
+ }
if (!parent()->isFrameSet() && !document()->printing()) {
setWidth(view()->viewWidth());
@@ -493,19 +479,15 @@ void RenderFrameSet::layout()
computeEdgeInfo();
+ updateLayerTransform();
+
if (doFullRepaint) {
- view()->repaintViewRectangle(oldBounds);
- LayoutRect newBounds = absoluteClippedOverflowRect();
+ repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds));
+ LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer);
if (newBounds != oldBounds)
- view()->repaintViewRectangle(newBounds);
+ repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds));
}
- // If this FrameSet has a transform matrix then we need to recompute it
- // because the transform origin is a function the size of the RenderFrameSet
- // which may not be computed until it is attached to the render tree.
- if (layer() && hasTransform())
- layer()->updateTransform();
-
setNeedsLayout(false);
}
@@ -700,7 +682,7 @@ bool RenderFrameSet::userResize(MouseEvent* evt)
if (needsLayout())
return false;
if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
- FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms | SnapOffsetForTransforms);
+ FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms);
startResizing(m_cols, localPos.x());
startResizing(m_rows, localPos.y());
if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
@@ -710,7 +692,7 @@ bool RenderFrameSet::userResize(MouseEvent* evt)
}
} else {
if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
- FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms | SnapOffsetForTransforms);
+ FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms);
continueResizing(m_cols, localPos.x());
continueResizing(m_rows, localPos.y());
if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) {
diff --git a/Source/WebCore/rendering/RenderFrameSet.h b/Source/WebCore/rendering/RenderFrameSet.h
index edab2d98c..0cfce5290 100644
--- a/Source/WebCore/rendering/RenderFrameSet.h
+++ b/Source/WebCore/rendering/RenderFrameSet.h
@@ -84,6 +84,7 @@ private:
public:
GridAxis();
void resize(int);
+
Vector<int> m_sizes;
Vector<int> m_deltas;
Vector<bool> m_preventResize;
@@ -99,7 +100,6 @@ private:
virtual bool isFrameSet() const { return true; }
virtual void layout();
- virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
virtual void paint(PaintInfo&, const LayoutPoint&);
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const;
@@ -137,7 +137,7 @@ private:
inline RenderFrameSet* toRenderFrameSet(RenderObject* object)
{
- ASSERT(!object || object->isFrameSet());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isFrameSet());
return static_cast<RenderFrameSet*>(object);
}
diff --git a/Source/WebCore/rendering/RenderFullScreen.cpp b/Source/WebCore/rendering/RenderFullScreen.cpp
index 2f1c311b1..af11971c1 100644
--- a/Source/WebCore/rendering/RenderFullScreen.cpp
+++ b/Source/WebCore/rendering/RenderFullScreen.cpp
@@ -39,9 +39,10 @@ using namespace WebCore;
class RenderFullScreenPlaceholder : public RenderBlock {
public:
RenderFullScreenPlaceholder(RenderFullScreen* owner)
- : RenderBlock(owner->document())
+ : RenderBlock(0)
, m_owner(owner)
- {
+ {
+ setDocumentForAnonymous(owner->document());
}
private:
virtual bool isRenderFullScreenPlaceholder() const { return true; }
@@ -55,13 +56,20 @@ void RenderFullScreenPlaceholder::willBeDestroyed()
RenderBlock::willBeDestroyed();
}
-RenderFullScreen::RenderFullScreen(Node* node)
- : RenderDeprecatedFlexibleBox(node)
+RenderFullScreen::RenderFullScreen()
+ : RenderFlexibleBox(0)
, m_placeholder(0)
-{
+{
setReplaced(false);
}
+RenderFullScreen* RenderFullScreen::createAnonymous(Document* document)
+{
+ RenderFullScreen* renderer = new (document->renderArena()) RenderFullScreen();
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
void RenderFullScreen::willBeDestroyed()
{
if (m_placeholder) {
@@ -76,7 +84,7 @@ void RenderFullScreen::willBeDestroyed()
if (document() && document()->fullScreenRenderer() == this)
document()->fullScreenRendererDestroyed();
- RenderDeprecatedFlexibleBox::willBeDestroyed();
+ RenderFlexibleBox::willBeDestroyed();
}
static PassRefPtr<RenderStyle> createFullScreenStyle()
@@ -89,10 +97,10 @@ static PassRefPtr<RenderStyle> createFullScreenStyle()
fullscreenStyle->setFontDescription(FontDescription());
fullscreenStyle->font().update(0);
- fullscreenStyle->setDisplay(BOX);
- fullscreenStyle->setBoxPack(Center);
- fullscreenStyle->setBoxAlign(BCENTER);
- fullscreenStyle->setBoxOrient(VERTICAL);
+ fullscreenStyle->setDisplay(FLEX);
+ fullscreenStyle->setJustifyContent(JustifyCenter);
+ fullscreenStyle->setAlignItems(AlignCenter);
+ fullscreenStyle->setFlexDirection(FlowColumn);
fullscreenStyle->setPosition(FixedPosition);
fullscreenStyle->setWidth(Length(100.0, Percent));
@@ -107,7 +115,7 @@ static PassRefPtr<RenderStyle> createFullScreenStyle()
RenderObject* RenderFullScreen::wrapRenderer(RenderObject* object, RenderObject* parent, Document* document)
{
- RenderFullScreen* fullscreenRenderer = new (document->renderArena()) RenderFullScreen(document);
+ RenderFullScreen* fullscreenRenderer = RenderFullScreen::createAnonymous(document);
fullscreenRenderer->setStyle(createFullScreenStyle());
if (parent && !parent->isChildAllowed(fullscreenRenderer, fullscreenRenderer->style())) {
fullscreenRenderer->destroy();
@@ -144,6 +152,11 @@ void RenderFullScreen::unwrapRenderer()
if (parent()) {
RenderObject* child;
while ((child = firstChild())) {
+ // We have to clear the override size, because as a flexbox, we
+ // may have set one on the child, and we don't want to leave that
+ // lying around on the child.
+ if (child->isBox())
+ toRenderBox(child)->clearOverrideSize();
child->remove();
parent()->addChild(child, this);
parent()->setNeedsLayoutAndPrefWidthsRecalc();
diff --git a/Source/WebCore/rendering/RenderFullScreen.h b/Source/WebCore/rendering/RenderFullScreen.h
index a54ac1561..976ebcefc 100644
--- a/Source/WebCore/rendering/RenderFullScreen.h
+++ b/Source/WebCore/rendering/RenderFullScreen.h
@@ -27,14 +27,15 @@
#if ENABLE(FULLSCREEN_API)
-#include "RenderDeprecatedFlexibleBox.h"
+#include "RenderFlexibleBox.h"
#include "StyleInheritedData.h"
namespace WebCore {
-class RenderFullScreen : public RenderDeprecatedFlexibleBox {
+class RenderFullScreen : public RenderFlexibleBox {
public:
- RenderFullScreen(Node*);
+ static RenderFullScreen* createAnonymous(Document*);
+
virtual bool isRenderFullScreen() const { return true; }
virtual const char* renderName() const { return "RenderFullScreen"; }
@@ -47,15 +48,16 @@ public:
void unwrapRenderer();
private:
+ RenderFullScreen();
virtual void willBeDestroyed();
-
+
protected:
RenderBlock* m_placeholder;
};
inline RenderFullScreen* toRenderFullScreen(RenderObject* object)
{
- ASSERT(object->isRenderFullScreen());
+ ASSERT_WITH_SECURITY_IMPLICATION(object->isRenderFullScreen());
return static_cast<RenderFullScreen*>(object);
}
diff --git a/Source/WebCore/rendering/RenderGeometryMap.cpp b/Source/WebCore/rendering/RenderGeometryMap.cpp
index 74434895f..4513ef6a1 100644
--- a/Source/WebCore/rendering/RenderGeometryMap.cpp
+++ b/Source/WebCore/rendering/RenderGeometryMap.cpp
@@ -51,6 +51,7 @@ void RenderGeometryMap::mapToContainer(TransformState& transformState, const Ren
// If the mapping includes something like columns, we have to go via renderers.
if (hasNonUniformStep()) {
m_mapping.last().m_renderer->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags);
+ transformState.flatten();
return;
}
@@ -104,7 +105,7 @@ FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLa
FloatPoint result;
if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer)))
- result = p + m_accumulatedOffset;
+ result = p + roundedIntSize(m_accumulatedOffset);
else {
TransformState transformState(TransformState::ApplyTransformDirection, p);
mapToContainer(transformState, container);
diff --git a/Source/WebCore/rendering/RenderGeometryMap.h b/Source/WebCore/rendering/RenderGeometryMap.h
index bab106f1d..00c41f7cc 100644
--- a/Source/WebCore/rendering/RenderGeometryMap.h
+++ b/Source/WebCore/rendering/RenderGeometryMap.h
@@ -74,7 +74,7 @@ struct RenderGeometryMapStep {
class RenderGeometryMap {
WTF_MAKE_NONCOPYABLE(RenderGeometryMap);
public:
- RenderGeometryMap(MapCoordinatesFlags = UseTransforms | SnapOffsetForTransforms);
+ RenderGeometryMap(MapCoordinatesFlags = UseTransforms);
~RenderGeometryMap();
MapCoordinatesFlags mapCoordinatesFlags() const { return m_mapCoordinatesFlags; }
diff --git a/Source/WebCore/rendering/RenderGrid.cpp b/Source/WebCore/rendering/RenderGrid.cpp
index e7a351c86..a65941552 100644
--- a/Source/WebCore/rendering/RenderGrid.cpp
+++ b/Source/WebCore/rendering/RenderGrid.cpp
@@ -33,18 +33,101 @@
namespace WebCore {
-class RenderGrid::GridTrack {
+static const int infinity = intMaxForLayoutUnit;
+
+class GridTrack {
public:
GridTrack()
: m_usedBreadth(0)
+ , m_maxBreadth(0)
+ {
+ }
+
+ void growUsedBreadth(LayoutUnit growth)
+ {
+ ASSERT(growth >= 0);
+ m_usedBreadth += growth;
+ }
+ LayoutUnit usedBreadth() const { return m_usedBreadth; }
+
+ void growMaxBreadth(LayoutUnit growth)
{
+ if (m_maxBreadth == infinity)
+ m_maxBreadth = m_usedBreadth + growth;
+ else
+ m_maxBreadth += growth;
+ }
+ LayoutUnit maxBreadthIfNotInfinite() const
+ {
+ return (m_maxBreadth == infinity) ? m_usedBreadth : m_maxBreadth;
}
LayoutUnit m_usedBreadth;
+ LayoutUnit m_maxBreadth;
+};
+
+class RenderGrid::GridIterator {
+ WTF_MAKE_NONCOPYABLE(GridIterator);
+public:
+ // |direction| is the direction that is fixed to |fixedTrackIndex| so e.g
+ // GridIterator(m_grid, ForColumns, 1) will walk over the rows of the 2nd column.
+ GridIterator(const Vector<Vector<Vector<RenderBox*, 1> > >& grid, TrackSizingDirection direction, size_t fixedTrackIndex)
+ : m_grid(grid)
+ , m_direction(direction)
+ , m_rowIndex((direction == ForColumns) ? 0 : fixedTrackIndex)
+ , m_columnIndex((direction == ForColumns) ? fixedTrackIndex : 0)
+ , m_childIndex(0)
+ {
+ ASSERT(m_rowIndex < m_grid.size());
+ ASSERT(m_columnIndex < m_grid[0].size());
+ }
+
+ RenderBox* nextGridItem()
+ {
+ if (!m_grid.size())
+ return 0;
+
+ size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m_columnIndex;
+ const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_grid.size() : m_grid[0].size();
+ for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex) {
+ const Vector<RenderBox*>& children = m_grid[m_rowIndex][m_columnIndex];
+ if (m_childIndex < children.size())
+ return children[m_childIndex++];
+
+ m_childIndex = 0;
+ }
+ return 0;
+ }
+
+ PassOwnPtr<GridCoordinate> nextEmptyGridArea()
+ {
+ if (m_grid.isEmpty())
+ return nullptr;
+
+ size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m_columnIndex;
+ const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_grid.size() : m_grid[0].size();
+ for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex) {
+ const Vector<RenderBox*>& children = m_grid[m_rowIndex][m_columnIndex];
+ if (children.isEmpty()) {
+ OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(GridSpan(m_rowIndex, m_rowIndex), GridSpan(m_columnIndex, m_columnIndex)));
+ // Advance the iterator to avoid an infinite loop where we would return the same grid area over and over.
+ ++varyingTrackIndex;
+ return result.release();
+ }
+ }
+ return nullptr;
+ }
+
+private:
+ const Vector<Vector<Vector<RenderBox*, 1> > >& m_grid;
+ TrackSizingDirection m_direction;
+ size_t m_rowIndex;
+ size_t m_columnIndex;
+ size_t m_childIndex;
};
-RenderGrid::RenderGrid(Node* node)
- : RenderBlock(node)
+RenderGrid::RenderGrid(Element* element)
+ : RenderBlock(element)
{
// All of our children must be block level.
setChildrenInline(false);
@@ -66,20 +149,18 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- if (inRenderFlowThread()) {
- // Regions changing widths can force us to relayout our children.
- if (logicalWidthChangedInRegions())
- relayoutChildren = true;
- }
- updateRegionsAndExclusionsLogicalSize();
+ // Regions changing widths can force us to relayout our children.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (logicalWidthChangedInRegions(flowThread))
+ relayoutChildren = true;
+ if (updateRegionsAndShapesBeforeChildLayout(flowThread))
+ relayoutChildren = true;
LayoutSize previousSize = size();
setLogicalHeight(0);
updateLogicalWidth();
- m_overflow.clear();
-
layoutGridItems();
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
@@ -90,7 +171,7 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
layoutPositionedObjects(relayoutChildren || isRoot());
- computeRegionRangeForBlock();
+ updateRegionsAndShapesAfterChildLayout(flowThread);
computeOverflow(oldClientAfterEdge);
statePusher.pop();
@@ -99,14 +180,35 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
- if (hasOverflowClip())
- layer()->updateScrollInfoAfterLayout();
+ updateScrollInfoAfterLayout();
repainter.repaintAfterLayout();
setNeedsLayout(false);
}
+void RenderGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ const_cast<RenderGrid*>(this)->placeItemsOnGrid();
+
+ // FIXME: This is an inefficient way to fill our sizes as it will try every grid areas, when we would
+ // only want to account for fixed grid tracks and grid items. Also this will be incorrect if we have spanning
+ // grid items.
+ for (size_t i = 0; i < gridColumnCount(); ++i) {
+ const GridTrackSize& trackSize = gridTrackSize(ForColumns, i);
+ LayoutUnit minTrackBreadth = computePreferredTrackWidth(trackSize.minTrackBreadth(), i);
+ LayoutUnit maxTrackBreadth = computePreferredTrackWidth(trackSize.maxTrackBreadth(), i);
+ maxTrackBreadth = std::max(maxTrackBreadth, minTrackBreadth);
+
+ minLogicalWidth += minTrackBreadth;
+ maxLogicalWidth += maxTrackBreadth;
+
+ // FIXME: This should add in the scrollbarWidth (e.g. see RenderFlexibleBox).
+ }
+
+ const_cast<RenderGrid*>(this)->clearGrid();
+}
+
void RenderGrid::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
@@ -114,64 +216,471 @@ void RenderGrid::computePreferredLogicalWidths()
m_minPreferredLogicalWidth = 0;
m_maxPreferredLogicalWidth = 0;
- // FIXME: We don't take our own logical width into account.
+ // FIXME: We don't take our own logical width into account. Once we do, we need to make sure
+ // we apply (and test the interaction with) min-width / max-width.
- const Vector<GridTrackSize>& trackStyles = style()->gridColumns();
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
- for (size_t i = 0; i < trackStyles.size(); ++i) {
- Length trackLength = trackStyles[i].length();
- if (!trackLength.isFixed()) {
- notImplemented();
- continue;
+ LayoutUnit borderAndPaddingInInlineDirection = borderAndPaddingLogicalWidth();
+ m_minPreferredLogicalWidth += borderAndPaddingInInlineDirection;
+ m_maxPreferredLogicalWidth += borderAndPaddingInInlineDirection;
+
+ setPreferredLogicalWidthsDirty(false);
+}
+
+LayoutUnit RenderGrid::computePreferredTrackWidth(const Length& length, size_t trackIndex) const
+{
+ if (length.isFixed()) {
+ // Grid areas don't have borders, margins or paddings so we don't need to account for them.
+ return length.intValue();
+ }
+
+ if (length.isMinContent()) {
+ LayoutUnit minContentSize = 0;
+ GridIterator iterator(m_grid, ForColumns, trackIndex);
+ while (RenderBox* gridItem = iterator.nextGridItem()) {
+ // FIXME: We should include the child's fixed margins like RenderFlexibleBox.
+ minContentSize = std::max(minContentSize, gridItem->minPreferredLogicalWidth());
}
+ return minContentSize;
+ }
- m_minPreferredLogicalWidth += trackLength.intValue();
- m_maxPreferredLogicalWidth += trackLength.intValue();
+ if (length.isMaxContent()) {
+ LayoutUnit maxContentSize = 0;
+ GridIterator iterator(m_grid, ForColumns, trackIndex);
+ while (RenderBox* gridItem = iterator.nextGridItem()) {
+ // FIXME: We should include the child's fixed margins like RenderFlexibleBox.
+ maxContentSize = std::max(maxContentSize, gridItem->maxPreferredLogicalWidth());
+ }
+ return maxContentSize;
}
- // FIXME: We should account for min / max logical width.
+ // FIXME: css3-sizing mentions that we should resolve "definite sizes"
+ // (including <percentage> and calc()) but we don't do it elsewhere.
+ return 0;
+}
- // FIXME: Include borders and paddings in inline direction.
+void RenderGrid::computedUsedBreadthOfGridTracks(TrackSizingDirection direction, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks)
+{
+ LayoutUnit availableLogicalSpace = (direction == ForColumns) ? availableLogicalWidth() : availableLogicalHeight(IncludeMarginBorderPadding);
+ Vector<GridTrack>& tracks = (direction == ForColumns) ? columnTracks : rowTracks;
+ for (size_t i = 0; i < tracks.size(); ++i) {
+ GridTrack& track = tracks[i];
+ const GridTrackSize& trackSize = gridTrackSize(direction, i);
+ const Length& minTrackBreadth = trackSize.minTrackBreadth();
+ const Length& maxTrackBreadth = trackSize.maxTrackBreadth();
+
+ track.m_usedBreadth = computeUsedBreadthOfMinLength(direction, minTrackBreadth);
+ track.m_maxBreadth = computeUsedBreadthOfMaxLength(direction, maxTrackBreadth);
+
+ track.m_maxBreadth = std::max(track.m_maxBreadth, track.m_usedBreadth);
+ }
- setPreferredLogicalWidthsDirty(false);
+ // FIXME: We shouldn't call resolveContentBasedTrackSizingFunctions if we have no min-content / max-content tracks.
+ resolveContentBasedTrackSizingFunctions(direction, columnTracks, rowTracks, availableLogicalSpace);
+
+ if (availableLogicalSpace <= 0)
+ return;
+
+ const size_t tracksSize = tracks.size();
+ Vector<GridTrack*> tracksForDistribution(tracksSize);
+ for (size_t i = 0; i < tracksSize; ++i)
+ tracksForDistribution[i] = tracks.data() + i;
+
+ distributeSpaceToTracks(tracksForDistribution, 0, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth, availableLogicalSpace);
+}
+
+LayoutUnit RenderGrid::computeUsedBreadthOfMinLength(TrackSizingDirection direction, const Length& trackLength) const
+{
+ if (trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage())
+ return computeUsedBreadthOfSpecifiedLength(direction, trackLength);
+
+ ASSERT(trackLength.isMinContent() || trackLength.isMaxContent() || trackLength.isAuto());
+ return 0;
+}
+
+LayoutUnit RenderGrid::computeUsedBreadthOfMaxLength(TrackSizingDirection direction, const Length& trackLength) const
+{
+ if (trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage()) {
+ LayoutUnit computedBreadth = computeUsedBreadthOfSpecifiedLength(direction, trackLength);
+ // FIXME: We should ASSERT that computedBreadth cannot return infinity but it's currently
+ // possible. See https://bugs.webkit.org/show_bug.cgi?id=107053
+ return computedBreadth;
+ }
+
+ ASSERT(trackLength.isMinContent() || trackLength.isMaxContent() || trackLength.isAuto());
+ return infinity;
}
-void RenderGrid::computedUsedBreadthOfGridTracks(TrackSizingDirection direction, Vector<GridTrack>& tracks)
+LayoutUnit RenderGrid::computeUsedBreadthOfSpecifiedLength(TrackSizingDirection direction, const Length& trackLength) const
+{
+ // FIXME: We still need to support calc() here (https://webkit.org/b/103761).
+ ASSERT(trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage());
+ return valueForLength(trackLength, direction == ForColumns ? logicalWidth() : computeContentLogicalHeight(style()->logicalHeight()), view());
+}
+
+const GridTrackSize& RenderGrid::gridTrackSize(TrackSizingDirection direction, size_t i) const
+{
+ const Vector<GridTrackSize>& trackStyles = (direction == ForColumns) ? style()->gridColumns() : style()->gridRows();
+ if (i >= trackStyles.size())
+ return (direction == ForColumns) ? style()->gridAutoColumns() : style()->gridAutoRows();
+
+ return trackStyles[i];
+}
+
+static size_t estimatedGridSizeForPosition(const GridPosition& position)
+{
+ if (position.isAuto())
+ return 1;
+
+ return std::max(position.integerPosition(), 1);
+}
+
+size_t RenderGrid::maximumIndexInDirection(TrackSizingDirection direction) const
{
const Vector<GridTrackSize>& trackStyles = (direction == ForColumns) ? style()->gridColumns() : style()->gridRows();
- for (size_t i = 0; i < trackStyles.size(); ++i) {
- GridTrack track;
- if (trackStyles[i].length().isFixed())
- track.m_usedBreadth = trackStyles[i].length().getFloatValue();
- else
- notImplemented();
- tracks.append(track);
+ size_t maximumIndex = std::max<size_t>(1, trackStyles.size());
+
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ // This function bypasses the cache (cachedGridCoordinate()) as it is used to build it.
+ // Also we can't call resolveGridPositionsFromStyle here as it assumes that the grid is build and we are in
+ // the middle of building it. However we should be able to share more code with the previous logic (FIXME).
+ const GridPosition& initialPosition = (direction == ForColumns) ? child->style()->gridItemStart() : child->style()->gridItemBefore();
+ const GridPosition& finalPosition = (direction == ForColumns) ? child->style()->gridItemEnd() : child->style()->gridItemAfter();
+
+ size_t estimatedSizeForInitialPosition = estimatedGridSizeForPosition(initialPosition);
+ size_t estimatedSizeForFinalPosition = estimatedGridSizeForPosition(finalPosition);
+ ASSERT(estimatedSizeForInitialPosition);
+ ASSERT(estimatedSizeForFinalPosition);
+
+ maximumIndex = std::max(maximumIndex, estimatedSizeForInitialPosition);
+ maximumIndex = std::max(maximumIndex, estimatedSizeForFinalPosition);
+ }
+
+ return maximumIndex;
+}
+
+LayoutUnit RenderGrid::logicalContentHeightForChild(RenderBox* child, Vector<GridTrack>& columnTracks)
+{
+ // FIXME: We shouldn't force a layout every time this function is called but
+ // 1) Return computeLogicalHeight's value if it's available. Unfortunately computeLogicalHeight
+ // doesn't return if the logical height is available so would need to be changed.
+ // 2) Relayout if the column track's used breadth changed OR the logical height is unavailable.
+ if (!child->needsLayout())
+ child->setNeedsLayout(true, MarkOnlyThis);
+
+ child->setOverrideContainingBlockContentLogicalWidth(gridAreaBreadthForChild(child, ForColumns, columnTracks));
+ // If |child| has a percentage logical height, we shouldn't let it override its intrinsic height, which is
+ // what we are interested in here. Thus we need to set the override logical height to -1 (no possible resolution).
+ child->setOverrideContainingBlockContentLogicalHeight(-1);
+ child->layout();
+ return child->logicalHeight();
+}
+
+LayoutUnit RenderGrid::minContentForChild(RenderBox* child, TrackSizingDirection direction, Vector<GridTrack>& columnTracks)
+{
+ bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
+ // FIXME: Properly support orthogonal writing mode.
+ if (hasOrthogonalWritingMode)
+ return 0;
+
+ if (direction == ForColumns) {
+ // FIXME: It's unclear if we should return the intrinsic width or the preferred width.
+ // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
+ return child->minPreferredLogicalWidth();
}
+
+ return logicalContentHeightForChild(child, columnTracks);
+}
+
+LayoutUnit RenderGrid::maxContentForChild(RenderBox* child, TrackSizingDirection direction, Vector<GridTrack>& columnTracks)
+{
+ bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
+ // FIXME: Properly support orthogonal writing mode.
+ if (hasOrthogonalWritingMode)
+ return LayoutUnit();
+
+ if (direction == ForColumns) {
+ // FIXME: It's unclear if we should return the intrinsic width or the preferred width.
+ // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
+ return child->maxPreferredLogicalWidth();
+ }
+
+ return logicalContentHeightForChild(child, columnTracks);
+}
+
+void RenderGrid::resolveContentBasedTrackSizingFunctions(TrackSizingDirection direction, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks, LayoutUnit& availableLogicalSpace)
+{
+ // FIXME: Split the grid tracks once we support fractions (step 1 of the algorithm).
+
+ Vector<GridTrack>& tracks = (direction == ForColumns) ? columnTracks : rowTracks;
+
+ // FIXME: Per step 2 of the specification, we should order the grid items by increasing span.
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ resolveContentBasedTrackSizingFunctionsForItems(direction, columnTracks, rowTracks, child, &GridTrackSize::hasMinOrMaxContentMinTrackBreadth, &RenderGrid::minContentForChild, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth);
+ resolveContentBasedTrackSizingFunctionsForItems(direction, columnTracks, rowTracks, child, &GridTrackSize::hasMaxContentMinTrackBreadth, &RenderGrid::maxContentForChild, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth);
+ resolveContentBasedTrackSizingFunctionsForItems(direction, columnTracks, rowTracks, child, &GridTrackSize::hasMinOrMaxContentMaxTrackBreadth, &RenderGrid::minContentForChild, &GridTrack::maxBreadthIfNotInfinite, &GridTrack::growMaxBreadth);
+ resolveContentBasedTrackSizingFunctionsForItems(direction, columnTracks, rowTracks, child, &GridTrackSize::hasMaxContentMaxTrackBreadth, &RenderGrid::maxContentForChild, &GridTrack::maxBreadthIfNotInfinite, &GridTrack::growMaxBreadth);
+ }
+
+ for (size_t i = 0; i < tracks.size(); ++i) {
+ GridTrack& track = tracks[i];
+ if (track.m_maxBreadth == infinity)
+ track.m_maxBreadth = track.m_usedBreadth;
+
+ availableLogicalSpace -= track.m_usedBreadth;
+ }
+}
+
+void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(TrackSizingDirection direction, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks, RenderBox* gridItem, FilterFunction filterFunction, SizingFunction sizingFunction, AccumulatorGetter trackGetter, AccumulatorGrowFunction trackGrowthFunction)
+{
+ const GridCoordinate coordinate = cachedGridCoordinate(gridItem);
+ const size_t initialTrackIndex = (direction == ForColumns) ? coordinate.columns.initialPositionIndex : coordinate.rows.initialPositionIndex;
+ const size_t finalTrackIndex = (direction == ForColumns) ? coordinate.columns.finalPositionIndex : coordinate.rows.finalPositionIndex;
+
+ Vector<GridTrack*> tracks;
+ for (size_t trackIndex = initialTrackIndex; trackIndex <= finalTrackIndex; ++trackIndex) {
+ const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex);
+ if (!(trackSize.*filterFunction)())
+ continue;
+
+ GridTrack& track = (direction == ForColumns) ? columnTracks[trackIndex] : rowTracks[trackIndex];
+ tracks.append(&track);
+ }
+
+ LayoutUnit additionalBreadthSpace = (this->*sizingFunction)(gridItem, direction, columnTracks);
+ for (size_t trackIndexForSpace = initialTrackIndex; trackIndexForSpace <= finalTrackIndex; ++trackIndexForSpace) {
+ GridTrack& track = (direction == ForColumns) ? columnTracks[trackIndexForSpace] : rowTracks[trackIndexForSpace];
+ additionalBreadthSpace -= (track.*trackGetter)();
+ }
+
+ // FIXME: We should pass different values for |tracksForGrowthAboveMaxBreadth|.
+ distributeSpaceToTracks(tracks, &tracks, trackGetter, trackGrowthFunction, additionalBreadthSpace);
+}
+
+static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTrack* track2)
+{
+ return (track1->m_maxBreadth - track1->m_usedBreadth) < (track2->m_maxBreadth - track2->m_usedBreadth);
+}
+
+void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, Vector<GridTrack*>* tracksForGrowthAboveMaxBreadth, AccumulatorGetter trackGetter, AccumulatorGrowFunction trackGrowthFunction, LayoutUnit& availableLogicalSpace)
+{
+ std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential);
+
+ size_t tracksSize = tracks.size();
+ Vector<LayoutUnit> updatedTrackBreadths(tracksSize);
+
+ for (size_t i = 0; i < tracksSize; ++i) {
+ GridTrack& track = *tracks[i];
+ LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksSize - i);
+ LayoutUnit trackBreadth = (tracks[i]->*trackGetter)();
+ LayoutUnit growthShare = std::min(availableLogicalSpaceShare, track.m_maxBreadth - trackBreadth);
+ updatedTrackBreadths[i] = trackBreadth + growthShare;
+ availableLogicalSpace -= growthShare;
+ }
+
+ if (availableLogicalSpace > 0 && tracksForGrowthAboveMaxBreadth) {
+ tracksSize = tracksForGrowthAboveMaxBreadth->size();
+ for (size_t i = 0; i < tracksSize; ++i) {
+ LayoutUnit growthShare = availableLogicalSpace / (tracksSize - i);
+ updatedTrackBreadths[i] += growthShare;
+ availableLogicalSpace -= growthShare;
+ }
+ }
+
+ for (size_t i = 0; i < tracksSize; ++i) {
+ LayoutUnit growth = updatedTrackBreadths[i] - (tracks[i]->*trackGetter)();
+ if (growth >= 0)
+ (tracks[i]->*trackGrowthFunction)(growth);
+ }
+}
+
+#ifndef NDEBUG
+bool RenderGrid::tracksAreWiderThanMinTrackBreadth(TrackSizingDirection direction, const Vector<GridTrack>& tracks)
+{
+ for (size_t i = 0; i < tracks.size(); ++i) {
+ const GridTrackSize& trackSize = gridTrackSize(direction, i);
+ const Length& minTrackBreadth = trackSize.minTrackBreadth();
+ if (computeUsedBreadthOfMinLength(direction, minTrackBreadth) > tracks[i].m_usedBreadth)
+ return false;
+ }
+ return true;
+}
+#endif
+
+void RenderGrid::growGrid(TrackSizingDirection direction)
+{
+ if (direction == ForColumns) {
+ const size_t oldColumnSize = m_grid[0].size();
+ for (size_t row = 0; row < m_grid.size(); ++row)
+ m_grid[row].grow(oldColumnSize + 1);
+ } else {
+ const size_t oldRowSize = m_grid.size();
+ m_grid.grow(oldRowSize + 1);
+ m_grid[oldRowSize].grow(m_grid[0].size());
+ }
+}
+
+void RenderGrid::insertItemIntoGrid(RenderBox* child, const GridCoordinate& coordinate)
+{
+ m_grid[coordinate.rows.initialPositionIndex][coordinate.columns.initialPositionIndex].append(child);
+ m_gridItemCoordinate.set(child, coordinate);
+}
+
+void RenderGrid::insertItemIntoGrid(RenderBox* child, size_t rowTrack, size_t columnTrack)
+{
+ const GridSpan& rowSpan = resolveGridPositionsFromAutoPlacementPosition(child, ForRows, rowTrack);
+ const GridSpan& columnSpan = resolveGridPositionsFromAutoPlacementPosition(child, ForColumns, columnTrack);
+ insertItemIntoGrid(child, GridCoordinate(rowSpan, columnSpan));
+}
+
+void RenderGrid::placeItemsOnGrid()
+{
+ ASSERT(!gridWasPopulated());
+ ASSERT(m_gridItemCoordinate.isEmpty());
+
+ m_grid.grow(maximumIndexInDirection(ForRows));
+ size_t maximumColumnIndex = maximumIndexInDirection(ForColumns);
+ for (size_t i = 0; i < m_grid.size(); ++i)
+ m_grid[i].grow(maximumColumnIndex);
+
+ Vector<RenderBox*> autoMajorAxisAutoGridItems;
+ Vector<RenderBox*> specifiedMajorAxisAutoGridItems;
+ GridAutoFlow autoFlow = style()->gridAutoFlow();
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ // FIXME: We never re-resolve positions if the grid is grown during auto-placement which may lead auto / <integer>
+ // positions to not match the author's intent. The specification is unclear on what should be done in this case.
+ OwnPtr<GridSpan> rowPositions = resolveGridPositionsFromStyle(child, ForRows);
+ OwnPtr<GridSpan> columnPositions = resolveGridPositionsFromStyle(child, ForColumns);
+ if (!rowPositions || !columnPositions) {
+ GridSpan* majorAxisPositions = (autoPlacementMajorAxisDirection() == ForColumns) ? columnPositions.get() : rowPositions.get();
+ if (!majorAxisPositions)
+ autoMajorAxisAutoGridItems.append(child);
+ else
+ specifiedMajorAxisAutoGridItems.append(child);
+ continue;
+ }
+ insertItemIntoGrid(child, GridCoordinate(*rowPositions, *columnPositions));
+ }
+
+ ASSERT(gridRowCount() >= style()->gridRows().size());
+ ASSERT(gridColumnCount() >= style()->gridColumns().size());
+
+ if (autoFlow == AutoFlowNone) {
+ // If we did collect some grid items, they won't be placed thus never laid out.
+ ASSERT(!autoMajorAxisAutoGridItems.size());
+ ASSERT(!specifiedMajorAxisAutoGridItems.size());
+ return;
+ }
+
+ placeSpecifiedMajorAxisItemsOnGrid(specifiedMajorAxisAutoGridItems);
+ placeAutoMajorAxisItemsOnGrid(autoMajorAxisAutoGridItems);
+}
+
+void RenderGrid::placeSpecifiedMajorAxisItemsOnGrid(Vector<RenderBox*> autoGridItems)
+{
+ for (size_t i = 0; i < autoGridItems.size(); ++i) {
+ OwnPtr<GridSpan> majorAxisPositions = resolveGridPositionsFromStyle(autoGridItems[i], autoPlacementMajorAxisDirection());
+ GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions->initialPositionIndex);
+ if (OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea()) {
+ insertItemIntoGrid(autoGridItems[i], emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex);
+ continue;
+ }
+
+ growGrid(autoPlacementMinorAxisDirection());
+ OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea();
+ ASSERT(emptyGridArea);
+ insertItemIntoGrid(autoGridItems[i], emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex);
+ }
+}
+
+void RenderGrid::placeAutoMajorAxisItemsOnGrid(Vector<RenderBox*> autoGridItems)
+{
+ for (size_t i = 0; i < autoGridItems.size(); ++i)
+ placeAutoMajorAxisItemOnGrid(autoGridItems[i]);
+}
+
+void RenderGrid::placeAutoMajorAxisItemOnGrid(RenderBox* gridItem)
+{
+ OwnPtr<GridSpan> minorAxisPositions = resolveGridPositionsFromStyle(gridItem, autoPlacementMinorAxisDirection());
+ ASSERT(!resolveGridPositionsFromStyle(gridItem, autoPlacementMajorAxisDirection()));
+ size_t minorAxisIndex = 0;
+ if (minorAxisPositions) {
+ minorAxisIndex = minorAxisPositions->initialPositionIndex;
+ GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisIndex);
+ if (OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea()) {
+ insertItemIntoGrid(gridItem, emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex);
+ return;
+ }
+ } else {
+ const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColumns) ? gridColumnCount() : gridRowCount();
+ for (size_t majorAxisIndex = 0; majorAxisIndex < endOfMajorAxis; ++majorAxisIndex) {
+ GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisIndex);
+ if (OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea()) {
+ insertItemIntoGrid(gridItem, emptyGridArea->rows.initialPositionIndex, emptyGridArea->columns.initialPositionIndex);
+ return;
+ }
+ }
+ }
+
+ // We didn't find an empty grid area so we need to create an extra major axis line and insert our gridItem in it.
+ const size_t columnIndex = (autoPlacementMajorAxisDirection() == ForColumns) ? m_grid[0].size() : minorAxisIndex;
+ const size_t rowIndex = (autoPlacementMajorAxisDirection() == ForColumns) ? minorAxisIndex : m_grid.size();
+ growGrid(autoPlacementMajorAxisDirection());
+ insertItemIntoGrid(gridItem, rowIndex, columnIndex);
+}
+
+RenderGrid::TrackSizingDirection RenderGrid::autoPlacementMajorAxisDirection() const
+{
+ GridAutoFlow flow = style()->gridAutoFlow();
+ ASSERT(flow != AutoFlowNone);
+ return (flow == AutoFlowColumn) ? ForColumns : ForRows;
+}
+
+RenderGrid::TrackSizingDirection RenderGrid::autoPlacementMinorAxisDirection() const
+{
+ GridAutoFlow flow = style()->gridAutoFlow();
+ ASSERT(flow != AutoFlowNone);
+ return (flow == AutoFlowColumn) ? ForRows : ForColumns;
+}
+
+void RenderGrid::clearGrid()
+{
+ m_grid.clear();
+ m_gridItemCoordinate.clear();
}
void RenderGrid::layoutGridItems()
{
- Vector<GridTrack> columnTracks, rowTracks;
- computedUsedBreadthOfGridTracks(ForColumns, columnTracks);
- // FIXME: The logical width of Grid Columns from the prior step is used in
- // the formatting of Grid items in content-sized Grid Rows to determine
- // their required height. We will probably need to pass columns through.
- computedUsedBreadthOfGridTracks(ForRows, rowTracks);
+ placeItemsOnGrid();
+
+ Vector<GridTrack> columnTracks(gridColumnCount());
+ Vector<GridTrack> rowTracks(gridRowCount());
+ computedUsedBreadthOfGridTracks(ForColumns, columnTracks, rowTracks);
+ ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns, columnTracks));
+ computedUsedBreadthOfGridTracks(ForRows, columnTracks, rowTracks);
+ ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, rowTracks));
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
LayoutPoint childPosition = findChildLogicalPosition(child, columnTracks, rowTracks);
- size_t columnTrack = resolveGridPosition(child->style()->gridItemColumn());
- size_t rowTrack = resolveGridPosition(child->style()->gridItemRow());
+ // Because the grid area cannot be styled, we don't need to adjust
+ // the grid breadth to account for 'box-sizing'.
+ LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOverrideContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogicalWidth() : LayoutUnit();
+ LayoutUnit oldOverrideContainingBlockContentLogicalHeight = child->hasOverrideContainingBlockLogicalHeight() ? child->overrideContainingBlockContentLogicalHeight() : LayoutUnit();
- // FIXME: Properly support implicit rows and columns (bug 103573).
- if (columnTrack < columnTracks.size() && rowTrack < rowTracks.size()) {
- // Because the grid area cannot be styled, we don't need to adjust
- // the grid breadth to account for 'box-sizing'.
- child->setOverrideContainingBlockContentLogicalWidth(columnTracks[columnTrack].m_usedBreadth);
- child->setOverrideContainingBlockContentLogicalHeight(rowTracks[rowTrack].m_usedBreadth);
- }
+ // FIXME: For children in a content sized track, we clear the overrideContainingBlockContentLogicalHeight
+ // in minContentForChild / maxContentForChild which means that we will always relayout the child.
+ LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForChild(child, ForColumns, columnTracks);
+ LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadthForChild(child, ForRows, rowTracks);
+ if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingBlockContentLogicalWidth || oldOverrideContainingBlockContentLogicalHeight != overrideContainingBlockContentLogicalHeight)
+ child->setNeedsLayout(true, MarkOnlyThis);
+
+ child->setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockContentLogicalWidth);
+ child->setOverrideContainingBlockContentLogicalHeight(overrideContainingBlockContentLogicalHeight);
+
+ LayoutRect oldChildRect = child->frameRect();
// FIXME: Grid items should stretch to fill their cells. Once we
// implement grid-{column,row}-align, we can also shrink to fit. For
@@ -180,43 +689,114 @@ void RenderGrid::layoutGridItems()
// FIXME: Handle border & padding on the grid element.
child->setLogicalLocation(childPosition);
+
+ // If the child moved, we have to repaint it as well as any floating/positioned
+ // descendants. An exception is if we need a layout. In this case, we know we're going to
+ // repaint ourselves (and the child) anyway.
+ if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldChildRect);
}
- // FIXME: Handle border & padding on the grid element.
for (size_t i = 0; i < rowTracks.size(); ++i)
setLogicalHeight(logicalHeight() + rowTracks[i].m_usedBreadth);
+
+ // FIXME: We should handle min / max logical height.
+
+ setLogicalHeight(logicalHeight() + borderAndPaddingLogicalHeight());
+ clearGrid();
+}
+
+RenderGrid::GridCoordinate RenderGrid::cachedGridCoordinate(const RenderBox* gridItem) const
+{
+ ASSERT(m_gridItemCoordinate.contains(gridItem));
+ return m_gridItemCoordinate.get(gridItem);
+}
+
+RenderGrid::GridSpan RenderGrid::resolveGridPositionsFromAutoPlacementPosition(const RenderBox*, TrackSizingDirection, size_t initialPosition) const
+{
+ // FIXME: We don't support spanning with auto positions yet. Once we do, this is wrong. Also we should make
+ // sure the grid can accomodate the new item as we only grow 1 position in a given direction.
+ return GridSpan(initialPosition, initialPosition);
}
-size_t RenderGrid::resolveGridPosition(const GridPosition& position) const
+PassOwnPtr<RenderGrid::GridSpan> RenderGrid::resolveGridPositionsFromStyle(const RenderBox* gridItem, TrackSizingDirection direction) const
{
+ ASSERT(gridWasPopulated());
+
+ const GridPosition& initialPosition = (direction == ForColumns) ? gridItem->style()->gridItemStart() : gridItem->style()->gridItemBefore();
+ const GridPositionSide initialPositionSide = (direction == ForColumns) ? StartSide : BeforeSide;
+ const GridPosition& finalPosition = (direction == ForColumns) ? gridItem->style()->gridItemEnd() : gridItem->style()->gridItemAfter();
+ const GridPositionSide finalPositionSide = (direction == ForColumns) ? EndSide : AfterSide;
+
+ if (initialPosition.isAuto() && finalPosition.isAuto()) {
+ if (style()->gridAutoFlow() == AutoFlowNone)
+ return adoptPtr(new GridSpan(0, 0));
+
+ // We can't get our grid positions without running the auto placement algorithm.
+ return nullptr;
+ }
+
+ if (initialPosition.isAuto()) {
+ // Infer the position from the final position ('auto / 1' case).
+ const size_t finalResolvedPosition = resolveGridPositionFromStyle(finalPosition, finalPositionSide);
+ return adoptPtr(new GridSpan(finalResolvedPosition, finalResolvedPosition));
+ }
+
+ if (finalPosition.isAuto()) {
+ // Infer our position from the initial position ('1 / auto' case).
+ const size_t initialResolvedPosition = resolveGridPositionFromStyle(initialPosition, initialPositionSide);
+ return adoptPtr(new GridSpan(initialResolvedPosition, initialResolvedPosition));
+ }
+
+ return adoptPtr(new GridSpan(resolveGridPositionFromStyle(initialPosition, initialPositionSide), resolveGridPositionFromStyle(finalPosition, finalPositionSide)));
+}
+
+size_t RenderGrid::resolveGridPositionFromStyle(const GridPosition& position, GridPositionSide side) const
+{
+ ASSERT(gridWasPopulated());
+
// FIXME: Handle other values for grid-{row,column} like ranges or line names.
switch (position.type()) {
- case IntegerPosition:
+ case IntegerPosition: {
// FIXME: What does a non-positive integer mean for a column/row?
- if (!position.isPositive())
- return 0;
+ size_t resolvedPosition = position.isPositive() ? position.integerPosition() - 1 : 0;
+
+ if (side == StartSide || side == BeforeSide)
+ return resolvedPosition;
- return position.integerPosition() - 1;
+ const size_t endOfTrack = (side == EndSide) ? gridColumnCount() - 1 : gridRowCount() - 1;
+ ASSERT(endOfTrack >= resolvedPosition);
+ return endOfTrack - resolvedPosition;
+ }
case AutoPosition:
- // FIXME: We should follow 'grid-auto-flow' for resolution.
- // Until then, we use the 'grid-auto-flow: none' behavior (which is the default)
- // and resolve 'auto' as the first row / column.
+ // 'auto' depends on the opposite position for resolution (e.g. grid-row: auto / 1).
+ ASSERT_NOT_REACHED();
return 0;
}
ASSERT_NOT_REACHED();
return 0;
}
+LayoutUnit RenderGrid::gridAreaBreadthForChild(const RenderBox* child, TrackSizingDirection direction, const Vector<GridTrack>& tracks) const
+{
+ const GridCoordinate& coordinate = cachedGridCoordinate(child);
+ const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coordinate.rows;
+ LayoutUnit gridAreaBreadth = 0;
+ for (size_t trackIndex = span.initialPositionIndex; trackIndex <= span.finalPositionIndex; ++trackIndex)
+ gridAreaBreadth += tracks[trackIndex].m_usedBreadth;
+ return gridAreaBreadth;
+}
+
LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks)
{
- size_t columnTrack = resolveGridPosition(child->style()->gridItemColumn());
- size_t rowTrack = resolveGridPosition(child->style()->gridItemRow());
+ const GridCoordinate& coordinate = cachedGridCoordinate(child);
- LayoutPoint offset;
+ // The grid items should be inside the grid container's border box, that's why they need to be shifted.
+ LayoutPoint offset(borderAndPaddingStart(), borderAndPaddingBefore());
// FIXME: |columnTrack| and |rowTrack| should be smaller than our column / row count.
- for (size_t i = 0; i < columnTrack && i < columnTracks.size(); ++i)
+ for (size_t i = 0; i < coordinate.columns.initialPositionIndex && i < columnTracks.size(); ++i)
offset.setX(offset.x() + columnTracks[i].m_usedBreadth);
- for (size_t i = 0; i < rowTrack && i < rowTracks.size(); ++i)
+ for (size_t i = 0; i < coordinate.rows.initialPositionIndex && i < rowTracks.size(); ++i)
offset.setY(offset.y() + rowTracks[i].m_usedBreadth);
// FIXME: Handle margins on the grid item.
diff --git a/Source/WebCore/rendering/RenderGrid.h b/Source/WebCore/rendering/RenderGrid.h
index 340c64851..eb2b2aaf2 100644
--- a/Source/WebCore/rendering/RenderGrid.h
+++ b/Source/WebCore/rendering/RenderGrid.h
@@ -30,27 +30,124 @@
namespace WebCore {
+class GridTrack;
+
class RenderGrid : public RenderBlock {
public:
- RenderGrid(Node*);
+ RenderGrid(Element*);
virtual ~RenderGrid();
virtual const char* renderName() const OVERRIDE;
virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE;
- virtual void computePreferredLogicalWidths() OVERRIDE;
virtual bool avoidsFloats() const OVERRIDE { return true; }
virtual bool canCollapseAnonymousBlockChild() const OVERRIDE { return false; }
private:
- class GridTrack;
+ virtual bool isRenderGrid() const OVERRIDE { return true; }
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
+
+ LayoutUnit computePreferredTrackWidth(const Length&, size_t) const;
+
+ struct GridSpan {
+ GridSpan(size_t initialPosition, size_t finalPosition)
+ : initialPositionIndex(initialPosition)
+ , finalPositionIndex(finalPosition)
+ {
+ ASSERT(initialPositionIndex <= finalPositionIndex);
+ }
+
+ size_t initialPositionIndex;
+ size_t finalPositionIndex;
+ };
+
+ struct GridCoordinate {
+ // HashMap requires a default constuctor.
+ GridCoordinate()
+ : columns(0, 0)
+ , rows(0, 0)
+ {
+ }
+
+ GridCoordinate(const GridSpan& r, const GridSpan& c)
+ : columns(c)
+ , rows(r)
+ {
+ }
+
+ GridSpan columns;
+ GridSpan rows;
+ };
+
+ class GridIterator;
enum TrackSizingDirection { ForColumns, ForRows };
- void computedUsedBreadthOfGridTracks(TrackSizingDirection, Vector<GridTrack>&);
+ void computedUsedBreadthOfGridTracks(TrackSizingDirection, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks);
+ LayoutUnit computeUsedBreadthOfMinLength(TrackSizingDirection, const Length&) const;
+ LayoutUnit computeUsedBreadthOfMaxLength(TrackSizingDirection, const Length&) const;
+ LayoutUnit computeUsedBreadthOfSpecifiedLength(TrackSizingDirection, const Length&) const;
+ void resolveContentBasedTrackSizingFunctions(TrackSizingDirection, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks, LayoutUnit& availableLogicalSpace);
+
+ void growGrid(TrackSizingDirection);
+ void insertItemIntoGrid(RenderBox*, size_t rowTrack, size_t columnTrack);
+ void insertItemIntoGrid(RenderBox*, const GridCoordinate&);
+ void placeItemsOnGrid();
+ void placeSpecifiedMajorAxisItemsOnGrid(Vector<RenderBox*>);
+ void placeAutoMajorAxisItemsOnGrid(Vector<RenderBox*>);
+ void placeAutoMajorAxisItemOnGrid(RenderBox*);
+ TrackSizingDirection autoPlacementMajorAxisDirection() const;
+ TrackSizingDirection autoPlacementMinorAxisDirection() const;
+
void layoutGridItems();
+ void clearGrid();
+
+ typedef LayoutUnit (RenderGrid::* SizingFunction)(RenderBox*, TrackSizingDirection, Vector<GridTrack>&);
+ typedef LayoutUnit (GridTrack::* AccumulatorGetter)() const;
+ typedef void (GridTrack::* AccumulatorGrowFunction)(LayoutUnit);
+ typedef bool (GridTrackSize::* FilterFunction)() const;
+ void resolveContentBasedTrackSizingFunctionsForItems(TrackSizingDirection, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks, RenderBox*, FilterFunction, SizingFunction, AccumulatorGetter, AccumulatorGrowFunction);
+ void distributeSpaceToTracks(Vector<GridTrack*>&, Vector<GridTrack*>* tracksForGrowthAboveMaxBreadth, AccumulatorGetter, AccumulatorGrowFunction, LayoutUnit& availableLogicalSpace);
+ const GridTrackSize& gridTrackSize(TrackSizingDirection, size_t) const;
+ size_t maximumIndexInDirection(TrackSizingDirection) const;
+
+ LayoutUnit logicalContentHeightForChild(RenderBox*, Vector<GridTrack>&);
+ LayoutUnit minContentForChild(RenderBox*, TrackSizingDirection, Vector<GridTrack>& columnTracks);
+ LayoutUnit maxContentForChild(RenderBox*, TrackSizingDirection, Vector<GridTrack>& columnTracks);
LayoutPoint findChildLogicalPosition(RenderBox*, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks);
- size_t resolveGridPosition(const GridPosition&) const;
+ GridCoordinate cachedGridCoordinate(const RenderBox*) const;
+
+ GridSpan resolveGridPositionsFromAutoPlacementPosition(const RenderBox*, TrackSizingDirection, size_t) const;
+ PassOwnPtr<GridSpan> resolveGridPositionsFromStyle(const RenderBox*, TrackSizingDirection) const;
+ enum GridPositionSide {
+ StartSide,
+ EndSide,
+ BeforeSide,
+ AfterSide
+ };
+ size_t resolveGridPositionFromStyle(const GridPosition&, GridPositionSide) const;
+
+ LayoutUnit gridAreaBreadthForChild(const RenderBox* child, TrackSizingDirection, const Vector<GridTrack>&) const;
+
+#ifndef NDEBUG
+ bool tracksAreWiderThanMinTrackBreadth(TrackSizingDirection, const Vector<GridTrack>&);
+ bool gridWasPopulated() const { return !m_grid.isEmpty() && !m_grid[0].isEmpty(); }
+#endif
+
+ size_t gridColumnCount() const
+ {
+ ASSERT(gridWasPopulated());
+ return m_grid[0].size();
+ }
+ size_t gridRowCount() const
+ {
+ ASSERT(gridWasPopulated());
+ return m_grid.size();
+ }
+
+ Vector<Vector<Vector<RenderBox*, 1> > > m_grid;
+ HashMap<const RenderBox*, GridCoordinate> m_gridItemCoordinate;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp
index bfa1c4fbf..e68927033 100644
--- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp
+++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp
@@ -44,7 +44,8 @@ using namespace HTMLNames;
RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element)
: RenderReplaced(element, element->size())
{
- view()->frameView()->setIsVisuallyNonEmpty();
+ // Actual size is not known yet, report the default intrinsic size.
+ view()->frameView()->incrementVisuallyNonEmptyPixelCount(roundedIntSize(intrinsicSize()));
}
bool RenderHTMLCanvas::requiresLayer() const
@@ -68,7 +69,7 @@ void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& pa
}
}
- bool useLowQualityScale = style()->imageRendering() == ImageRenderingOptimizeContrast;
+ bool useLowQualityScale = style()->imageRendering() == ImageRenderingCrispEdges || style()->imageRendering() == ImageRenderingOptimizeSpeed;
static_cast<HTMLCanvasElement*>(node())->paint(paintInfo.context, rect, useLowQualityScale);
}
diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.h b/Source/WebCore/rendering/RenderHTMLCanvas.h
index 5bed27f4f..f4e07cc63 100644
--- a/Source/WebCore/rendering/RenderHTMLCanvas.h
+++ b/Source/WebCore/rendering/RenderHTMLCanvas.h
@@ -49,7 +49,7 @@ private:
inline RenderHTMLCanvas* toRenderHTMLCanvas(RenderObject* object)
{
- ASSERT(!object || !strcmp(object->renderName(), "RenderHTMLCanvas"));
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isCanvas());
return static_cast<RenderHTMLCanvas*>(object);
}
diff --git a/Source/WebCore/rendering/RenderIFrame.cpp b/Source/WebCore/rendering/RenderIFrame.cpp
index 2fcd58a77..2262a3fc9 100644
--- a/Source/WebCore/rendering/RenderIFrame.cpp
+++ b/Source/WebCore/rendering/RenderIFrame.cpp
@@ -33,6 +33,7 @@
#include "Page.h"
#include "RenderView.h"
#include "Settings.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -63,7 +64,7 @@ LayoutUnit RenderIFrame::minPreferredLogicalWidth() const
if (!childRoot)
return 0;
- return childRoot->minPreferredLogicalWidth();
+ return childRoot->minPreferredLogicalWidth() + borderAndPaddingLogicalWidth();
}
LayoutUnit RenderIFrame::maxPreferredLogicalWidth() const
@@ -75,20 +76,25 @@ LayoutUnit RenderIFrame::maxPreferredLogicalWidth() const
if (!childRoot)
return 0;
- return childRoot->maxPreferredLogicalWidth();
+ return childRoot->maxPreferredLogicalWidth() + borderAndPaddingLogicalWidth();
}
bool RenderIFrame::isSeamless() const
{
- return node() && node()->hasTagName(iframeTag) && static_cast<HTMLIFrameElement*>(node())->shouldDisplaySeamlessly();
+ return node() && node()->hasTagName(iframeTag) && toHTMLIFrameElement(node())->shouldDisplaySeamlessly();
+}
+
+bool RenderIFrame::requiresLayer() const
+{
+ return RenderFrameBase::requiresLayer() || style()->resize() != RESIZE_NONE;
}
RenderView* RenderIFrame::contentRootRenderer() const
{
// FIXME: Is this always a valid cast? What about plugins?
ASSERT(!widget() || widget()->isFrameView());
- FrameView* childFrameView = static_cast<FrameView*>(widget());
- return childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0;
+ FrameView* childFrameView = toFrameView(widget());
+ return childFrameView ? childFrameView->frame()->contentRenderer() : 0;
}
bool RenderIFrame::flattenFrame() const
@@ -96,7 +102,7 @@ bool RenderIFrame::flattenFrame() const
if (!node() || !node()->hasTagName(iframeTag))
return false;
- HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node());
+ HTMLIFrameElement* element = toHTMLIFrameElement(node());
Frame* frame = element->document()->frame();
if (isSeamless())
@@ -130,17 +136,17 @@ void RenderIFrame::layoutSeamlessly()
updateWidgetPosition(); // Tell the Widget about our new width/height (it will also layout the child document).
// Laying out our kids is normally responsible for adjusting our height, so we set it here.
- // Replaced elements do not respect padding, so we just add border to the child's height.
- // FIXME: It's possible that seamless iframes (since they act like divs) *should* respect padding.
- FrameView* childFrameView = static_cast<FrameView*>(widget());
+ // Replaced elements normally do not respect padding, but seamless elements should: we'll add
+ // both padding and border to the child's logical height here.
+ FrameView* childFrameView = toFrameView(widget());
if (childFrameView) // Widget should never be null during layout(), but just in case.
- setLogicalHeight(childFrameView->contentsHeight() + borderTop() + borderBottom());
+ setLogicalHeight(childFrameView->contentsHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom());
updateLogicalHeight();
updateWidgetPosition(); // Notify the Widget of our final height.
// Assert that the child document did a complete layout.
- RenderView* childRoot = childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0;
+ RenderView* childRoot = childFrameView ? childFrameView->frame()->contentRenderer() : 0;
ASSERT(!childFrameView || !childFrameView->layoutPending());
ASSERT_UNUSED(childRoot, !childRoot || !childRoot->needsLayout());
}
diff --git a/Source/WebCore/rendering/RenderIFrame.h b/Source/WebCore/rendering/RenderIFrame.h
index 74163eb79..aac06560f 100644
--- a/Source/WebCore/rendering/RenderIFrame.h
+++ b/Source/WebCore/rendering/RenderIFrame.h
@@ -52,6 +52,8 @@ private:
virtual const char* renderName() const OVERRIDE { return "RenderPartObject"; } // Lying for now to avoid breaking tests
+ virtual bool requiresLayer() const OVERRIDE;
+
void layoutSeamlessly();
RenderView* contentRootRenderer() const;
@@ -59,13 +61,13 @@ private:
inline RenderIFrame* toRenderIFrame(RenderObject* object)
{
- ASSERT(!object || object->isRenderIFrame());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderIFrame());
return static_cast<RenderIFrame*>(object);
}
inline const RenderIFrame* toRenderIFrame(const RenderObject* object)
{
- ASSERT(!object || object->isRenderIFrame());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderIFrame());
return static_cast<const RenderIFrame*>(object);
}
diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
index c3bcf3a1a..698894bb9 100644
--- a/Source/WebCore/rendering/RenderImage.cpp
+++ b/Source/WebCore/rendering/RenderImage.cpp
@@ -29,6 +29,7 @@
#include "RenderImage.h"
#include "BitmapImage.h"
+#include "CachedImage.h"
#include "Font.h"
#include "FontCache.h"
#include "Frame.h"
@@ -44,7 +45,7 @@
#include "PaintInfo.h"
#include "RenderView.h"
#include "SVGImage.h"
-#include <wtf/UnusedParam.h>
+#include <wtf/StackStats.h>
using namespace std;
@@ -52,8 +53,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderImage::RenderImage(Node* node)
- : RenderReplaced(node, IntSize())
+RenderImage::RenderImage(Element* element)
+ : RenderReplaced(element, IntSize())
, m_needsToSetSizeForAltText(false)
, m_didIncrementVisuallyNonEmptyPixelCount(false)
, m_isGeneratedContent(false)
@@ -61,6 +62,13 @@ RenderImage::RenderImage(Node* node)
updateAltText();
}
+RenderImage* RenderImage::createAnonymous(Document* document)
+{
+ RenderImage* image = new (document->renderArena()) RenderImage(0);
+ image->setDocumentForAnonymous(document);
+ return image;
+}
+
RenderImage::~RenderImage()
{
ASSERT(m_imageResource);
@@ -119,8 +127,8 @@ bool RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */)
FontCachePurgePreventer fontCachePurgePreventer;
const Font& font = style()->font();
- IntSize textSize(min(font.width(RenderBlock::constructTextRun(this, font, m_altText, style())), maxAltTextWidth), min(font.fontMetrics().height(), maxAltTextHeight));
- imageSize = imageSize.expandedTo(textSize);
+ IntSize paddedTextSize(paddingWidth + min(ceilf(font.width(RenderBlock::constructTextRun(this, font, m_altText, style()))), maxAltTextWidth), paddingHeight + min(font.fontMetrics().height(), maxAltTextHeight));
+ imageSize = imageSize.expandedTo(paddedTextSize);
}
if (imageSize == intrinsicSize())
@@ -157,7 +165,7 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
if (hasBoxDecorations() || hasMask())
RenderReplaced::imageChanged(newImage, rect);
-
+
if (!m_imageResource)
return;
@@ -222,13 +230,27 @@ void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* r
if (intrinsicSizeChanged) {
if (!preferredLogicalWidthsDirty())
setPreferredLogicalWidthsDirty(true);
- LogicalExtentComputedValues computedValues;
- computeLogicalWidthInRegion(computedValues);
- LayoutUnit newWidth = computedValues.m_extent;
- computeLogicalHeight(height(), 0, computedValues);
- LayoutUnit newHeight = computedValues.m_extent;
- if (imageSizeChanged || width() != newWidth || height() != newHeight) {
+ bool hasOverrideSize = hasOverrideHeight() || hasOverrideWidth();
+ if (!hasOverrideSize && !imageSizeChanged) {
+ LogicalExtentComputedValues computedValues;
+ computeLogicalWidthInRegion(computedValues);
+ LayoutUnit newWidth = computedValues.m_extent;
+ computeLogicalHeight(height(), 0, computedValues);
+ LayoutUnit newHeight = computedValues.m_extent;
+
+ imageSizeChanged = width() != newWidth || height() != newHeight;
+ }
+
+ // FIXME: We only need to recompute the containing block's preferred size
+ // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing).
+ // There's no easy way to detect that shrink-to-fit is needed, always force a layout.
+ bool containingBlockNeedsToRecomputePreferredSize =
+ style()->logicalWidth().isPercent()
+ || style()->logicalMaxWidth().isPercent()
+ || style()->logicalMinWidth().isPercent();
+
+ if (imageSizeChanged || hasOverrideSize || containingBlockNeedsToRecomputePreferredSize) {
shouldRepaint = false;
if (!selfNeedsLayout())
setNeedsLayout(true);
@@ -263,6 +285,8 @@ void RenderImage::notifyFinished(CachedResource* newImage)
if (documentBeingDestroyed())
return;
+ invalidateBackgroundObscurationStatus();
+
#if USE(ACCELERATED_COMPOSITING)
if (newImage == m_imageResource->cachedImage()) {
// tell any potential compositing layers
@@ -297,6 +321,8 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
page->addRelevantUnpaintedObject(this, visualOverflowRect());
if (cWidth > 2 && cHeight > 2) {
+ const int borderWidth = 1;
+
// Draw an outline rect where the image should be.
context->setStrokeStyle(SolidStroke);
context->setStrokeColor(Color::lightGray, style()->colorSpace());
@@ -307,8 +333,8 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
LayoutSize imageOffset;
// When calculating the usable dimensions, exclude the pixels of
// the ouline rect so the error image/alt text doesn't draw on it.
- LayoutUnit usableWidth = cWidth - 2;
- LayoutUnit usableHeight = cHeight - 2;
+ LayoutUnit usableWidth = cWidth - 2 * borderWidth;
+ LayoutUnit usableHeight = cHeight - 2 * borderWidth;
RefPtr<Image> image = m_imageResource->image();
@@ -326,7 +352,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
LayoutUnit centerY = (usableHeight - imageSize.height()) / 2;
if (centerY < 0)
centerY = 0;
- imageOffset = LayoutSize(leftBorder + leftPad + centerX + 1, topBorder + topPad + centerY + 1);
+ imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth);
context->drawImage(image.get(), style()->colorSpace(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, shouldRespectImageOrientation());
errorPictureDrawn = true;
}
@@ -338,7 +364,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
const FontMetrics& fontMetrics = font.fontMetrics();
LayoutUnit ascent = fontMetrics.ascent();
LayoutPoint altTextOffset = paintOffset;
- altTextOffset.move(leftBorder + leftPad, topBorder + topPad + ascent);
+ altTextOffset.move(leftBorder + leftPad + (paddingWidth / 2) - borderWidth, topBorder + topPad + ascent + (paddingHeight / 2) - borderWidth);
// Only draw the alt text if it'll fit within the content box,
// and only if it fits above the error image.
@@ -347,7 +373,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
if (errorPictureDrawn) {
if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height())
context->drawText(font, textRun, altTextOffset);
- } else if (usableWidth >= textWidth && cHeight >= fontMetrics.height())
+ } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height())
context->drawText(font, textRun, altTextOffset);
}
}
@@ -398,11 +424,11 @@ void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo)
if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints())
return;
- Node* focusedNode = document->focusedNode();
- if (!focusedNode || !focusedNode->hasTagName(areaTag))
+ Element* focusedElement = document->focusedElement();
+ if (!focusedElement || !isHTMLAreaElement(focusedElement))
return;
- HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(focusedNode);
+ HTMLAreaElement* areaElement = toHTMLAreaElement(focusedElement);
if (areaElement->imageElement() != node())
return;
@@ -445,7 +471,7 @@ void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect
if (!img || img->isNull())
return;
- HTMLImageElement* imageElt = hostImageElement();
+ HTMLImageElement* imageElt = (node() && isHTMLImageElement(node())) ? toHTMLImageElement(node()) : 0;
CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
Image* image = m_imageResource->image().get();
bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size());
@@ -457,33 +483,38 @@ bool RenderImage::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance
if (!RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(bleedAvoidance))
return false;
- return !backgroundIsObscured();
+ return !const_cast<RenderImage*>(this)->backgroundIsKnownToBeObscured();
}
-bool RenderImage::backgroundIsObscured() const
+bool RenderImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
{
+ UNUSED_PARAM(maxDepthToTest);
if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
return false;
-
if (m_imageResource->cachedImage() && !m_imageResource->cachedImage()->isLoaded())
return false;
-
+ if (!contentBoxRect().contains(localRect))
+ return false;
EFillBox backgroundClip = style()->backgroundClip();
-
// Background paints under borders.
if (backgroundClip == BorderFillBox && style()->hasBorder() && !borderObscuresBackground())
return false;
-
// Background shows in padding area.
if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
return false;
+ // Check for image with alpha.
+ return m_imageResource->cachedImage() && m_imageResource->cachedImage()->currentFrameKnownToBeOpaque(this);
+}
- // Check for bitmap image with alpha.
- Image* image = m_imageResource->image().get();
- if (!image || !image->isBitmapImage() || image->currentFrameHasAlpha())
+bool RenderImage::computeBackgroundIsKnownToBeObscured()
+{
+ if (!hasBackground())
return false;
-
- return true;
+
+ LayoutRect paintedExtent;
+ if (!getBackgroundPaintedExtent(paintedExtent))
+ return false;
+ return foregroundIsKnownToBeOpaqueInRect(paintedExtent, 0);
}
LayoutUnit RenderImage::minimumReplacedHeight() const
@@ -493,7 +524,7 @@ LayoutUnit RenderImage::minimumReplacedHeight() const
HTMLMapElement* RenderImage::imageMap() const
{
- HTMLImageElement* i = hostImageElement();
+ HTMLImageElement* i = node() && isHTMLImageElement(node()) ? toHTMLImageElement(node()) : 0;
return i ? i->treeScope()->getImageMap(i->fastGetAttribute(usemapAttr)) : 0;
}
@@ -526,10 +557,10 @@ void RenderImage::updateAltText()
if (!node())
return;
- if (node()->hasTagName(inputTag))
- m_altText = static_cast<HTMLInputElement*>(node())->altText();
- else if (HTMLImageElement* image = hostImageElement())
- m_altText = image->altText();
+ if (isHTMLInputElement(node()))
+ m_altText = toHTMLInputElement(node())->altText();
+ else if (isHTMLImageElement(node()))
+ m_altText = toHTMLImageElement(node())->altText();
}
void RenderImage::layout()
@@ -553,7 +584,7 @@ void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, dou
if (containingBlock->isBox()) {
RenderBox* box = toRenderBox(containingBlock);
intrinsicSize.setWidth(box->availableLogicalWidth());
- intrinsicSize.setHeight(box->availableLogicalHeight());
+ intrinsicSize.setHeight(box->availableLogicalHeight(IncludeMarginBorderPadding));
}
}
// Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image.
@@ -563,24 +594,6 @@ void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, dou
}
}
-HTMLImageElement* RenderImage::hostImageElement() const
-{
- if (!node())
- return 0;
-
- if (isHTMLImageElement(node()))
- return toHTMLImageElement(node());
-
- if (node()->hasTagName(webkitInnerImageTag)) {
- if (Node* ancestor = node()->shadowAncestorNode()) {
- if (ancestor->hasTagName(imgTag))
- return toHTMLImageElement(ancestor);
- }
- }
-
- return 0;
-}
-
bool RenderImage::needsPreferredWidthsRecalculation() const
{
if (RenderReplaced::needsPreferredWidthsRecalculation())
diff --git a/Source/WebCore/rendering/RenderImage.h b/Source/WebCore/rendering/RenderImage.h
index e734fdd4d..afd8e908c 100644
--- a/Source/WebCore/rendering/RenderImage.h
+++ b/Source/WebCore/rendering/RenderImage.h
@@ -31,14 +31,15 @@
namespace WebCore {
class HTMLAreaElement;
-class HTMLImageElement;
class HTMLMapElement;
class RenderImage : public RenderReplaced {
public:
- RenderImage(Node*);
+ RenderImage(Element*);
virtual ~RenderImage();
+ static RenderImage* createAnonymous(Document*);
+
void setImageResource(PassOwnPtr<RenderImageResource>);
RenderImageResource* imageResource() { return m_imageResource.get(); }
@@ -58,12 +59,13 @@ public:
bool isGeneratedContent() const { return m_isGeneratedContent; }
-protected:
- HTMLImageElement* hostImageElement() const;
+ String altText() const { return m_altText; }
+protected:
virtual bool needsPreferredWidthsRecalculation() const;
virtual RenderBox* embeddedContentBox() const;
virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const;
+ virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const OVERRIDE;
virtual void styleDidChange(StyleDifference, const RenderStyle*);
@@ -87,7 +89,7 @@ private:
virtual void paintReplaced(PaintInfo&, const LayoutPoint&);
- virtual bool backgroundIsObscured() const;
+ virtual bool computeBackgroundIsKnownToBeObscured() OVERRIDE;
virtual LayoutUnit minimumReplacedHeight() const OVERRIDE;
@@ -114,13 +116,13 @@ private:
inline RenderImage* toRenderImage(RenderObject* object)
{
- ASSERT(!object || object->isRenderImage());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderImage());
return static_cast<RenderImage*>(object);
}
inline const RenderImage* toRenderImage(const RenderObject* object)
{
- ASSERT(!object || object->isRenderImage());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderImage());
return static_cast<const RenderImage*>(object);
}
diff --git a/Source/WebCore/rendering/RenderImageResource.cpp b/Source/WebCore/rendering/RenderImageResource.cpp
index 0c3a79e45..a0b46d358 100644
--- a/Source/WebCore/rendering/RenderImageResource.cpp
+++ b/Source/WebCore/rendering/RenderImageResource.cpp
@@ -28,6 +28,7 @@
#include "config.h"
#include "RenderImageResource.h"
+#include "CachedImage.h"
#include "Image.h"
#include "RenderImageResourceStyleImage.h"
#include "RenderObject.h"
@@ -36,7 +37,6 @@ namespace WebCore {
RenderImageResource::RenderImageResource()
: m_renderer(0)
- , m_cachedImage(0)
{
}
@@ -89,6 +89,16 @@ void RenderImageResource::resetAnimation()
m_renderer->repaint();
}
+PassRefPtr<Image> RenderImageResource::image(int, int) const
+{
+ return m_cachedImage ? m_cachedImage->imageForRenderer(m_renderer) : nullImage();
+}
+
+bool RenderImageResource::errorOccurred() const
+{
+ return m_cachedImage && m_cachedImage->errorOccurred();
+}
+
void RenderImageResource::setContainerSizeForRenderer(const IntSize& imageContainerSize)
{
ASSERT(m_renderer);
@@ -101,4 +111,24 @@ Image* RenderImageResource::nullImage()
return Image::nullImage();
}
+bool RenderImageResource::usesImageContainerSize() const
+{
+ return m_cachedImage ? m_cachedImage->usesImageContainerSize() : false;
+}
+
+bool RenderImageResource::imageHasRelativeWidth() const
+{
+ return m_cachedImage ? m_cachedImage->imageHasRelativeWidth() : false;
+}
+
+bool RenderImageResource::imageHasRelativeHeight() const
+{
+ return m_cachedImage ? m_cachedImage->imageHasRelativeHeight() : false;
+}
+
+LayoutSize RenderImageResource::imageSize(float multiplier) const
+{
+ return m_cachedImage ? m_cachedImage->imageSizeForRenderer(m_renderer, multiplier) : LayoutSize();
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderImageResource.h b/Source/WebCore/rendering/RenderImageResource.h
index 4bc6e973a..28dbd31a8 100644
--- a/Source/WebCore/rendering/RenderImageResource.h
+++ b/Source/WebCore/rendering/RenderImageResource.h
@@ -26,7 +26,6 @@
#ifndef RenderImageResource_h
#define RenderImageResource_h
-#include "CachedImage.h"
#include "CachedResourceHandle.h"
#include "Image.h"
#include "LayoutSize.h"
@@ -55,15 +54,15 @@ public:
void resetAnimation();
- virtual PassRefPtr<Image> image(int /* width */ = 0, int /* height */ = 0) const { return m_cachedImage ? m_cachedImage->imageForRenderer(m_renderer) : nullImage(); }
- virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); }
+ virtual PassRefPtr<Image> image(int width = 0, int height = 0) const;
+ virtual bool errorOccurred() const;
virtual void setContainerSizeForRenderer(const IntSize&);
- virtual bool usesImageContainerSize() const { return m_cachedImage ? m_cachedImage->usesImageContainerSize() : false; }
- virtual bool imageHasRelativeWidth() const { return m_cachedImage ? m_cachedImage->imageHasRelativeWidth() : false; }
- virtual bool imageHasRelativeHeight() const { return m_cachedImage ? m_cachedImage->imageHasRelativeHeight() : false; }
+ virtual bool usesImageContainerSize() const;
+ virtual bool imageHasRelativeWidth() const;
+ virtual bool imageHasRelativeHeight() const;
- virtual LayoutSize imageSize(float multiplier) const { return m_cachedImage ? m_cachedImage->imageSizeForRenderer(m_renderer, multiplier) : LayoutSize(); }
+ virtual LayoutSize imageSize(float multiplier) const;
virtual WrappedImagePtr imagePtr() const { return m_cachedImage.get(); }
diff --git a/Source/WebCore/rendering/RenderImageResourceStyleImage.cpp b/Source/WebCore/rendering/RenderImageResourceStyleImage.cpp
index ddb13447e..51cd80963 100644
--- a/Source/WebCore/rendering/RenderImageResourceStyleImage.cpp
+++ b/Source/WebCore/rendering/RenderImageResourceStyleImage.cpp
@@ -28,6 +28,7 @@
#include "config.h"
#include "RenderImageResourceStyleImage.h"
+#include "CachedImage.h"
#include "RenderObject.h"
#include "StyleCachedImage.h"
diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp
index db1b185f6..5e6d643a7 100644
--- a/Source/WebCore/rendering/RenderInline.cpp
+++ b/Source/WebCore/rendering/RenderInline.cpp
@@ -32,6 +32,7 @@
#include "RenderArena.h"
#include "RenderBlock.h"
#include "RenderFlowThread.h"
+#include "RenderFullScreen.h"
#include "RenderGeometryMap.h"
#include "RenderLayer.h"
#include "RenderTheme.h"
@@ -40,8 +41,6 @@
#include "TransformState.h"
#include "VisiblePosition.h"
-#include <wtf/TemporaryChange.h>
-
#if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
#include "Frame.h"
#endif
@@ -50,13 +49,20 @@ using namespace std;
namespace WebCore {
-RenderInline::RenderInline(Node* node)
- : RenderBoxModelObject(node)
+RenderInline::RenderInline(Element* element)
+ : RenderBoxModelObject(element)
, m_alwaysCreateLineBoxes(false)
{
setChildrenInline(true);
}
+RenderInline* RenderInline::createAnonymous(Document* document)
+{
+ RenderInline* renderer = new (document->renderArena()) RenderInline(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
void RenderInline::willBeDestroyed()
{
#if !ASSERT_DISABLED
@@ -169,18 +175,11 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
// need to pass its style on to anyone else.
RenderStyle* newStyle = style();
RenderInline* continuation = inlineElementContinuation();
- {
- TemporaryChange<bool> enableAfter(RenderObjectChildList::s_enableUpdateBeforeAfterContent, false);
- RenderInline* nextInlineElementCont = 0;
- for (RenderInline* currCont = continuation; currCont; currCont = nextInlineElementCont) {
- nextInlineElementCont = currCont->inlineElementContinuation();
- // We need to update :after content for the last continuation in the chain.
- RenderObjectChildList::s_enableUpdateBeforeAfterContent = !nextInlineElementCont;
- RenderBoxModelObject* nextCont = currCont->continuation();
- currCont->setContinuation(0);
- currCont->setStyle(newStyle);
- currCont->setContinuation(nextCont);
- }
+ for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
+ RenderBoxModelObject* nextCont = currCont->continuation();
+ currCont->setContinuation(0);
+ currCont->setStyle(newStyle);
+ currCont->setContinuation(nextCont);
}
// If an inline's in-flow positioning has changed then any descendant blocks will need to change their in-flow positioning accordingly.
@@ -201,12 +200,6 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
}
m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
}
-
- // Update pseudos for :before and :after now.
- if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules()) {
- children()->updateBeforeAfterContent(this, BEFORE);
- children()->updateBeforeAfterContent(this, AFTER);
- }
}
void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
@@ -219,13 +212,14 @@ void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
RenderStyle* parentStyle = parent()->style();
RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
bool checkFonts = document()->inNoQuirksMode();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
|| (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
|| style()->verticalAlign() != BASELINE
|| style()->textEmphasisMark() != TextEmphasisMarkNone
|| (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
|| parentStyle->lineHeight() != style()->lineHeight()))
- || (inRenderFlowThread() && enclosingRenderFlowThread()->hasRegionsWithStyling());
+ || (flowThread && flowThread->hasRegionsWithStyling());
if (!alwaysCreateLineBoxes && checkFonts && document()->styleSheetCollection()->usesFirstLineRules()) {
// Have to check the first line style as well.
@@ -324,21 +318,11 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb
if (RenderObject* positionedAncestor = inFlowPositionedInlineAncestor(this))
newStyle->setPosition(positionedAncestor->style()->position());
- RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
+ RenderBlock* newBox = RenderBlock::createAnonymous(document());
newBox->setStyle(newStyle.release());
RenderBoxModelObject* oldContinuation = continuation();
setContinuation(newBox);
- // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
- // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
- // content gets properly destroyed.
- bool isLastChild = (beforeChild == lastChild());
- if (document()->styleSheetCollection()->usesBeforeAfterRules())
- children()->updateBeforeAfterContent(this, AFTER);
- if (isLastChild && beforeChild != lastChild())
- beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
- // point to be 0. It's just a straight append now.
-
splitFlow(beforeChild, newBox, newChild, oldContinuation);
return;
}
@@ -352,7 +336,7 @@ RenderInline* RenderInline::clone() const
{
RenderInline* cloneInline = new (renderArena()) RenderInline(node());
cloneInline->setStyle(style());
- cloneInline->setInRenderFlowThread(inRenderFlowThread());
+ cloneInline->setFlowThreadState(flowThreadState());
return cloneInline;
}
@@ -364,6 +348,17 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
RenderInline* cloneInline = clone();
cloneInline->setContinuation(oldCont);
+#if ENABLE(FULLSCREEN_API)
+ // If we're splitting the inline containing the fullscreened element,
+ // |beforeChild| may be the renderer for the fullscreened element. However,
+ // that renderer is wrapped in a RenderFullScreen, so |this| is not its
+ // parent. Since the splitting logic expects |this| to be the parent, set
+ // |beforeChild| to be the RenderFullScreen.
+ const Element* fullScreenElement = document()->webkitCurrentFullScreenElement();
+ if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
+ beforeChild = document()->fullScreenRenderer();
+#endif
+
// Now take all of the children from beforeChild to the end and remove
// them from |this| and place them in the clone.
RenderObject* o = beforeChild;
@@ -405,12 +400,6 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
inlineCurr->setContinuation(cloneInline);
cloneInline->setContinuation(oldCont);
- // Someone may have indirectly caused a <q> to split. When this happens, the :after content
- // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
- // content gets properly destroyed.
- if (document()->styleSheetCollection()->usesBeforeAfterRules())
- inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
-
// Now we need to take all of the children starting from the first child
// *after* currChild and append them all to the clone.
o = currChild->nextSibling();
@@ -762,9 +751,12 @@ const char* RenderInline::renderName() const
return "RenderInline (relative positioned)";
if (isStickyPositioned())
return "RenderInline (sticky positioned)";
+ // FIXME: Temporary hack while the new generated content system is being implemented.
+ if (isPseudoElement())
+ return "RenderInline (generated)";
if (isAnonymous())
return "RenderInline (generated)";
- if (isRunIn())
+ if (style() && isRunIn())
return "RenderInline (run-in)";
return "RenderInline";
}
@@ -811,7 +803,7 @@ bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestRes
// We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
// because it can only handle rectangular targets.
result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
- return regionResult.contains(enclosingIntRect(tmpLocation.boundingBox()));
+ return regionResult.contains(tmpLocation.boundingBox());
}
return false;
}
@@ -1149,7 +1141,9 @@ LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const Layo
offset -= toRenderBox(container)->scrolledContentOffset();
if (offsetDependsOnPoint)
- *offsetDependsOnPoint = container->hasColumns() || (container->isBox() && container->style()->isFlippedBlocksWritingMode());
+ *offsetDependsOnPoint = container->hasColumns()
+ || (container->isBox() && container->style()->isFlippedBlocksWritingMode())
+ || container->isRenderFlowThread();
return offset;
}
@@ -1184,8 +1178,6 @@ void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintCont
}
LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
- if (mode & SnapOffsetForTransforms)
- containerOffset = roundedIntSize(containerOffset);
bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
@@ -1224,8 +1216,6 @@ const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelO
bool offsetDependsOnPoint = false;
LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
- if (geometryMap.mapCoordinatesFlags() & SnapOffsetForTransforms)
- containerOffset = roundedIntSize(containerOffset);
bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
if (shouldUseTransformFromContainer(container)) {
@@ -1400,7 +1390,7 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
repaint();
}
-void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
+void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
{
AbsoluteRectsGeneratorContext context(rects, additionalOffset);
generateLineBoxRects(context);
@@ -1410,22 +1400,22 @@ void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&
FloatPoint pos(additionalOffset);
// FIXME: This doesn't work correctly with transforms.
if (curr->hasLayer())
- pos = curr->localToAbsolute();
+ pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
else if (curr->isBox())
pos.move(toRenderBox(curr)->locationOffset());
- curr->addFocusRingRects(rects, flooredIntPoint(pos));
+ curr->addFocusRingRects(rects, flooredIntPoint(pos), paintContainer);
}
}
if (continuation()) {
if (continuation()->isInline())
- continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()));
+ continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()), paintContainer);
else
- continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()));
+ continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()), paintContainer);
}
}
-void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset)
+void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (!hasOutline())
return;
@@ -1434,10 +1424,11 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPo
if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
if (!theme()->supportsFocusRing(styleToUse)) {
// Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
- paintFocusRing(graphicsContext, paintOffset, styleToUse);
+ paintFocusRing(paintInfo, paintOffset, styleToUse);
}
}
+ GraphicsContext* graphicsContext = paintInfo.context;
if (graphicsContext->paintingDisabled())
return;
diff --git a/Source/WebCore/rendering/RenderInline.h b/Source/WebCore/rendering/RenderInline.h
index 845904b65..6407de412 100644
--- a/Source/WebCore/rendering/RenderInline.h
+++ b/Source/WebCore/rendering/RenderInline.h
@@ -33,13 +33,17 @@ class Position;
class RenderInline : public RenderBoxModelObject {
public:
- explicit RenderInline(Node*);
+ explicit RenderInline(Element*);
+
+ static RenderInline* createAnonymous(Document*);
RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); }
RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); }
virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
+ Element* node() const { return toElement(RenderBoxModelObject::node()); }
+
virtual LayoutUnit marginLeft() const;
virtual LayoutUnit marginRight() const;
virtual LayoutUnit marginTop() const;
@@ -77,8 +81,8 @@ public:
LayoutSize offsetForInFlowPositionedInline(const RenderBox* child) const;
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
- void paintOutline(GraphicsContext*, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
+ void paintOutline(PaintInfo&, const LayoutPoint&);
using RenderBoxModelObject::continuation;
using RenderBoxModelObject::setContinuation;
@@ -140,7 +144,7 @@ private:
virtual LayoutRect rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const OVERRIDE;
virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed) const OVERRIDE;
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual VisiblePosition positionForPoint(const LayoutPoint&);
@@ -186,13 +190,13 @@ private:
inline RenderInline* toRenderInline(RenderObject* object)
{
- ASSERT(!object || object->isRenderInline());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderInline());
return static_cast<RenderInline*>(object);
}
inline const RenderInline* toRenderInline(const RenderObject* object)
{
- ASSERT(!object || object->isRenderInline());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderInline());
return static_cast<const RenderInline*>(object);
}
diff --git a/Source/WebCore/rendering/RenderInputSpeech.cpp b/Source/WebCore/rendering/RenderInputSpeech.cpp
index 8d42d3be8..65ee27503 100644
--- a/Source/WebCore/rendering/RenderInputSpeech.cpp
+++ b/Source/WebCore/rendering/RenderInputSpeech.cpp
@@ -29,9 +29,8 @@
*/
#include "config.h"
-#include "RenderInputSpeech.h"
-
#if ENABLE(INPUT_SPEECH)
+#include "RenderInputSpeech.h"
#include "GraphicsContext.h"
#include "HTMLNames.h"
diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp
index c8437895f..c378f18e6 100644
--- a/Source/WebCore/rendering/RenderLayer.cpp
+++ b/Source/WebCore/rendering/RenderLayer.cpp
@@ -44,22 +44,21 @@
#include "config.h"
#include "RenderLayer.h"
+#include "AnimationController.h"
#include "ColumnInfo.h"
#include "CSSPropertyNames.h"
#include "Chrome.h"
#include "Document.h"
#include "DocumentEventQueue.h"
#include "EventHandler.h"
-#if ENABLE(CSS_FILTERS)
-#include "FEColorMatrix.h"
-#include "FEMerge.h"
-#include "FilterEffectRenderer.h"
-#endif
+#include "FeatureObserver.h"
#include "FloatConversion.h"
#include "FloatPoint3D.h"
#include "FloatRect.h"
#include "FocusController.h"
#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
#include "FrameSelection.h"
#include "FrameTree.h"
#include "FrameView.h"
@@ -68,6 +67,7 @@
#include "HTMLFrameElement.h"
#include "HTMLFrameOwnerElement.h"
#include "HTMLNames.h"
+#include "HistogramSupport.h"
#include "HitTestingTransformState.h"
#include "HitTestRequest.h"
#include "HitTestResult.h"
@@ -93,6 +93,7 @@
#include "ScrollbarTheme.h"
#include "ScrollingCoordinator.h"
#include "Settings.h"
+#include "ShadowRoot.h"
#include "SourceGraphic.h"
#include "StylePropertySet.h"
#include "StyleResolver.h"
@@ -100,9 +101,15 @@
#include "TransformationMatrix.h"
#include "TranslateTransformOperation.h"
#include <wtf/StdLibExtras.h>
-#include <wtf/UnusedParam.h>
#include <wtf/text/CString.h>
+#if ENABLE(CSS_FILTERS)
+#include "FEColorMatrix.h"
+#include "FEMerge.h"
+#include "FilterEffectRenderer.h"
+#include "RenderLayerFilterInfo.h"
+#endif
+
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerBacking.h"
#include "RenderLayerCompositor.h"
@@ -119,10 +126,6 @@
#include "ValidatedCustomFilterOperation.h"
#endif
-#if PLATFORM(BLACKBERRY)
-#define DISABLE_ROUNDED_CORNER_CLIPPING
-#endif
-
#define MIN_INTERSECT_FOR_REVEAL 32
using namespace std;
@@ -134,17 +137,32 @@ using namespace HTMLNames;
const int MinimumWidthWhileResizing = 100;
const int MinimumHeightWhileResizing = 40;
-bool ClipRect::intersects(const HitTestLocation& hitTestLocation)
+bool ClipRect::intersects(const HitTestLocation& hitTestLocation) const
{
return hitTestLocation.intersects(m_rect);
}
+void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
+{
+#if !ENABLE(3D_RENDERING)
+ UNUSED_PARAM(has3DRendering);
+ matrix.makeAffine();
+#else
+ if (!has3DRendering)
+ matrix.makeAffine();
+#endif
+}
+
RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
: m_inResizeMode(false)
, m_scrollDimensionsDirty(true)
, m_normalFlowListDirty(true)
, m_hasSelfPaintingLayerDescendant(false)
, m_hasSelfPaintingLayerDescendantDirty(false)
+ , m_hasOutOfFlowPositionedDescendant(false)
+ , m_hasOutOfFlowPositionedDescendantDirty(true)
+ , m_needsCompositedScrolling(false)
+ , m_descendantsAreContiguousInStackingOrder(false)
, m_isRootLayer(renderer->isRenderView())
, m_usedTransparency(false)
, m_paintingInsideReflection(false)
@@ -160,6 +178,7 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
#if USE(ACCELERATED_COMPOSITING)
, m_hasCompositingDescendant(false)
, m_indirectCompositingReason(NoIndirectCompositingReason)
+ , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
#endif
, m_containsDirtyOverlayScrollbars(false)
, m_updatingMarqueePosition(false)
@@ -183,13 +202,14 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
, m_reflection(0)
, m_scrollCorner(0)
, m_resizer(0)
+ , m_enclosingPaginationLayer(0)
{
m_isNormalFlowOnly = shouldBeNormalFlowOnly();
m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
- // Non-stacking contexts should have empty z-order lists. As this is already the case,
+ // Non-stacking containers should have empty z-order lists. As this is already the case,
// there is no need to dirty / recompute these lists.
- m_zOrderListsDirty = isStackingContext();
+ m_zOrderListsDirty = isStackingContainer();
ScrollableArea::setConstrainsScrollingToContentEdge(false);
@@ -230,6 +250,11 @@ RenderLayer::~RenderLayer()
destroyScrollbar(HorizontalScrollbar);
destroyScrollbar(VerticalScrollbar);
+ if (renderer()->frame() && renderer()->frame()->page()) {
+ if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->page()->scrollingCoordinator())
+ scrollingCoordinator->willDestroyScrollableArea(this);
+ }
+
if (m_reflection)
removeReflection();
@@ -250,6 +275,38 @@ RenderLayer::~RenderLayer()
m_resizer->destroy();
}
+String RenderLayer::name() const
+{
+ StringBuilder name;
+ name.append(renderer()->renderName());
+
+ if (Element* element = renderer()->node() && renderer()->node()->isElementNode() ? toElement(renderer()->node()) : 0) {
+ name.append(' ');
+ name.append(element->tagName());
+
+ if (element->hasID()) {
+ name.appendLiteral(" id=\'");
+ name.append(element->getIdAttribute());
+ name.append('\'');
+ }
+
+ if (element->hasClass()) {
+ name.appendLiteral(" class=\'");
+ for (size_t i = 0; i < element->classNames().size(); ++i) {
+ if (i > 0)
+ name.append(' ');
+ name.append(element->classNames()[i]);
+ }
+ name.append('\'');
+ }
+ }
+
+ if (isReflection())
+ name.appendLiteral(" (reflection)");
+
+ return name.toString();
+}
+
#if USE(ACCELERATED_COMPOSITING)
RenderLayerCompositor* RenderLayer::compositor() const
{
@@ -303,6 +360,28 @@ bool RenderLayer::requiresFullLayerImageForFilters() const
FilterEffectRenderer* filter = filterRenderer();
return filter ? filter->hasFilterThatMovesPixels() : false;
}
+
+FilterEffectRenderer* RenderLayer::filterRenderer() const
+{
+ RenderLayerFilterInfo* filterInfo = this->filterInfo();
+ return filterInfo ? filterInfo->renderer() : 0;
+}
+
+RenderLayerFilterInfo* RenderLayer::filterInfo() const
+{
+ return hasFilterInfo() ? RenderLayerFilterInfo::filterInfoForRenderLayer(this) : 0;
+}
+
+RenderLayerFilterInfo* RenderLayer::ensureFilterInfo()
+{
+ return RenderLayerFilterInfo::createFilterInfoForRenderLayerIfNeeded(this);
+}
+
+void RenderLayer::removeFilterInfoIfNeeded()
+{
+ if (hasFilterInfo())
+ RenderLayerFilterInfo::removeFilterInfoForRenderLayer(this);
+}
#endif
LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
@@ -355,15 +434,17 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
// as canUseConvertToLayerCoords may be true for an ancestor layer.
convertToLayerCoords(root(), offsetFromRoot);
}
- positionOverflowControls(toSize(roundedIntPoint(offsetFromRoot)));
+ positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
}
updateDescendantDependentFlags();
if (flags & UpdatePagination)
updatePagination();
- else
+ else {
m_isPaginated = false;
+ m_enclosingPaginationLayer = 0;
+ }
if (m_hasVisibleContent) {
RenderView* view = renderer()->view();
@@ -406,6 +487,11 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
flags &= ~IsCompositingUpdateRoot;
#endif
+ if (useRegionBasedColumns() && renderer()->isInFlowRenderFlowThread()) {
+ updatePagination();
+ flags |= UpdatePagination;
+ }
+
if (renderer()->hasColumns())
flags |= UpdatePagination;
@@ -413,8 +499,14 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
child->updateLayerPositions(geometryMap, flags);
#if USE(ACCELERATED_COMPOSITING)
- if ((flags & UpdateCompositingLayers) && isComposited())
- backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot);
+ if ((flags & UpdateCompositingLayers) && isComposited()) {
+ RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
+ if (flags & NeedsFullRepaintInBacking)
+ updateFlags |= RenderLayerBacking::NeedsFullRepaint;
+ if (isUpdateRoot)
+ updateFlags |= RenderLayerBacking::IsUpdateRoot;
+ backing()->updateAfterLayout(updateFlags);
+ }
#endif
// With all our children positioned, now update our marquee if we need to.
@@ -467,6 +559,170 @@ void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
}
}
+bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
+{
+ return renderer()->frame()
+ && renderer()->frame()->page()
+ && renderer()->frame()->page()->settings()->acceleratedCompositingForOverflowScrollEnabled();
+}
+
+// If we are a stacking container, then this function will determine if our
+// descendants for a contiguous block in stacking order. This is required in
+// order for an element to be safely promoted to a stacking container. It is safe
+// to become a stacking container if this change would not alter the stacking
+// order of layers on the page. That can only happen if a non-descendant appear
+// between us and our descendants in stacking order. Here's an example:
+//
+// this
+// / | \.
+// A B C
+// /\ | /\.
+// 0 -8 D 2 7
+// |
+// 5
+//
+// I've labeled our normal flow descendants A, B, C, and D, our stacking
+// container descendants with their z indices, and us with 'this' (we're a
+// stacking container and our zIndex doesn't matter here). These nodes appear in
+// three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal
+// flow layers don't overlap). So if we arrange these lists in order we get our
+// stacking order:
+//
+// [-8], [A-D], [0, 2, 5, 7]--> pos z-order.
+// | |
+// Neg z-order. <-+ +--> Normal flow descendants.
+//
+// We can then assign new, 'stacking' order indices to these elements as follows:
+//
+// [-8], [A-D], [0, 2, 5, 7]
+// 'Stacking' indices: -1 0 1 2 3 4
+//
+// Note that the normal flow descendants can share an index because they don't
+// stack/overlap. Now our problem becomes very simple: a layer can safely become
+// a stacking container if the stacking-order indices of it and its descendants
+// appear in a contiguous block in the list of stacking indices. This problem
+// can be solved very efficiently by calculating the min/max stacking indices in
+// the subtree, and the number stacking container descendants. Once we have this
+// information, we know that the subtree's indices form a contiguous block if:
+//
+// maxStackIndex - minStackIndex == numSCDescendants
+//
+// So for node A in the example above we would have:
+// maxStackIndex = 1
+// minStackIndex = -1
+// numSCDecendants = 2
+//
+// and so,
+// maxStackIndex - minStackIndex == numSCDescendants
+// ===> 1 - (-1) == 2
+// ===> 2 == 2
+//
+// Since this is true, A can safely become a stacking container.
+// Now, for node C we have:
+//
+// maxStackIndex = 4
+// minStackIndex = 0 <-- because C has stacking index 0.
+// numSCDecendants = 2
+//
+// and so,
+// maxStackIndex - minStackIndex == numSCDescendants
+// ===> 4 - 0 == 2
+// ===> 4 == 2
+//
+// Since this is false, C cannot be safely promoted to a stacking container. This
+// happened because of the elements with z-index 5 and 0. Now if 5 had been a
+// child of C rather than D, and A had no child with Z index 0, we would have had:
+//
+// maxStackIndex = 3
+// minStackIndex = 0 <-- because C has stacking index 0.
+// numSCDecendants = 3
+//
+// and so,
+// maxStackIndex - minStackIndex == numSCDescendants
+// ===> 3 - 0 == 3
+// ===> 3 == 3
+//
+// And we would conclude that C could be promoted.
+void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
+{
+ if (!isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
+ return;
+
+ ASSERT(!m_normalFlowListDirty);
+ ASSERT(!m_zOrderListsDirty);
+
+ OwnPtr<Vector<RenderLayer*> > posZOrderList;
+ OwnPtr<Vector<RenderLayer*> > negZOrderList;
+ rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
+
+ // Create a reverse lookup.
+ HashMap<const RenderLayer*, int> lookup;
+
+ if (negZOrderList) {
+ int stackingOrderIndex = -1;
+ size_t listSize = negZOrderList->size();
+ for (size_t i = 0; i < listSize; ++i) {
+ RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1);
+ if (!currentLayer->isStackingContext())
+ continue;
+ lookup.set(currentLayer, stackingOrderIndex--);
+ }
+ }
+
+ if (posZOrderList) {
+ size_t listSize = posZOrderList->size();
+ int stackingOrderIndex = 1;
+ for (size_t i = 0; i < listSize; ++i) {
+ RenderLayer* currentLayer = posZOrderList->at(i);
+ if (!currentLayer->isStackingContext())
+ continue;
+ lookup.set(currentLayer, stackingOrderIndex++);
+ }
+ }
+
+ int minIndex = 0;
+ int maxIndex = 0;
+ int count = 0;
+ bool firstIteration = true;
+ updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration);
+}
+
+void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration)
+{
+ if (isStackingContext() && !firstIteration) {
+ if (lookup.contains(this)) {
+ minIndex = std::min(minIndex, lookup.get(this));
+ maxIndex = std::max(maxIndex, lookup.get(this));
+ count++;
+ }
+ return;
+ }
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ int childMinIndex = 0;
+ int childMaxIndex = 0;
+ int childCount = 0;
+ child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false);
+ if (childCount) {
+ count += childCount;
+ minIndex = std::min(minIndex, childMinIndex);
+ maxIndex = std::max(maxIndex, childMaxIndex);
+ }
+ }
+
+ if (!isStackingContext()) {
+ bool newValue = maxIndex - minIndex == count;
+#if USE(ACCELERATED_COMPOSITING)
+ bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
+#endif
+ m_descendantsAreContiguousInStackingOrder = newValue;
+#if USE(ACCELERATED_COMPOSITING)
+ if (didUpdate)
+ updateNeedsCompositedScrolling();
+#endif
+ }
+}
+
void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
{
ASSERT(!m_visibleContentStatusDirty);
@@ -572,6 +828,22 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap
geometryMap->popMappingsToAncestor(parent());
}
+#if USE(ACCELERATED_COMPOSITING)
+void RenderLayer::positionNewlyCreatedOverflowControls()
+{
+ if (!backing()->hasUnpositionedOverflowControlsLayers())
+ return;
+
+ RenderGeometryMap geometryMap(UseTransforms);
+ RenderView* view = renderer()->view();
+ if (this != view->layer() && parent())
+ geometryMap.pushMappingsToAncestor(parent(), 0);
+
+ LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
+ positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
+}
+#endif
+
#if ENABLE(CSS_COMPOSITING)
void RenderLayer::updateBlendMode()
{
@@ -657,6 +929,18 @@ TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavio
return *m_transform;
}
+RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
+{
+ const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
+ while (layer) {
+ if (layer->renderer()->hasOverflowClip())
+ return const_cast<RenderLayer*>(layer);
+
+ layer = layer->parent();
+ }
+ return 0;
+}
+
static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer)
{
RenderView* view = renderer->view();
@@ -679,30 +963,88 @@ static bool checkContainingBlockChainForPagination(RenderLayerModelObject* rende
return true;
}
+bool RenderLayer::useRegionBasedColumns() const
+{
+ const Settings* settings = renderer()->document()->settings();
+ return settings && settings->regionBasedColumnsEnabled();
+}
+
void RenderLayer::updatePagination()
{
m_isPaginated = false;
+ m_enclosingPaginationLayer = 0;
+
if (isComposited() || !parent())
return; // FIXME: We will have to deal with paginated compositing layers someday.
// FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
-
+
+ // The main difference between the paginated booleans for the old column code and the new column code
+ // is that each paginated layer has to paint on its own with the new code. There is no
+ // recurring into child layers. This means that the m_isPaginated bits for the new column code can't just be set on
+ // "roots" that get split and paint all their descendants. Instead each layer has to be checked individually and
+ // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
+ // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
+ // to that layer easily.
+ bool regionBasedColumnsUsed = useRegionBasedColumns();
+ if (regionBasedColumnsUsed && renderer()->isInFlowRenderFlowThread()) {
+ m_enclosingPaginationLayer = this;
+ return;
+ }
+
if (isNormalFlowOnly()) {
- m_isPaginated = parent()->renderer()->hasColumns();
+ if (regionBasedColumnsUsed) {
+ // Content inside a transform is not considered to be paginated, since we simply
+ // paint the transform multiple times in each column, so we don't have to use
+ // fragments for the transformed content.
+ m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
+ if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
+ m_enclosingPaginationLayer = 0;
+ } else
+ m_isPaginated = parent()->renderer()->hasColumns();
return;
}
- // If we're not normal flow, then we need to look for a multi-column object between us and our stacking context.
- RenderLayer* ancestorStackingContext = stackingContext();
+ // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
+ // we find one, then we just check its pagination status.
+ if (regionBasedColumnsUsed) {
+ RenderView* view = renderer()->view();
+ RenderBlock* containingBlock;
+ for (containingBlock = renderer()->containingBlock();
+ containingBlock && containingBlock != view;
+ containingBlock = containingBlock->containingBlock()) {
+ if (containingBlock->hasLayer()) {
+ // Content inside a transform is not considered to be paginated, since we simply
+ // paint the transform multiple times in each column, so we don't have to use
+ // fragments for the transformed content.
+ m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer();
+ if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
+ m_enclosingPaginationLayer = 0;
+ return;
+ }
+ }
+ return;
+ }
+
+ // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container.
+ RenderLayer* ancestorStackingContainer = stackingContainer();
for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns()) {
m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
return;
}
- if (curr == ancestorStackingContext)
+ if (curr == ancestorStackingContainer)
return;
}
}
+bool RenderLayer::canBeStackingContainer() const
+{
+ if (isStackingContext() || !stackingContainer())
+ return true;
+
+ return m_descendantsAreContiguousInStackingOrder;
+}
+
void RenderLayer::setHasVisibleContent()
{
if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
@@ -715,9 +1057,9 @@ void RenderLayer::setHasVisibleContent()
computeRepaintRects(renderer()->containerForRepaint());
if (!isNormalFlowOnly()) {
// We don't collect invisible layers in z-order lists if we are not in compositing mode.
- // As we became visible, we need to dirty our stacking contexts ancestors to be properly
+ // As we became visible, we need to dirty our stacking containers ancestors to be properly
// collected. FIXME: When compositing, we could skip this dirtying phase.
- for (RenderLayer* sc = stackingContext(); sc; sc = sc->stackingContext()) {
+ for (RenderLayer* sc = stackingContainer(); sc; sc = sc->stackingContainer()) {
sc->dirtyZOrderLists();
if (sc->hasVisibleContent())
break;
@@ -756,25 +1098,51 @@ void RenderLayer::setAncestorChainHasVisibleDescendant()
}
}
-void RenderLayer::updateDescendantDependentFlags()
+void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
{
- if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty) {
+ if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) {
m_hasVisibleDescendant = false;
m_hasSelfPaintingLayerDescendant = false;
+ m_hasOutOfFlowPositionedDescendant = false;
+
+ HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- child->updateDescendantDependentFlags();
+ childOutOfFlowDescendantContainingBlocks.clear();
+ child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
+
+ bool childIsOutOfFlowPositioned = child->renderer() && child->renderer()->isOutOfFlowPositioned();
+ if (childIsOutOfFlowPositioned)
+ childOutOfFlowDescendantContainingBlocks.add(child->renderer()->containingBlock());
+
+ if (outOfFlowDescendantContainingBlocks) {
+ HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
+ for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
+ outOfFlowDescendantContainingBlocks->add(*it);
+ }
bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant;
bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
+ bool hasOutOfFlowPositionedDescendant = !childOutOfFlowDescendantContainingBlocks.isEmpty();
m_hasVisibleDescendant |= hasVisibleDescendant;
m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant;
+ m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant;
- if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant)
+ if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && m_hasOutOfFlowPositionedDescendant)
break;
}
+
+ if (outOfFlowDescendantContainingBlocks && renderer())
+ outOfFlowDescendantContainingBlocks->remove(renderer());
+
m_visibleDescendantStatusDirty = false;
m_hasSelfPaintingLayerDescendantDirty = false;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_hasOutOfFlowPositionedDescendantDirty)
+ updateNeedsCompositedScrolling();
+#endif
+ m_hasOutOfFlowPositionedDescendantDirty = false;
}
if (m_visibleContentStatusDirty) {
@@ -810,15 +1178,15 @@ void RenderLayer::updateDescendantDependentFlags()
void RenderLayer::dirty3DTransformedDescendantStatus()
{
- RenderLayer* curr = stackingContext();
+ RenderLayer* curr = stackingContainer();
if (curr)
curr->m_3DTransformedDescendantStatusDirty = true;
// This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
- // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts.
+ // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
while (curr && curr->preserves3D()) {
curr->m_3DTransformedDescendantStatusDirty = true;
- curr = curr->stackingContext();
+ curr = curr->stackingContainer();
}
}
@@ -893,28 +1261,20 @@ bool RenderLayer::updateLayerPosition()
RenderLayer* positionedParent = enclosingPositionedAncestor();
// For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
- LayoutSize offset = positionedParent->scrolledContentOffset();
- localPoint -= offset;
+ if (positionedParent->renderer()->hasOverflowClip()) {
+ LayoutSize offset = positionedParent->scrolledContentOffset();
+ localPoint -= offset;
+ }
if (renderer()->isOutOfFlowPositioned() && positionedParent->renderer()->isInFlowPositioned() && positionedParent->renderer()->isRenderInline()) {
LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(toRenderBox(renderer()));
localPoint += offset;
}
} else if (parent()) {
- if (isComposited()) {
- // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
- // They won't split across columns properly.
- LayoutSize columnOffset;
- if (!parent()->renderer()->hasColumns() && parent()->renderer()->isRoot() && renderer()->view()->hasColumns())
- renderer()->view()->adjustForColumns(columnOffset, localPoint);
- else
- parent()->renderer()->adjustForColumns(columnOffset, localPoint);
-
- localPoint += columnOffset;
+ if (parent()->renderer()->hasOverflowClip()) {
+ IntSize scrollOffset = parent()->scrolledContentOffset();
+ localPoint -= scrollOffset;
}
-
- IntSize scrollOffset = parent()->scrolledContentOffset();
- localPoint -= scrollOffset;
}
bool positionOrOffsetChanged = false;
@@ -977,11 +1337,13 @@ FloatPoint RenderLayer::perspectiveOrigin() const
floatValueForLength(style->perspectiveOriginY(), borderBox.height()));
}
-RenderLayer* RenderLayer::stackingContext() const
+RenderLayer* RenderLayer::stackingContainer() const
{
RenderLayer* layer = parent();
- while (layer && !layer->isRootLayer() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex())
+ while (layer && !layer->isStackingContainer())
layer = layer->parent();
+
+ ASSERT(!layer || layer->isStackingContainer());
return layer;
}
@@ -1020,6 +1382,14 @@ IntRect RenderLayer::scrollableAreaBoundingBox() const
return renderer()->absoluteBoundingBoxRect();
}
+bool RenderLayer::scrollbarAnimationsAreSuppressed() const
+{
+ RenderView* view = renderer()->view();
+ if (!view)
+ return false;
+ return view->frameView()->scrollbarAnimationsAreSuppressed();
+}
+
RenderLayer* RenderLayer::enclosingTransformedAncestor() const
{
RenderLayer* curr = parent();
@@ -1031,7 +1401,7 @@ RenderLayer* RenderLayer::enclosingTransformedAncestor() const
static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
{
- return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext();
+ return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContainer();
}
inline bool RenderLayer::shouldRepaintAfterLayout() const
@@ -1050,9 +1420,9 @@ inline bool RenderLayer::shouldRepaintAfterLayout() const
}
#if USE(ACCELERATED_COMPOSITING)
-RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
+RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
{
- if (includeSelf && isComposited())
+ if (includeSelf == IncludeSelf && isComposited())
return const_cast<RenderLayer*>(this);
for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
@@ -1063,9 +1433,9 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
return 0;
}
-RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const
+RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
{
- if (includeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
+ if (includeSelf == IncludeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
return const_cast<RenderLayer*>(this);
for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
@@ -1078,9 +1448,9 @@ RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf)
#endif
#if ENABLE(CSS_FILTERS)
-RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const
+RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
{
- const RenderLayer* curr = includeSelf ? this : parent();
+ const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
for (; curr; curr = curr->parent()) {
if (curr->requiresFullLayerImageForFilters())
return const_cast<RenderLayer*>(curr);
@@ -1104,18 +1474,7 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect,
return;
LayoutRect rectForRepaint = rect;
-
-#if ENABLE(CSS_FILTERS)
- if (renderer()->style()->hasFilterOutsets()) {
- int topOutset;
- int rightOutset;
- int bottomOutset;
- int leftOutset;
- renderer()->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset);
- rectForRepaint.move(-leftOutset, -topOutset);
- rectForRepaint.expand(leftOutset + rightOutset, topOutset + bottomOutset);
- }
-#endif
+ renderer()->style()->filterOutsets().expandRect(rectForRepaint);
RenderLayerFilterInfo* filterInfo = this->filterInfo();
ASSERT(filterInfo);
@@ -1202,7 +1561,7 @@ RenderLayer* RenderLayer::clippingRootForPainting() const
LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
{
// We don't use convertToLayerCoords because it doesn't know about transforms
- return roundedLayoutPoint(renderer()->absoluteToLocal(absolutePoint, UseTransforms | SnapOffsetForTransforms));
+ return roundedLayoutPoint(renderer()->absoluteToLocal(absolutePoint, UseTransforms));
}
bool RenderLayer::cannotBlitToWindow() const
@@ -1237,18 +1596,29 @@ RenderLayer* RenderLayer::transparentPaintingAncestor()
return 0;
}
-static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, PaintBehavior);
+enum TransparencyClipBoxBehavior {
+ PaintingTransparencyClipBox,
+ HitTestingTransparencyClipBox
+};
+
+enum TransparencyClipBoxMode {
+ DescendantsOfTransparencyClipBox,
+ RootOfTransparencyClipBox
+};
-static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
+static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
+
+static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
+ TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
{
// If we have a mask, then the clip is limited to the border box area (and there is
// no need to examine child layers).
if (!layer->renderer()->hasMask()) {
// Note: we don't have to walk z-order lists since transparent elements always establish
- // a stacking context. This means we can just walk the layer tree directly.
+ // a stacking container. This means we can just walk the layer tree directly.
for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
if (!layer->reflection() || layer->reflectionLayer() != curr)
- clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
+ clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
}
}
@@ -1265,35 +1635,60 @@ static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons
}
}
-static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
+static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
+ TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
{
// FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
// paintDirtyRect, and that should cut down on the amount we have to paint. Still it
// would be better to respect clips.
- if (rootLayer != layer && layer->paintsWithTransform(paintBehavior)) {
+ if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
+ || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) {
// The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
// the transformed layer and all of its children.
+ const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0;
+ const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
LayoutPoint delta;
- layer->convertToLayerCoords(rootLayer, delta);
+ layer->convertToLayerCoords(rootLayerForTransform, delta);
TransformationMatrix transform;
transform.translate(delta.x(), delta.y());
transform = transform * *layer->transform();
+ // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
+ // paints unfragmented.
LayoutRect clipRect = layer->boundingBox(layer);
- expandClipRectForDescendantsAndReflection(clipRect, layer, layer, paintBehavior);
- return transform.mapRect(clipRect);
+ expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior);
+#if ENABLE(CSS_FILTERS)
+ layer->renderer()->style()->filterOutsets().expandRect(clipRect);
+#endif
+ LayoutRect result = transform.mapRect(clipRect);
+ if (!paginationLayer)
+ return result;
+
+ // We have to break up the transformed extent across our columns.
+ // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
+ // get our true bounding box.
+ RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
+ result = enclosingFlowThread->fragmentsBoundingBox(result);
+
+ LayoutPoint rootLayerDelta;
+ paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
+ result.moveBy(rootLayerDelta);
+ return result;
}
- LayoutRect clipRect = layer->boundingBox(rootLayer);
- expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, paintBehavior);
+ LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes);
+ expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
+#if ENABLE(CSS_FILTERS)
+ layer->renderer()->style()->filterOutsets().expandRect(clipRect);
+#endif
return clipRect;
}
LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
{
- return intersection(transparencyClipBox(this, rootLayer, paintBehavior), paintDirtyRect);
+ return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
}
void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
@@ -1360,10 +1755,10 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
dirtyNormalFlowList();
if (!child->isNormalFlowOnly() || child->firstChild()) {
- // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
- // case where we're building up generated content layers. This is ok, since the lists will start
+ // Dirty the z-order list in which we are contained. The stackingContainer() can be null in the
+ // case where we're building up generated content layers. This is ok, since the lists will start
// off dirty in that case anyway.
- child->dirtyStackingContextZOrderLists();
+ child->dirtyStackingContainerZOrderLists();
}
child->updateDescendantDependentFlags();
@@ -1373,6 +1768,9 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
setAncestorChainHasSelfPaintingLayerDescendant();
+ if (child->renderer() && (child->renderer()->isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant()))
+ setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer()->containingBlock());
+
#if USE(ACCELERATED_COMPOSITING)
compositor()->layerWasAdded(this, child);
#endif
@@ -1401,10 +1799,13 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
// Dirty the z-order list in which we are contained. When called via the
// reattachment process in removeOnlyThisLayer, the layer may already be disconnected
- // from the main layer tree, so we need to null-check the |stackingContext| value.
- oldChild->dirtyStackingContextZOrderLists();
+ // from the main layer tree, so we need to null-check the |stackingContainer| value.
+ oldChild->dirtyStackingContainerZOrderLists();
}
+ if ((oldChild->renderer() && oldChild->renderer()->isOutOfFlowPositioned()) || oldChild->hasOutOfFlowPositionedDescendant())
+ dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
oldChild->setParent(0);
@@ -1479,34 +1880,39 @@ void RenderLayer::insertOnlyThisLayer()
clearClipRectsIncludingDescendants();
}
-void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation) const
+void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
{
LayoutPoint location = roundedLocation;
- convertToLayerCoords(ancestorLayer, location);
+ convertToLayerCoords(ancestorLayer, location, adjustForColumns);
roundedLocation = roundedIntPoint(location);
}
-void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect) const
+void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect, ColumnOffsetAdjustment adjustForColumns) const
{
LayoutRect rect = roundedRect;
- convertToLayerCoords(ancestorLayer, rect);
+ convertToLayerCoords(ancestorLayer, rect, adjustForColumns);
roundedRect = pixelSnappedIntRect(rect);
}
// Returns the layer reached on the walk up towards the ancestor.
-static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location)
+static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
{
ASSERT(ancestorLayer != layer);
const RenderLayerModelObject* renderer = layer->renderer();
EPosition position = renderer->style()->position();
+ // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
+ RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer->flowThreadContainingBlock() : 0;
+ if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
+ fixedFlowThreadContainer = 0;
+
// FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
// may need to be revisited in a future patch.
// If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
// since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
// positioned in a completely different place in the viewport (RenderView).
- if (position == FixedPosition && !renderer->inRenderFlowThread() && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
+ if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
// If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
// localToAbsolute() on the RenderView.
FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed);
@@ -1517,7 +1923,7 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
// For the fixed positioned elements inside a render flow thread, we should also skip the code path below
// Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
// element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
- if (position == FixedPosition && !renderer->inRenderFlowThread()) {
+ if (position == FixedPosition && !fixedFlowThreadContainer) {
// For a fixed layers, we need to walk up to the root to see if there's a fixed position container
// (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
// so we should always find the ancestor at or before we find the fixed position container.
@@ -1570,7 +1976,7 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
// We should not reach RenderView layer past the RenderFlowThread layer for any
// children of the RenderFlowThread.
- if (renderer->inRenderFlowThread() && !renderer->isRenderFlowThread())
+ if (renderer->flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
ASSERT(parentLayer != renderer->view()->layer());
if (foundAncestorFirst) {
@@ -1594,37 +2000,83 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
return 0;
location += toSize(layer->location());
+
+ if (adjustForColumns == RenderLayer::AdjustForColumns) {
+ if (RenderLayer* parentLayer = layer->parent()) {
+ LayoutSize layerColumnOffset;
+ parentLayer->renderer()->adjustForColumns(layerColumnOffset, location);
+ location += layerColumnOffset;
+ }
+ }
+
return parentLayer;
}
-void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const
+void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
{
if (ancestorLayer == this)
return;
const RenderLayer* currLayer = this;
while (currLayer && currLayer != ancestorLayer)
- currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location);
+ currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location, adjustForColumns);
}
-void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const
+void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect, ColumnOffsetAdjustment adjustForColumns) const
{
LayoutPoint delta;
- convertToLayerCoords(ancestorLayer, delta);
+ convertToLayerCoords(ancestorLayer, delta, adjustForColumns);
rect.move(-delta.x(), -delta.y());
}
#if USE(ACCELERATED_COMPOSITING)
bool RenderLayer::usesCompositedScrolling() const
{
- if (!scrollsOverflow() || !allowsScrolling())
- return false;
+ return isComposited() && backing()->scrollingLayer();
+}
+
+bool RenderLayer::needsCompositedScrolling() const
+{
+ return m_needsCompositedScrolling;
+}
+
+void RenderLayer::updateNeedsCompositedScrolling()
+{
+ bool oldNeedsCompositedScrolling = m_needsCompositedScrolling;
+
+ FrameView* frameView = renderer()->view()->frameView();
+ if (!frameView || !frameView->containsScrollableArea(this))
+ m_needsCompositedScrolling = false;
+ else {
+ bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
+ && canBeStackingContainer()
+ && !hasOutOfFlowPositionedDescendant();
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
- return renderer()->style()->useTouchOverflowScrolling();
+ m_needsCompositedScrolling = forceUseCompositedScrolling || renderer()->style()->useTouchOverflowScrolling();
#else
- return false;
+ m_needsCompositedScrolling = forceUseCompositedScrolling;
#endif
+ // We gather a boolean value for use with Google UMA histograms to
+ // quantify the actual effects of a set of patches attempting to
+ // relax composited scrolling requirements, thereby increasing the
+ // number of composited overflow divs.
+ if (acceleratedCompositingForOverflowScrollEnabled())
+ HistogramSupport::histogramEnumeration("Renderer.NeedsCompositedScrolling", m_needsCompositedScrolling, 2);
+ }
+
+ if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
+ updateSelfPaintingLayer();
+ if (isStackingContainer())
+ dirtyZOrderLists();
+ else
+ clearZOrderLists();
+
+ dirtyStackingContainerZOrderLists();
+
+ compositor()->setShouldReevaluateCompositingAfterLayout();
+ compositor()->setCompositingLayersNeedRebuild();
+ }
}
#endif
@@ -1653,16 +2105,16 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
if (!frame)
return;
- IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
+ IntPoint lastKnownMousePosition = frame->eventHandler()->lastKnownMousePosition();
- // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
+ // We need to check if the last known mouse position is out of the window. When the mouse is out of the window, the position is incoherent
static IntPoint previousMousePosition;
- if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
- currentMousePosition = previousMousePosition;
+ if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
+ lastKnownMousePosition = previousMousePosition;
else
- previousMousePosition = currentMousePosition;
+ previousMousePosition = lastKnownMousePosition;
- IntSize delta = currentMousePosition - sourcePoint;
+ IntSize delta = lastKnownMousePosition - sourcePoint;
if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
delta.setWidth(0);
@@ -1699,6 +2151,7 @@ void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping
// If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
// have an overflow clip. Which means that it is a document node that can be scrolled.
renderer()->view()->frameView()->scrollBy(delta);
+
// FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
// https://bugs.webkit.org/show_bug.cgi?id=28237
}
@@ -1721,7 +2174,7 @@ void RenderLayer::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClampi
{
IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
if (newScrollOffset != this->scrollOffset())
- scrollToOffsetWithoutAnimation(toPoint(newScrollOffset));
+ scrollToOffsetWithoutAnimation(IntPoint(newScrollOffset));
}
void RenderLayer::scrollTo(int x, int y)
@@ -1784,12 +2237,19 @@ void RenderLayer::scrollTo(int x, int y)
FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
if (repaintContainer)
- quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent, SnapOffsetForTransforms);
+ quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
}
+ bool requiresRepaint = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (compositor()->inCompositingMode() && usesCompositedScrolling())
+ requiresRepaint = false;
+#endif
+
// Just schedule a full repaint of our object.
- if (view && !usesCompositedScrolling())
+ if (view && requiresRepaint)
renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
// Schedule the scroll DOM event.
@@ -1797,12 +2257,14 @@ void RenderLayer::scrollTo(int x, int y)
renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), DocumentEventQueue::ScrollEventElementTarget);
InspectorInstrumentation::didScrollLayer(frame);
+ if (scrollsOverflow())
+ frame->loader()->client()->didChangeScrollOffset();
}
-static inline bool frameElementAndViewPermitScroll(HTMLFrameElement* frameElement, FrameView* frameView)
+static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
{
// If scrollbars aren't explicitly forbidden, permit scrolling.
- if (frameElement && frameElement->scrollingMode() != ScrollbarAlwaysOff)
+ if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
return true;
// If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
@@ -1836,21 +2298,17 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm
// This will prevent us from revealing text hidden by the slider in Safari RSS.
RenderBox* box = renderBox();
ASSERT(box);
- FloatPoint absPos = box->localToAbsolute();
- absPos.move(box->borderLeft(), box->borderTop());
+ LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
+ LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
+ LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
- LayoutRect layerBounds = LayoutRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight());
- LayoutRect exposeRect = LayoutRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
- LayoutRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
-
- int roundedAdjustedX = roundToInt(r.x() - absPos.x());
- int roundedAdjustedY = roundToInt(r.y() - absPos.y());
- IntSize clampedScrollOffset = clampScrollOffset(IntSize(roundedAdjustedX, roundedAdjustedY));
+ IntSize clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
if (clampedScrollOffset != scrollOffset()) {
IntSize oldScrollOffset = scrollOffset();
scrollToOffset(clampedScrollOffset);
IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
- newRect.move(-scrollOffsetDifference);
+ localExposeRect.move(-scrollOffsetDifference);
+ newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
}
} else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled()) {
if (frameView) {
@@ -1859,14 +2317,14 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm
ownerElement = renderer()->document()->ownerElement();
if (ownerElement && ownerElement->renderer()) {
- HTMLFrameElement* frameElement = 0;
+ HTMLFrameElementBase* frameElementBase = 0;
if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))
- frameElement = static_cast<HTMLFrameElement*>(ownerElement);
+ frameElementBase = toHTMLFrameElementBase(ownerElement);
- if (frameElementAndViewPermitScroll(frameElement, frameView)) {
+ if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
LayoutRect viewRect = frameView->visibleContentRect();
- LayoutRect exposeRect = getRectToExpose(viewRect, rect, alignX, alignY);
+ LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
int xOffset = roundToInt(exposeRect.x());
int yOffset = roundToInt(exposeRect.y());
@@ -1877,6 +2335,8 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm
frameView->setScrollPosition(IntPoint(xOffset, yOffset));
if (frameView->safeToPropagateScrollToParent()) {
parentLayer = ownerElement->renderer()->enclosingLayer();
+ // FIXME: This doesn't correctly convert the rect to
+ // absolute coordinates in the parent.
newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
} else
@@ -1884,7 +2344,11 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm
}
} else {
LayoutRect viewRect = frameView->visibleContentRect();
- LayoutRect r = getRectToExpose(viewRect, rect, alignX, alignY);
+ LayoutRect visibleRectRelativeToDocument = viewRect;
+ IntSize scrollOffsetRelativeToDocument = frameView->scrollOffsetRelativeToDocument();
+ visibleRectRelativeToDocument.setLocation(IntPoint(scrollOffsetRelativeToDocument.width(), scrollOffsetRelativeToDocument.height()));
+
+ LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
frameView->setScrollPosition(roundedIntPoint(r.location()));
@@ -1895,7 +2359,7 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm
// The canAutoscroll function in EventHandler also knows about this.
if (Frame* frame = frameView->frame()) {
if (Page* page = frame->page())
- page->chrome()->scrollRectIntoView(pixelSnappedIntRect(rect));
+ page->chrome().scrollRectIntoView(pixelSnappedIntRect(rect));
}
}
}
@@ -1912,21 +2376,19 @@ void RenderLayer::updateCompositingLayersAfterScroll()
{
#if USE(ACCELERATED_COMPOSITING)
if (compositor()->inCompositingMode()) {
- // Our stacking context is guaranteed to contain all of our descendants that may need
+ // Our stacking container is guaranteed to contain all of our descendants that may need
// repositioning, so update compositing layers from there.
- if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) {
- if (compositor()->compositingConsultsOverlap())
+ if (RenderLayer* compositingAncestor = stackingContainer()->enclosingCompositingLayer()) {
+ if (usesCompositedScrolling() && !hasOutOfFlowPositionedDescendant())
+ compositor()->updateCompositingLayers(CompositingUpdateOnCompositedScroll, compositingAncestor);
+ else
compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
- else {
- bool isUpdateRoot = true;
- compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot);
- }
}
}
#endif
}
-LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
// Determine the appropriate X behavior.
ScrollBehavior scrollX;
@@ -1966,7 +2428,7 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
// Determine the appropriate Y behavior.
ScrollBehavior scrollY;
LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
- LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height();
+ LayoutUnit intersectHeight = intersection(visibleRectRelativeToDocument, exposeRectY).height();
if (intersectHeight == exposeRect.height())
// If the rectangle is fully visible, use the specified visible behavior.
scrollY = ScrollAlignment::getVisibleBehavior(alignY);
@@ -1999,7 +2461,7 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
return LayoutRect(LayoutPoint(x, y), visibleRect.size());
}
-void RenderLayer::autoscroll()
+void RenderLayer::autoscroll(const IntPoint& position)
{
Frame* frame = renderer()->frame();
if (!frame)
@@ -2009,28 +2471,30 @@ void RenderLayer::autoscroll()
if (!frameView)
return;
-#if ENABLE(DRAG_SUPPORT)
- frame->eventHandler()->updateSelectionForMouseDrag();
-#endif
-
- IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
+ IntPoint currentDocumentPosition = frameView->windowToContents(position);
scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
}
+bool RenderLayer::canResize() const
+{
+ if (!renderer())
+ return false;
+ // We need a special case for <iframe> because they never have
+ // hasOverflowClip(). However, they do "implicitly" clip their contents, so
+ // we want to allow resizing them also.
+ return (renderer()->hasOverflowClip() || renderer()->isRenderIFrame()) && renderer()->style()->resize() != RESIZE_NONE;
+}
+
void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
{
// FIXME: This should be possible on generated content but is not right now.
- if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node())
+ if (!inResizeMode() || !canResize() || !renderer()->node())
return;
ASSERT(renderer()->node()->isElementNode());
- Element* element = static_cast<Element*>(renderer()->node());
+ Element* element = toElement(renderer()->node());
RenderBox* renderer = toRenderBox(element->renderer());
- EResize resize = renderer->style()->resize();
- if (resize == RESIZE_NONE)
- return;
-
Document* document = element->document();
if (!document->frame()->eventHandler()->mousePressed())
return;
@@ -2053,10 +2517,11 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOff
LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
- ASSERT(element->isStyledElement());
+ ASSERT_WITH_SECURITY_IMPLICATION(element->isStyledElement());
StyledElement* styledElement = static_cast<StyledElement*>(element);
bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
+ EResize resize = renderer->style()->resize();
if (resize != RESIZE_VERTICAL && difference.width()) {
if (element->isFormControlElement()) {
// Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
@@ -2106,25 +2571,25 @@ int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
IntPoint RenderLayer::scrollPosition() const
{
- return scrollOrigin() + m_scrollOffset;
+ return IntPoint(m_scrollOffset);
}
IntPoint RenderLayer::minimumScrollPosition() const
{
- return scrollOrigin();
+ return -scrollOrigin();
}
IntPoint RenderLayer::maximumScrollPosition() const
{
// FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
- return scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRect(true).size();
+ return -scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRect(IncludeScrollbars).size();
}
-IntRect RenderLayer::visibleContentRect(bool includeScrollbars) const
+IntRect RenderLayer::visibleContentRect(VisibleContentRectIncludesScrollbars scrollbarInclusion) const
{
int verticalScrollbarWidth = 0;
int horizontalScrollbarHeight = 0;
- if (includeScrollbars) {
+ if (scrollbarInclusion == IncludeScrollbars) {
verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
}
@@ -2292,9 +2757,14 @@ bool RenderLayer::scrollbarsCanBeActive() const
return view->frameView()->scrollbarsCanBeActive();
}
-IntPoint RenderLayer::currentMousePosition() const
+IntPoint RenderLayer::lastKnownMousePosition() const
{
- return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : IntPoint();
+ return renderer()->frame() ? renderer()->frame()->eventHandler()->lastKnownMousePosition() : IntPoint();
+}
+
+bool RenderLayer::isHandlingWheelEvent() const
+{
+ return renderer()->frame() ? renderer()->frame()->eventHandler()->isHandlingWheelEvent() : false;
}
IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
@@ -2382,7 +2852,9 @@ void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& r
scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
else
scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
- renderer()->repaintRectangle(scrollRect);
+ LayoutRect repaintRect = scrollRect;
+ renderBox()->flipForWritingMode(repaintRect);
+ renderer()->repaintRectangle(repaintRect);
}
void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
@@ -2399,19 +2871,28 @@ void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
m_resizer->repaintRectangle(rect);
}
+static inline RenderObject* rendererForScrollbar(RenderObject* renderer)
+{
+ if (Node* node = renderer->node()) {
+ if (ShadowRoot* shadowRoot = node->containingShadowRoot()) {
+ if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
+ return shadowRoot->host()->renderer();
+ }
+ }
+
+ return renderer;
+}
+
PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
{
RefPtr<Scrollbar> widget;
- RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
+ RenderObject* actualRenderer = rendererForScrollbar(renderer());
bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
if (hasCustomScrollbarStyle)
widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node());
else {
widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
- if (orientation == HorizontalScrollbar)
- didAddHorizontalScrollbar(widget.get());
- else
- didAddVerticalScrollbar(widget.get());
+ didAddScrollbar(widget.get(), orientation);
}
renderer()->document()->view()->addChild(widget.get());
return widget.release();
@@ -2423,12 +2904,8 @@ void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
if (!scrollbar)
return;
- if (!scrollbar->isCustomScrollbar()) {
- if (orientation == HorizontalScrollbar)
- willRemoveHorizontalScrollbar(scrollbar.get());
- else
- willRemoveVerticalScrollbar(scrollbar.get());
- }
+ if (!scrollbar->isCustomScrollbar())
+ willRemoveScrollbar(scrollbar.get(), orientation);
scrollbar->removeFromParent();
scrollbar->disconnectFromScrollableArea();
@@ -2443,11 +2920,6 @@ bool RenderLayer::scrollsOverflow() const
return toRenderBox(renderer())->scrollsOverflow();
}
-bool RenderLayer::allowsScrolling() const
-{
- return (m_hBar && m_hBar->enabled()) || (m_vBar && m_vBar->enabled());
-}
-
void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
{
if (hasScrollbar == hasHorizontalScrollbar())
@@ -2506,14 +2978,14 @@ ScrollableArea* RenderLayer::enclosingScrollableArea() const
int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
{
- if (!m_vBar || (m_vBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
+ if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
return 0;
return m_vBar->width();
}
int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
{
- if (!m_hBar || (m_hBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
+ if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
return 0;
return m_hBar->height();
}
@@ -2525,7 +2997,7 @@ IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
IntSize elementSize = size();
if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
elementSize.setWidth(0);
- IntPoint resizerPoint = toPoint(elementSize);
+ IntPoint resizerPoint = IntPoint(elementSize);
IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
return localPoint - resizerPoint;
}
@@ -2537,7 +3009,7 @@ bool RenderLayer::hasOverflowControls() const
void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
{
- if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
+ if (!m_hBar && !m_vBar && !canResize())
return;
RenderBox* box = renderBox();
@@ -2633,6 +3105,16 @@ void RenderLayer::computeScrollDimensions()
setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
}
+bool RenderLayer::hasScrollableHorizontalOverflow() const
+{
+ return hasHorizontalOverflow() && renderBox()->scrollsOverflowX();
+}
+
+bool RenderLayer::hasScrollableVerticalOverflow() const
+{
+ return hasVerticalOverflow() && renderBox()->scrollsOverflowY();
+}
+
bool RenderLayer::hasHorizontalOverflow() const
{
ASSERT(!m_scrollDimensionsDirty);
@@ -2715,7 +3197,7 @@ void RenderLayer::updateScrollbarsAfterLayout()
m_vBar->setProportion(clientHeight, m_scrollSize.height());
}
- updateScrollableAreaSet((hasHorizontalOverflow || hasVerticalOverflow) && scrollsOverflow() && allowsScrolling());
+ updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
}
void RenderLayer::updateScrollInfoAfterLayout()
@@ -2740,7 +3222,7 @@ void RenderLayer::updateScrollInfoAfterLayout()
updateScrollbarsAfterLayout();
if (originalScrollOffset != scrollOffset())
- scrollToOffsetWithoutAnimation(toPoint(scrollOffset()));
+ scrollToOffsetWithoutAnimation(IntPoint(scrollOffset()));
#if USE(ACCELERATED_COMPOSITING)
// Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
@@ -2816,7 +3298,7 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint
// Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
// widgets can move without layout occurring (most notably when you scroll a document that
// contains fixed positioned elements).
- positionOverflowControls(toSize(adjustedPaintOffset));
+ positionOverflowControls(toIntSize(adjustedPaintOffset));
// Now that we're sure the scrollbars are in the right place, paint them.
if (m_hBar
@@ -2941,7 +3423,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, const IntPoint& paintOf
bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
{
- if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
+ if (!canResize())
return false;
RenderBox* box = renderBox();
@@ -2952,10 +3434,10 @@ bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
IntRect localBounds(0, 0, box->pixelSnappedWidth(), box->pixelSnappedHeight());
return resizerCornerRect(this, localBounds).contains(localPoint);
}
-
+
bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
{
- if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
+ if (!m_hBar && !m_vBar && !canResize())
return false;
RenderBox* box = renderBox();
@@ -2970,6 +3452,8 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint&
int resizeControlSize = max(resizeControlRect.height(), 0);
+ // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
+
if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
LayoutRect vBarRect(verticalScrollbarStart(0, box->width()),
box->borderTop(),
@@ -3001,11 +3485,11 @@ bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularit
return ScrollableArea::scroll(direction, granularity, multiplier);
}
-void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, PaintLayerFlags paintFlags)
+void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot, RenderRegion* region, PaintLayerFlags paintFlags)
{
OverlapTestRequestMap overlapTestRequests;
- LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, region, &overlapTestRequests);
+ LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), subtreePaintRoot, region, &overlapTestRequests);
paintLayer(context, paintingInfo, paintFlags);
OverlapTestRequestMap::iterator end = overlapTestRequests.end();
@@ -3013,18 +3497,17 @@ void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect,
it->key->setOverlapTestResult(false);
}
-void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot)
+void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot)
{
if (!m_containsDirtyOverlayScrollbars)
return;
- LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot);
+ LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), subtreePaintRoot);
paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars);
m_containsDirtyOverlayScrollbars = false;
}
-#ifndef DISABLE_ROUNDED_CORNER_CLIPPING
static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer)
{
if (startLayer == endLayer)
@@ -3038,20 +3521,18 @@ static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLaye
return false;
}
-#endif
void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect,
BorderRadiusClippingRule rule)
{
- if (clipRect.rect() == paintDirtyRect)
- return;
- context->save();
- context->clip(pixelSnappedIntRect(clipRect.rect()));
-
+ if (clipRect.rect() != paintDirtyRect) {
+ context->save();
+ context->clip(pixelSnappedIntRect(clipRect.rect()));
+ }
+
if (!clipRect.hasRadius())
return;
-#ifndef DISABLE_ROUNDED_CORNER_CLIPPING
// If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
// any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
// containing block chain so we check that also.
@@ -3059,13 +3540,12 @@ void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, c
if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) {
LayoutPoint delta;
layer->convertToLayerCoords(rootLayer, delta);
- context->addRoundedRectClip(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
+ context->clipRoundedRect(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
}
if (layer == rootLayer)
break;
}
-#endif
}
void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect)
@@ -3114,6 +3594,12 @@ static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
return false;
}
+#if USE(ACCELERATED_COMPOSITING)
+static bool paintForFixedRootBackground(const RenderLayer* layer, RenderLayer::PaintLayerFlags paintFlags)
+{
+ return layer->renderer()->isRoot() && (paintFlags & RenderLayer::PaintLayerPaintingRootBackgroundOnly);
+}
+#endif
void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
@@ -3125,10 +3611,15 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo&
paintFlags |= PaintLayerTemporaryClipRects;
else if (!backing()->paintsIntoWindow()
&& !backing()->paintsIntoCompositedAncestor()
- && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
+ && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)
+ && !paintForFixedRootBackground(this, paintFlags)) {
// If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
return;
}
+ } else if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) {
+ // Don't paint out-of-view viewport constrained layers (when doing prepainting) because they will never be visible
+ // unless their position or viewport size is changed.
+ return;
}
#endif
@@ -3162,6 +3653,11 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo&
beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
}
+ if (enclosingPaginationLayer()) {
+ paintTransformedLayerIntoFragments(context, paintingInfo, paintFlags);
+ return;
+ }
+
// Make sure the parent's clip rects have been calculated.
ClipRect clipRect = paintingInfo.paintDirtyRect;
if (parent()) {
@@ -3174,25 +3670,7 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo&
parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
}
- // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
- // This involves subtracting out the position of the layer in our current coordinate space, but preserving
- // the accumulated error for sub-pixel layout.
- LayoutPoint delta;
- convertToLayerCoords(paintingInfo.rootLayer, delta);
- TransformationMatrix transform(layerTransform);
- IntPoint roundedDelta = roundedIntPoint(delta);
- transform.translateRight(roundedDelta.x(), roundedDelta.y());
- LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
-
- // Apply the transform.
- {
- GraphicsContextStateSaver stateSaver(*context);
- context->concatCTM(transform.toAffineTransform());
-
- // Now do a paint with the root layer shifted to be us.
- LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior, adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.region, paintingInfo.overlapTestRequests);
- paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
- }
+ paintLayerByApplyingTransform(context, paintingInfo, paintFlags);
// Restore the clip.
if (parent())
@@ -3222,31 +3700,11 @@ void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, cons
paintLayerContents(context, paintingInfo, localPaintFlags);
}
-void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+bool RenderLayer::setupFontSubpixelQuantization(GraphicsContext* context, bool& didQuantizeFonts)
{
- ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
-
- PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
- bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency;
- bool isSelfPaintingLayer = this->isSelfPaintingLayer();
- bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
- // Outline always needs to be painted even if we have no visible content.
- bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars;
- bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
-
- bool useClipRect = true;
- GraphicsContext* transparencyLayerContext = context;
-
- // Ensure our lists are up-to-date.
- updateLayerListsIfNeeded();
-
- LayoutPoint offsetFromRoot;
- convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
-
- IntRect rootRelativeBounds;
- bool rootRelativeBoundsComputed = false;
+ if (context->paintingDisabled())
+ return false;
- bool didQuantizeFonts = true;
bool scrollingOnMainThread = true;
Frame* frame = renderer()->frame();
#if ENABLE(THREADED_SCROLLING)
@@ -3260,180 +3718,232 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
// FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those
// things on the scrolling thread.
- bool needToAdjustSubpixelQuantization = scrollingOnMainThread || (renderer()->hasOverflowClip() && !usesCompositedScrolling()) || (frame && frame->ownerElement());
- if (needToAdjustSubpixelQuantization) {
+ bool contentsScrollByPainting = (renderer()->hasOverflowClip() && !usesCompositedScrolling()) || (frame && frame->ownerElement());
+ if (scrollingOnMainThread || contentsScrollByPainting) {
didQuantizeFonts = context->shouldSubpixelQuantizeFonts();
context->setShouldSubpixelQuantizeFonts(false);
+ return true;
}
+ return false;
+}
+
+bool RenderLayer::setupClipPath(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, const LayoutPoint& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
+{
+ if (!renderer()->hasClipPath() || context->paintingDisabled())
+ return false;
- // Apply clip-path to context.
- bool hasClipPath = false;
RenderStyle* style = renderer()->style();
- if (renderer()->hasClipPath() && !context->paintingDisabled() && style) {
- ASSERT(style->clipPath());
- if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) {
- hasClipPath = true;
- context->save();
- ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath());
+ ASSERT(style->clipPath());
+ if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) {
+ ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath());
+
+ if (!rootRelativeBoundsComputed) {
+ rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
+ rootRelativeBoundsComputed = true;
+ }
+
+ context->save();
+ context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
+ return true;
+ }
+
+#if ENABLE(SVG)
+ if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) {
+ ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath());
+ Document* document = renderer()->document();
+ Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0;
+ if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
if (!rootRelativeBoundsComputed) {
rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
rootRelativeBoundsComputed = true;
}
- context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
- }
-#if ENABLE(SVG)
- else if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) {
- ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath());
- Document* document = renderer()->document();
- // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
- Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0;
- if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
-
- static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context);
- }
+ // FIXME: This should use a safer cast such as toRenderSVGResourceContainer().
+ // FIXME: Should this do a context->save() and return true so we restore the context?
+ static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context);
}
-#endif
}
+#endif
+
+ return false;
+}
- LayerPaintingInfo localPaintingInfo(paintingInfo);
#if ENABLE(CSS_FILTERS)
- FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters());
- if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) {
- RenderLayerFilterInfo* filterInfo = this->filterInfo();
- ASSERT(filterInfo);
- LayoutRect filterRepaintRect = filterInfo->dirtySourceRect();
- filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y());
+PassOwnPtr<FilterEffectRendererHelper> RenderLayer::setupFilters(GraphicsContext* context, LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
+{
+ if (context->paintingDisabled())
+ return nullptr;
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
+ if (paintFlags & PaintLayerPaintingOverlayScrollbars)
+ return nullptr;
- if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) {
- // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero.
- filterInfo->resetDirtySourceRect();
-
- // Rewire the old context to a memory buffer, so that we can capture the contents of the layer.
- // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer
- // on the original context and avoid duplicating "beginFilterEffect" after each transpareny layer call. Also, note that
- // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method.
- context = filterPainter.beginFilterEffect(context);
-
- // Check that we didn't fail to allocate the graphics context for the offscreen buffer.
- if (filterPainter.hasStartedFilterEffect()) {
- localPaintingInfo.paintDirtyRect = filterPainter.repaintRect();
- // If the filter needs the full source image, we need to avoid using the clip rectangles.
- // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
- // Note that we will still apply the clipping on the final rendering of the filter.
- useClipRect = !filterRenderer()->hasFilterThatMovesPixels();
- }
- }
+ bool hasPaintedFilter = filterRenderer() && paintsWithFilters();
+ if (!hasPaintedFilter)
+ return nullptr;
+
+ OwnPtr<FilterEffectRendererHelper> filterPainter = adoptPtr(new FilterEffectRendererHelper(hasPaintedFilter));
+ if (!filterPainter->haveFilterEffect())
+ return nullptr;
+
+ RenderLayerFilterInfo* filterInfo = this->filterInfo();
+ ASSERT(filterInfo);
+ LayoutRect filterRepaintRect = filterInfo->dirtySourceRect();
+ filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y());
+
+ if (!rootRelativeBoundsComputed) {
+ rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
+ rootRelativeBoundsComputed = true;
+ }
+
+ if (filterPainter->prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) {
+ // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero.
+ filterInfo->resetDirtySourceRect();
+
+ if (!filterPainter->beginFilterEffect())
+ return nullptr;
+
+ // Check that we didn't fail to allocate the graphics context for the offscreen buffer.
+ ASSERT(filterPainter->hasStartedFilterEffect());
+
+ paintingInfo.paintDirtyRect = filterPainter->repaintRect();
+ // If the filter needs the full source image, we need to avoid using the clip rectangles.
+ // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
+ // Note that we will still apply the clipping on the final rendering of the filter.
+ paintingInfo.clipToDirtyRect = !filterRenderer()->hasFilterThatMovesPixels();
+ return filterPainter.release();
}
+ return nullptr;
+}
+
+GraphicsContext* RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext* originalContext, LayerPaintingInfo& paintingInfo, LayerFragments& layerFragments)
+{
+ ASSERT(filterPainter->hasStartedFilterEffect());
+ // Apply the correct clipping (ie. overflow: hidden).
+ // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
+ ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
+ clipToRect(paintingInfo.rootLayer, originalContext, paintingInfo.paintDirtyRect, backgroundRect);
+ filterPainter->applyFilterEffect(originalContext);
+ restoreClip(originalContext, paintingInfo.paintDirtyRect, backgroundRect);
+ return originalContext;
+}
#endif
- // Calculate the clip rects we should use only when we need them.
- LayoutRect layerBounds;
- ClipRect damageRect, clipRectToApply, outlineRect;
- LayoutPoint paintOffset;
+void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+{
+ ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
- if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
- ClipRectsContext clipRectsContext(localPaintingInfo.rootLayer, localPaintingInfo.region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, localPaintFlags & PaintLayerPaintingOverflowContents ? IgnoreOverflowClip : RespectOverflowClip);
- calculateRects(clipRectsContext, localPaintingInfo.paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, &offsetFromRoot);
- paintOffset = toPoint(layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation);
- if (this == localPaintingInfo.rootLayer)
- paintOffset = roundedIntPoint(paintOffset);
+ PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
+ bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency;
+ bool isSelfPaintingLayer = this->isSelfPaintingLayer();
+ bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
+ bool isPaintingScrollingContent = paintFlags & PaintLayerPaintingCompositingScrollingPhase;
+ bool isPaintingCompositedForeground = paintFlags & PaintLayerPaintingCompositingForegroundPhase;
+ bool isPaintingCompositedBackground = paintFlags & PaintLayerPaintingCompositingBackgroundPhase;
+ bool isPaintingOverflowContents = paintFlags & PaintLayerPaintingOverflowContents;
+ // Outline always needs to be painted even if we have no visible content. Also,
+ // the outline is painted in the background phase during composited scrolling.
+ // If it were painted in the foreground phase, it would move with the scrolled
+ // content. When not composited scrolling, the outline is painted in the
+ // foreground phase. Since scrolled contents are moved by repainting in this
+ // case, the outline won't get 'dragged along'.
+ bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars
+ && ((isPaintingScrollingContent && isPaintingCompositedBackground)
+ || (!isPaintingScrollingContent && isPaintingCompositedForeground));
+ bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
+
+ if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isRoot())
+ return;
+
+ // Ensure our lists are up-to-date.
+ updateLayerListsIfNeeded();
+
+ LayoutPoint offsetFromRoot;
+ convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
+
+ LayoutRect rootRelativeBounds;
+ bool rootRelativeBoundsComputed = false;
+
+ // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those
+ // things on the scrolling thread.
+ bool didQuantizeFonts = true;
+ bool needToAdjustSubpixelQuantization = setupFontSubpixelQuantization(context, didQuantizeFonts);
+
+ // Apply clip-path to context.
+ bool hasClipPath = setupClipPath(context, paintingInfo, offsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
+
+ LayerPaintingInfo localPaintingInfo(paintingInfo);
+
+ GraphicsContext* transparencyLayerContext = context;
+#if ENABLE(CSS_FILTERS)
+ OwnPtr<FilterEffectRendererHelper> filterPainter = setupFilters(context, localPaintingInfo, paintFlags, offsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
+ if (filterPainter) {
+ context = filterPainter->filterContext();
+ if (context != transparencyLayerContext && haveTransparency) {
+ // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context.
+ beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
+ }
}
+#endif
- bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText;
- bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
-
- // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
- // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
- // Else, our renderer tree may or may not contain the painting root, so we pass that root along
+ // If this layer's renderer is a child of the subtreePaintRoot, we render unconditionally, which
+ // is done by passing a nil subtreePaintRoot down to our renderer (as if no subtreePaintRoot was ever set).
+ // Otherwise, our renderer tree may or may not contain the subtreePaintRoot root, so we pass that root along
// so it will be tested against as we descend through the renderers.
- RenderObject* paintingRootForRenderer = 0;
- if (localPaintingInfo.paintingRoot && !renderer()->isDescendantOf(localPaintingInfo.paintingRoot))
- paintingRootForRenderer = localPaintingInfo.paintingRoot;
+ RenderObject* subtreePaintRootForRenderer = 0;
+ if (localPaintingInfo.subtreePaintRoot && !renderer()->isDescendantOf(localPaintingInfo.subtreePaintRoot))
+ subtreePaintRootForRenderer = localPaintingInfo.subtreePaintRoot;
if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer)
performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this);
- // We want to paint our layer, but only if we intersect the damage rect.
- if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents))
- shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), localPaintingInfo.rootLayer, &offsetFromRoot);
+ bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText;
+ bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
- if (localPaintFlags & PaintLayerPaintingCompositingBackgroundPhase) {
- if (shouldPaintContent && !selectionOnly) {
- // Begin transparency layers lazily now that we know we have to paint something.
- if (haveTransparency)
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
-
- if (useClipRect) {
- // Paint our background first, before painting any child layers.
- // Establish the clip used to paint our background.
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
- }
-
- // Paint the background.
- PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, localPaintingInfo.region, 0);
- renderer()->paint(paintInfo, paintOffset);
+ PaintBehavior paintBehavior = PaintBehaviorNormal;
+ if (localPaintFlags & PaintLayerPaintingSkipRootBackground)
+ paintBehavior |= PaintBehaviorSkipRootBackground;
+ else if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly)
+ paintBehavior |= PaintBehaviorRootBackgroundOnly;
- if (useClipRect) {
- // Restore the clip.
- restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect);
- }
+ LayerFragments layerFragments;
+ if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
+ // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
+ // fragment should paint. If the parent's filter dictates full repaint to ensure proper filter effect,
+ // use the overflow clip as dirty rect, instead of no clipping. It maintains proper clipping for overflow::scroll.
+ LayoutRect paintDirtyRect = localPaintingInfo.paintDirtyRect;
+ if (!paintingInfo.clipToDirtyRect && renderer()->hasOverflowClip()) {
+ // We can turn clipping back by requesting full repaint for the overflow area.
+ localPaintingInfo.clipToDirtyRect = true;
+ paintDirtyRect = selfClipRect();
}
+ collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.region, paintDirtyRect,
+ (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetFromRoot);
+ updatePaintingInfoForFragments(layerFragments, localPaintingInfo, localPaintFlags, shouldPaintContent, &offsetFromRoot);
+ }
+
+ if (isPaintingCompositedBackground) {
+ // Paint only the backgrounds for all of the fragments of the layer.
+ if (shouldPaintContent && !selectionOnly)
+ paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
+ localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
+ }
- // Now walk the sorted list of children with negative z-indices.
+ // Now walk the sorted list of children with negative z-indices.
+ if ((isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground))
paintList(negZOrderList(), context, localPaintingInfo, localPaintFlags);
- }
- if (localPaintFlags & PaintLayerPaintingCompositingForegroundPhase) {
- // Now establish the appropriate clip and paint our child RenderObjects.
- if (shouldPaintContent && !clipRectToApply.isEmpty()) {
- // Begin transparency layers lazily now that we know we have to paint something.
- if (haveTransparency)
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
-
- if (useClipRect) {
- // Set up the clip used when painting our children.
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, clipRectToApply);
- }
-
- PaintInfo paintInfo(context, pixelSnappedIntRect(clipRectToApply.rect()),
- selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
- forceBlackText, paintingRootForRenderer, localPaintingInfo.region, 0);
- renderer()->paint(paintInfo, paintOffset);
- if (!selectionOnly) {
- paintInfo.phase = PaintPhaseFloat;
- renderer()->paint(paintInfo, paintOffset);
- paintInfo.phase = PaintPhaseForeground;
- paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
- renderer()->paint(paintInfo, paintOffset);
- paintInfo.phase = PaintPhaseChildOutlines;
- renderer()->paint(paintInfo, paintOffset);
- }
+ if (isPaintingCompositedForeground) {
+ if (shouldPaintContent)
+ paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
+ localPaintingInfo, paintBehavior, subtreePaintRootForRenderer, selectionOnly, forceBlackText);
+ }
- if (useClipRect) {
- // Now restore our clip.
- restoreClip(context, localPaintingInfo.paintDirtyRect, clipRectToApply);
- }
- }
+ if (shouldPaintOutline)
+ paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
- if (shouldPaintOutline && !outlineRect.isEmpty()) {
- // Paint our own outline
- PaintInfo paintInfo(context, pixelSnappedIntRect(outlineRect.rect()), PaintPhaseSelfOutline, false, paintingRootForRenderer, localPaintingInfo.region, 0);
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, outlineRect, DoNotIncludeSelfForBorderRadius);
- renderer()->paint(paintInfo, paintOffset);
- restoreClip(context, localPaintingInfo.paintDirtyRect, outlineRect);
- }
-
+ if (isPaintingCompositedForeground) {
// Paint any child layers that have overflow.
paintList(m_normalFlowList.get(), context, localPaintingInfo, localPaintFlags);
@@ -3441,36 +3951,22 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
paintList(posZOrderList(), context, localPaintingInfo, localPaintFlags);
}
- if (isPaintingOverlayScrollbars) {
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect);
- paintOverflowControls(context, roundedIntPoint(paintOffset), pixelSnappedIntRect(damageRect.rect()), true);
- restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect);
- }
+ if (isPaintingOverlayScrollbars)
+ paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo);
#if ENABLE(CSS_FILTERS)
- if (filterPainter.hasStartedFilterEffect()) {
- // Apply the correct clipping (ie. overflow: hidden).
- clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, damageRect);
- context = filterPainter.applyFilterEffect();
- restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, damageRect);
+ if (filterPainter) {
+ context = applyFilters(filterPainter.get(), transparencyLayerContext, localPaintingInfo, layerFragments);
+ filterPainter.clear();
}
#endif
-
+
// Make sure that we now use the original transparency context.
ASSERT(transparencyLayerContext == context);
if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly) {
- if (useClipRect)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
-
- // Paint the mask.
- PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseMask, false, paintingRootForRenderer, localPaintingInfo.region, 0);
- renderer()->paint(paintInfo, paintOffset);
-
- if (useClipRect) {
- // Restore the clip.
- restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect);
- }
+ // Paint the mask for the fragments.
+ paintMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
}
// End our transparency layer
@@ -3488,6 +3984,28 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
context->restore();
}
+void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset)
+{
+ // This involves subtracting out the position of the layer in our current coordinate space, but preserving
+ // the accumulated error for sub-pixel layout.
+ LayoutPoint delta;
+ convertToLayerCoords(paintingInfo.rootLayer, delta);
+ delta.moveBy(translationOffset);
+ TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
+ IntPoint roundedDelta = roundedIntPoint(delta);
+ transform.translateRight(roundedDelta.x(), roundedDelta.y());
+ LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
+
+ // Apply the transform.
+ GraphicsContextStateSaver stateSaver(*context);
+ context->concatCTM(transform.toAffineTransform());
+
+ // Now do a paint with the root layer shifted to be us.
+ LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior,
+ adjustedSubPixelAccumulation, paintingInfo.subtreePaintRoot, paintingInfo.region, paintingInfo.overlapTestRequests);
+ paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
+}
+
void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
if (!list)
@@ -3502,6 +4020,8 @@ void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context
for (size_t i = 0; i < list->size(); ++i) {
RenderLayer* childLayer = list->at(i);
+ if (childLayer->isOutOfFlowRenderFlowThread())
+ continue;
if (!childLayer->isPaginated())
childLayer->paintLayer(context, paintingInfo, paintFlags);
else
@@ -3509,11 +4029,267 @@ void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context
}
}
+void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect,
+ ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
+ const LayoutRect* layerBoundingBox)
+{
+ if (!enclosingPaginationLayer() || hasTransform()) {
+ // For unpaginated layers, there is only one fragment.
+ LayerFragment fragment;
+ ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
+ fragments.append(fragment);
+ return;
+ }
+
+ // Compute our offset within the enclosing pagination layer.
+ LayoutPoint offsetWithinPaginatedLayer;
+ convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer);
+
+ // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
+ // layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that.
+ ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ LayoutRect layerBoundsInFlowThread;
+ ClipRect backgroundRectInFlowThread;
+ ClipRect foregroundRectInFlowThread;
+ ClipRect outlineRectInFlowThread;
+ calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
+ outlineRectInFlowThread, &offsetWithinPaginatedLayer);
+
+ // Take our bounding box within the flow thread and clip it.
+ LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer);
+ layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
+
+ // Shift the dirty rect into flow thread coordinates.
+ LayoutPoint offsetOfPaginationLayerFromRoot;
+ enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
+ LayoutRect dirtyRectInFlowThread(dirtyRect);
+ dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot);
+
+ // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
+ // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
+ RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
+ enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread);
+
+ if (fragments.isEmpty())
+ return;
+
+ // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents.
+ ClipRect ancestorClipRect = dirtyRect;
+ if (enclosingPaginationLayer()->parent()) {
+ ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ ancestorClipRect = enclosingPaginationLayer()->backgroundClipRect(clipRectsContext);
+ ancestorClipRect.intersect(dirtyRect);
+ }
+
+ for (size_t i = 0; i < fragments.size(); ++i) {
+ LayerFragment& fragment = fragments.at(i);
+
+ // Set our four rects with all clipping applied that was internal to the flow thread.
+ fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread);
+
+ // Shift to the root-relative physical position used when painting the flow thread in this fragment.
+ fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
+
+ // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
+ // properly clipped by the overflow.
+ fragment.intersect(ancestorClipRect.rect());
+
+ // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
+ // clip, so the column clip ends up being all we apply.
+ fragment.intersect(fragment.paginationClip);
+ }
+}
+
+void RenderLayer::updatePaintingInfoForFragments(LayerFragments& fragments, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags localPaintFlags,
+ bool shouldPaintContent, const LayoutPoint* offsetFromRoot)
+{
+ ASSERT(offsetFromRoot);
+ for (size_t i = 0; i < fragments.size(); ++i) {
+ LayerFragment& fragment = fragments.at(i);
+ fragment.shouldPaintContent = shouldPaintContent;
+ if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) {
+ LayoutPoint newOffsetFromRoot = *offsetFromRoot + fragment.paginationOffset;
+ fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot);
+ }
+ }
+}
+
+void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+{
+ LayerFragments enclosingPaginationFragments;
+ LayoutPoint offsetOfPaginationLayerFromRoot;
+ LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior);
+ enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.region, paintingInfo.paintDirtyRect,
+ (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
+
+ for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) {
+ const LayerFragment& fragment = enclosingPaginationFragments.at(i);
+
+ // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
+ // the enclosing pagination layer.
+ LayoutRect clipRect = fragment.backgroundRect.rect();
+
+ // Now compute the clips within a given fragment
+ if (parent() != enclosingPaginationLayer()) {
+ enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot);
+
+ ClipRectsContext clipRectsContext(enclosingPaginationLayer(), paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
+ IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
+ LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
+ parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
+ clipRect.intersect(parentClipRect);
+ }
+
+ parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
+ paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset);
+ parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
+ }
+}
+
+void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
+ const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
+ RenderObject* subtreePaintRootForRenderer)
+{
+ for (size_t i = 0; i < layerFragments.size(); ++i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if (!fragment.shouldPaintContent)
+ continue;
+
+ // Begin transparency layers lazily now that we know we have to paint something.
+ if (haveTransparency)
+ beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior);
+
+ if (localPaintingInfo.clipToDirtyRect) {
+ // Paint our background first, before painting any child layers.
+ // Establish the clip used to paint our background.
+ clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
+ }
+
+ // Paint the background.
+ // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
+ renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+
+ if (localPaintingInfo.clipToDirtyRect)
+ restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ }
+}
+
+void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
+ const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
+ RenderObject* subtreePaintRootForRenderer, bool selectionOnly, bool forceBlackText)
+{
+ // Begin transparency if we have something to paint.
+ if (haveTransparency) {
+ for (size_t i = 0; i < layerFragments.size(); ++i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) {
+ beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior);
+ break;
+ }
+ }
+ }
+
+ PaintBehavior localPaintBehavior = forceBlackText ? (PaintBehavior)PaintBehaviorForceBlackText : paintBehavior;
+
+ // Optimize clipping for the single fragment case.
+ bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
+ if (shouldClip)
+ clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect);
+
+ // We have to loop through every fragment multiple times, since we have to repaint in each specific phase in order for
+ // interleaving of the fragments to work properly.
+ paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, layerFragments,
+ context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
+
+ if (!selectionOnly) {
+ paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
+ paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
+ paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
+ }
+
+ if (shouldClip)
+ restoreClip(context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect);
+}
+
+void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context,
+ const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* subtreePaintRootForRenderer)
+{
+ bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1;
+
+ for (size_t i = 0; i < layerFragments.size(); ++i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if (!fragment.shouldPaintContent || fragment.foregroundRect.isEmpty())
+ continue;
+
+ if (shouldClip)
+ clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
+
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
+ if (phase == PaintPhaseForeground)
+ paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
+ renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+
+ if (shouldClip)
+ restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
+ }
+}
+
+void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
+ PaintBehavior paintBehavior, RenderObject* subtreePaintRootForRenderer)
+{
+ for (size_t i = 0; i < layerFragments.size(); ++i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if (fragment.outlineRect.isEmpty())
+ continue;
+
+ // Paint our own outline
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
+ clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.outlineRect, DoNotIncludeSelfForBorderRadius);
+ renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect);
+ }
+}
+
+void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
+ RenderObject* subtreePaintRootForRenderer)
+{
+ for (size_t i = 0; i < layerFragments.size(); ++i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if (!fragment.shouldPaintContent)
+ continue;
+
+ if (localPaintingInfo.clipToDirtyRect)
+ clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
+
+ // Paint the mask.
+ // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
+ renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+
+ if (localPaintingInfo.clipToDirtyRect)
+ restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ }
+}
+
+void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo)
+{
+ for (size_t i = 0; i < layerFragments.size(); ++i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)),
+ pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
+ restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ }
+}
+
void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
// We need to do multiple passes, breaking up our child layer into strips.
Vector<RenderLayer*> columnLayers;
- RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
+ RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContainer();
for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
columnLayers.append(curr);
@@ -3548,30 +4324,19 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsCo
ColumnInfo* colInfo = columnBlock->columnInfo();
unsigned colCount = columnBlock->columnCount(colInfo);
- LayoutUnit currLogicalTopOffset = 0;
+ LayoutUnit currLogicalTopOffset = columnBlock->initialBlockOffsetForPainting();
+ LayoutUnit blockDelta = columnBlock->blockDeltaForPaintingNextColumn();
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
columnBlock->flipForWritingMode(colRect);
- LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
- LayoutSize offset;
- if (isHorizontal) {
- if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
- offset = LayoutSize(logicalLeftOffset, currLogicalTopOffset);
- else
- offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
- } else {
- if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
- offset = LayoutSize(currLogicalTopOffset, logicalLeftOffset);
- else
- offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
- }
+ LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
+ LayoutSize offset = isHorizontal ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
colRect.moveBy(layerOffset);
-
+
LayoutRect localDirtyRect(paintingInfo.paintDirtyRect);
localDirtyRect.intersect(colRect);
-
if (!localDirtyRect.isEmpty()) {
GraphicsContextStateSaver stateSaver(*context);
@@ -3618,11 +4383,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsCo
}
// Move to the next position.
- LayoutUnit blockDelta = isHorizontal ? colRect.height() : colRect.width();
- if (columnBlock->style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset += blockDelta;
- else
- currLogicalTopOffset -= blockDelta;
+ currLogicalTopOffset += blockDelta;
}
}
@@ -3646,7 +4407,7 @@ bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation&
renderer()->document()->updateLayout();
- LayoutRect hitTestArea = renderer()->isRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect();
+ LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect();
if (!request.ignoreClipping())
hitTestArea.intersect(frameVisibleRect(renderer()));
@@ -3655,7 +4416,7 @@ bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation&
// We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
// return ourselves. We do this so mouse events continue getting delivered after a drag has
// exited the WebView, and so hit testing over a scrollbar hits the content document.
- if ((request.active() || request.release()) && isRootLayer()) {
+ if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) {
renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
insideLayer = this;
}
@@ -3664,7 +4425,7 @@ bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation&
// Now determine if the result is inside an anchor - if the urlElement isn't already set.
Node* node = result.innerNode();
if (node && !result.URLElement())
- result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
+ result.setURLElement(toElement(node->enclosingLinkEventParentOrSelf()));
// Now return whether we were inside this layer (this will always be true for the root
// layer).
@@ -3717,7 +4478,8 @@ static double computeZOffset(const HitTestingTransformState& transformState)
PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
- const HitTestingTransformState* containerTransformState) const
+ const HitTestingTransformState* containerTransformState,
+ const LayoutPoint& translationOffset) const
{
RefPtr<HitTestingTransformState> transformState;
LayoutPoint offset;
@@ -3731,7 +4493,8 @@ PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(Rend
transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
convertToLayerCoords(rootLayer, offset);
}
-
+ offset.moveBy(translationOffset);
+
RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
TransformationMatrix containerTransform;
@@ -3788,6 +4551,9 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
// Apply a transform if we have one.
if (transform() && !appliedTransform) {
+ if (enclosingPaginationLayer())
+ return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
+
// Make sure the parent's clip rects have been calculated.
if (parent()) {
ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
@@ -3797,30 +4563,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
return 0;
}
- // Create a transform state to accumulate this transform.
- RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
-
- // If the transform can't be inverted, then don't hit test this layer at all.
- if (!newTransformState->m_accumulatedTransform.isInvertible())
- return 0;
-
- // Compute the point and the hit test rect in the coords of this layer by using the values
- // from the transformState, which store the point and quad in the coords of the last flattened
- // layer, and the accumulated transform which lets up map through preserve-3d layers.
- //
- // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
- // by our container.
- FloatPoint localPoint = newTransformState->mappedPoint();
- FloatQuad localPointQuad = newTransformState->mappedQuad();
- LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
- HitTestLocation newHitTestLocation;
- if (hitTestLocation.isRectBasedTest())
- newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
- else
- newHitTestLocation = HitTestLocation(localPoint);
-
- // Now do a hit test with the root layer shifted to be us.
- return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset);
+ return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
}
// Ensure our lists and 3d status are up-to-date.
@@ -3852,16 +4595,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
// This layer is flattening, so flatten the state passed to descendants.
localTransformState->flatten();
}
-
- // Calculate the clip rects we should use.
- LayoutRect layerBounds;
- ClipRect bgRect;
- ClipRect fgRect;
- ClipRect outlineRect;
- ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
- calculateRects(clipRectsContext, hitTestRect, layerBounds, bgRect, fgRect, outlineRect);
-
// The following are used for keeping track of the z-depth of the hit point of 3d-transformed
// descendants.
double localZOffset = -numeric_limits<double>::infinity();
@@ -3906,11 +4640,22 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
candidateLayer = hitLayer;
}
- // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
- if (fgRect.intersects(hitTestLocation) && isSelfPaintingLayer()) {
+ // Collect the fragments. This will compute the clip rectangles for each layer fragment.
+ LayerFragments layerFragments;
+ collectFragments(layerFragments, rootLayer, hitTestLocation.region(), hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
+
+ if (canResize() && hitTestResizerInFragments(layerFragments, hitTestLocation)) {
+ renderer()->updateHitTestResult(result, hitTestLocation.point());
+ return this;
+ }
+
+ // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check
+ // every fragment in reverse order.
+ if (isSelfPaintingLayer()) {
// Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
HitTestResult tempResult(result.hitTestLocation());
- if (hitTestContents(request, tempResult, layerBounds, hitTestLocation, HitTestDescendants)
+ bool insideFragmentForegroundRect = false;
+ if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestDescendants, insideFragmentForegroundRect)
&& isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
if (result.isRectBasedTest())
result.append(tempResult);
@@ -3920,13 +4665,13 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
return this;
// Foreground can depth-sort with descendant layers, so keep this as a candidate.
candidateLayer = this;
- } else if (result.isRectBasedTest())
+ } else if (insideFragmentForegroundRect && result.isRectBasedTest())
result.append(tempResult);
}
// Now check our negative z-index children.
hitLayer = hitTestList(negZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation,
- localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
+ localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
return hitLayer;
@@ -3937,9 +4682,10 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
if (candidateLayer)
return candidateLayer;
- if (bgRect.intersects(hitTestLocation) && isSelfPaintingLayer()) {
+ if (isSelfPaintingLayer()) {
HitTestResult tempResult(result.hitTestLocation());
- if (hitTestContents(request, tempResult, layerBounds, hitTestLocation, HitTestSelf)
+ bool insideFragmentBackgroundRect = false;
+ if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestSelf, insideFragmentBackgroundRect)
&& isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
if (result.isRectBasedTest())
result.append(tempResult);
@@ -3947,20 +4693,119 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
result = tempResult;
return this;
}
- if (result.isRectBasedTest())
+ if (insideFragmentBackgroundRect && result.isRectBasedTest())
result.append(tempResult);
}
return 0;
}
+bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragments, const HitTestRequest& request, HitTestResult& result,
+ const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& insideClipRect) const
+{
+ if (layerFragments.isEmpty())
+ return false;
+
+ for (int i = layerFragments.size() - 1; i >= 0; --i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects(hitTestLocation))
+ || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.intersects(hitTestLocation)))
+ continue;
+ insideClipRect = true;
+ if (hitTestContents(request, result, fragment.layerBounds, hitTestLocation, hitTestFilter))
+ return true;
+ }
+
+ return false;
+}
+
+bool RenderLayer::hitTestResizerInFragments(const LayerFragments& layerFragments, const HitTestLocation& hitTestLocation) const
+{
+ if (layerFragments.isEmpty())
+ return false;
+
+ for (int i = layerFragments.size() - 1; i >= 0; --i) {
+ const LayerFragment& fragment = layerFragments.at(i);
+ if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(this, pixelSnappedIntRect(fragment.layerBounds)).contains(hitTestLocation.roundedPoint()))
+ return true;
+ }
+
+ return false;
+}
+
+RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
+ const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
+{
+ LayerFragments enclosingPaginationFragments;
+ LayoutPoint offsetOfPaginationLayerFromRoot;
+ LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox);
+ enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestLocation.region(), hitTestRect,
+ RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
+
+ for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
+ const LayerFragment& fragment = enclosingPaginationFragments.at(i);
+
+ // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
+ // the enclosing pagination layer.
+ LayoutRect clipRect = fragment.backgroundRect.rect();
+
+ // Now compute the clips within a given fragment
+ if (parent() != enclosingPaginationLayer()) {
+ enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
+
+ ClipRectsContext clipRectsContext(enclosingPaginationLayer(), hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
+ LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
+ parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
+ clipRect.intersect(parentClipRect);
+ }
+
+ if (!hitTestLocation.intersects(clipRect))
+ continue;
+
+ RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation,
+ transformState, zOffset, fragment.paginationOffset);
+ if (hitLayer)
+ return hitLayer;
+ }
+
+ return 0;
+}
+
+RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
+ const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
+ const LayoutPoint& translationOffset)
+{
+ // Create a transform state to accumulate this transform.
+ RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
+
+ // If the transform can't be inverted, then don't hit test this layer at all.
+ if (!newTransformState->m_accumulatedTransform.isInvertible())
+ return 0;
+
+ // Compute the point and the hit test rect in the coords of this layer by using the values
+ // from the transformState, which store the point and quad in the coords of the last flattened
+ // layer, and the accumulated transform which lets up map through preserve-3d layers.
+ //
+ // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
+ // by our container.
+ FloatPoint localPoint = newTransformState->mappedPoint();
+ FloatQuad localPointQuad = newTransformState->mappedQuad();
+ LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
+ HitTestLocation newHitTestLocation;
+ if (hitTestLocation.isRectBasedTest())
+ newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
+ else
+ newHitTestLocation = HitTestLocation(localPoint);
+
+ // Now do a hit test with the root layer shifted to be us.
+ return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset);
+}
+
bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const
{
ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
- if (!renderer()->hitTest(request, result, hitTestLocation,
- toLayoutPoint(layerBounds.location() - renderBoxLocation()),
- hitTestFilter)) {
+ if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - renderBoxLocation()), hitTestFilter)) {
// It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
// a rect-based test.
ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
@@ -3999,6 +4844,8 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r
RenderLayer* resultLayer = 0;
for (int i = list->size() - 1; i >= 0; --i) {
RenderLayer* childLayer = list->at(i);
+ if (childLayer->isOutOfFlowRenderFlowThread())
+ continue;
RenderLayer* hitLayer = 0;
HitTestResult tempResult(result.hitTestLocation());
if (childLayer->isPaginated())
@@ -4027,7 +4874,7 @@ RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, Re
const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
{
Vector<RenderLayer*> columnLayers;
- RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
+ RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContainer();
for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
columnLayers.append(curr);
@@ -4059,39 +4906,17 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
// We have to go backwards from the last column to the first.
bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent();
- LayoutUnit currLogicalTopOffset = 0;
- int i;
- for (i = 0; i < colCount; i++) {
- LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
- LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
- if (columnBlock->style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset += blockDelta;
- else
- currLogicalTopOffset -= blockDelta;
- }
- for (i = colCount - 1; i >= 0; i--) {
+ LayoutUnit currLogicalTopOffset = columnBlock->initialBlockOffsetForPainting();
+ LayoutUnit blockDelta = columnBlock->blockDeltaForPaintingNextColumn();
+ currLogicalTopOffset += colCount * blockDelta;
+ for (int i = colCount - 1; i >= 0; i--) {
// For each rect, we clip to the rect, and then we adjust our coords.
LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
columnBlock->flipForWritingMode(colRect);
LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
- LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
- if (columnBlock->style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset -= blockDelta;
- else
- currLogicalTopOffset += blockDelta;
+ currLogicalTopOffset -= blockDelta;
- LayoutSize offset;
- if (isHorizontal) {
- if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
- offset = LayoutSize(currLogicalLeftOffset, currLogicalTopOffset);
- else
- offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
- } else {
- if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
- offset = LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
- else
- offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
- }
+ LayoutSize offset = isHorizontal ? LayoutSize(currLogicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
colRect.moveBy(layerOffset);
@@ -4147,9 +4972,8 @@ void RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext)
{
ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
ASSERT(clipRectsType < NumCachedClipRectsTypes);
- if (m_clipRectsCache && m_clipRectsCache->m_clipRects[clipRectsType]) {
+ if (m_clipRectsCache && m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) {
ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
- ASSERT(m_clipRectsCache->m_respectingOverflowClip[clipRectsType] == (clipRectsContext.respectOverflowClip == RespectOverflowClip));
ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy);
#ifdef CHECK_CACHED_CLIP_RECTS
@@ -4158,7 +4982,7 @@ void RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext)
tempContext.clipRectsType = TemporaryClipRects;
ClipRects clipRects;
calculateClipRects(tempContext, clipRects);
- ASSERT(clipRects == *m_clipRectsCache->m_clipRects[clipRectsType].get());
+ ASSERT(clipRects == *m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip).get());
#endif
return; // We have the correct cached value.
}
@@ -4175,14 +4999,13 @@ void RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext)
if (!m_clipRectsCache)
m_clipRectsCache = adoptPtr(new ClipRectsCache);
- if (parentLayer && parentLayer->clipRects(clipRectsType) && clipRects == *parentLayer->clipRects(clipRectsType))
- m_clipRectsCache->m_clipRects[clipRectsType] = parentLayer->clipRects(clipRectsType);
+ if (parentLayer && parentLayer->clipRects(clipRectsContext) && clipRects == *parentLayer->clipRects(clipRectsContext))
+ m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentLayer->clipRects(clipRectsContext));
else
- m_clipRectsCache->m_clipRects[clipRectsType] = ClipRects::create(clipRects);
+ m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, ClipRects::create(clipRects));
#ifndef NDEBUG
m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer;
- m_clipRectsCache->m_respectingOverflowClip[clipRectsType] = clipRectsContext.respectOverflowClip == RespectOverflowClip;
m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy;
#endif
}
@@ -4204,8 +5027,8 @@ void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, C
// Ensure that our parent's clip has been calculated so that we can examine the values.
if (parentLayer) {
- if (useCached && parentLayer->clipRects(clipRectsType))
- clipRects = *parentLayer->clipRects(clipRectsType);
+ if (useCached && parentLayer->clipRects(clipRectsContext))
+ clipRects = *parentLayer->clipRects(clipRectsContext);
else {
ClipRectsContext parentContext(clipRectsContext);
parentContext.overlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize; // FIXME: why?
@@ -4241,7 +5064,7 @@ void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, C
}
if (renderer()->hasOverflowClip()) {
- ClipRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy);
+ ClipRect newOverflowClip = toRenderBox(renderer())->overflowClipRectForChildLayers(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy);
if (renderer()->style()->hasBorderRadius())
newOverflowClip.setHasRadius(true);
clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
@@ -4266,7 +5089,7 @@ void RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext, Clip
}
parent()->updateClipRects(clipRectsContext);
- clipRects = *parent()->clipRects(clipRectsContext.clipRectsType);
+ clipRects = *parent()->clipRects(clipRectsContext);
}
static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position)
@@ -4283,8 +5106,18 @@ static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRect
ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const
{
ASSERT(parent());
+
ClipRects parentRects;
- parentClipRects(clipRectsContext, parentRects);
+
+ // If we cross into a different pagination context, then we can't rely on the cache.
+ // Just switch over to using TemporaryClipRects.
+ if (clipRectsContext.clipRectsType != TemporaryClipRects && parent()->enclosingPaginationLayer() != enclosingPaginationLayer()) {
+ ClipRectsContext tempContext(clipRectsContext);
+ tempContext.clipRectsType = TemporaryClipRects;
+ parentClipRects(tempContext, parentRects);
+ } else
+ parentClipRects(clipRectsContext, parentRects);
+
ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position());
RenderView* view = renderer()->view();
ASSERT(view);
@@ -4364,7 +5197,7 @@ LayoutRect RenderLayer::childrenClipRect() const
ClipRectsContext clipRectsContext(clippingRootLayer, 0, TemporaryClipRects);
// Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>).
calculateRects(clipRectsContext, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect()), SnapOffsetForTransforms).enclosingBoundingBox();
+ return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox();
}
LayoutRect RenderLayer::selfClipRect() const
@@ -4377,7 +5210,7 @@ LayoutRect RenderLayer::selfClipRect() const
ClipRect backgroundRect, foregroundRect, outlineRect;
ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects);
calculateRects(clipRectsContext, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect()), SnapOffsetForTransforms).enclosingBoundingBox();
+ return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox();
}
LayoutRect RenderLayer::localClipRect() const
@@ -4452,10 +5285,10 @@ bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const Layo
// Otherwise we need to compute the bounding box of this single layer and see if it intersects
// the damage rect.
- return boundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
+ return boundingBox(rootLayer, 0, offsetFromRoot).intersects(damageRect);
}
-LayoutRect RenderLayer::localBoundingBox() const
+LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const
{
// There are three special cases we need to consider.
// (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
@@ -4483,7 +5316,7 @@ LayoutRect RenderLayer::localBoundingBox() const
} else {
RenderBox* box = renderBox();
ASSERT(box);
- if (box->hasMask()) {
+ if (!(flags & DontConstrainForMask) && box->hasMask()) {
result = box->maskClipRect();
box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not.
} else {
@@ -4503,14 +5336,33 @@ LayoutRect RenderLayer::localBoundingBox() const
return result;
}
-LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const
+LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags, const LayoutPoint* offsetFromRoot) const
{
- LayoutRect result = localBoundingBox();
+ LayoutRect result = localBoundingBox(flags);
if (renderer()->isBox())
renderBox()->flipForWritingMode(result);
else
renderer()->containingBlock()->flipForWritingMode(result);
+ if (enclosingPaginationLayer() && (flags & UseFragmentBoxes)) {
+ // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
+ // get our true bounding box.
+ LayoutPoint offsetWithinPaginationLayer;
+ convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginationLayer);
+ result.moveBy(offsetWithinPaginationLayer);
+
+ RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
+ result = enclosingFlowThread->fragmentsBoundingBox(result);
+
+ LayoutPoint delta;
+ if (offsetFromRoot)
+ delta = *offsetFromRoot;
+ else
+ enclosingPaginationLayer()->convertToLayerCoords(ancestorLayer, delta);
+ result.moveBy(delta);
+ return result;
+ }
+
LayoutPoint delta;
if (offsetFromRoot)
delta = *offsetFromRoot;
@@ -4526,14 +5378,14 @@ IntRect RenderLayer::absoluteBoundingBox() const
return pixelSnappedIntRect(boundingBox(root()));
}
-IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
+LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
{
if (!isSelfPaintingLayer())
- return IntRect();
+ return LayoutRect();
// FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
- return IntRect();
+ return LayoutRect();
RenderLayerModelObject* renderer = this->renderer();
@@ -4542,7 +5394,7 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
return renderer->view()->unscaledDocumentRect();
}
- LayoutRect boundingBoxRect = localBoundingBox();
+ LayoutRect boundingBoxRect = localBoundingBox(flags);
if (renderer->isBox())
toRenderBox(renderer)->flipForWritingMode(boundingBoxRect);
@@ -4573,23 +5425,23 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
LayoutPoint ancestorRelOffset;
convertToLayerCoords(ancestorLayer, ancestorRelOffset);
localClipRect.moveBy(ancestorRelOffset);
- return pixelSnappedIntRect(localClipRect);
+ return localClipRect;
}
}
// FIXME: should probably just pass 'flags' down to descendants.
- CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants);
+ CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants) | (flags & IncludeCompositedDescendants);
const_cast<RenderLayer*>(this)->updateLayerListsIfNeeded();
if (RenderLayer* reflection = reflectionLayer()) {
if (!reflection->isComposited()) {
- IntRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags);
+ LayoutRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags);
unionBounds.unite(childUnionBounds);
}
}
- ASSERT(isStackingContext() || (!posZOrderList() || !posZOrderList()->size()));
+ ASSERT(isStackingContainer() || (!posZOrderList() || !posZOrderList()->size()));
#if !ASSERT_DISABLED
LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this));
@@ -4599,8 +5451,8 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = negZOrderList->at(i);
- if (!curLayer->isComposited()) {
- IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
+ if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
+ LayoutRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
unionBounds.unite(childUnionBounds);
}
}
@@ -4610,8 +5462,8 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = posZOrderList->at(i);
- if (!curLayer->isComposited()) {
- IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
+ if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
+ LayoutRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
unionBounds.unite(childUnionBounds);
}
}
@@ -4621,8 +5473,11 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
size_t listSize = normalFlowList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = normalFlowList->at(i);
- if (!curLayer->isComposited()) {
- IntRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
+ // RenderView will always return the size of the document, before reaching this point,
+ // so there's no way we could hit a RenderNamedFlowThread here.
+ ASSERT(!curLayer->isOutOfFlowRenderFlowThread());
+ if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
+ LayoutRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
unionBounds.unite(curAbsBounds);
}
}
@@ -4632,15 +5487,8 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
// FIXME: We can optimize the size of the composited layers, by not enlarging
// filtered areas with the outsets if we know that the filter is going to render in hardware.
// https://bugs.webkit.org/show_bug.cgi?id=81239
- if ((flags & IncludeLayerFilterOutsets) && renderer->style()->hasFilterOutsets()) {
- int topOutset;
- int rightOutset;
- int bottomOutset;
- int leftOutset;
- renderer->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset);
- unionBounds.move(-leftOutset, -topOutset);
- unionBounds.expand(leftOutset + rightOutset, topOutset + bottomOutset);
- }
+ if (flags & IncludeLayerFilterOutsets)
+ renderer->style()->filterOutsets().expandRect(unionBounds);
#endif
if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal)) {
@@ -4656,7 +5504,7 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, cons
convertToLayerCoords(ancestorLayer, ancestorRelOffset);
unionBounds.moveBy(ancestorRelOffset);
- return pixelSnappedIntRect(unionBounds);
+ return unionBounds;
}
void RenderLayer::clearClipRectsIncludingDescendants(ClipRectsType typeToClear)
@@ -4677,7 +5525,9 @@ void RenderLayer::clearClipRects(ClipRectsType typeToClear)
m_clipRectsCache = nullptr;
else {
ASSERT(typeToClear < NumCachedClipRectsTypes);
- m_clipRectsCache->m_clipRects[typeToClear] = nullptr;
+ RefPtr<ClipRects> dummy;
+ m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, dummy);
+ m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, dummy);
}
}
@@ -4717,6 +5567,11 @@ bool RenderLayer::hasCompositedMask() const
return m_backing && m_backing->hasMaskLayer();
}
+GraphicsLayer* RenderLayer::layerForScrolling() const
+{
+ return m_backing ? m_backing->scrollingContentsLayer() : 0;
+}
+
GraphicsLayer* RenderLayer::layerForHorizontalScrollbar() const
{
return m_backing ? m_backing->layerForHorizontalScrollbar() : 0;
@@ -4743,6 +5598,73 @@ bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || paintsToWindow);
}
+bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
+{
+ if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
+ return false;
+
+ if (paintsWithTransparency(PaintBehaviorNormal))
+ return false;
+
+ // We can't use hasVisibleContent(), because that will be true if our renderer is hidden, but some child
+ // is visible and that child doesn't cover the entire rect.
+ if (renderer()->style()->visibility() != VISIBLE)
+ return false;
+
+#if ENABLE(CSS_FILTERS)
+ if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffectsOpacity())
+ return false;
+#endif
+
+ // FIXME: Handle simple transforms.
+ if (paintsWithTransform(PaintBehaviorNormal))
+ return false;
+
+ // FIXME: Remove this check.
+ // This function should not be called when layer-lists are dirty.
+ // It is somehow getting triggered during style update.
+ if (m_zOrderListsDirty || m_normalFlowListDirty)
+ return false;
+
+ // FIXME: We currently only check the immediate renderer,
+ // which will miss many cases.
+ if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect))
+ return true;
+
+ // We can't consult child layers if we clip, since they might cover
+ // parts of the rect that are clipped out.
+ if (renderer()->hasOverflowClip())
+ return false;
+
+ return listBackgroundIsKnownToBeOpaqueInRect(posZOrderList(), localRect)
+ || listBackgroundIsKnownToBeOpaqueInRect(negZOrderList(), localRect)
+ || listBackgroundIsKnownToBeOpaqueInRect(normalFlowList(), localRect);
+}
+
+bool RenderLayer::listBackgroundIsKnownToBeOpaqueInRect(const Vector<RenderLayer*>* list, const LayoutRect& localRect) const
+{
+ if (!list || list->isEmpty())
+ return false;
+
+ for (Vector<RenderLayer*>::const_reverse_iterator iter = list->rbegin(); iter != list->rend(); ++iter) {
+ const RenderLayer* childLayer = *iter;
+ if (childLayer->isComposited())
+ continue;
+
+ if (!childLayer->canUseConvertToLayerCoords())
+ continue;
+
+ LayoutPoint childOffset;
+ LayoutRect childLocalRect(localRect);
+ childLayer->convertToLayerCoords(this, childOffset);
+ childLocalRect.moveBy(-childOffset);
+
+ if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
+ return true;
+ }
+ return false;
+}
+
void RenderLayer::setParent(RenderLayer* parent)
{
if (parent == m_parent)
@@ -4770,7 +5692,7 @@ static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
void RenderLayer::dirtyZOrderLists()
{
ASSERT(m_layerListMutationAllowed);
- ASSERT(isStackingContext());
+ ASSERT(isStackingContainer());
if (m_posZOrderList)
m_posZOrderList->clear();
@@ -4779,14 +5701,17 @@ void RenderLayer::dirtyZOrderLists()
m_zOrderListsDirty = true;
#if USE(ACCELERATED_COMPOSITING)
- if (!renderer()->documentBeingDestroyed())
+ if (!renderer()->documentBeingDestroyed()) {
compositor()->setCompositingLayersNeedRebuild();
+ if (acceleratedCompositingForOverflowScrollEnabled())
+ compositor()->setShouldReevaluateCompositingAfterLayout();
+ }
#endif
}
-void RenderLayer::dirtyStackingContextZOrderLists()
+void RenderLayer::dirtyStackingContainerZOrderLists()
{
- RenderLayer* sc = stackingContext();
+ RenderLayer* sc = stackingContainer();
if (sc)
sc->dirtyZOrderLists();
}
@@ -4800,16 +5725,24 @@ void RenderLayer::dirtyNormalFlowList()
m_normalFlowListDirty = true;
#if USE(ACCELERATED_COMPOSITING)
- if (!renderer()->documentBeingDestroyed())
+ if (!renderer()->documentBeingDestroyed()) {
compositor()->setCompositingLayersNeedRebuild();
+ if (acceleratedCompositingForOverflowScrollEnabled())
+ compositor()->setShouldReevaluateCompositingAfterLayout();
+ }
#endif
}
void RenderLayer::rebuildZOrderLists()
{
ASSERT(m_layerListMutationAllowed);
- ASSERT(isDirtyStackingContext());
+ ASSERT(isDirtyStackingContainer());
+ rebuildZOrderLists(StopAtStackingContainers, m_posZOrderList, m_negZOrderList);
+ m_zOrderListsDirty = false;
+}
+void RenderLayer::rebuildZOrderLists(CollectLayersBehavior behavior, OwnPtr<Vector<RenderLayer*> >& posZOrderList, OwnPtr<Vector<RenderLayer*> >& negZOrderList)
+{
#if USE(ACCELERATED_COMPOSITING)
bool includeHiddenLayers = compositor()->inCompositingMode();
#else
@@ -4817,14 +5750,14 @@ void RenderLayer::rebuildZOrderLists()
#endif
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
if (!m_reflection || reflectionLayer() != child)
- child->collectLayers(includeHiddenLayers, m_posZOrderList, m_negZOrderList);
+ child->collectLayers(includeHiddenLayers, behavior, posZOrderList, negZOrderList);
// Sort the two lists.
- if (m_posZOrderList)
- std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
+ if (posZOrderList)
+ std::stable_sort(posZOrderList->begin(), posZOrderList->end(), compareZIndex);
- if (m_negZOrderList)
- std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
+ if (negZOrderList)
+ std::stable_sort(negZOrderList->begin(), negZOrderList->end(), compareZIndex);
#if ENABLE(DIALOG_ELEMENT)
// Append layers for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes.
@@ -4832,16 +5765,15 @@ void RenderLayer::rebuildZOrderLists()
if (isRootLayer()) {
RenderObject* view = renderer()->view();
for (RenderObject* child = view->firstChild(); child; child = child->nextSibling()) {
- Element* childElement = child->node()->isElementNode() ? toElement(child->node()) : 0;
+ Element* childElement = (child->node() && child->node()->isElementNode()) ? toElement(child->node()) : 0;
if (childElement && childElement->isInTopLayer()) {
RenderLayer* layer = toRenderLayerModelObject(child)->layer();
- m_posZOrderList->append(layer);
+ posZOrderList->append(layer);
}
}
}
#endif
- m_zOrderListsDirty = false;
}
void RenderLayer::updateNormalFlowList()
@@ -4863,7 +5795,7 @@ void RenderLayer::updateNormalFlowList()
m_normalFlowListDirty = false;
}
-void RenderLayer::collectLayers(bool includeHiddenLayers, OwnPtr<Vector<RenderLayer*> >& posBuffer, OwnPtr<Vector<RenderLayer*> >& negBuffer)
+void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior behavior, OwnPtr<Vector<RenderLayer*> >& posBuffer, OwnPtr<Vector<RenderLayer*> >& negBuffer)
{
#if ENABLE(DIALOG_ELEMENT)
if (isInTopLayer())
@@ -4872,9 +5804,10 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, OwnPtr<Vector<RenderLa
updateDescendantDependentFlags();
+ bool isStacking = behavior == StopAtStackingContexts ? isStackingContext() : isStackingContainer();
// Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
- bool includeHiddenLayer = includeHiddenLayers || (m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext()));
- if (includeHiddenLayer && !isNormalFlowOnly() && !renderer()->isRenderFlowThread()) {
+ bool includeHiddenLayer = includeHiddenLayers || (m_hasVisibleContent || (m_hasVisibleDescendant && isStacking));
+ if (includeHiddenLayer && !isNormalFlowOnly()) {
// Determine which buffer the child should be in.
OwnPtr<Vector<RenderLayer*> >& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
@@ -4887,18 +5820,19 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, OwnPtr<Vector<RenderLa
}
// Recur into our children to collect more layers, but only if we don't establish
- // a stacking context.
- if ((includeHiddenLayers || m_hasVisibleDescendant) && !isStackingContext()) {
+ // a stacking context/container.
+ if ((includeHiddenLayers || m_hasVisibleDescendant) && !isStacking) {
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
// Ignore reflections.
if (!m_reflection || reflectionLayer() != child)
- child->collectLayers(includeHiddenLayers, posBuffer, negBuffer);
+ child->collectLayers(includeHiddenLayers, behavior, posBuffer, negBuffer);
}
}
}
void RenderLayer::updateLayerListsIfNeeded()
{
+ bool shouldUpdateDescendantsAreContiguousInStackingOrder = isStackingContext() && (m_zOrderListsDirty || m_normalFlowListDirty);
updateZOrderLists();
updateNormalFlowList();
@@ -4906,13 +5840,21 @@ void RenderLayer::updateLayerListsIfNeeded()
reflectionLayer->updateZOrderLists();
reflectionLayer->updateNormalFlowList();
}
+
+ if (shouldUpdateDescendantsAreContiguousInStackingOrder) {
+ updateDescendantsAreContiguousInStackingOrder();
+ // The above function can cause us to update m_needsCompositedScrolling
+ // and dirty our layer lists. Refresh them if necessary.
+ updateZOrderLists();
+ updateNormalFlowList();
+ }
}
void RenderLayer::updateCompositingAndLayerListsIfNeeded()
{
#if USE(ACCELERATED_COMPOSITING)
if (compositor()->inCompositingMode()) {
- if (isDirtyStackingContext() || m_normalFlowListDirty)
+ if (isDirtyStackingContainer() || m_normalFlowListDirty)
compositor()->updateCompositingLayers(CompositingUpdateOnHitTest, this);
return;
}
@@ -4993,14 +5935,15 @@ bool RenderLayer::shouldBeNormalFlowOnly() const
&& !renderer()->hasBlendMode()
#endif
&& !isTransparent()
- && !usesCompositedScrolling();
+ && !needsCompositedScrolling()
+ ;
}
bool RenderLayer::shouldBeSelfPaintingLayer() const
{
return !isNormalFlowOnly()
|| hasOverlayScrollbars()
- || usesCompositedScrolling()
+ || needsCompositedScrolling()
|| renderer()->hasReflection()
|| renderer()->hasMask()
|| renderer()->isTableRow()
@@ -5025,6 +5968,59 @@ void RenderLayer::updateSelfPaintingLayer()
parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
}
+bool RenderLayer::hasNonEmptyChildRenderers() const
+{
+ // Some HTML can cause whitespace text nodes to have renderers, like:
+ // <div>
+ // <img src=...>
+ // </div>
+ // so test for 0x0 RenderTexts here
+ for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
+ if (!child->hasLayer()) {
+ if (child->isRenderInline() || !child->isBox())
+ return true;
+
+ if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool hasBoxDecorations(const RenderStyle* style)
+{
+ return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter();
+}
+
+bool RenderLayer::hasBoxDecorationsOrBackground() const
+{
+ return hasBoxDecorations(renderer()->style()) || renderer()->hasBackground();
+}
+
+bool RenderLayer::hasVisibleBoxDecorations() const
+{
+ if (!hasVisibleContent())
+ return false;
+
+ return hasBoxDecorationsOrBackground() || hasOverflowControls();
+}
+
+bool RenderLayer::isVisuallyNonEmpty() const
+{
+ ASSERT(!m_visibleDescendantStatusDirty);
+
+ if (hasVisibleContent() && hasNonEmptyChildRenderers())
+ return true;
+
+ if (renderer()->isReplaced() || renderer()->hasMask())
+ return true;
+
+ if (hasVisibleBoxDecorations())
+ return true;
+
+ return false;
+}
+
void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldStyle)
{
if (!oldStyle)
@@ -5033,7 +6029,7 @@ void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldS
bool wasStackingContext = isStackingContext(oldStyle);
bool isStackingContext = this->isStackingContext();
if (isStackingContext != wasStackingContext) {
- dirtyStackingContextZOrderLists();
+ dirtyStackingContainerZOrderLists();
if (isStackingContext)
dirtyZOrderLists();
else
@@ -5044,7 +6040,7 @@ void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldS
// FIXME: RenderLayer already handles visibility changes through our visiblity dirty bits. This logic could
// likely be folded along with the rest.
if (oldStyle->zIndex() != renderer()->style()->zIndex() || oldStyle->visibility() != renderer()->style()->visibility()) {
- dirtyStackingContextZOrderLists();
+ dirtyStackingContainerZOrderLists();
if (isStackingContext)
dirtyZOrderLists();
}
@@ -5093,9 +6089,59 @@ void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle)
}
if (!m_scrollDimensionsDirty)
- updateScrollableAreaSet((hasHorizontalOverflow() || hasVerticalOverflow()) && scrollsOverflow() && allowsScrolling());
+ updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
+}
+
+void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant(RenderObject* containingBlock)
+{
+ for (RenderLayer* layer = this; layer; layer = layer->parent()) {
+ if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant())
+ break;
+
+ layer->m_hasOutOfFlowPositionedDescendantDirty = false;
+ layer->m_hasOutOfFlowPositionedDescendant = true;
+#if USE(ACCELERATED_COMPOSITING)
+ layer->updateNeedsCompositedScrolling();
+#endif
+
+ if (layer->renderer() && layer->renderer() == containingBlock)
+ break;
+ }
+}
+
+void RenderLayer::dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus()
+{
+ m_hasOutOfFlowPositionedDescendantDirty = true;
+ if (parent())
+ parent()->dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+}
+
+void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
+{
+ bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition);
+ if (parent() && ((renderer() && renderer()->isOutOfFlowPositioned()) != wasOutOfFlowPositioned)) {
+ parent()->dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+#if USE(ACCELERATED_COMPOSITING)
+ if (!renderer()->documentBeingDestroyed() && acceleratedCompositingForOverflowScrollEnabled())
+ compositor()->setShouldReevaluateCompositingAfterLayout();
+#endif
+ }
}
+#if USE(ACCELERATED_COMPOSITING)
+inline bool RenderLayer::needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
+{
+ ASSERT(newStyle);
+ return oldStyle && (oldStyle->clip() != newStyle->clip() || oldStyle->hasClip() != newStyle->hasClip());
+}
+
+inline bool RenderLayer::needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
+{
+ ASSERT(newStyle);
+ return !isComposited() && oldStyle && (oldStyle->overflowX() != newStyle->overflowX()) && stackingContainer()->hasCompositingDescendant();
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
{
bool isNormalFlowOnly = shouldBeNormalFlowOnly();
@@ -5104,29 +6150,32 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
RenderLayer* p = parent();
if (p)
p->dirtyNormalFlowList();
- dirtyStackingContextZOrderLists();
+ dirtyStackingContainerZOrderLists();
}
if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) {
if (!m_marquee)
m_marquee = adoptPtr(new RenderMarquee(this));
+ FeatureObserver::observe(renderer()->document(), renderer()->isHTMLMarquee() ? FeatureObserver::HTMLMarqueeElement : FeatureObserver::CSSOverflowMarquee);
m_marquee->updateMarqueeStyle();
}
else if (m_marquee) {
m_marquee.clear();
}
- updateStackingContextsAfterStyleChange(oldStyle);
updateScrollbarsAfterStyleChange(oldStyle);
+ updateStackingContextsAfterStyleChange(oldStyle);
// Overlay scrollbars can make this layer self-painting so we need
// to recompute the bit once scrollbars have been updated.
updateSelfPaintingLayer();
+ updateOutOfFlowPositioned(oldStyle);
if (!hasReflection() && m_reflection)
removeReflection();
else if (hasReflection()) {
if (!m_reflection)
createReflection();
+ FeatureObserver::observe(renderer()->document(), FeatureObserver::Reflection);
updateReflectionStyle();
}
@@ -5149,16 +6198,15 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
#endif
#if USE(ACCELERATED_COMPOSITING)
- if (compositor()->updateLayerCompositingState(this))
- compositor()->setCompositingLayersNeedRebuild();
- else if (oldStyle && (oldStyle->clip() != renderer()->style()->clip() || oldStyle->hasClip() != renderer()->style()->hasClip()))
+ updateNeedsCompositedScrolling();
+
+ const RenderStyle* newStyle = renderer()->style();
+ if (compositor()->updateLayerCompositingState(this)
+ || needsCompositingLayersRebuiltForClip(oldStyle, newStyle)
+ || needsCompositingLayersRebuiltForOverflow(oldStyle, newStyle))
compositor()->setCompositingLayersNeedRebuild();
- else if (m_backing)
- m_backing->updateGraphicsLayerGeometry();
- else if (oldStyle && oldStyle->overflowX() != renderer()->style()->overflowX()) {
- if (stackingContext()->hasCompositingDescendant())
- compositor()->setCompositingLayersNeedRebuild();
- }
+ else if (isComposited())
+ backing()->updateGraphicsLayerGeometry();
#endif
#if ENABLE(CSS_FILTERS)
@@ -5188,19 +6236,27 @@ void RenderLayer::updateScrollableAreaSet(bool hasOverflow)
if (HTMLFrameOwnerElement* owner = frame->ownerElement())
isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting();
- if (hasOverflow && isVisibleToHitTest)
- frameView->addScrollableArea(this);
+ bool isScrollable = hasOverflow && isVisibleToHitTest;
+ bool addedOrRemoved = false;
+ if (isScrollable)
+ addedOrRemoved = frameView->addScrollableArea(this);
else
- frameView->removeScrollableArea(this);
+ addedOrRemoved = frameView->removeScrollableArea(this);
+
+ if (addedOrRemoved) {
+#if USE(ACCELERATED_COMPOSITING)
+ updateNeedsCompositedScrolling();
+#endif
+ }
}
void RenderLayer::updateScrollCornerStyle()
{
- RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
- RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
+ RenderObject* actualRenderer = rendererForScrollbar(renderer());
+ RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
if (corner) {
if (!m_scrollCorner) {
- m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
+ m_scrollCorner = RenderScrollbarPart::createAnonymous(renderer()->document());
m_scrollCorner->setParent(renderer());
}
m_scrollCorner->setStyle(corner.release());
@@ -5212,11 +6268,11 @@ void RenderLayer::updateScrollCornerStyle()
void RenderLayer::updateResizerStyle()
{
- RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
- RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RESIZER, actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
+ RenderObject* actualRenderer = rendererForScrollbar(renderer());
+ RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
if (resizer) {
if (!m_resizer) {
- m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
+ m_resizer = RenderScrollbarPart::createAnonymous(renderer()->document());
m_resizer->setParent(renderer());
}
m_resizer->setStyle(resizer.release());
@@ -5234,7 +6290,7 @@ RenderLayer* RenderLayer::reflectionLayer() const
void RenderLayer::createReflection()
{
ASSERT(!m_reflection);
- m_reflection = new (renderer()->renderArena()) RenderReplica(renderer()->document());
+ m_reflection = RenderReplica::createAnonymous(renderer()->document());
m_reflection->setParent(renderer()); // We create a 1-way connection.
}
@@ -5321,14 +6377,20 @@ FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style)
RefPtr<CustomFilterProgram> program = customOperation->program();
if (!program->isLoaded())
continue;
-
- CustomFilterGlobalContext* globalContext = renderer()->view()->customFilterGlobalContext();
- RefPtr<CustomFilterValidatedProgram> validatedProgram = globalContext->getValidatedProgram(program->programInfo());
+
+ RefPtr<CustomFilterValidatedProgram> validatedProgram = program->validatedProgram();
+ if (!validatedProgram) {
+ // Lazily create a validated program and store it on the CustomFilterProgram.
+ CustomFilterGlobalContext* globalContext = renderer()->view()->customFilterGlobalContext();
+ validatedProgram = CustomFilterValidatedProgram::create(globalContext, program->programInfo());
+ program->setValidatedProgram(validatedProgram);
+ }
+
if (!validatedProgram->isInitialized())
continue;
RefPtr<ValidatedCustomFilterOperation> validatedOperation = ValidatedCustomFilterOperation::create(validatedProgram.release(),
- customOperation->parameters(), customOperation->meshRows(), customOperation->meshColumns(), customOperation->meshBoxType(), customOperation->meshType());
+ customOperation->parameters(), customOperation->meshRows(), customOperation->meshColumns(), customOperation->meshType());
outputFilters.operations().append(validatedOperation.release());
continue;
}
@@ -5391,7 +6453,7 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer()
// If the filter fails to build, remove it from the layer. It will still attempt to
// go through regular processing (e.g. compositing), but never apply anything.
- if (!filterInfo->renderer()->build(renderer()->document(), computeFilterOperations(renderer()->style())))
+ if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style())))
filterInfo->setRenderer(0);
}
diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h
index c5e652411..48113920a 100644
--- a/Source/WebCore/rendering/RenderLayer.h
+++ b/Source/WebCore/rendering/RenderLayer.h
@@ -49,19 +49,18 @@
#include "ScrollableArea.h"
#include <wtf/OwnPtr.h>
-#if ENABLE(CSS_FILTERS)
-#include "RenderLayerFilterInfo.h"
-#endif
-
namespace WebCore {
#if ENABLE(CSS_FILTERS)
class FilterEffectRenderer;
+class FilterEffectRendererHelper;
class FilterOperations;
+class RenderLayerFilterInfo;
#endif
class HitTestRequest;
class HitTestResult;
class HitTestingTransformState;
+class RenderFlowThread;
class RenderGeometryMap;
class RenderMarquee;
class RenderReplica;
@@ -77,11 +76,12 @@ class RenderLayerCompositor;
#endif
enum BorderRadiusClippingRule { IncludeSelfForBorderRadius, DoNotIncludeSelfForBorderRadius };
+enum IncludeSelfOrNot { IncludeSelf, ExcludeSelf };
enum RepaintStatus {
- NeedsNormalRepaint = 0,
- NeedsFullRepaint = 1 << 0,
- NeedsFullRepaintForPositionedMovementLayout = 1 << 1
+ NeedsNormalRepaint,
+ NeedsFullRepaint,
+ NeedsFullRepaintForPositionedMovementLayout
};
class ClipRect {
@@ -114,10 +114,11 @@ public:
}
void move(LayoutUnit x, LayoutUnit y) { m_rect.move(x, y); }
void move(const LayoutSize& size) { m_rect.move(size); }
+ void moveBy(const LayoutPoint& point) { m_rect.moveBy(point); }
bool isEmpty() const { return m_rect.isEmpty(); }
- bool intersects(const LayoutRect& rect) { return m_rect.intersects(rect); }
- bool intersects(const HitTestLocation&);
+ bool intersects(const LayoutRect& rect) const { return m_rect.intersects(rect); }
+ bool intersects(const HitTestLocation&) const;
private:
LayoutRect m_rect;
@@ -229,6 +230,11 @@ enum ClipRectsType {
TemporaryClipRects
};
+enum ShouldRespectOverflowClip {
+ IgnoreOverflowClip,
+ RespectOverflowClip
+};
+
struct ClipRectsCache {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -237,20 +243,77 @@ public:
#ifndef NDEBUG
for (int i = 0; i < NumCachedClipRectsTypes; ++i) {
m_clipRectsRoot[i] = 0;
- m_respectingOverflowClip[i] = false;
m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize;
}
#endif
}
- RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes];
+ PassRefPtr<ClipRects> getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) { return m_clipRects[getIndex(clipRectsType, respectOverflow)]; }
+ void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, PassRefPtr<ClipRects> clipRects) { m_clipRects[getIndex(clipRectsType, respectOverflow)] = clipRects; }
+
#ifndef NDEBUG
const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
- bool m_respectingOverflowClip[NumCachedClipRectsTypes];
OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes];
#endif
+
+private:
+ int getIndex(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow)
+ {
+ int index = static_cast<int>(clipRectsType);
+ if (respectOverflow == RespectOverflowClip)
+ index += static_cast<int>(NumCachedClipRectsTypes);
+ return index;
+ }
+
+ RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2];
+};
+
+struct LayerFragment {
+public:
+ LayerFragment()
+ : shouldPaintContent(false)
+ { }
+
+ void setRects(const LayoutRect& bounds, const ClipRect& background, const ClipRect& foreground, const ClipRect& outline)
+ {
+ layerBounds = bounds;
+ backgroundRect = background;
+ foregroundRect = foreground;
+ outlineRect = outline;
+ }
+
+ void moveBy(const LayoutPoint& offset)
+ {
+ layerBounds.moveBy(offset);
+ backgroundRect.moveBy(offset);
+ foregroundRect.moveBy(offset);
+ outlineRect.moveBy(offset);
+ paginationClip.moveBy(offset);
+ }
+
+ void intersect(const LayoutRect& rect)
+ {
+ backgroundRect.intersect(rect);
+ foregroundRect.intersect(rect);
+ outlineRect.intersect(rect);
+ }
+
+ bool shouldPaintContent;
+ LayoutRect layerBounds;
+ ClipRect backgroundRect;
+ ClipRect foregroundRect;
+ ClipRect outlineRect;
+
+ // Unique to paginated fragments. The physical translation to apply to shift the layer when painting/hit-testing.
+ LayoutPoint paginationOffset;
+
+ // Also unique to paginated fragments. An additional clip that applies to the layer. It is in layer-local
+ // (physical) coordinates.
+ LayoutRect paginationClip;
};
+typedef Vector<LayerFragment, 1> LayerFragments;
+
class RenderLayer : public ScrollableArea {
public:
friend class RenderReplica;
@@ -258,6 +321,8 @@ public:
RenderLayer(RenderLayerModelObject*);
~RenderLayer();
+ String name() const;
+
RenderLayerModelObject* renderer() const { return m_renderer; }
RenderBox* renderBox() const { return m_renderer && m_renderer->isBox() ? toRenderBox(m_renderer) : 0; }
RenderLayer* parent() const { return m_parent; }
@@ -338,10 +403,9 @@ public:
void scrollRectToVisible(const LayoutRect&, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
- LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
+ LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& visibleRectRelativeToDocument, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
bool scrollsOverflow() const;
- bool allowsScrolling() const; // Returns true if at least one scrollbar is visible and enabled.
bool hasScrollbars() const { return m_hBar || m_vBar; }
void setHasHorizontalScrollbar(bool);
void setHasVerticalScrollbar(bool);
@@ -372,8 +436,9 @@ public:
void updateScrollInfoAfterLayout();
bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1);
- void autoscroll();
+ void autoscroll(const IntPoint&);
+ bool canResize() const;
void resize(const PlatformMouseEvent&, const LayoutSize&);
bool inResizeMode() const { return m_inResizeMode; }
void setInResizeMode(bool b) { m_inResizeMode = b; }
@@ -390,14 +455,12 @@ public:
bool canRender3DTransforms() const;
- // Returns true if the position changed.
- bool updateLayerPosition();
-
enum UpdateLayerPositionsFlag {
- CheckForRepaint = 1,
- IsCompositingUpdateRoot = 1 << 1,
- UpdateCompositingLayers = 1 << 2,
- UpdatePagination = 1 << 3
+ CheckForRepaint = 1 << 0,
+ NeedsFullRepaintInBacking = 1 << 1,
+ IsCompositingUpdateRoot = 1 << 2,
+ UpdateCompositingLayers = 1 << 3,
+ UpdatePagination = 1 << 4
};
typedef unsigned UpdateLayerPositionsFlags;
static const UpdateLayerPositionsFlags defaultFlags = CheckForRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers;
@@ -406,8 +469,13 @@ public:
void updateLayerPositionsAfterOverflowScroll();
void updateLayerPositionsAfterDocumentScroll();
+
+#if USE(ACCELERATED_COMPOSITING)
+ void positionNewlyCreatedOverflowControls();
+#endif
bool isPaginated() const { return m_isPaginated; }
+ RenderLayer* enclosingPaginationLayer() const { return m_enclosingPaginationLayer; }
void updateTransform();
@@ -424,18 +492,30 @@ public:
void clearBlockSelectionGapsBounds();
void repaintBlockSelectionGaps();
- // Get the enclosing stacking context for this layer. A stacking context is a layer
- // that has a non-auto z-index.
- RenderLayer* stackingContext() const;
+ // A stacking context is a layer that has a non-auto z-index.
bool isStackingContext() const { return isStackingContext(renderer()->style()); }
+ // A stacking container can have z-order lists. All stacking contexts are
+ // stacking containers, but the converse is not true. Layers that use
+ // composited scrolling are stacking containers, but they may not
+ // necessarily be stacking contexts.
+ bool isStackingContainer() const { return isStackingContext() || needsCompositedScrolling(); }
+
+ // Gets the enclosing stacking container for this layer, excluding this
+ // layer itself.
+ RenderLayer* stackingContainer() const;
+
+ // Gets the enclosing stacking container for this layer, possibly the layer
+ // itself, if it is a stacking container.
+ RenderLayer* enclosingStackingContainer() { return isStackingContainer() ? this : stackingContainer(); }
+
void dirtyZOrderLists();
- void dirtyStackingContextZOrderLists();
+ void dirtyStackingContainerZOrderLists();
Vector<RenderLayer*>* posZOrderList() const
{
ASSERT(!m_zOrderListsDirty);
- ASSERT(isStackingContext() || !m_posZOrderList);
+ ASSERT(isStackingContainer() || !m_posZOrderList);
return m_posZOrderList.get();
}
@@ -444,7 +524,7 @@ public:
Vector<RenderLayer*>* negZOrderList() const
{
ASSERT(!m_zOrderListsDirty);
- ASSERT(isStackingContext() || !m_negZOrderList);
+ ASSERT(isStackingContainer() || !m_negZOrderList);
return m_negZOrderList.get();
}
@@ -462,10 +542,25 @@ public:
void setHasVisibleContent();
void dirtyVisibleContentStatus();
+ bool hasBoxDecorationsOrBackground() const;
+ bool hasVisibleBoxDecorations() const;
+ // Returns true if this layer has visible content (ignoring any child layers).
+ bool isVisuallyNonEmpty() const;
+ // True if this layer container renderers that paint.
+ bool hasNonEmptyChildRenderers() const;
+
// FIXME: We should ASSERT(!m_hasSelfPaintingLayerDescendantDirty); here but we hit the same bugs as visible content above.
// Part of the issue is with subtree relayout: we don't check if our ancestors have some descendant flags dirty, missing some updates.
bool hasSelfPaintingLayerDescendant() const { return m_hasSelfPaintingLayerDescendant; }
+ // This returns true if we have an out of flow positioned descendant whose
+ // containing block is not a descendant of ours. If this is true, we cannot
+ // automatically opt into composited scrolling since this out of flow
+ // positioned descendant would become clipped by us, possibly altering the
+ // rendering of the page.
+ // FIXME: We should ASSERT(!m_hasOutOfFlowPositionedDescendantDirty); here but we may hit the same bugs as visible content above.
+ bool hasOutOfFlowPositionedDescendant() const { return m_hasOutOfFlowPositionedDescendant; }
+
// Gets the nearest enclosing positioned ancestor layer (also includes
// the <html> layer and the root layer).
RenderLayer* enclosingPositionedAncestor() const;
@@ -476,16 +571,18 @@ public:
// The layer relative to which clipping rects for this layer are computed.
RenderLayer* clippingRootForPainting() const;
+ RenderLayer* enclosingOverflowClipLayer(IncludeSelfOrNot) const;
+
#if USE(ACCELERATED_COMPOSITING)
// Enclosing compositing layer; if includeSelf is true, may return this.
- RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const;
- RenderLayer* enclosingCompositingLayerForRepaint(bool includeSelf = true) const;
+ RenderLayer* enclosingCompositingLayer(IncludeSelfOrNot = IncludeSelf) const;
+ RenderLayer* enclosingCompositingLayerForRepaint(IncludeSelfOrNot = IncludeSelf) const;
// Ancestor compositing layer, excluding this.
- RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(false); }
+ RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(ExcludeSelf); }
#endif
#if ENABLE(CSS_FILTERS)
- RenderLayer* enclosingFilterLayer(bool includeSelf = true) const;
+ RenderLayer* enclosingFilterLayer(IncludeSelfOrNot = IncludeSelf) const;
RenderLayer* enclosingFilterRepaintLayer() const;
void setFilterBackendNeedsRepaintingInRect(const LayoutRect&, bool immediate);
bool hasAncestorWithFilterOutsets() const;
@@ -501,10 +598,12 @@ public:
;
}
- void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& location) const;
- void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect&) const;
- void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const;
- void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect&) const;
+ // FIXME: adjustForColumns allows us to position compositing layers in columns correctly, but eventually they need to be split across columns too.
+ enum ColumnOffsetAdjustment { DontAdjustForColumns, AdjustForColumns };
+ void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& location, ColumnOffsetAdjustment adjustForColumns = DontAdjustForColumns) const;
+ void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect&, ColumnOffsetAdjustment adjustForColumns = DontAdjustForColumns) const;
+ void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint&, ColumnOffsetAdjustment adjustForColumns = DontAdjustForColumns) const;
+ void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect&, ColumnOffsetAdjustment adjustForColumns = DontAdjustForColumns) const;
int zIndex() const { return renderer()->style()->zIndex(); }
@@ -517,7 +616,10 @@ public:
PaintLayerPaintingCompositingBackgroundPhase = 1 << 5,
PaintLayerPaintingCompositingForegroundPhase = 1 << 6,
PaintLayerPaintingCompositingMaskPhase = 1 << 7,
- PaintLayerPaintingOverflowContents = 1 << 8,
+ PaintLayerPaintingCompositingScrollingPhase = 1 << 8,
+ PaintLayerPaintingOverflowContents = 1 << 9,
+ PaintLayerPaintingRootBackgroundOnly = 1 << 10,
+ PaintLayerPaintingSkipRootBackground = 1 << 11,
PaintLayerPaintingCompositingAllPhases = (PaintLayerPaintingCompositingBackgroundPhase | PaintLayerPaintingCompositingForegroundPhase | PaintLayerPaintingCompositingMaskPhase)
};
@@ -527,13 +629,11 @@ public:
// paints the layers that intersect the damage rect from back to
// front. The hitTest method looks for mouse events by walking
// layers that intersect the point from front to back.
- void paint(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0,
+ void paint(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* subtreePaintRoot = 0,
RenderRegion* = 0, PaintLayerFlags = 0);
bool hitTest(const HitTestRequest&, HitTestResult&);
bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&);
- void paintOverlayScrollbars(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior, RenderObject* paintingRoot = 0);
-
- enum ShouldRespectOverflowClip { IgnoreOverflowClip, RespectOverflowClip };
+ void paintOverlayScrollbars(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior, RenderObject* subtreePaintRoot = 0);
struct ClipRectsContext {
ClipRectsContext(const RenderLayer* inRootLayer, RenderRegion* inRegion, ClipRectsType inClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip inRespectOverflowClip = RespectOverflowClip)
@@ -563,10 +663,10 @@ public:
// (rather than computing them all from scratch up the parent chain).
void calculateClipRects(const ClipRectsContext&, ClipRects&) const;
- ClipRects* clipRects(ClipRectsType type) const
+ ClipRects* clipRects(const ClipRectsContext& context) const
{
- ASSERT(type < NumCachedClipRectsTypes);
- return m_clipRectsCache ? m_clipRectsCache->m_clipRects[type].get() : 0;
+ ASSERT(context.clipRectsType < NumCachedClipRectsTypes);
+ return m_clipRectsCache ? m_clipRectsCache->getClipRects(context.clipRectsType, context.respectOverflowClip).get() : 0;
}
LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space.
@@ -576,23 +676,38 @@ public:
// Pass offsetFromRoot if known.
bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0) const;
- // Bounding box relative to some ancestor layer. Pass offsetFromRoot if known.
- LayoutRect boundingBox(const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0) const;
- // Bounding box in the coordinates of this layer.
- LayoutRect localBoundingBox() const;
- // Pixel snapped bounding box relative to the root.
- IntRect absoluteBoundingBox() const;
-
enum CalculateLayerBoundsFlag {
IncludeSelfTransform = 1 << 0,
UseLocalClipRectIfPossible = 1 << 1,
IncludeLayerFilterOutsets = 1 << 2,
ExcludeHiddenDescendants = 1 << 3,
- DefaultCalculateLayerBoundsFlags = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets
+ DontConstrainForMask = 1 << 4,
+ IncludeCompositedDescendants = 1 << 5,
+ UseFragmentBoxes = 1 << 6,
+ DefaultCalculateLayerBoundsFlags = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets | UseFragmentBoxes
};
typedef unsigned CalculateLayerBoundsFlags;
+
+ // Bounding box relative to some ancestor layer. Pass offsetFromRoot if known.
+ LayoutRect boundingBox(const RenderLayer* rootLayer, CalculateLayerBoundsFlags = 0, const LayoutPoint* offsetFromRoot = 0) const;
+ // Bounding box in the coordinates of this layer.
+ LayoutRect localBoundingBox(CalculateLayerBoundsFlags = 0) const;
+ // Pixel snapped bounding box relative to the root.
+ IntRect absoluteBoundingBox() const;
+
+ // Bounds used for layer overlap testing in RenderLayerCompositor.
+ LayoutRect overlapBounds() const { return overlapBoundsIncludeChildren() ? calculateLayerBounds(this) : localBoundingBox(); }
+
+#if ENABLE(CSS_FILTERS)
+ // If true, this layer's children are included in its bounds for overlap testing.
+ // We can't rely on the children's positions if this layer has a filter that could have moved the children's pixels around.
+ bool overlapBoundsIncludeChildren() const { return hasFilter() && renderer()->style()->filter().hasFilterThatMovesPixels(); }
+#else
+ bool overlapBoundsIncludeChildren() const { return false; }
+#endif
+
// Can pass offsetFromRoot if known.
- IntRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const;
+ LayoutRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const;
// WARNING: This method returns the offset for the parent as this is what updateLayerPositions expects.
LayoutPoint computeOffsetFromRoot(bool& hasLayerOffset) const;
@@ -652,14 +767,19 @@ public:
RenderLayerBacking* backing() const { return m_backing.get(); }
RenderLayerBacking* ensureBacking();
void clearBacking(bool layerBeingDestroyed = false);
+ virtual GraphicsLayer* layerForScrolling() const;
virtual GraphicsLayer* layerForHorizontalScrollbar() const;
virtual GraphicsLayer* layerForVerticalScrollbar() const;
virtual GraphicsLayer* layerForScrollCorner() const;
virtual bool usesCompositedScrolling() const OVERRIDE;
+ bool needsCompositedScrolling() const;
+ bool needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const;
+ bool needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const;
#else
bool isComposited() const { return false; }
bool hasCompositedMask() const { return false; }
bool usesCompositedScrolling() const { return false; }
+ bool needsCompositedScrolling() const { return false; }
#endif
bool paintsWithTransparency(PaintBehavior paintBehavior) const
@@ -669,6 +789,10 @@ public:
bool paintsWithTransform(PaintBehavior) const;
+ // Returns true if background phase is painted opaque in the given rect.
+ // The query rect is given in local coordinates.
+ bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const;
+
bool containsDirtyOverlayScrollbars() const { return m_containsDirtyOverlayScrollbars; }
void setContainsDirtyOverlayScrollbars(bool dirtyScrollbars) { m_containsDirtyOverlayScrollbars = dirtyScrollbars; }
@@ -680,19 +804,11 @@ public:
FilterOperations computeFilterOperations(const RenderStyle*);
bool paintsWithFilters() const;
bool requiresFullLayerImageForFilters() const;
- FilterEffectRenderer* filterRenderer() const
- {
- RenderLayerFilterInfo* filterInfo = this->filterInfo();
- return filterInfo ? filterInfo->renderer() : 0;
- }
-
- RenderLayerFilterInfo* filterInfo() const { return hasFilterInfo() ? RenderLayerFilterInfo::filterInfoForRenderLayer(this) : 0; }
- RenderLayerFilterInfo* ensureFilterInfo() { return RenderLayerFilterInfo::createFilterInfoForRenderLayerIfNeeded(this); }
- void removeFilterInfoIfNeeded()
- {
- if (hasFilterInfo())
- RenderLayerFilterInfo::removeFilterInfoForRenderLayer(this);
- }
+ FilterEffectRenderer* filterRenderer() const;
+
+ RenderLayerFilterInfo* filterInfo() const;
+ RenderLayerFilterInfo* ensureFilterInfo();
+ void removeFilterInfoIfNeeded();
bool hasFilterInfo() const { return m_hasFilterInfo; }
void setHasFilterInfo(bool hasFilterInfo) { m_hasFilterInfo = hasFilterInfo; }
@@ -710,19 +826,43 @@ public:
bool isInTopLayerSubtree() const;
#endif
+#if USE(ACCELERATED_COMPOSITING)
+ enum ViewportConstrainedNotCompositedReason {
+ NoNotCompositedReason,
+ NotCompositedForBoundsOutOfView,
+ NotCompositedForNonViewContainer,
+ NotCompositedForNoVisibleContent,
+ };
+
+ void setViewportConstrainedNotCompositedReason(ViewportConstrainedNotCompositedReason reason) { m_viewportConstrainedNotCompositedReason = reason; }
+ ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason() const { return static_cast<ViewportConstrainedNotCompositedReason>(m_viewportConstrainedNotCompositedReason); }
+#endif
+
+ bool isOutOfFlowRenderFlowThread() const { return renderer()->isOutOfFlowRenderFlowThread(); }
+
private:
+ enum CollectLayersBehavior { StopAtStackingContexts, StopAtStackingContainers };
+
void updateZOrderLists();
void rebuildZOrderLists();
+ void rebuildZOrderLists(CollectLayersBehavior, OwnPtr<Vector<RenderLayer*> >&, OwnPtr<Vector<RenderLayer*> >&);
void clearZOrderLists();
void updateNormalFlowList();
+ // Non-auto z-index always implies stacking context here, because StyleResolver::adjustRenderStyle already adjusts z-index
+ // based on positioning and other criteria.
bool isStackingContext(const RenderStyle* style) const { return !style->hasAutoZIndex() || isRootLayer(); }
- bool isDirtyStackingContext() const { return m_zOrderListsDirty && isStackingContext(); }
+
+ bool isDirtyStackingContainer() const { return m_zOrderListsDirty && isStackingContainer(); }
void setAncestorChainHasSelfPaintingLayerDescendant();
void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
+ bool acceleratedCompositingForOverflowScrollEnabled() const;
+ void updateDescendantsAreContiguousInStackingOrder();
+ void updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>&, int& minIndex, int& maxIndex, int& count, bool firstIteration);
+
void computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* = 0);
void computeRepaintRectsIncludingDescendants();
void clearRepaintRects();
@@ -739,6 +879,15 @@ private:
void updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle);
void updateScrollbarsAfterLayout();
+ void setAncestorChainHasOutOfFlowPositionedDescendant(RenderObject* containingBlock);
+ void dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+ void updateOutOfFlowPositioned(const RenderStyle* oldStyle);
+
+ void updateNeedsCompositedScrolling();
+
+ // Returns true if the position changed.
+ bool updateLayerPosition();
+
void updateLayerPositions(RenderGeometryMap* = 0, UpdateLayerPositionsFlags = defaultFlags);
enum UpdateLayerPositionsAfterScrollFlag {
@@ -766,42 +915,68 @@ private:
void setLastChild(RenderLayer* last) { m_last = last; }
LayoutPoint renderBoxLocation() const { return renderer()->isBox() ? toRenderBox(renderer())->location() : LayoutPoint(); }
- LayoutUnit renderBoxX() const { return renderBoxLocation().x(); }
- LayoutUnit renderBoxY() const { return renderBoxLocation().y(); }
- void collectLayers(bool includeHiddenLayers, OwnPtr<Vector<RenderLayer*> >&, OwnPtr<Vector<RenderLayer*> >&);
+ void collectLayers(bool includeHiddenLayers, CollectLayersBehavior, OwnPtr<Vector<RenderLayer*> >&, OwnPtr<Vector<RenderLayer*> >&);
void updateCompositingAndLayerListsIfNeeded();
struct LayerPaintingInfo {
- LayerPaintingInfo(RenderLayer* inRootLayer, const LayoutRect& inDirtyRect, PaintBehavior inPaintBehavior, const LayoutSize& inSubPixelAccumulation, RenderObject* inPaintingRoot = 0, RenderRegion*inRegion = 0, OverlapTestRequestMap* inOverlapTestRequests = 0)
+ LayerPaintingInfo(RenderLayer* inRootLayer, const LayoutRect& inDirtyRect, PaintBehavior inPaintBehavior, const LayoutSize& inSubPixelAccumulation, RenderObject* inSubtreePaintRoot = 0, RenderRegion*inRegion = 0, OverlapTestRequestMap* inOverlapTestRequests = 0)
: rootLayer(inRootLayer)
- , paintingRoot(inPaintingRoot)
+ , subtreePaintRoot(inSubtreePaintRoot)
, paintDirtyRect(inDirtyRect)
, subPixelAccumulation(inSubPixelAccumulation)
, region(inRegion)
, overlapTestRequests(inOverlapTestRequests)
, paintBehavior(inPaintBehavior)
+ , clipToDirtyRect(true)
{ }
RenderLayer* rootLayer;
- RenderObject* paintingRoot; // only paint descendants of this object
+ RenderObject* subtreePaintRoot; // only paint descendants of this object
LayoutRect paintDirtyRect; // relative to rootLayer;
LayoutSize subPixelAccumulation;
RenderRegion* region; // May be null.
OverlapTestRequestMap* overlapTestRequests; // May be null.
PaintBehavior paintBehavior;
+ bool clipToDirtyRect;
};
-
+
+ bool setupFontSubpixelQuantization(GraphicsContext*, bool& didQuantizeFonts);
+ bool setupClipPath(GraphicsContext*, const LayerPaintingInfo&, const LayoutPoint& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed);
+#if ENABLE(CSS_FILTERS)
+ PassOwnPtr<FilterEffectRendererHelper> setupFilters(GraphicsContext*, LayerPaintingInfo&, PaintLayerFlags, const LayoutPoint& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed);
+ GraphicsContext* applyFilters(FilterEffectRendererHelper*, GraphicsContext* originalContext, LayerPaintingInfo&, LayerFragments&);
+#endif
+
void paintLayer(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
void paintLayerContentsAndReflection(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
+ void paintLayerByApplyingTransform(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags, const LayoutPoint& translationOffset = LayoutPoint());
void paintLayerContents(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
void paintList(Vector<RenderLayer*>*, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
void paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
void paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags, const Vector<RenderLayer*>& columnLayers, size_t columnIndex);
+ void collectFragments(LayerFragments&, const RenderLayer* rootLayer, RenderRegion*, const LayoutRect& dirtyRect,
+ ClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize,
+ ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutRect* layerBoundingBox = 0);
+ void updatePaintingInfoForFragments(LayerFragments&, const LayerPaintingInfo&, PaintLayerFlags, bool shouldPaintContent, const LayoutPoint* offsetFromRoot);
+ void paintBackgroundForFragments(const LayerFragments&, GraphicsContext*, GraphicsContext* transparencyLayerContext,
+ const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer);
+ void paintForegroundForFragments(const LayerFragments&, GraphicsContext*, GraphicsContext* transparencyLayerContext,
+ const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer,
+ bool selectionOnly, bool forceBlackText);
+ void paintForegroundForFragmentsWithPhase(PaintPhase, const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer);
+ void paintOutlineForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer);
+ void paintOverflowControlsForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&);
+ void paintMaskForFragments(const LayerFragments&, GraphicsContext*, const LayerPaintingInfo&, RenderObject* paintingRootForRenderer);
+ void paintTransformedLayerIntoFragments(GraphicsContext*, const LayerPaintingInfo&, PaintLayerFlags);
+
RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
const LayoutRect& hitTestRect, const HitTestLocation&, bool appliedTransform,
const HitTestingTransformState* transformState = 0, double* zOffset = 0);
+ RenderLayer* hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest&, HitTestResult&,
+ const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* = 0, double* zOffset = 0,
+ const LayoutPoint& translationOffset = LayoutPoint());
RenderLayer* hitTestList(Vector<RenderLayer*>*, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
const LayoutRect& hitTestRect, const HitTestLocation&,
const HitTestingTransformState* transformState, double* zOffsetForDescendants, double* zOffset,
@@ -816,13 +991,22 @@ private:
PassRefPtr<HitTestingTransformState> createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
const LayoutRect& hitTestRect, const HitTestLocation&,
- const HitTestingTransformState* containerTransformState) const;
+ const HitTestingTransformState* containerTransformState,
+ const LayoutPoint& translationOffset = LayoutPoint()) const;
bool hitTestContents(const HitTestRequest&, HitTestResult&, const LayoutRect& layerBounds, const HitTestLocation&, HitTestFilter) const;
+ bool hitTestContentsForFragments(const LayerFragments&, const HitTestRequest&, HitTestResult&, const HitTestLocation&, HitTestFilter, bool& insideClipRect) const;
+ bool hitTestResizerInFragments(const LayerFragments&, const HitTestLocation&) const;
+ RenderLayer* hitTestTransformedLayerInFragments(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest&, HitTestResult&,
+ const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* = 0, double* zOffset = 0);
+
+ bool listBackgroundIsKnownToBeOpaqueInRect(const Vector<RenderLayer*>*, const LayoutRect&) const;
void computeScrollDimensions();
bool hasHorizontalOverflow() const;
bool hasVerticalOverflow() const;
+ bool hasScrollableHorizontalOverflow() const;
+ bool hasScrollableVerticalOverflow() const;
bool shouldBeNormalFlowOnly() const;
@@ -845,15 +1029,17 @@ private:
virtual IntPoint scrollPosition() const;
virtual IntPoint minimumScrollPosition() const;
virtual IntPoint maximumScrollPosition() const;
- virtual IntRect visibleContentRect(bool includeScrollbars) const;
+ virtual IntRect visibleContentRect(VisibleContentRectIncludesScrollbars) const;
virtual int visibleHeight() const;
virtual int visibleWidth() const;
virtual IntSize contentsSize() const;
virtual IntSize overhangAmount() const;
- virtual IntPoint currentMousePosition() const;
+ virtual IntPoint lastKnownMousePosition() const;
+ virtual bool isHandlingWheelEvent() const OVERRIDE;
virtual bool shouldSuspendScrollAnimations() const;
virtual bool scrollbarsCanBeActive() const;
virtual IntRect scrollableAreaBoundingBox() const OVERRIDE;
+ virtual bool scrollbarAnimationsAreSuppressed() const OVERRIDE;
// Rectangle encompassing the scroll corner and resizer rect.
IntRect scrollCornerAndResizerRect() const;
@@ -869,7 +1055,7 @@ private:
void dirtyAncestorChainVisibleDescendantStatus();
void setAncestorChainHasVisibleDescendant();
- void updateDescendantDependentFlags();
+ void updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks = 0);
// This flag is computed by RenderLayerCompositor, which knows more about 3d hierarchies than we do.
void setHas3DTransformedDescendant(bool b) { m_has3DTransformedDescendant = b; }
@@ -909,6 +1095,9 @@ private:
void updatePagination();
+ // FIXME: Temporary. Remove when new columns come online.
+ bool useRegionBasedColumns() const;
+
#if USE(ACCELERATED_COMPOSITING)
bool hasCompositingDescendant() const { return m_hasCompositingDescendant; }
void setHasCompositingDescendant(bool b) { m_hasCompositingDescendant = b; }
@@ -928,6 +1117,9 @@ private:
bool mustCompositeForIndirectReasons() const { return m_indirectCompositingReason; }
#endif
+ // Returns true if z ordering would not change if this layer were a stacking container.
+ bool canBeStackingContainer() const;
+
friend class RenderLayerBacking;
friend class RenderLayerCompositor;
friend class RenderLayerModelObject;
@@ -966,6 +1158,19 @@ protected:
bool m_hasSelfPaintingLayerDescendant : 1;
bool m_hasSelfPaintingLayerDescendantDirty : 1;
+ // If we have no out of flow positioned descendants and no non-descendant
+ // appears between our descendants in stacking order, then we may become a
+ // stacking context.
+ bool m_hasOutOfFlowPositionedDescendant : 1;
+ bool m_hasOutOfFlowPositionedDescendantDirty : 1;
+
+ bool m_needsCompositedScrolling : 1;
+
+ // If this is true, then no non-descendant appears between any of our
+ // descendants in stacking order. This is one of the requirements of being
+ // able to safely become a stacking context.
+ bool m_descendantsAreContiguousInStackingOrder : 1;
+
const bool m_isRootLayer : 1;
bool m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether
@@ -988,6 +1193,7 @@ protected:
#if USE(ACCELERATED_COMPOSITING)
bool m_hasCompositingDescendant : 1; // In the z-order tree.
unsigned m_indirectCompositingReason : 3;
+ unsigned m_viewportConstrainedNotCompositedReason : 2;
#endif
bool m_containsDirtyOverlayScrollbars : 1;
@@ -1065,6 +1271,9 @@ protected:
RenderScrollbarPart* m_scrollCorner;
RenderScrollbarPart* m_resizer;
+ // Pointer to the enclosing RenderLayer that caused us to be paginated. It is 0 if we are not paginated.
+ RenderLayer* m_enclosingPaginationLayer;
+
private:
IntRect m_blockSelectionGapsBounds;
@@ -1075,7 +1284,7 @@ private:
inline void RenderLayer::clearZOrderLists()
{
- ASSERT(!isStackingContext());
+ ASSERT(!isStackingContainer());
m_posZOrderList.clear();
m_negZOrderList.clear();
@@ -1086,7 +1295,7 @@ inline void RenderLayer::updateZOrderLists()
if (!m_zOrderListsDirty)
return;
- if (!isStackingContext()) {
+ if (!isStackingContainer()) {
clearZOrderLists();
m_zOrderListsDirty = false;
return;
@@ -1116,6 +1325,7 @@ private:
};
#endif
+void makeMatrixRenderable(TransformationMatrix&, bool has3DRendering);
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp
index 88be08dfe..955315eef 100644
--- a/Source/WebCore/rendering/RenderLayerBacking.cpp
+++ b/Source/WebCore/rendering/RenderLayerBacking.cpp
@@ -32,6 +32,7 @@
#include "AnimationController.h"
#include "CanvasRenderingContext.h"
#include "CSSPropertyNames.h"
+#include "CachedImage.h"
#include "Chrome.h"
#include "FontCache.h"
#include "FrameView.h"
@@ -41,9 +42,11 @@
#include "HTMLIFrameElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
#include "InspectorInstrumentation.h"
#include "KeyframeList.h"
#include "PluginViewBase.h"
+#include "ProgressTracker.h"
#include "RenderApplet.h"
#include "RenderIFrame.h"
#include "RenderImage.h"
@@ -55,7 +58,6 @@
#include "Settings.h"
#include "StyleResolver.h"
#include "TiledBacking.h"
-#include <wtf/CurrentTime.h>
#include <wtf/text/StringBuilder.h>
#if ENABLE(CSS_FILTERS)
@@ -75,8 +77,6 @@ namespace WebCore {
using namespace HTMLNames;
-static bool hasBoxDecorations(const RenderStyle*);
-static bool hasBoxDecorationsOrBackground(const RenderObject*);
static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*);
static IntRect clipBox(RenderBox* renderer);
@@ -94,18 +94,31 @@ static inline bool isAcceleratedCanvas(RenderObject* renderer)
return false;
}
+// Get the scrolling coordinator in a way that works inside RenderLayerBacking's destructor.
+static ScrollingCoordinator* scrollingCoordinatorFromLayer(RenderLayer* layer)
+{
+ Page* page = layer->renderer()->frame()->page();
+ if (!page)
+ return 0;
+
+ return page->scrollingCoordinator();
+}
+
bool RenderLayerBacking::m_creatingPrimaryGraphicsLayer = false;
RenderLayerBacking::RenderLayerBacking(RenderLayer* layer)
: m_owningLayer(layer)
, m_scrollLayerID(0)
, m_artificiallyInflatedBounds(false)
+ , m_boundsConstrainedByClipping(false)
, m_isMainFrameRenderViewLayer(false)
, m_usingTiledCacheLayer(false)
, m_requiresOwnBackingStore(true)
#if ENABLE(CSS_FILTERS)
, m_canCompositeFilters(false)
#endif
+ , m_backgroundLayerPaintsFixedRootBackground(false)
+ , m_didSwitchToFullTileCoverageDuringLoading(false)
{
if (layer->isRootLayer()) {
Frame* frame = toRenderView(renderer())->frameView()->frame();
@@ -127,9 +140,13 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer)
TiledBacking* tiledBacking = this->tiledBacking();
if (Page* page = renderer()->frame()->page()) {
Frame* frame = renderer()->frame();
- tiledBacking->setIsInWindow(page->isOnscreen());
+ tiledBacking->setIsInWindow(page->isInWindow());
+
+ if (m_isMainFrameRenderViewLayer)
+ tiledBacking->setUnparentsOffscreenTiles(true);
+
tiledBacking->setScrollingPerformanceLoggingEnabled(frame->settings() && frame->settings()->scrollingPerformanceLoggingEnabled());
- adjustTileCacheCoverage();
+ adjustTiledBackingCoverage();
}
}
}
@@ -139,17 +156,26 @@ RenderLayerBacking::~RenderLayerBacking()
updateClippingLayers(false, false);
updateOverflowControlsLayers(false, false, false);
updateForegroundLayer(false);
+ updateBackgroundLayer(false);
updateMaskLayer(false);
updateScrollingLayers(false);
detachFromScrollingCoordinator();
destroyGraphicsLayers();
}
+void RenderLayerBacking::willDestroyLayer(const GraphicsLayer* layer)
+{
+ if (layer && layer->usingTiledBacking()) {
+ if (RenderLayerCompositor* compositor = this->compositor())
+ compositor->layerTiledBackingUsageChanged(layer, false);
+ }
+}
+
PassOwnPtr<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String& name)
{
GraphicsLayerFactory* graphicsLayerFactory = 0;
if (Page* page = renderer()->frame()->page())
- graphicsLayerFactory = page->chrome()->client()->graphicsLayerFactory();
+ graphicsLayerFactory = page->chrome().client()->graphicsLayerFactory();
OwnPtr<GraphicsLayer> graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, this);
@@ -167,39 +193,61 @@ PassOwnPtr<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String&
return graphicsLayer.release();
}
-bool RenderLayerBacking::shouldUseTileCache(const GraphicsLayer*) const
+bool RenderLayerBacking::shouldUseTiledBacking(const GraphicsLayer*) const
{
return m_usingTiledCacheLayer && m_creatingPrimaryGraphicsLayer;
}
+void RenderLayerBacking::tiledBackingUsageChanged(const GraphicsLayer* layer, bool usingTiledBacking)
+{
+ compositor()->layerTiledBackingUsageChanged(layer, usingTiledBacking);
+}
+
TiledBacking* RenderLayerBacking::tiledBacking() const
{
return m_graphicsLayer->tiledBacking();
}
-void RenderLayerBacking::adjustTileCacheCoverage()
+static TiledBacking::TileCoverage computeTileCoverage(RenderLayerBacking* backing)
{
- if (!m_usingTiledCacheLayer)
- return;
+ // FIXME: When we use TiledBacking for overflow, this should look at RenderView scrollability.
+ Frame* frame = backing->owningLayer()->renderer()->frame();
+ if (!frame)
+ return TiledBacking::CoverageForVisibleArea;
TiledBacking::TileCoverage tileCoverage = TiledBacking::CoverageForVisibleArea;
-
- // FIXME: When we use TiledBacking for overflow, this should look at RenderView scrollability.
- Frame* frame = renderer()->frame();
- if (frame) {
- FrameView* frameView = frame->view();
- if (frameView->horizontalScrollbarMode() != ScrollbarAlwaysOff)
+ FrameView* frameView = frame->view();
+ bool useMinimalTilesDuringLiveResize = frameView->inLiveResize();
+ bool useMinimalTilesDuringLoading = false;
+ // Avoid churn.
+ if (!backing->didSwitchToFullTileCoverageDuringLoading()) {
+ useMinimalTilesDuringLoading = !frameView->isVisuallyNonEmpty() || (frame->page()->progress()->isMainLoadProgressing() && !frameView->wasScrolledByUser());
+ if (!useMinimalTilesDuringLoading)
+ backing->setDidSwitchToFullTileCoverageDuringLoading();
+ }
+ if (!(useMinimalTilesDuringLoading || useMinimalTilesDuringLiveResize)) {
+ bool clipsToExposedRect = backing->tiledBacking()->clipsToExposedRect();
+ if (frameView->horizontalScrollbarMode() != ScrollbarAlwaysOff || clipsToExposedRect)
tileCoverage |= TiledBacking::CoverageForHorizontalScrolling;
- if (frameView->verticalScrollbarMode() != ScrollbarAlwaysOff)
+ if (frameView->verticalScrollbarMode() != ScrollbarAlwaysOff || clipsToExposedRect)
tileCoverage |= TiledBacking::CoverageForVerticalScrolling;
-
- if (ScrollingCoordinator* scrollingCoordinator = frame->page()->scrollingCoordinator()) {
- if (scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread())
- tileCoverage |= TiledBacking::CoverageForSlowScrolling;
- }
}
+ if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(backing->owningLayer())) {
+ // Ask our TiledBacking for large tiles unless the only reason we're main-thread-scrolling
+ // is a page overlay (find-in-page, the Web Inspector highlight mechanism, etc.).
+ if (scrollingCoordinator->mainThreadScrollingReasons() & ~ScrollingCoordinator::ForcedOnMainThread)
+ tileCoverage |= TiledBacking::CoverageForSlowScrolling;
+ }
+ return tileCoverage;
+}
+
+void RenderLayerBacking::adjustTiledBackingCoverage()
+{
+ if (!m_usingTiledCacheLayer)
+ return;
+ TiledBacking::TileCoverage tileCoverage = computeTileCoverage(this);
tiledBacking()->setTileCoverage(tileCoverage);
}
@@ -215,6 +263,14 @@ void RenderLayerBacking::updateDebugIndicators(bool showBorder, bool showRepaint
m_foregroundLayer->setShowDebugBorder(showBorder);
m_foregroundLayer->setShowRepaintCounter(showRepaintCounter);
}
+
+ if (m_contentsContainmentLayer)
+ m_contentsContainmentLayer->setShowDebugBorder(showBorder);
+
+ if (m_backgroundLayer) {
+ m_backgroundLayer->setShowDebugBorder(showBorder);
+ m_backgroundLayer->setShowRepaintCounter(showRepaintCounter);
+ }
if (m_maskLayer) {
m_maskLayer->setShowDebugBorder(showBorder);
@@ -243,11 +299,11 @@ void RenderLayerBacking::createPrimaryGraphicsLayer()
{
String layerName;
#ifndef NDEBUG
- layerName = nameForLayer();
+ layerName = m_owningLayer->name();
#endif
// The call to createGraphicsLayer ends calling back into here as
- // a GraphicsLayerClient to ask if it shouldUseTileCache(). We only want
+ // a GraphicsLayerClient to ask if it shouldUseTiledBacking(). We only want
// the tile cache on our main layer. This is pretty ugly, but saves us from
// exposing the API to all clients.
@@ -256,14 +312,10 @@ void RenderLayerBacking::createPrimaryGraphicsLayer()
m_creatingPrimaryGraphicsLayer = false;
if (m_usingTiledCacheLayer)
- m_containmentLayer = createGraphicsLayer("TileCache Flattening Layer");
+ m_childContainmentLayer = createGraphicsLayer("TiledBacking Flattening Layer");
if (m_isMainFrameRenderViewLayer) {
- bool isTransparent = false;
- if (FrameView* frameView = toRenderView(renderer())->frameView())
- isTransparent = frameView->isTransparent();
-
- m_graphicsLayer->setContentsOpaque(!isTransparent);
+ m_graphicsLayer->setContentsOpaque(true);
m_graphicsLayer->setAppliesPageScale();
}
@@ -287,12 +339,17 @@ void RenderLayerBacking::createPrimaryGraphicsLayer()
void RenderLayerBacking::destroyGraphicsLayers()
{
- if (m_graphicsLayer)
+ if (m_graphicsLayer) {
+ willDestroyLayer(m_graphicsLayer.get());
m_graphicsLayer->removeFromParent();
+ }
+ m_ancestorClippingLayer = nullptr;
+ m_contentsContainmentLayer = nullptr;
m_graphicsLayer = nullptr;
m_foregroundLayer = nullptr;
- m_containmentLayer = nullptr;
+ m_backgroundLayer = nullptr;
+ m_childContainmentLayer = nullptr;
m_maskLayer = nullptr;
m_scrollingLayer = nullptr;
@@ -314,7 +371,11 @@ void RenderLayerBacking::updateTransform(const RenderStyle* style)
makeMatrixRenderable(t, compositor()->canRender3DTransforms());
}
- m_graphicsLayer->setTransform(t);
+ if (m_contentsContainmentLayer) {
+ m_contentsContainmentLayer->setTransform(t);
+ m_graphicsLayer->setTransform(TransformationMatrix());
+ } else
+ m_graphicsLayer->setTransform(t);
}
#if ENABLE(CSS_FILTERS)
@@ -340,7 +401,7 @@ static bool hasNonZeroTransformOrigin(const RenderObject* renderer)
static bool layerOrAncestorIsTransformedOrUsingCompositedScrolling(RenderLayer* layer)
{
for (RenderLayer* curr = layer; curr; curr = curr->parent()) {
- if (curr->hasTransform() || curr->usesCompositedScrolling())
+ if (curr->hasTransform() || curr->needsCompositedScrolling())
return true;
}
@@ -354,9 +415,6 @@ bool RenderLayerBacking::shouldClipCompositedBounds() const
return false;
if (m_usingTiledCacheLayer)
- return true;
-
- if (!compositor()->compositingConsultsOverlap())
return false;
if (layerOrAncestorIsTransformedOrUsingCompositedScrolling(m_owningLayer))
@@ -365,10 +423,9 @@ bool RenderLayerBacking::shouldClipCompositedBounds() const
return true;
}
-
void RenderLayerBacking::updateCompositedBounds()
{
- IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
+ LayoutRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
// Clip to the size of the document or enclosing overflow-scroll layer.
// If this or an ancestor is transformed, we can't currently compute the correct rect to intersect with.
@@ -377,18 +434,23 @@ void RenderLayerBacking::updateCompositedBounds()
RenderView* view = m_owningLayer->renderer()->view();
RenderLayer* rootLayer = view->layer();
- // Start by clipping to the view's bounds.
- LayoutRect clippingBounds = view->unscaledDocumentRect();
+ LayoutRect clippingBounds;
+ if (renderer()->style()->position() == FixedPosition && renderer()->container() == view)
+ clippingBounds = view->frameView()->viewportConstrainedVisibleContentRect();
+ else
+ clippingBounds = view->unscaledDocumentRect();
if (m_owningLayer != rootLayer)
clippingBounds.intersect(m_owningLayer->backgroundClipRect(RenderLayer::ClipRectsContext(rootLayer, 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions.
LayoutPoint delta;
- m_owningLayer->convertToLayerCoords(rootLayer, delta);
+ m_owningLayer->convertToLayerCoords(rootLayer, delta, RenderLayer::AdjustForColumns);
clippingBounds.move(-delta.x(), -delta.y());
- layerBounds.intersect(pixelSnappedIntRect(clippingBounds));
- }
+ layerBounds.intersect(clippingBounds);
+ m_boundsConstrainedByClipping = true;
+ } else
+ m_boundsConstrainedByClipping = false;
// If the element has a transform-origin that has fixed lengths, and the renderer has zero size,
// then we need to ensure that the compositing layer has non-zero size so that we can apply
@@ -408,12 +470,12 @@ void RenderLayerBacking::updateAfterWidgetResize()
if (renderer()->isRenderPart()) {
if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::frameContentsCompositor(toRenderPart(renderer()))) {
innerCompositor->frameViewDidChangeSize();
- innerCompositor->frameViewDidChangeLocation(contentsBox().location());
+ innerCompositor->frameViewDidChangeLocation(flooredIntPoint(contentsBox().location()));
}
}
}
-void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth, bool isUpdateRoot)
+void RenderLayerBacking::updateAfterLayout(UpdateAfterLayoutFlags flags)
{
RenderLayerCompositor* layerCompositor = compositor();
if (!layerCompositor->compositingLayersNeedRebuild()) {
@@ -425,13 +487,19 @@ void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth, bool isUpdat
// The solution is to update compositing children of this layer here,
// via updateCompositingChildrenGeometry().
updateCompositedBounds();
- layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, updateDepth);
+ layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, flags & CompositingChildrenOnly);
- if (isUpdateRoot) {
+ if (flags & IsUpdateRoot) {
updateGraphicsLayerGeometry();
layerCompositor->updateRootLayerPosition();
+ RenderLayer* stackingContainer = m_owningLayer->enclosingStackingContainer();
+ if (!layerCompositor->compositingLayersNeedRebuild() && stackingContainer && (stackingContainer != m_owningLayer))
+ layerCompositor->updateCompositingDescendantGeometry(stackingContainer, stackingContainer, flags & CompositingChildrenOnly);
}
}
+
+ if (flags & NeedsFullRepaint && !paintsIntoWindow() && !paintsIntoCompositedAncestor())
+ setContentsNeedDisplay();
}
bool RenderLayerBacking::updateGraphicsLayerConfiguration()
@@ -439,16 +507,23 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
RenderLayerCompositor* compositor = this->compositor();
RenderObject* renderer = this->renderer();
+ m_owningLayer->updateDescendantDependentFlags();
m_owningLayer->updateZOrderLists();
bool layerConfigChanged = false;
+ setBackgroundLayerPaintsFixedRootBackground(compositor->needsFixedRootBackgroundLayer(m_owningLayer));
+
+ // The background layer is currently only used for fixed root backgrounds.
+ if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground))
+ layerConfigChanged = true;
+
if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer)))
layerConfigChanged = true;
bool needsDescendentsClippingLayer = compositor->clipsCompositingDescendants(m_owningLayer);
// Our scrolling layer will clip.
- if (m_owningLayer->usesCompositedScrolling())
+ if (m_owningLayer->needsCompositedScrolling())
needsDescendentsClippingLayer = false;
if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), needsDescendentsClippingLayer))
@@ -457,7 +532,7 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer()))
layerConfigChanged = true;
- if (updateScrollingLayers(m_owningLayer->usesCompositedScrolling()))
+ if (updateScrollingLayers(m_owningLayer->needsCompositedScrolling()))
layerConfigChanged = true;
if (layerConfigChanged)
@@ -479,16 +554,23 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
} else
m_graphicsLayer->setReplicatedByLayer(0);
+ bool isSimpleContainer = isSimpleContainerCompositingLayer();
+ bool didUpdateContentsRect = false;
+ updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
+
+ updateRootLayerConfiguration();
+
if (isDirectlyCompositedImage())
updateImageContents();
if (renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing()) {
- PluginViewBase* pluginViewBase = static_cast<PluginViewBase*>(toRenderWidget(renderer)->widget());
- m_graphicsLayer->setContentsToMedia(pluginViewBase->platformLayer());
+ PluginViewBase* pluginViewBase = toPluginViewBase(toRenderWidget(renderer)->widget());
+ if (!pluginViewBase->shouldNotAddLayer())
+ m_graphicsLayer->setContentsToMedia(pluginViewBase->platformLayer());
}
#if ENABLE(VIDEO)
else if (renderer->isVideo()) {
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(renderer->node());
+ HTMLMediaElement* mediaElement = toHTMLMediaElement(renderer->node());
m_graphicsLayer->setContentsToMedia(mediaElement->platformLayer());
}
#endif
@@ -500,19 +582,6 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
layerConfigChanged = true;
}
#endif
-#if ENABLE(FULLSCREEN_API)
- else if (renderer->isRenderFullScreen()) {
- // RenderFullScreen renderers have no content, and only a solid
- // background color. They also can be large enough to trigger the
- // creation of a tiled-layer, which can cause flashing problems
- // during repainting. Special case the RenderFullScreen case because
- // we know its style does not come from CSS and it is therefore will
- // not contain paintable content (e.g. background images, gradients,
- // etc), so safe to set the layer's background color to the renderer's
- // style's background color.
- updateBackgroundColor();
- }
-#endif
if (renderer->isRenderPart())
layerConfigChanged = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(renderer));
@@ -534,7 +603,7 @@ static IntRect clipBox(RenderBox* renderer)
void RenderLayerBacking::updateGraphicsLayerGeometry()
{
// If we haven't built z-order lists yet, wait until later.
- if (m_owningLayer->isStackingContext() && m_owningLayer->m_zOrderListsDirty)
+ if (m_owningLayer->isStackingContainer() && m_owningLayer->m_zOrderListsDirty)
return;
// Set transform property, if it is not animating. We have to do this here because the transform
@@ -553,6 +622,8 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
#if ENABLE(CSS_COMPOSITING)
updateLayerBlendMode(renderer()->style());
#endif
+
+ bool isSimpleContainer = isSimpleContainerCompositingLayer();
m_owningLayer->updateDescendantDependentFlags();
@@ -562,26 +633,11 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
m_graphicsLayer->setContentsVisible(m_owningLayer->hasVisibleContent() || hasVisibleNonCompositingDescendantLayers());
RenderStyle* style = renderer()->style();
- m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection());
+ // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959
+ bool preserves3D = style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection();
+ m_graphicsLayer->setPreserves3D(preserves3D);
m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible);
- // Register fixed position layers and their containers with the scrolling coordinator.
- if (Page* page = renderer()->frame()->page()) {
- if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) {
- if (style->position() == FixedPosition || compositor()->fixedPositionedByAncestor(m_owningLayer))
- scrollingCoordinator->setLayerIsFixedToContainerLayer(childForSuperlayers(), true);
- else {
- if (m_ancestorClippingLayer)
- scrollingCoordinator->setLayerIsFixedToContainerLayer(m_ancestorClippingLayer.get(), false);
- scrollingCoordinator->setLayerIsFixedToContainerLayer(m_graphicsLayer.get(), false);
- }
- // Page scale is applied as a transform on the root render view layer. Because the scroll
- // layer is further up in the hierarchy, we need to avoid marking the root render view
- // layer as a container.
- bool isContainer = m_owningLayer->hasTransform() && !m_owningLayer->isRootLayer();
- scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(childForSuperlayers(), isContainer);
- }
- }
RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer();
// We compute everything relative to the enclosing compositing layer.
@@ -591,11 +647,16 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
ancestorCompositingBounds = pixelSnappedIntRect(compAncestor->backing()->compositedBounds());
}
- IntRect localCompositingBounds = pixelSnappedIntRect(compositedBounds());
+ LayoutRect localRawCompositingBounds = compositedBounds();
+ LayoutPoint rawDelta;
+ m_owningLayer->convertToLayerCoords(compAncestor, rawDelta, RenderLayer::AdjustForColumns);
+ IntPoint delta = flooredIntPoint(rawDelta);
+ m_subpixelAccumulation = toLayoutSize(rawDelta.fraction());
+ // Move the bounds by the subpixel accumulation so that it pixel-snaps relative to absolute pixels instead of local coordinates.
+ localRawCompositingBounds.move(m_subpixelAccumulation);
+ IntRect localCompositingBounds = pixelSnappedIntRect(localRawCompositingBounds);
IntRect relativeCompositingBounds(localCompositingBounds);
- IntPoint delta;
- m_owningLayer->convertToPixelSnappedLayerCoords(compAncestor, delta);
relativeCompositingBounds.moveBy(delta);
IntPoint graphicsLayerParentLocation;
@@ -609,7 +670,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
else
graphicsLayerParentLocation = renderer()->view()->documentRect().location();
- if (compAncestor && compAncestor->usesCompositedScrolling()) {
+ if (compAncestor && compAncestor->needsCompositedScrolling()) {
RenderBox* renderBox = toRenderBox(compAncestor->renderer());
IntSize scrollOffset = compAncestor->scrolledContentOffset();
IntPoint scrollOrigin(renderBox->borderLeft(), renderBox->borderTop());
@@ -620,10 +681,10 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
// Call calculateRects to get the backgroundRect which is what is used to clip the contents of this
// layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects
// for a compositing layer, rootLayer is the layer itself.
- RenderLayer::ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, RenderLayer::IgnoreOverflowClip);
+ RenderLayer::ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, IgnoreOverflowClip);
IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(clipRectsContext).rect()); // FIXME: Incorrect for CSS regions.
ASSERT(parentClipRect != PaintInfo::infiniteRect());
- m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation));
+ m_ancestorClippingLayer->setPosition(FloatPoint(parentClipRect.location() - graphicsLayerParentLocation));
m_ancestorClippingLayer->setSize(parentClipRect.size());
// backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords.
@@ -633,26 +694,41 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
graphicsLayerParentLocation = parentClipRect.location();
}
- m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation));
- m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint());
+ FloatSize contentsSize = relativeCompositingBounds.size();
+ if (m_contentsContainmentLayer) {
+ m_contentsContainmentLayer->setPreserves3D(preserves3D);
+ m_contentsContainmentLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation));
+ // Use the same size as m_graphicsLayer so transforms behave correctly.
+ m_contentsContainmentLayer->setSize(contentsSize);
+ graphicsLayerParentLocation = relativeCompositingBounds.location();
+ }
+
+ m_graphicsLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation));
+ m_graphicsLayer->setOffsetFromRenderer(toIntSize(localCompositingBounds.location()));
+
FloatSize oldSize = m_graphicsLayer->size();
- FloatSize newSize = relativeCompositingBounds.size();
- if (oldSize != newSize) {
- m_graphicsLayer->setSize(newSize);
- // A bounds change will almost always require redisplay. Usually that redisplay
- // will happen because of a repaint elsewhere, but not always:
- // e.g. see RenderView::setMaximalOutlineSize()
- m_graphicsLayer->setNeedsDisplay();
+ if (oldSize != contentsSize) {
+ m_graphicsLayer->setSize(contentsSize);
+ // Usually invalidation will happen via layout etc, but if we've affected the layer
+ // size by constraining relative to a clipping ancestor or the viewport, we
+ // have to invalidate to avoid showing stretched content.
+ if (m_boundsConstrainedByClipping)
+ m_graphicsLayer->setNeedsDisplay();
+ }
+ if (!m_isMainFrameRenderViewLayer) {
+ // For non-root layers, background is always painted by the primary graphics layer.
+ ASSERT(!m_backgroundLayer);
+ m_graphicsLayer->setContentsOpaque(m_owningLayer->backgroundIsKnownToBeOpaqueInRect(localCompositingBounds));
}
// If we have a layer that clips children, position it.
IntRect clippingBox;
if (GraphicsLayer* clipLayer = clippingLayer()) {
clippingBox = clipBox(toRenderBox(renderer()));
- clipLayer->setPosition(FloatPoint() + (clippingBox.location() - localCompositingBounds.location()));
+ clipLayer->setPosition(FloatPoint(clippingBox.location() - localCompositingBounds.location()));
clipLayer->setSize(clippingBox.size());
- clipLayer->setOffsetFromRenderer(clippingBox.location() - IntPoint());
+ clipLayer->setOffsetFromRenderer(toIntSize(clippingBox.location()));
}
if (m_maskLayer) {
@@ -668,7 +744,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect();
// Get layout bounds in the coords of compAncestor to match relativeCompositingBounds.
- IntRect layerBounds = IntRect(delta, borderBox.size());
+ IntRect layerBounds(delta, borderBox.size());
// Update properties that depend on layer dimensions
FloatPoint3D transformOrigin = computeTransformOrigin(borderBox);
@@ -676,7 +752,10 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
FloatPoint3D anchor(relativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width() : 0.5f,
relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f,
transformOrigin.z());
- m_graphicsLayer->setAnchorPoint(anchor);
+ if (m_contentsContainmentLayer)
+ m_contentsContainmentLayer->setAnchorPoint(anchor);
+ else
+ m_graphicsLayer->setAnchorPoint(anchor);
RenderStyle* style = renderer()->style();
GraphicsLayer* clipLayer = clippingLayer();
@@ -697,17 +776,19 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
}
} else {
m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0));
+ if (m_contentsContainmentLayer)
+ m_contentsContainmentLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0));
}
if (m_foregroundLayer) {
FloatPoint foregroundPosition;
- FloatSize foregroundSize = newSize;
+ FloatSize foregroundSize = contentsSize;
IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer();
if (hasClippingLayer()) {
// If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
// so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
foregroundSize = FloatSize(clippingBox.size());
- foregroundOffset = clippingBox.location() - IntPoint();
+ foregroundOffset = toIntSize(clippingBox.location());
}
m_foregroundLayer->setPosition(foregroundPosition);
@@ -718,6 +799,22 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
m_foregroundLayer->setOffsetFromRenderer(foregroundOffset);
}
+ if (m_backgroundLayer) {
+ FloatPoint backgroundPosition;
+ FloatSize backgroundSize = contentsSize;
+ if (backgroundLayerPaintsFixedRootBackground()) {
+ FrameView* frameView = toRenderView(renderer())->frameView();
+ backgroundPosition = IntPoint(frameView->scrollOffsetForFixedPosition());
+ backgroundSize = frameView->visibleContentRect().size();
+ }
+ m_backgroundLayer->setPosition(backgroundPosition);
+ if (backgroundSize != m_backgroundLayer->size()) {
+ m_backgroundLayer->setSize(backgroundSize);
+ m_backgroundLayer->setNeedsDisplay();
+ }
+ m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
+ }
+
if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) {
RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing();
reflectionBacking->updateGraphicsLayerGeometry();
@@ -726,22 +823,22 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
// but the reflected layer is the bounds of this layer, so we need to position it appropriately.
FloatRect layerBounds = compositedBounds();
FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds();
- reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location()));
+ reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint(layerBounds.location() - reflectionLayerBounds.location()));
}
if (m_scrollingLayer) {
ASSERT(m_scrollingContentsLayer);
RenderBox* renderBox = toRenderBox(renderer());
IntRect paddingBox(renderBox->borderLeft(), renderBox->borderTop(), renderBox->width() - renderBox->borderLeft() - renderBox->borderRight(), renderBox->height() - renderBox->borderTop() - renderBox->borderBottom());
- IntSize scrollOffset = m_owningLayer->scrolledContentOffset();
+ IntSize scrollOffset = m_owningLayer->scrollOffset();
- m_scrollingLayer->setPosition(FloatPoint() + (paddingBox.location() - localCompositingBounds.location()));
+ m_scrollingLayer->setPosition(FloatPoint(paddingBox.location() - localCompositingBounds.location()));
m_scrollingLayer->setSize(paddingBox.size());
m_scrollingContentsLayer->setPosition(FloatPoint(-scrollOffset.width(), -scrollOffset.height()));
IntSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer();
- m_scrollingLayer->setOffsetFromRenderer(IntPoint() - paddingBox.location());
+ m_scrollingLayer->setOffsetFromRenderer(-toIntSize(paddingBox.location()));
bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer();
@@ -749,41 +846,96 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
if (scrollSize != m_scrollingContentsLayer->size() || paddingBoxOffsetChanged)
m_scrollingContentsLayer->setNeedsDisplay();
- IntSize scrollingContentsOffset = paddingBox.location() - IntPoint() - scrollOffset;
+ IntSize scrollingContentsOffset = toIntSize(paddingBox.location() - scrollOffset);
if (scrollingContentsOffset != m_scrollingContentsLayer->offsetFromRenderer() || scrollSize != m_scrollingContentsLayer->size())
compositor()->scrollingLayerDidChange(m_owningLayer);
m_scrollingContentsLayer->setSize(scrollSize);
// FIXME: The paint offset and the scroll offset should really be separate concepts.
m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset, GraphicsLayer::DontSetNeedsDisplay);
- }
- m_graphicsLayer->setContentsRect(contentsBox());
+ if (m_foregroundLayer) {
+ if (m_foregroundLayer->size() != m_scrollingContentsLayer->size())
+ m_foregroundLayer->setSize(m_scrollingContentsLayer->size());
+ m_foregroundLayer->setNeedsDisplay();
+ m_foregroundLayer->setOffsetFromRenderer(m_scrollingContentsLayer->offsetFromRenderer());
+ }
+ }
// If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
- setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor));
+ setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor, relativeCompositingBounds, ancestorCompositingBounds));
+
+ bool didUpdateContentsRect = false;
+ updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
+ if (!didUpdateContentsRect && m_graphicsLayer->hasContentsLayer())
+ resetContentsRect();
- updateDrawsContent();
+ updateDrawsContent(isSimpleContainer);
updateAfterWidgetResize();
+ registerScrollingLayers();
+}
+
+void RenderLayerBacking::updateDirectlyCompositedContents(bool isSimpleContainer, bool& didUpdateContentsRect)
+{
+ if (!m_owningLayer->hasVisibleContent())
+ return;
+
+ // The order of operations here matters, since the last valid type of contents needs
+ // to also update the contentsRect.
+ updateDirectlyCompositedBackgroundColor(isSimpleContainer, didUpdateContentsRect);
+ updateDirectlyCompositedBackgroundImage(isSimpleContainer, didUpdateContentsRect);
+}
+
+void RenderLayerBacking::registerScrollingLayers()
+{
+ // Register fixed position layers and their containers with the scrolling coordinator.
+ ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer);
+ if (!scrollingCoordinator)
+ return;
+
+ compositor()->updateViewportConstraintStatus(m_owningLayer);
+
+ if (!scrollingCoordinator->supportsFixedPositionLayers())
+ return;
+
+ scrollingCoordinator->updateLayerPositionConstraint(m_owningLayer);
+
+ // Page scale is applied as a transform on the root render view layer. Because the scroll
+ // layer is further up in the hierarchy, we need to avoid marking the root render view
+ // layer as a container.
+ bool isContainer = m_owningLayer->hasTransform() && !m_owningLayer->isRootLayer();
+ scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(childForSuperlayers(), isContainer);
}
void RenderLayerBacking::updateInternalHierarchy()
{
// m_foregroundLayer has to be inserted in the correct order with child layers,
// so it's not inserted here.
- if (m_ancestorClippingLayer) {
+ if (m_ancestorClippingLayer)
m_ancestorClippingLayer->removeAllChildren();
- m_graphicsLayer->removeFromParent();
- m_ancestorClippingLayer->addChild(m_graphicsLayer.get());
+
+ if (m_contentsContainmentLayer) {
+ m_contentsContainmentLayer->removeAllChildren();
+ if (m_ancestorClippingLayer)
+ m_ancestorClippingLayer->addChild(m_contentsContainmentLayer.get());
}
+
+ if (m_backgroundLayer)
+ m_contentsContainmentLayer->addChild(m_backgroundLayer.get());
- if (m_containmentLayer) {
- m_containmentLayer->removeFromParent();
- m_graphicsLayer->addChild(m_containmentLayer.get());
+ m_graphicsLayer->removeFromParent();
+ if (m_contentsContainmentLayer)
+ m_contentsContainmentLayer->addChild(m_graphicsLayer.get());
+ else if (m_ancestorClippingLayer)
+ m_ancestorClippingLayer->addChild(m_graphicsLayer.get());
+
+ if (m_childContainmentLayer) {
+ m_childContainmentLayer->removeFromParent();
+ m_graphicsLayer->addChild(m_childContainmentLayer.get());
}
if (m_scrollingLayer) {
- GraphicsLayer* superlayer = m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get();
+ GraphicsLayer* superlayer = m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get();
m_scrollingLayer->removeFromParent();
superlayer->addChild(m_scrollingLayer.get());
}
@@ -805,14 +957,27 @@ void RenderLayerBacking::updateInternalHierarchy()
}
}
+void RenderLayerBacking::resetContentsRect()
+{
+ IntRect rect = pixelSnappedIntRect(contentsBox());
+ m_graphicsLayer->setContentsRect(rect);
+ m_graphicsLayer->setContentsTileSize(IntSize());
+ m_graphicsLayer->setContentsTilePhase(IntPoint());
+}
+
void RenderLayerBacking::updateDrawsContent()
{
+ updateDrawsContent(isSimpleContainerCompositingLayer());
+}
+
+void RenderLayerBacking::updateDrawsContent(bool isSimpleContainer)
+{
if (m_scrollingLayer) {
// We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere.
// m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint.
// m_scrollingLayer never has backing store.
// m_scrollingContentsLayer only needs backing store if the scrolled contents need to paint.
- bool hasNonScrollingPaintedContent = m_owningLayer->hasVisibleContent() && hasBoxDecorationsOrBackground(renderer());
+ bool hasNonScrollingPaintedContent = m_owningLayer->hasVisibleContent() && m_owningLayer->hasBoxDecorationsOrBackground();
m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent);
bool hasScrollingPaintedContent = m_owningLayer->hasVisibleContent() && (renderer()->hasBackground() || paintsChildren());
@@ -820,12 +985,15 @@ void RenderLayerBacking::updateDrawsContent()
return;
}
- bool hasPaintedContent = containsPaintedContent();
+ bool hasPaintedContent = containsPaintedContent(isSimpleContainer);
// FIXME: we could refine this to only allocate backing for one of these layers if possible.
m_graphicsLayer->setDrawsContent(hasPaintedContent);
if (m_foregroundLayer)
m_foregroundLayer->setDrawsContent(hasPaintedContent);
+
+ if (m_backgroundLayer)
+ m_backgroundLayer->setDrawsContent(hasPaintedContent);
}
// Return true if the layers changed.
@@ -840,87 +1008,100 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs
layersChanged = true;
}
} else if (m_ancestorClippingLayer) {
+ willDestroyLayer(m_ancestorClippingLayer.get());
m_ancestorClippingLayer->removeFromParent();
m_ancestorClippingLayer = nullptr;
layersChanged = true;
}
if (needsDescendantClip) {
- if (!m_containmentLayer && !m_usingTiledCacheLayer) {
- m_containmentLayer = createGraphicsLayer("Child clipping Layer");
- m_containmentLayer->setMasksToBounds(true);
+ if (!m_childContainmentLayer && !m_usingTiledCacheLayer) {
+ m_childContainmentLayer = createGraphicsLayer("Child clipping Layer");
+ m_childContainmentLayer->setMasksToBounds(true);
layersChanged = true;
}
} else if (hasClippingLayer()) {
- m_containmentLayer->removeFromParent();
- m_containmentLayer = nullptr;
+ willDestroyLayer(m_childContainmentLayer.get());
+ m_childContainmentLayer->removeFromParent();
+ m_childContainmentLayer = nullptr;
layersChanged = true;
}
return layersChanged;
}
+void RenderLayerBacking::setBackgroundLayerPaintsFixedRootBackground(bool backgroundLayerPaintsFixedRootBackground)
+{
+ m_backgroundLayerPaintsFixedRootBackground = backgroundLayerPaintsFixedRootBackground;
+}
+
bool RenderLayerBacking::requiresHorizontalScrollbarLayer() const
{
-#if !PLATFORM(CHROMIUM)
- if (!m_owningLayer->hasOverlayScrollbars())
+ if (!m_owningLayer->hasOverlayScrollbars() && !m_owningLayer->needsCompositedScrolling())
return false;
-#endif
return m_owningLayer->horizontalScrollbar();
}
bool RenderLayerBacking::requiresVerticalScrollbarLayer() const
{
-#if !PLATFORM(CHROMIUM)
- if (!m_owningLayer->hasOverlayScrollbars())
+ if (!m_owningLayer->hasOverlayScrollbars() && !m_owningLayer->needsCompositedScrolling())
return false;
-#endif
return m_owningLayer->verticalScrollbar();
}
bool RenderLayerBacking::requiresScrollCornerLayer() const
{
-#if !PLATFORM(CHROMIUM)
- if (!m_owningLayer->hasOverlayScrollbars())
+ if (!m_owningLayer->hasOverlayScrollbars() && !m_owningLayer->needsCompositedScrolling())
return false;
-#endif
return !m_owningLayer->scrollCornerAndResizerRect().isEmpty();
}
bool RenderLayerBacking::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer)
{
- bool layersChanged = false;
+ bool horizontalScrollbarLayerChanged = false;
if (needsHorizontalScrollbarLayer) {
if (!m_layerForHorizontalScrollbar) {
m_layerForHorizontalScrollbar = createGraphicsLayer("horizontal scrollbar");
- layersChanged = true;
+ horizontalScrollbarLayerChanged = true;
}
} else if (m_layerForHorizontalScrollbar) {
- m_layerForHorizontalScrollbar.clear();
- layersChanged = true;
+ willDestroyLayer(m_layerForHorizontalScrollbar.get());
+ m_layerForHorizontalScrollbar = nullptr;
+ horizontalScrollbarLayerChanged = true;
}
+ bool verticalScrollbarLayerChanged = false;
if (needsVerticalScrollbarLayer) {
if (!m_layerForVerticalScrollbar) {
m_layerForVerticalScrollbar = createGraphicsLayer("vertical scrollbar");
- layersChanged = true;
+ verticalScrollbarLayerChanged = true;
}
} else if (m_layerForVerticalScrollbar) {
- m_layerForVerticalScrollbar.clear();
- layersChanged = true;
+ willDestroyLayer(m_layerForVerticalScrollbar.get());
+ m_layerForVerticalScrollbar = nullptr;
+ verticalScrollbarLayerChanged = true;
}
+ bool scrollCornerLayerChanged = false;
if (needsScrollCornerLayer) {
if (!m_layerForScrollCorner) {
m_layerForScrollCorner = createGraphicsLayer("scroll corner");
- layersChanged = true;
+ scrollCornerLayerChanged = true;
}
} else if (m_layerForScrollCorner) {
- m_layerForScrollCorner.clear();
- layersChanged = true;
+ willDestroyLayer(m_layerForScrollCorner.get());
+ m_layerForScrollCorner = nullptr;
+ scrollCornerLayerChanged = true;
}
- return layersChanged;
+ if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) {
+ if (horizontalScrollbarLayerChanged)
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer, HorizontalScrollbar);
+ if (verticalScrollbarLayerChanged)
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer, VerticalScrollbar);
+ }
+
+ return horizontalScrollbarLayerChanged || verticalScrollbarLayerChanged || scrollCornerLayerChanged;
}
void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFromRoot)
@@ -931,8 +1112,10 @@ void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFro
if (hBar) {
layer->setPosition(hBar->frameRect().location() - offsetFromRoot - offsetFromRenderer);
layer->setSize(hBar->frameRect().size());
+ if (layer->hasContentsLayer())
+ layer->setContentsRect(IntRect(IntPoint(), hBar->frameRect().size()));
}
- layer->setDrawsContent(hBar);
+ layer->setDrawsContent(hBar && !layer->hasContentsLayer());
}
if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
@@ -940,8 +1123,10 @@ void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFro
if (vBar) {
layer->setPosition(vBar->frameRect().location() - offsetFromRoot - offsetFromRenderer);
layer->setSize(vBar->frameRect().size());
+ if (layer->hasContentsLayer())
+ layer->setContentsRect(IntRect(IntPoint(), vBar->frameRect().size()));
}
- layer->setDrawsContent(vBar);
+ layer->setDrawsContent(vBar && !layer->hasContentsLayer());
}
if (GraphicsLayer* layer = layerForScrollCorner()) {
@@ -952,6 +1137,23 @@ void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFro
}
}
+bool RenderLayerBacking::hasUnpositionedOverflowControlsLayers() const
+{
+ if (GraphicsLayer* layer = layerForHorizontalScrollbar())
+ if (!layer->drawsContent())
+ return true;
+
+ if (GraphicsLayer* layer = layerForVerticalScrollbar())
+ if (!layer->drawsContent())
+ return true;
+
+ if (GraphicsLayer* layer = layerForScrollCorner())
+ if (!layer->drawsContent())
+ return true;
+
+ return false;
+}
+
bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
{
bool layerChanged = false;
@@ -959,7 +1161,7 @@ bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
if (!m_foregroundLayer) {
String layerName;
#ifndef NDEBUG
- layerName = nameForLayer() + " (foreground)";
+ layerName = m_owningLayer->name() + " (foreground)";
#endif
m_foregroundLayer = createGraphicsLayer(layerName);
m_foregroundLayer->setDrawsContent(true);
@@ -967,17 +1169,72 @@ bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
layerChanged = true;
}
} else if (m_foregroundLayer) {
+ willDestroyLayer(m_foregroundLayer.get());
m_foregroundLayer->removeFromParent();
m_foregroundLayer = nullptr;
layerChanged = true;
}
- if (layerChanged)
+ if (layerChanged) {
+ m_graphicsLayer->setNeedsDisplay();
m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer());
+ }
return layerChanged;
}
+bool RenderLayerBacking::updateBackgroundLayer(bool needsBackgroundLayer)
+{
+ bool layerChanged = false;
+ if (needsBackgroundLayer) {
+ if (!m_backgroundLayer) {
+ String layerName;
+#ifndef NDEBUG
+ layerName = m_owningLayer->name() + " (background)";
+#endif
+ m_backgroundLayer = createGraphicsLayer(layerName);
+ m_backgroundLayer->setDrawsContent(true);
+ m_backgroundLayer->setAnchorPoint(FloatPoint3D());
+ m_backgroundLayer->setPaintingPhase(GraphicsLayerPaintBackground);
+ layerChanged = true;
+ }
+
+ if (!m_contentsContainmentLayer) {
+ String layerName;
+#ifndef NDEBUG
+ layerName = m_owningLayer->name() + " (contents containment)";
+#endif
+ m_contentsContainmentLayer = createGraphicsLayer(layerName);
+ m_contentsContainmentLayer->setAppliesPageScale(true);
+ m_graphicsLayer->setAppliesPageScale(false);
+ layerChanged = true;
+ }
+ } else {
+ if (m_backgroundLayer) {
+ willDestroyLayer(m_backgroundLayer.get());
+ m_backgroundLayer->removeFromParent();
+ m_backgroundLayer = nullptr;
+ layerChanged = true;
+ }
+ if (m_contentsContainmentLayer) {
+ willDestroyLayer(m_contentsContainmentLayer.get());
+ m_contentsContainmentLayer->removeFromParent();
+ m_contentsContainmentLayer = nullptr;
+ layerChanged = true;
+ m_graphicsLayer->setAppliesPageScale(true);
+ }
+ }
+
+ if (layerChanged) {
+ m_graphicsLayer->setNeedsDisplay();
+ // This assumes that the background layer is only used for fixed backgrounds, which is currently a correct assumption.
+ if (renderer()->view())
+ compositor()->fixedRootBackgroundLayerChanged();
+ }
+
+ return layerChanged;
+}
+
bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer)
{
bool layerChanged = false;
@@ -989,6 +1246,7 @@ bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer)
layerChanged = true;
}
} else if (m_maskLayer) {
+ willDestroyLayer(m_maskLayer.get());
m_maskLayer = nullptr;
layerChanged = true;
}
@@ -1001,6 +1259,8 @@ bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer)
bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers)
{
+ ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer);
+
bool layerChanged = false;
if (needsScrollingLayers) {
if (!m_scrollingLayer) {
@@ -1012,15 +1272,24 @@ bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers)
// Inner layer which renders the content that scrolls.
m_scrollingContentsLayer = createGraphicsLayer("Scrolled Contents");
m_scrollingContentsLayer->setDrawsContent(true);
- m_scrollingContentsLayer->setPaintingPhase(GraphicsLayerPaintForeground | GraphicsLayerPaintOverflowContents);
+ GraphicsLayerPaintingPhase paintPhase = GraphicsLayerPaintOverflowContents | GraphicsLayerPaintCompositedScroll;
+ if (!m_foregroundLayer)
+ paintPhase |= GraphicsLayerPaintForeground;
+ m_scrollingContentsLayer->setPaintingPhase(paintPhase);
m_scrollingLayer->addChild(m_scrollingContentsLayer.get());
layerChanged = true;
+ if (scrollingCoordinator)
+ scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer);
}
} else if (m_scrollingLayer) {
+ willDestroyLayer(m_scrollingLayer.get());
+ willDestroyLayer(m_scrollingContentsLayer.get());
m_scrollingLayer = nullptr;
m_scrollingContentsLayer = nullptr;
layerChanged = true;
+ if (scrollingCoordinator)
+ scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer);
}
if (layerChanged) {
@@ -1034,17 +1303,9 @@ bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers)
return layerChanged;
}
-void RenderLayerBacking::attachToScrollingCoordinator(RenderLayerBacking* parent)
+void RenderLayerBacking::attachToScrollingCoordinatorWithParent(RenderLayerBacking* parent)
{
- // If m_scrollLayerID non-zero, then this backing is already attached to the ScrollingCoordinator.
- if (m_scrollLayerID)
- return;
-
- Page* page = renderer()->frame()->page();
- if (!page)
- return;
-
- ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
+ ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer);
if (!scrollingCoordinator)
return;
@@ -1053,11 +1314,13 @@ void RenderLayerBacking::attachToScrollingCoordinator(RenderLayerBacking* parent
ScrollingNodeType nodeType;
if (renderer()->style()->position() == FixedPosition)
nodeType = FixedNode;
+ else if (renderer()->style()->position() == StickyPosition)
+ nodeType = StickyNode;
else
nodeType = ScrollingNode;
ScrollingNodeID parentID = parent ? parent->scrollLayerID() : 0;
- m_scrollLayerID = scrollingCoordinator->attachToStateTree(nodeType, scrollingCoordinator->uniqueScrollLayerID(), parentID);
+ m_scrollLayerID = scrollingCoordinator->attachToStateTree(nodeType, m_scrollLayerID ? m_scrollLayerID : scrollingCoordinator->uniqueScrollLayerID(), parentID);
}
void RenderLayerBacking::detachFromScrollingCoordinator()
@@ -1066,11 +1329,7 @@ void RenderLayerBacking::detachFromScrollingCoordinator()
if (!m_scrollLayerID)
return;
- Page* page = renderer()->frame()->page();
- if (!page)
- return;
-
- ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
+ ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer);
if (!scrollingCoordinator)
return;
@@ -1080,14 +1339,18 @@ void RenderLayerBacking::detachFromScrollingCoordinator()
GraphicsLayerPaintingPhase RenderLayerBacking::paintingPhaseForPrimaryLayer() const
{
- unsigned phase = GraphicsLayerPaintBackground;
+ unsigned phase = 0;
+ if (!m_backgroundLayer)
+ phase |= GraphicsLayerPaintBackground;
if (!m_foregroundLayer)
phase |= GraphicsLayerPaintForeground;
if (!m_maskLayer)
phase |= GraphicsLayerPaintMask;
- if (m_scrollingContentsLayer)
+ if (m_scrollingContentsLayer) {
phase &= ~GraphicsLayerPaintForeground;
+ phase |= GraphicsLayerPaintCompositedScroll;
+ }
return static_cast<GraphicsLayerPaintingPhase>(phase);
}
@@ -1099,7 +1362,7 @@ float RenderLayerBacking::compositingOpacity(float rendererOpacity) const
for (RenderLayer* curr = m_owningLayer->parent(); curr; curr = curr->parent()) {
// We only care about parents that are stacking contexts.
// Recall that opacity creates stacking context.
- if (!curr->isStackingContext())
+ if (!curr->isStackingContainer())
continue;
// If we found a compositing layer, we want to compute opacity
@@ -1118,14 +1381,17 @@ static bool hasBoxDecorations(const RenderStyle* style)
return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter();
}
-static bool hasBoxDecorationsOrBackground(const RenderObject* renderer)
-{
- return hasBoxDecorations(renderer->style()) || renderer->hasBackground();
-}
+static bool canCreateTiledImage(const RenderStyle*);
static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style)
{
- return hasBoxDecorations(style) || style->hasBackgroundImage();
+ if (hasBoxDecorations(style))
+ return true;
+
+ if (!style->hasBackgroundImage())
+ return false;
+
+ return !GraphicsLayer::supportsContentsTiling() || !canCreateTiledImage(style);
}
Color RenderLayerBacking::rendererBackgroundColor() const
@@ -1137,20 +1403,128 @@ Color RenderLayerBacking::rendererBackgroundColor() const
return backgroundRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
}
-void RenderLayerBacking::updateBackgroundColor()
+void RenderLayerBacking::updateDirectlyCompositedBackgroundColor(bool isSimpleContainer, bool& didUpdateContentsRect)
{
- m_graphicsLayer->setContentsToBackgroundColor(rendererBackgroundColor());
+ if (!isSimpleContainer) {
+ m_graphicsLayer->setContentsToSolidColor(Color());
+ return;
+ }
+
+ Color backgroundColor = rendererBackgroundColor();
+
+ // An unset (invalid) color will remove the solid color.
+ m_graphicsLayer->setContentsToSolidColor(backgroundColor);
+ m_graphicsLayer->setContentsRect(backgroundBox());
+ didUpdateContentsRect = true;
}
-bool RenderLayerBacking::paintsBoxDecorations() const
+bool canCreateTiledImage(const RenderStyle* style)
{
- if (!m_owningLayer->hasVisibleContent())
+ const FillLayer* fillLayer = style->backgroundLayers();
+ if (fillLayer->next())
return false;
- if (hasBoxDecorationsOrBackground(renderer()))
- return true;
+ if (!fillLayer->imagesAreLoaded())
+ return false;
+
+ if (fillLayer->attachment() != ScrollBackgroundAttachment)
+ return false;
+
+ Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
+
+ // FIXME: Allow color+image compositing when it makes sense.
+ // For now bailing out.
+ if (color.isValid() && color.alpha())
+ return false;
+
+ StyleImage* styleImage = fillLayer->image();
+
+ // FIXME: support gradients with isGeneratedImage.
+ if (!styleImage->isCachedImage())
+ return false;
+
+ Image* image = styleImage->cachedImage()->image();
+ if (!image->isBitmapImage())
+ return false;
+
+ return true;
+}
+
+void RenderLayerBacking::updateDirectlyCompositedBackgroundImage(bool isSimpleContainer, bool& didUpdateContentsRect)
+{
+ if (!GraphicsLayer::supportsContentsTiling())
+ return;
+
+ if (isDirectlyCompositedImage())
+ return;
+
+ const RenderStyle* style = renderer()->style();
+
+ if (!isSimpleContainer || !style->hasBackgroundImage()) {
+ m_graphicsLayer->setContentsToImage(0);
+ return;
+ }
+
+ IntRect destRect = backgroundBox();
+ IntPoint phase;
+ IntSize tileSize;
+
+ RefPtr<Image> image = style->backgroundLayers()->image()->cachedImage()->image();
+ toRenderBox(renderer())->getGeometryForBackgroundImage(m_owningLayer->renderer(), destRect, phase, tileSize);
+ m_graphicsLayer->setContentsTileSize(tileSize);
+ m_graphicsLayer->setContentsTilePhase(phase);
+ m_graphicsLayer->setContentsRect(destRect);
+ m_graphicsLayer->setContentsToImage(image.get());
+ didUpdateContentsRect = true;
+}
+
+void RenderLayerBacking::updateRootLayerConfiguration()
+{
+ if (!m_usingTiledCacheLayer)
+ return;
+
+ Color backgroundColor;
+ bool viewIsTransparent = compositor()->viewHasTransparentBackground(&backgroundColor);
+
+ if (m_backgroundLayerPaintsFixedRootBackground && m_backgroundLayer) {
+ m_backgroundLayer->setBackgroundColor(backgroundColor);
+ m_backgroundLayer->setContentsOpaque(!viewIsTransparent);
+
+ m_graphicsLayer->setBackgroundColor(Color());
+ m_graphicsLayer->setContentsOpaque(false);
+ } else {
+ m_graphicsLayer->setBackgroundColor(backgroundColor);
+ m_graphicsLayer->setContentsOpaque(!viewIsTransparent);
+ }
+}
+
+static bool supportsDirectBoxDecorationsComposition(const RenderObject* renderer)
+{
+ if (!GraphicsLayer::supportsBackgroundColorContent())
+ return false;
+
+ if (renderer->hasClip())
+ return false;
+
+ if (hasBoxDecorationsOrBackgroundImage(renderer->style()))
+ return false;
+
+ // FIXME: we should be able to allow backgroundComposite; However since this is not a common use case it has been deferred for now.
+ if (renderer->style()->backgroundComposite() != CompositeSourceOver)
+ return false;
- if (m_owningLayer->hasOverflowControls())
+ if (renderer->style()->backgroundClip() == TextFillBox)
+ return false;
+
+ return true;
+}
+
+bool RenderLayerBacking::paintsBoxDecorations() const
+{
+ if (!m_owningLayer->hasVisibleBoxDecorations())
+ return false;
+
+ if (!supportsDirectBoxDecorationsComposition(renderer()))
return true;
return false;
@@ -1158,15 +1532,27 @@ bool RenderLayerBacking::paintsBoxDecorations() const
bool RenderLayerBacking::paintsChildren() const
{
- if (m_owningLayer->hasVisibleContent() && containsNonEmptyRenderers())
+ if (m_owningLayer->hasVisibleContent() && m_owningLayer->hasNonEmptyChildRenderers())
return true;
-
+
if (hasVisibleNonCompositingDescendantLayers())
return true;
return false;
}
+static bool isRestartedPlugin(RenderObject* renderer)
+{
+ if (!renderer->isEmbeddedObject())
+ return false;
+
+ Element* element = toElement(renderer->node());
+ if (!element || !element->isPluginElement())
+ return false;
+
+ return toHTMLPlugInElement(element)->isRestartedPlugin();
+}
+
static bool isCompositedPlugin(RenderObject* renderer)
{
return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing();
@@ -1181,12 +1567,15 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
if (renderObject->hasMask()) // masks require special treatment
return false;
- if (renderObject->isReplaced() && !isCompositedPlugin(renderObject))
- return false;
-
+ if (renderObject->isReplaced() && (!isCompositedPlugin(renderObject) || isRestartedPlugin(renderObject)))
+ return false;
+
if (paintsBoxDecorations() || paintsChildren())
return false;
-
+
+ if (renderObject->isRenderRegion())
+ return false;
+
if (renderObject->node() && renderObject->node()->isDocumentNode()) {
// Look to see if the root object has a non-simple background
RenderObject* rootObject = renderObject->document()->documentElement() ? renderObject->document()->documentElement()->renderer() : 0;
@@ -1215,63 +1604,46 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
return true;
}
-bool RenderLayerBacking::containsNonEmptyRenderers() const
-{
- // Some HTML can cause whitespace text nodes to have renderers, like:
- // <div>
- // <img src=...>
- // </div>
- // so test for 0x0 RenderTexts here
- for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
- if (!child->hasLayer()) {
- if (child->isRenderInline() || !child->isBox())
- return true;
-
- if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
- return true;
- }
- }
- return false;
-}
-
-// Conservative test for having no rendered children.
-bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const
+static bool hasVisibleNonCompositingDescendant(RenderLayer* parent)
{
// FIXME: We shouldn't be called with a stale z-order lists. See bug 85512.
- m_owningLayer->updateLayerListsIfNeeded();
+ parent->updateLayerListsIfNeeded();
#if !ASSERT_DISABLED
- LayerListMutationDetector mutationChecker(m_owningLayer);
+ LayerListMutationDetector mutationChecker(parent);
#endif
- if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) {
+ if (Vector<RenderLayer*>* normalFlowList = parent->normalFlowList()) {
size_t listSize = normalFlowList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = normalFlowList->at(i);
- if (!curLayer->isComposited() && curLayer->hasVisibleContent())
+ if (!curLayer->isComposited()
+ && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer)))
return true;
}
}
- if (m_owningLayer->isStackingContext()) {
- if (!m_owningLayer->hasVisibleDescendant())
+ if (parent->isStackingContainer()) {
+ if (!parent->hasVisibleDescendant())
return false;
// Use the m_hasCompositingDescendant bit to optimize?
- if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) {
+ if (Vector<RenderLayer*>* negZOrderList = parent->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = negZOrderList->at(i);
- if (!curLayer->isComposited() && curLayer->hasVisibleContent())
+ if (!curLayer->isComposited()
+ && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer)))
return true;
}
}
- if (Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList()) {
+ if (Vector<RenderLayer*>* posZOrderList = parent->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = posZOrderList->at(i);
- if (!curLayer->isComposited() && curLayer->hasVisibleContent())
+ if (!curLayer->isComposited()
+ && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer)))
return true;
}
}
@@ -1280,9 +1652,15 @@ bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const
return false;
}
-bool RenderLayerBacking::containsPaintedContent() const
+// Conservative test for having no rendered children.
+bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const
{
- if (isSimpleContainerCompositingLayer() || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
+ return hasVisibleNonCompositingDescendant(m_owningLayer);
+}
+
+bool RenderLayerBacking::containsPaintedContent(bool isSimpleContainer) const
+{
+ if (isSimpleContainer || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
return false;
if (isDirectlyCompositedImage())
@@ -1292,12 +1670,12 @@ bool RenderLayerBacking::containsPaintedContent() const
// and set background color on the layer in that case, instead of allocating backing store and painting.
#if ENABLE(VIDEO)
if (renderer()->isVideo() && toRenderVideo(renderer())->shouldDisplayVideo())
- return hasBoxDecorationsOrBackground(renderer());
+ return m_owningLayer->hasBoxDecorationsOrBackground();
#endif
#if PLATFORM(MAC) && USE(CA) && (PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
#elif ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS)
if (isAcceleratedCanvas(renderer()))
- return hasBoxDecorationsOrBackground(renderer());
+ return m_owningLayer->hasBoxDecorationsOrBackground();
#endif
return true;
@@ -1308,8 +1686,8 @@ bool RenderLayerBacking::containsPaintedContent() const
bool RenderLayerBacking::isDirectlyCompositedImage() const
{
RenderObject* renderObject = renderer();
-
- if (!renderObject->isImage() || hasBoxDecorationsOrBackground(renderObject) || renderObject->hasClip())
+
+ if (!renderObject->isImage() || m_owningLayer->hasBoxDecorationsOrBackground() || renderObject->hasClip())
return false;
RenderImage* imageRenderer = toRenderImage(renderObject);
@@ -1333,12 +1711,14 @@ void RenderLayerBacking::contentChanged(ContentChangeType changeType)
updateImageContents();
return;
}
-
+
+ if ((changeType == BackgroundImageChanged) && canCreateTiledImage(renderer()->style()))
+ updateGraphicsLayerGeometry();
+
if ((changeType == MaskImageChanged) && m_maskLayer) {
// The composited layer bounds relies on box->maskClipRect(), which changes
// when the mask image becomes available.
- bool isUpdateRoot = true;
- updateAfterLayout(CompositingChildren, isUpdateRoot);
+ updateAfterLayout(CompositingChildrenOnly | IsUpdateRoot);
}
#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS)
@@ -1367,8 +1747,10 @@ void RenderLayerBacking::updateImageContents()
return;
// This is a no-op if the layer doesn't have an inner layer for the image.
+ m_graphicsLayer->setContentsRect(pixelSnappedIntRect(contentsBox()));
m_graphicsLayer->setContentsToImage(image);
- updateDrawsContent();
+ bool isSimpleContainer = false;
+ updateDrawsContent(isSimpleContainer);
// Image animation is "lazy", in that it automatically stops unless someone is drawing
// the image. So we have to kick the animation each time; this has the downside that the
@@ -1403,36 +1785,73 @@ FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox
}
// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted.
-IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const
+LayoutSize RenderLayerBacking::contentOffsetInCompostingLayer() const
{
- return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y());
+ return LayoutSize(-m_compositedBounds.x(), -m_compositedBounds.y());
}
-IntRect RenderLayerBacking::contentsBox() const
+LayoutRect RenderLayerBacking::contentsBox() const
{
if (!renderer()->isBox())
- return IntRect();
+ return LayoutRect();
- IntRect contentsRect;
+ LayoutRect contentsRect;
#if ENABLE(VIDEO)
if (renderer()->isVideo()) {
RenderVideo* videoRenderer = toRenderVideo(renderer());
contentsRect = videoRenderer->videoBox();
} else
#endif
- contentsRect = pixelSnappedIntRect(toRenderBox(renderer())->contentBoxRect());
+ contentsRect = toRenderBox(renderer())->contentBoxRect();
- IntSize contentOffset = contentOffsetInCompostingLayer();
- contentsRect.move(contentOffset);
+ contentsRect.move(contentOffsetInCompostingLayer());
return contentsRect;
}
+static LayoutRect backgroundRectForBox(const RenderBox* box)
+{
+ switch (box->style()->backgroundClip()) {
+ case BorderFillBox:
+ return box->borderBoxRect();
+ case PaddingFillBox:
+ return box->paddingBoxRect();
+ case ContentFillBox:
+ return box->contentBoxRect();
+ case TextFillBox:
+ break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutRect();
+}
+
+IntRect RenderLayerBacking::backgroundBox() const
+{
+ if (!renderer()->isBox())
+ return IntRect();
+
+ LayoutRect backgroundBox = backgroundRectForBox(toRenderBox(renderer()));
+ backgroundBox.move(contentOffsetInCompostingLayer());
+ return pixelSnappedIntRect(backgroundBox);
+}
+
GraphicsLayer* RenderLayerBacking::parentForSublayers() const
{
if (m_scrollingContentsLayer)
return m_scrollingContentsLayer.get();
- return m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get();
+ return m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get();
+}
+
+GraphicsLayer* RenderLayerBacking::childForSuperlayers() const
+{
+ if (m_ancestorClippingLayer)
+ return m_ancestorClippingLayer.get();
+
+ if (m_contentsContainmentLayer)
+ return m_contentsContainmentLayer.get();
+
+ return m_graphicsLayer.get();
}
bool RenderLayerBacking::paintsIntoWindow() const
@@ -1441,7 +1860,7 @@ bool RenderLayerBacking::paintsIntoWindow() const
return false;
if (m_owningLayer->isRootLayer()) {
-#if PLATFORM(BLACKBERRY)
+#if PLATFORM(BLACKBERRY) || USE(COORDINATED_GRAPHICS)
if (compositor()->inForcedCompositingMode())
return false;
#endif
@@ -1483,6 +1902,9 @@ void RenderLayerBacking::setContentsNeedDisplay()
if (m_foregroundLayer && m_foregroundLayer->drawsContent())
m_foregroundLayer->setNeedsDisplay();
+ if (m_backgroundLayer && m_backgroundLayer->drawsContent())
+ m_backgroundLayer->setNeedsDisplay();
+
if (m_maskLayer && m_maskLayer->drawsContent())
m_maskLayer->setNeedsDisplay();
@@ -1507,6 +1929,13 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
m_foregroundLayer->setNeedsDisplayInRect(layerDirtyRect);
}
+ // FIXME: need to split out repaints for the background.
+ if (m_backgroundLayer && m_backgroundLayer->drawsContent()) {
+ IntRect layerDirtyRect = r;
+ layerDirtyRect.move(-m_backgroundLayer->offsetFromRenderer());
+ m_backgroundLayer->setNeedsDisplayInRect(layerDirtyRect);
+ }
+
if (m_maskLayer && m_maskLayer->drawsContent()) {
IntRect layerDirtyRect = r;
layerDirtyRect.move(-m_maskLayer->offsetFromRenderer());
@@ -1520,7 +1949,7 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
}
}
-void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context,
+void RenderLayerBacking::paintIntoLayer(const GraphicsLayer* graphicsLayer, GraphicsContext* context,
const IntRect& paintDirtyRect, // In the coords of rootLayer.
PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase)
{
@@ -1540,14 +1969,23 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
paintFlags |= RenderLayer::PaintLayerPaintingCompositingMaskPhase;
if (paintingPhase & GraphicsLayerPaintOverflowContents)
paintFlags |= RenderLayer::PaintLayerPaintingOverflowContents;
+ if (paintingPhase & GraphicsLayerPaintCompositedScroll)
+ paintFlags |= RenderLayer::PaintLayerPaintingCompositingScrollingPhase;
+
+ if (graphicsLayer == m_backgroundLayer)
+ paintFlags |= (RenderLayer::PaintLayerPaintingRootBackgroundOnly | RenderLayer::PaintLayerPaintingCompositingForegroundPhase); // Need PaintLayerPaintingCompositingForegroundPhase to walk child layers.
+ else if (compositor()->fixedRootBackgroundLayer())
+ paintFlags |= RenderLayer::PaintLayerPaintingSkipRootBackground;
// FIXME: GraphicsLayers need a way to split for RenderRegions.
- RenderLayer::LayerPaintingInfo paintingInfo(rootLayer, paintDirtyRect, paintBehavior, LayoutSize());
+ RenderLayer::LayerPaintingInfo paintingInfo(m_owningLayer, paintDirtyRect, paintBehavior, m_subpixelAccumulation);
m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags);
if (m_owningLayer->containsDirtyOverlayScrollbars())
m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags | RenderLayer::PaintLayerPaintingOverlayScrollbars);
+ compositor()->didPaintBacking(this);
+
ASSERT(!m_owningLayer->m_usedTransparency);
}
@@ -1573,21 +2011,22 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph
page->setIsPainting(true);
#endif
- if (graphicsLayer == m_graphicsLayer.get() || graphicsLayer == m_foregroundLayer.get() || graphicsLayer == m_maskLayer.get() || graphicsLayer == m_scrollingContentsLayer.get()) {
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame());
+ if (graphicsLayer == m_graphicsLayer.get()
+ || graphicsLayer == m_foregroundLayer.get()
+ || graphicsLayer == m_backgroundLayer.get()
+ || graphicsLayer == m_maskLayer.get()
+ || graphicsLayer == m_scrollingContentsLayer.get()) {
+ InspectorInstrumentation::willPaint(renderer());
// The dirtyRect is in the coords of the painting root.
IntRect dirtyRect = clip;
if (!(paintingPhase & GraphicsLayerPaintOverflowContents))
- dirtyRect.intersect(compositedBounds());
+ dirtyRect.intersect(enclosingIntRect(compositedBounds()));
// We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
- paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase);
-
- if (m_usingTiledCacheLayer)
- m_owningLayer->renderer()->frame()->view()->setLastPaintTime(currentTime());
+ paintIntoLayer(graphicsLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase);
- InspectorInstrumentation::didPaint(cookie, &context, clip);
+ InspectorInstrumentation::didPaint(renderer(), &context, clip);
} else if (graphicsLayer == layerForHorizontalScrollbar()) {
paintScrollbar(m_owningLayer->horizontalScrollbar(), context, clip);
} else if (graphicsLayer == layerForVerticalScrollbar()) {
@@ -1618,14 +2057,15 @@ float RenderLayerBacking::deviceScaleFactor() const
return compositor()->deviceScaleFactor();
}
-void RenderLayerBacking::didCommitChangesForLayer(const GraphicsLayer*) const
+void RenderLayerBacking::didCommitChangesForLayer(const GraphicsLayer* layer) const
{
- compositor()->didFlushChangesForLayer(m_owningLayer);
+ compositor()->didFlushChangesForLayer(m_owningLayer, layer);
}
bool RenderLayerBacking::getCurrentTransform(const GraphicsLayer* graphicsLayer, TransformationMatrix& transform) const
{
- if (graphicsLayer != m_graphicsLayer)
+ GraphicsLayer* transformedLayer = m_contentsContainmentLayer.get() ? m_contentsContainmentLayer.get() : m_graphicsLayer.get();
+ if (graphicsLayer != transformedLayer)
return false;
if (m_owningLayer->hasTransform()) {
@@ -1681,39 +2121,31 @@ bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim
bool isFirstOrLastKeyframe = key == 0 || key == 1;
if ((hasTransform && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitTransform))
- transformVector.insert(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf));
-
+ transformVector.insert(TransformAnimationValue::create(key, keyframeStyle->transform(), tf));
+
if ((hasOpacity && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyOpacity))
- opacityVector.insert(new FloatAnimationValue(key, keyframeStyle->opacity(), tf));
+ opacityVector.insert(FloatAnimationValue::create(key, keyframeStyle->opacity(), tf));
#if ENABLE(CSS_FILTERS)
if ((hasFilter && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitFilter))
- filterVector.insert(new FilterAnimationValue(key, &(keyframeStyle->filter()), tf));
+ filterVector.insert(FilterAnimationValue::create(key, keyframeStyle->filter(), tf));
#endif
}
- bool didAnimateTransform = false;
- bool didAnimateOpacity = false;
-#if ENABLE(CSS_FILTERS)
- bool didAnimateFilter = false;
-#endif
+ bool didAnimate = false;
if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), anim, keyframes.animationName(), timeOffset))
- didAnimateTransform = true;
+ didAnimate = true;
if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset))
- didAnimateOpacity = true;
+ didAnimate = true;
#if ENABLE(CSS_FILTERS)
if (hasFilter && m_graphicsLayer->addAnimation(filterVector, IntSize(), anim, keyframes.animationName(), timeOffset))
- didAnimateFilter = true;
+ didAnimate = true;
#endif
-#if ENABLE(CSS_FILTERS)
- return didAnimateTransform || didAnimateOpacity || didAnimateFilter;
-#else
- return didAnimateTransform || didAnimateOpacity;
-#endif
+ return didAnimate;
}
void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName)
@@ -1728,11 +2160,7 @@ void RenderLayerBacking::animationFinished(const String& animationName)
bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID property, const RenderStyle* fromStyle, const RenderStyle* toStyle)
{
- bool didAnimateOpacity = false;
- bool didAnimateTransform = false;
-#if ENABLE(CSS_FILTERS)
- bool didAnimateFilter = false;
-#endif
+ bool didAnimate = false;
ASSERT(property != CSSPropertyInvalid);
@@ -1740,13 +2168,13 @@ bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID proper
const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity);
if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) {
KeyframeValueList opacityVector(AnimatedPropertyOpacity);
- opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity())));
- opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity())));
+ opacityVector.insert(FloatAnimationValue::create(0, compositingOpacity(fromStyle->opacity())));
+ opacityVector.insert(FloatAnimationValue::create(1, compositingOpacity(toStyle->opacity())));
// The boxSize param is only used for transform animations (which can only run on RenderBoxes), so we pass an empty size here.
if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyOpacity), timeOffset)) {
// To ensure that the correct opacity is visible when the animation ends, also set the final opacity.
updateOpacity(toStyle);
- didAnimateOpacity = true;
+ didAnimate = true;
}
}
}
@@ -1755,12 +2183,12 @@ bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID proper
const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform);
if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) {
KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
- transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform()));
- transformVector.insert(new TransformAnimationValue(1, &toStyle->transform()));
+ transformVector.insert(TransformAnimationValue::create(0, fromStyle->transform()));
+ transformVector.insert(TransformAnimationValue::create(1, toStyle->transform()));
if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), transformAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyWebkitTransform), timeOffset)) {
// To ensure that the correct transform is visible when the animation ends, also set the final transform.
updateTransform(toStyle);
- didAnimateTransform = true;
+ didAnimate = true;
}
}
}
@@ -1770,22 +2198,18 @@ bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID proper
const Animation* filterAnim = toStyle->transitionForProperty(CSSPropertyWebkitFilter);
if (filterAnim && !filterAnim->isEmptyOrZeroDuration()) {
KeyframeValueList filterVector(AnimatedPropertyWebkitFilter);
- filterVector.insert(new FilterAnimationValue(0, &fromStyle->filter()));
- filterVector.insert(new FilterAnimationValue(1, &toStyle->filter()));
+ filterVector.insert(FilterAnimationValue::create(0, fromStyle->filter()));
+ filterVector.insert(FilterAnimationValue::create(1, toStyle->filter()));
if (m_graphicsLayer->addAnimation(filterVector, IntSize(), filterAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyWebkitFilter), timeOffset)) {
// To ensure that the correct filter is visible when the animation ends, also set the final filter.
updateFilters(toStyle);
- didAnimateFilter = true;
+ didAnimate = true;
}
}
}
#endif
-#if ENABLE(CSS_FILTERS)
- return didAnimateOpacity || didAnimateTransform || didAnimateFilter;
-#else
- return didAnimateOpacity || didAnimateTransform;
-#endif
+ return didAnimate;
}
void RenderLayerBacking::transitionPaused(double timeOffset, CSSPropertyID property)
@@ -1807,10 +2231,11 @@ void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double tim
renderer()->animation()->notifyAnimationStarted(renderer(), time);
}
-void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer*)
+void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer)
{
- if (!renderer()->documentBeingDestroyed())
- compositor()->scheduleLayerFlush();
+ if (renderer()->documentBeingDestroyed())
+ return;
+ compositor()->scheduleLayerFlush(layer->canThrottleLayerFlush());
}
void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer)
@@ -1829,12 +2254,12 @@ void RenderLayerBacking::resumeAnimations()
m_graphicsLayer->resumeAnimations();
}
-IntRect RenderLayerBacking::compositedBounds() const
+LayoutRect RenderLayerBacking::compositedBounds() const
{
return m_compositedBounds;
}
-void RenderLayerBacking::setCompositedBounds(const IntRect& bounds)
+void RenderLayerBacking::setCompositedBounds(const LayoutRect& bounds)
{
m_compositedBounds = bounds;
}
@@ -1885,46 +2310,13 @@ AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(CSSPropertyID
return AnimatedPropertyInvalid;
}
-String RenderLayerBacking::nameForLayer() const
-{
- StringBuilder name;
- name.append(renderer()->renderName());
- if (Node* node = renderer()->node()) {
- if (node->isElementNode()) {
- name.append(' ');
- name.append(static_cast<Element*>(node)->tagName());
- }
- if (node->hasID()) {
- name.appendLiteral(" id=\'");
- name.append(static_cast<Element*>(node)->getIdAttribute());
- name.append('\'');
- }
-
- if (node->hasClass()) {
- name.appendLiteral(" class=\'");
- StyledElement* styledElement = static_cast<StyledElement*>(node);
- for (size_t i = 0; i < styledElement->classNames().size(); ++i) {
- if (i > 0)
- name.append(' ');
- name.append(styledElement->classNames()[i]);
- }
- name.append('\'');
- }
- }
-
- if (m_owningLayer->isReflection())
- name.appendLiteral(" (reflection)");
-
- return name.toString();
-}
-
CompositingLayerType RenderLayerBacking::compositingLayerType() const
{
if (m_graphicsLayer->hasContentsLayer())
return MediaCompositingLayer;
if (m_graphicsLayer->drawsContent())
- return m_graphicsLayer->usingTiledLayer() ? TiledCompositingLayer : NormalCompositingLayer;
+ return m_graphicsLayer->usingTiledBacking() ? TiledCompositingLayer : NormalCompositingLayer;
return ContainerCompositingLayer;
}
@@ -1933,10 +2325,12 @@ double RenderLayerBacking::backingStoreMemoryEstimate() const
{
double backingMemory;
- // m_ancestorClippingLayer and m_containmentLayer are just used for masking or containment, so have no backing.
+ // m_ancestorClippingLayer, m_contentsContainmentLayer and m_childContainmentLayer are just used for masking or containment, so have no backing.
backingMemory = m_graphicsLayer->backingStoreMemoryEstimate();
if (m_foregroundLayer)
backingMemory += m_foregroundLayer->backingStoreMemoryEstimate();
+ if (m_backgroundLayer)
+ backingMemory += m_backgroundLayer->backingStoreMemoryEstimate();
if (m_maskLayer)
backingMemory += m_maskLayer->backingStoreMemoryEstimate();
@@ -1955,20 +2349,6 @@ double RenderLayerBacking::backingStoreMemoryEstimate() const
return backingMemory;
}
-#if PLATFORM(BLACKBERRY)
-bool RenderLayerBacking::contentsVisible(const GraphicsLayer*, const IntRect& localContentRect) const
-{
- Frame* frame = renderer()->frame();
- FrameView* view = frame ? frame->view() : 0;
- if (!view)
- return false;
-
- IntRect visibleContentRect(view->visibleContentRect());
- FloatQuad absoluteContentQuad = renderer()->localToAbsoluteQuad(FloatRect(localContentRect), SnapOffsetForTransforms);
- return absoluteContentQuad.enclosingBoundingBox().intersects(visibleContentRect);
-}
-#endif
-
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h
index cdcc030c2..134001ebf 100644
--- a/Source/WebCore/rendering/RenderLayerBacking.h
+++ b/Source/WebCore/rendering/RenderLayerBacking.h
@@ -33,13 +33,13 @@
#include "GraphicsLayer.h"
#include "GraphicsLayerClient.h"
#include "RenderLayer.h"
-#include "TransformationMatrix.h"
namespace WebCore {
class KeyframeList;
class RenderLayerCompositor;
class TiledBacking;
+class TransformationMatrix;
enum CompositingLayerType {
NormalCompositingLayer, // non-tiled layer with backing store
@@ -57,13 +57,18 @@ enum CompositingLayerType {
class RenderLayerBacking : public GraphicsLayerClient {
WTF_MAKE_NONCOPYABLE(RenderLayerBacking); WTF_MAKE_FAST_ALLOCATED;
public:
- RenderLayerBacking(RenderLayer*);
+ explicit RenderLayerBacking(RenderLayer*);
~RenderLayerBacking();
RenderLayer* owningLayer() const { return m_owningLayer; }
- enum UpdateDepth { CompositingChildren, AllDescendants };
- void updateAfterLayout(UpdateDepth, bool isUpdateRoot);
+ enum UpdateAfterLayoutFlag {
+ CompositingChildrenOnly = 1 << 0,
+ NeedsFullRepaint = 1 << 1,
+ IsUpdateRoot = 1 << 2
+ };
+ typedef unsigned UpdateAfterLayoutFlags;
+ void updateAfterLayout(UpdateAfterLayoutFlags);
// Returns true if layer configuration changed.
bool updateGraphicsLayerConfiguration();
@@ -75,28 +80,33 @@ public:
GraphicsLayer* graphicsLayer() const { return m_graphicsLayer.get(); }
// Layer to clip children
- bool hasClippingLayer() const { return (m_containmentLayer && !m_usingTiledCacheLayer); }
- GraphicsLayer* clippingLayer() const { return !m_usingTiledCacheLayer ? m_containmentLayer.get() : 0; }
+ bool hasClippingLayer() const { return (m_childContainmentLayer && !m_usingTiledCacheLayer); }
+ GraphicsLayer* clippingLayer() const { return !m_usingTiledCacheLayer ? m_childContainmentLayer.get() : 0; }
// Layer to get clipped by ancestor
bool hasAncestorClippingLayer() const { return m_ancestorClippingLayer != 0; }
GraphicsLayer* ancestorClippingLayer() const { return m_ancestorClippingLayer.get(); }
+ GraphicsLayer* contentsContainmentLayer() const { return m_contentsContainmentLayer.get(); }
+
bool hasContentsLayer() const { return m_foregroundLayer != 0; }
GraphicsLayer* foregroundLayer() const { return m_foregroundLayer.get(); }
+ GraphicsLayer* backgroundLayer() const { return m_backgroundLayer.get(); }
+ bool backgroundLayerPaintsFixedRootBackground() const { return m_backgroundLayerPaintsFixedRootBackground; }
+
bool hasScrollingLayer() const { return m_scrollingLayer; }
GraphicsLayer* scrollingLayer() const { return m_scrollingLayer.get(); }
GraphicsLayer* scrollingContentsLayer() const { return m_scrollingContentsLayer.get(); }
- void attachToScrollingCoordinator(RenderLayerBacking* parent);
+ void attachToScrollingCoordinatorWithParent(RenderLayerBacking* parent);
void detachFromScrollingCoordinator();
uint64_t scrollLayerID() const { return m_scrollLayerID; }
bool hasMaskLayer() const { return m_maskLayer != 0; }
GraphicsLayer* parentForSublayers() const;
- GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer.get() : m_graphicsLayer.get(); }
+ GraphicsLayer* childForSuperlayers() const;
// RenderLayers with backing normally short-circuit paintLayer() because
// their content is rendered via callbacks from GraphicsLayer. However, the document
@@ -131,21 +141,23 @@ public:
void suspendAnimations(double time = 0);
void resumeAnimations();
- IntRect compositedBounds() const;
- void setCompositedBounds(const IntRect&);
+ LayoutRect compositedBounds() const;
+ void setCompositedBounds(const LayoutRect&);
void updateCompositedBounds();
void updateAfterWidgetResize();
void positionOverflowControlsLayers(const IntSize& offsetFromRoot);
+ bool hasUnpositionedOverflowControlsLayers() const;
- bool usingTileCache() const { return m_usingTiledCacheLayer; }
+ bool usingTiledBacking() const { return m_usingTiledCacheLayer; }
TiledBacking* tiledBacking() const;
- void adjustTileCacheCoverage();
+ void adjustTiledBackingCoverage();
void updateDebugIndicators(bool showBorder, bool showRepaintCounter);
-
+
// GraphicsLayerClient interface
- virtual bool shouldUseTileCache(const GraphicsLayer*) const OVERRIDE;
+ virtual bool shouldUseTiledBacking(const GraphicsLayer*) const OVERRIDE;
+ virtual void tiledBackingUsageChanged(const GraphicsLayer*, bool /*usingTiledBacking*/) OVERRIDE;
virtual void notifyAnimationStarted(const GraphicsLayer*, double startTime) OVERRIDE;
virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE;
virtual void notifyFlushBeforeDisplayRefresh(const GraphicsLayer*) OVERRIDE;
@@ -163,7 +175,8 @@ public:
virtual void verifyNotPainting();
#endif
- IntRect contentsBox() const;
+ LayoutRect contentsBox() const;
+ IntRect backgroundBox() const;
// For informative purposes only.
CompositingLayerType compositingLayerType() const;
@@ -179,8 +192,9 @@ public:
// Return an estimate of the backing store area (in pixels) allocated by this object's GraphicsLayers.
double backingStoreMemoryEstimate() const;
- String nameForLayer() const;
-
+ bool didSwitchToFullTileCoverageDuringLoading() const { return m_didSwitchToFullTileCoverageDuringLoading; }
+ void setDidSwitchToFullTileCoverageDuringLoading() { m_didSwitchToFullTileCoverageDuringLoading = true; }
+
#if ENABLE(CSS_COMPOSITING)
void setBlendMode(BlendMode);
#endif
@@ -189,6 +203,8 @@ private:
void createPrimaryGraphicsLayer();
void destroyGraphicsLayers();
+ void willDestroyLayer(const GraphicsLayer*);
+
PassOwnPtr<GraphicsLayer> createGraphicsLayer(const String&);
RenderLayerModelObject* renderer() const { return m_owningLayer->renderer(); }
@@ -198,15 +214,22 @@ private:
bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip);
bool updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer);
bool updateForegroundLayer(bool needsForegroundLayer);
+ bool updateBackgroundLayer(bool needsBackgroundLayer);
bool updateMaskLayer(bool needsMaskLayer);
bool requiresHorizontalScrollbarLayer() const;
bool requiresVerticalScrollbarLayer() const;
bool requiresScrollCornerLayer() const;
bool updateScrollingLayers(bool scrollingLayers);
+ void updateDrawsContent(bool isSimpleContainer);
+ void registerScrollingLayers();
+
+ void updateRootLayerConfiguration();
+
+ void setBackgroundLayerPaintsFixedRootBackground(bool);
GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const;
- IntSize contentOffsetInCompostingLayer() const;
+ LayoutSize contentOffsetInCompostingLayer() const;
// Result is transform origin in pixels.
FloatPoint3D computeTransformOrigin(const IntRect& borderBox) const;
// Result is perspective origin in pixels.
@@ -231,53 +254,62 @@ private:
// Returns true if this compositing layer has no visible content.
bool isSimpleContainerCompositingLayer() const;
// Returns true if this layer has content that needs to be rendered by painting into the backing store.
- bool containsPaintedContent() const;
+ bool containsPaintedContent(bool isSimpleContainer) const;
// Returns true if the RenderLayer just contains an image that we can composite directly.
bool isDirectlyCompositedImage() const;
void updateImageContents();
Color rendererBackgroundColor() const;
- void updateBackgroundColor();
+ void updateDirectlyCompositedBackgroundColor(bool isSimpleContainer, bool& didUpdateContentsRect);
+ void updateDirectlyCompositedBackgroundImage(bool isSimpleContainer, bool& didUpdateContentsRect);
+ void updateDirectlyCompositedContents(bool isSimpleContainer, bool& didUpdateContentsRect);
+
+ void resetContentsRect();
- bool containsNonEmptyRenderers() const;
bool hasVisibleNonCompositingDescendantLayers() const;
bool shouldClipCompositedBounds() const;
- bool hasTileCacheFlatteningLayer() const { return (m_containmentLayer && m_usingTiledCacheLayer); }
- GraphicsLayer* tileCacheFlatteningLayer() const { return m_usingTiledCacheLayer ? m_containmentLayer.get() : 0; }
+ bool hasTiledBackingFlatteningLayer() const { return (m_childContainmentLayer && m_usingTiledCacheLayer); }
+ GraphicsLayer* tileCacheFlatteningLayer() const { return m_usingTiledCacheLayer ? m_childContainmentLayer.get() : 0; }
- void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, PaintBehavior, GraphicsLayerPaintingPhase);
+ void paintIntoLayer(const GraphicsLayer*, GraphicsContext*, const IntRect& paintDirtyRect, PaintBehavior, GraphicsLayerPaintingPhase);
static CSSPropertyID graphicsLayerToCSSProperty(AnimatedPropertyID);
static AnimatedPropertyID cssToGraphicsLayerProperty(CSSPropertyID);
RenderLayer* m_owningLayer;
- OwnPtr<GraphicsLayer> m_ancestorClippingLayer; // only used if we are clipped by an ancestor which is not a stacking context
+ OwnPtr<GraphicsLayer> m_ancestorClippingLayer; // Only used if we are clipped by an ancestor which is not a stacking context.
+ OwnPtr<GraphicsLayer> m_contentsContainmentLayer; // Only used if we have a background layer; takes the transform.
OwnPtr<GraphicsLayer> m_graphicsLayer;
- OwnPtr<GraphicsLayer> m_foregroundLayer; // only used in cases where we need to draw the foreground separately
- OwnPtr<GraphicsLayer> m_containmentLayer; // Only used if we have clipping on a stacking context with compositing children, or if the layer has a tile cache.
- OwnPtr<GraphicsLayer> m_maskLayer; // only used if we have a mask
+ OwnPtr<GraphicsLayer> m_foregroundLayer; // Only used in cases where we need to draw the foreground separately.
+ OwnPtr<GraphicsLayer> m_backgroundLayer; // Only used in cases where we need to draw the background separately.
+ OwnPtr<GraphicsLayer> m_childContainmentLayer; // Only used if we have clipping on a stacking context with compositing children, or if the layer has a tile cache.
+ OwnPtr<GraphicsLayer> m_maskLayer; // Only used if we have a mask.
OwnPtr<GraphicsLayer> m_layerForHorizontalScrollbar;
OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar;
OwnPtr<GraphicsLayer> m_layerForScrollCorner;
- OwnPtr<GraphicsLayer> m_scrollingLayer; // only used if the layer is using composited scrolling.
- OwnPtr<GraphicsLayer> m_scrollingContentsLayer; // only used if the layer is using composited scrolling.
+ OwnPtr<GraphicsLayer> m_scrollingLayer; // Only used if the layer is using composited scrolling.
+ OwnPtr<GraphicsLayer> m_scrollingContentsLayer; // Only used if the layer is using composited scrolling.
uint64_t m_scrollLayerID;
- IntRect m_compositedBounds;
+ LayoutRect m_compositedBounds;
+ LayoutSize m_subpixelAccumulation; // The accumulated subpixel offset of the compositedBounds compared to absolute coordinates.
- bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
+ bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
+ bool m_boundsConstrainedByClipping;
bool m_isMainFrameRenderViewLayer;
bool m_usingTiledCacheLayer;
bool m_requiresOwnBackingStore;
#if ENABLE(CSS_FILTERS)
bool m_canCompositeFilters;
#endif
+ bool m_backgroundLayerPaintsFixedRootBackground;
+ bool m_didSwitchToFullTileCoverageDuringLoading;
static bool m_creatingPrimaryGraphicsLayer;
};
diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp
index badb782c4..6f1fd3e0b 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp
@@ -40,6 +40,8 @@
#include "HTMLIFrameElement.h"
#include "HTMLNames.h"
#include "HitTestResult.h"
+#include "InspectorInstrumentation.h"
+#include "Logging.h"
#include "NodeList.h"
#include "Page.h"
#include "RenderApplet.h"
@@ -57,15 +59,16 @@
#include "Settings.h"
#include "TiledBacking.h"
#include "TransformState.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/TemporaryChange.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLAudioElement.h"
#include "HTMLMediaElement.h"
#endif
-#if !LOG_DISABLED
-#include <wtf/CurrentTime.h>
-#endif
-
#ifndef NDEBUG
#include "RenderTreeAsText.h"
#endif
@@ -75,8 +78,16 @@
bool WebCoreHas3DRendering = true;
#endif
+#if !PLATFORM(MAC) && !PLATFORM(IOS)
+#define WTF_USE_COMPOSITING_FOR_SMALL_CANVASES 1
+#endif
+
namespace WebCore {
+static const int canvasAreaThresholdRequiringCompositing = 50 * 100;
+// During page loading delay layer flushes up to this many seconds to allow them coalesce, reducing workload.
+static const double throttledLayerFlushDelay = .5;
+
using namespace HTMLNames;
class RenderLayerCompositor::OverlapMap {
@@ -108,12 +119,7 @@ public:
bool overlapsLayers(const IntRect& bounds) const
{
- const RectList& layerRects = m_overlapStack.last();
- for (unsigned i = 0; i < layerRects.size(); i++) {
- if (layerRects[i].intersects(bounds))
- return true;
- }
- return false;
+ return m_overlapStack.last().intersects(bounds);
}
bool isEmpty()
@@ -135,14 +141,42 @@ public:
RenderGeometryMap& geometryMap() { return m_geometryMap; }
private:
- typedef Vector<IntRect> RectList;
+ struct RectList {
+ Vector<IntRect> rects;
+ IntRect boundingRect;
+
+ void append(const IntRect& rect)
+ {
+ rects.append(rect);
+ boundingRect.unite(rect);
+ }
+
+ void append(const RectList& rectList)
+ {
+ rects.appendVector(rectList.rects);
+ boundingRect.unite(rectList.boundingRect);
+ }
+
+ bool intersects(const IntRect& rect) const
+ {
+ if (!rects.size() || !boundingRect.intersects(rect))
+ return false;
+
+ for (unsigned i = 0; i < rects.size(); i++) {
+ if (rects[i].intersects(rect))
+ return true;
+ }
+ return false;
+ }
+ };
+
Vector<RectList> m_overlapStack;
HashSet<const RenderLayer*> m_layers;
RenderGeometryMap m_geometryMap;
};
struct CompositingState {
- CompositingState(RenderLayer* compAncestor, bool testOverlap)
+ CompositingState(RenderLayer* compAncestor, bool testOverlap = true)
: m_compositingAncestor(compAncestor)
, m_subtreeIsCompositing(false)
, m_testingOverlap(testOverlap)
@@ -189,15 +223,21 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
, m_showDebugBorders(false)
, m_showRepaintCounter(false)
, m_acceleratedDrawingEnabled(false)
- , m_compositingConsultsOverlap(true)
, m_reevaluateCompositingAfterLayout(false)
, m_compositing(false)
, m_compositingLayersNeedRebuild(false)
, m_flushingLayers(false)
, m_shouldFlushOnReattach(false)
, m_forceCompositingMode(false)
+ , m_inPostLayoutUpdate(false)
, m_isTrackingRepaints(false)
+ , m_layersWithTiledBackingCount(0)
, m_rootLayerAttachment(RootLayerUnattached)
+ , m_layerFlushTimer(this, &RenderLayerCompositor::layerFlushTimerFired)
+ , m_layerFlushThrottlingEnabled(false)
+ , m_layerFlushThrottlingTemporarilyDisabledForInteraction(false)
+ , m_hasPendingLayerFlush(false)
+ , m_paintRelatedMilestonesTimer(this, &RenderLayerCompositor::paintRelatedMilestonesTimerFired)
#if !LOG_DISABLED
, m_rootLayerUpdateCount(0)
, m_obligateCompositedLayerCount(0)
@@ -210,6 +250,9 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
RenderLayerCompositor::~RenderLayerCompositor()
{
+ // Take care that the owned GraphicsLayers are deleted first as their destructors may call back here.
+ m_clipLayer = nullptr;
+ m_scrollLayer = nullptr;
ASSERT(m_rootLayerAttachment == RootLayerUnattached);
}
@@ -241,7 +284,7 @@ void RenderLayerCompositor::cacheAcceleratedCompositingFlags()
// on a chrome that doesn't allow accelerated compositing.
if (hasAcceleratedCompositing) {
if (Page* page = this->page()) {
- ChromeClient* chromeClient = page->chrome()->client();
+ ChromeClient* chromeClient = page->chrome().client();
m_compositingTriggers = chromeClient->allowedCompositingTriggers();
hasAcceleratedCompositing = m_compositingTriggers;
}
@@ -252,7 +295,7 @@ void RenderLayerCompositor::cacheAcceleratedCompositingFlags()
forceCompositingMode = settings->forceCompositingMode() && hasAcceleratedCompositing;
if (forceCompositingMode && m_renderView->document()->ownerElement())
- forceCompositingMode = settings->acceleratedCompositingForScrollableFramesEnabled() && requiresCompositingForScrollableFrame();
+ forceCompositingMode = requiresCompositingForScrollableFrame();
acceleratedDrawingEnabled = settings->acceleratedDrawingEnabled();
}
@@ -290,10 +333,39 @@ void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild)
m_compositingLayersNeedRebuild = needRebuild;
}
-void RenderLayerCompositor::scheduleLayerFlush()
+void RenderLayerCompositor::customPositionForVisibleRectComputation(const GraphicsLayer* graphicsLayer, FloatPoint& position) const
+{
+ if (graphicsLayer != m_scrollLayer.get())
+ return;
+
+ FrameView* frameView = m_renderView ? m_renderView->frameView() : 0;
+ if (!frameView)
+ return;
+
+ FloatPoint scrollPosition = -position;
+ scrollPosition = frameView->constrainScrollPositionForOverhang(roundedIntPoint(scrollPosition));
+ position = -scrollPosition;
+}
+
+void RenderLayerCompositor::notifyFlushRequired(const GraphicsLayer* layer)
{
+ scheduleLayerFlush(layer->canThrottleLayerFlush());
+}
+
+void RenderLayerCompositor::scheduleLayerFlushNow()
+{
+ m_hasPendingLayerFlush = false;
if (Page* page = this->page())
- page->chrome()->client()->scheduleCompositingLayerFlush();
+ page->chrome().client()->scheduleCompositingLayerFlush();
+}
+
+void RenderLayerCompositor::scheduleLayerFlush(bool canThrottle)
+{
+ if (canThrottle && isThrottlingLayerFlushes()) {
+ m_hasPendingLayerFlush = true;
+ return;
+ }
+ scheduleLayerFlushNow();
}
void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
@@ -315,8 +387,8 @@ void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
ASSERT(!m_flushingLayers);
m_flushingLayers = true;
+ FrameView* frameView = m_renderView ? m_renderView->frameView() : 0;
if (GraphicsLayer* rootLayer = rootGraphicsLayer()) {
- FrameView* frameView = m_renderView ? m_renderView->frameView() : 0;
if (frameView) {
// Having a m_clipLayer indicates that we're doing scrolling via GraphicsLayers.
IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect();
@@ -334,12 +406,43 @@ void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
m_viewportConstrainedLayersNeedingUpdate.clear();
}
+ startLayerFlushTimerIfNeeded();
}
-void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer)
+void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer, const GraphicsLayer* graphicsLayer)
{
if (m_viewportConstrainedLayers.contains(layer))
m_viewportConstrainedLayersNeedingUpdate.add(layer);
+
+ RenderLayerBacking* backing = layer->backing();
+ if (backing->backgroundLayerPaintsFixedRootBackground() && graphicsLayer == backing->backgroundLayer())
+ fixedRootBackgroundLayerChanged();
+}
+
+void RenderLayerCompositor::didPaintBacking(RenderLayerBacking*)
+{
+ FrameView* frameView = m_renderView->frameView();
+
+ frameView->setLastPaintTime(currentTime());
+
+ if (frameView->milestonesPendingPaint() && !m_paintRelatedMilestonesTimer.isActive())
+ m_paintRelatedMilestonesTimer.startOneShot(0);
+}
+
+void RenderLayerCompositor::didChangeVisibleRect()
+{
+ GraphicsLayer* rootLayer = rootGraphicsLayer();
+ if (!rootLayer)
+ return;
+
+ FrameView* frameView = m_renderView ? m_renderView->frameView() : 0;
+ if (!frameView)
+ return;
+
+ IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect();
+ if (!rootLayer->visibleRectChangeRequiresFlush(visibleRect))
+ return;
+ scheduleLayerFlushNow();
}
void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*)
@@ -347,7 +450,7 @@ void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*
if (!m_layerUpdater) {
PlatformDisplayID displayID = 0;
if (Page* page = this->page())
- displayID = page->displayID();
+ displayID = page->chrome().displayID();
m_layerUpdater = adoptPtr(new GraphicsLayerUpdater(this, displayID));
}
@@ -360,6 +463,16 @@ void RenderLayerCompositor::flushLayers(GraphicsLayerUpdater*)
flushPendingLayerChanges(true); // FIXME: deal with iframes
}
+void RenderLayerCompositor::layerTiledBackingUsageChanged(const GraphicsLayer*, bool usingTiledBacking)
+{
+ if (usingTiledBacking)
+ ++m_layersWithTiledBackingCount;
+ else {
+ ASSERT(m_layersWithTiledBackingCount > 0);
+ --m_layersWithTiledBackingCount;
+ }
+}
+
RenderLayerCompositor* RenderLayerCompositor::enclosingCompositorFlushingLayers() const
{
if (!m_renderView->frameView())
@@ -398,6 +511,10 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
if (!m_renderView->document()->visualUpdatesAllowed())
return;
+ // Avoid updating the layers with old values. Compositing layers will be updated after the layout is finished.
+ if (m_renderView->needsLayout())
+ return;
+
if (m_forceCompositingMode && !m_compositing)
enableCompositingMode(true);
@@ -406,6 +523,8 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
AnimationUpdateBlock animationUpdateBlock(m_renderView->frameView()->frame()->animation());
+ TemporaryChange<bool> postLayoutChange(m_inPostLayoutUpdate, true);
+
bool checkForHierarchyUpdate = m_reevaluateCompositingAfterLayout;
bool needGeometryUpdate = false;
@@ -416,11 +535,13 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
checkForHierarchyUpdate = true;
break;
case CompositingUpdateOnScroll:
- if (m_compositingConsultsOverlap)
- checkForHierarchyUpdate = true; // Overlap can change with scrolling, so need to check for hierarchy updates.
+ checkForHierarchyUpdate = true; // Overlap can change with scrolling, so need to check for hierarchy updates.
needGeometryUpdate = true;
break;
+ case CompositingUpdateOnCompositedScroll:
+ needGeometryUpdate = true;
+ break;
}
if (!checkForHierarchyUpdate && !needGeometryUpdate)
@@ -428,11 +549,10 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
bool needHierarchyUpdate = m_compositingLayersNeedRebuild;
bool isFullUpdate = !updateRoot;
- if (!updateRoot || m_compositingConsultsOverlap) {
- // Only clear the flag if we're updating the entire hierarchy.
- m_compositingLayersNeedRebuild = false;
- updateRoot = rootRenderLayer();
- }
+
+ // Only clear the flag if we're updating the entire hierarchy.
+ m_compositingLayersNeedRebuild = false;
+ updateRoot = rootRenderLayer();
if (isFullUpdate && updateType == CompositingUpdateAfterLayout)
m_reevaluateCompositingAfterLayout = false;
@@ -448,15 +568,11 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
if (checkForHierarchyUpdate) {
// Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers.
// FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex.
- CompositingState compState(updateRoot, m_compositingConsultsOverlap);
+ CompositingState compState(updateRoot);
bool layersChanged = false;
bool saw3DTransform = false;
- if (m_compositingConsultsOverlap) {
- OverlapMap overlapTestRequestMap;
- computeCompositingRequirements(0, updateRoot, &overlapTestRequestMap, compState, layersChanged, saw3DTransform);
- } else
- computeCompositingRequirements(0, updateRoot, 0, compState, layersChanged, saw3DTransform);
-
+ OverlapMap overlapTestRequestMap;
+ computeCompositingRequirements(0, updateRoot, &overlapTestRequestMap, compState, layersChanged, saw3DTransform);
needHierarchyUpdate |= layersChanged;
}
@@ -469,8 +585,7 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
Frame* frame = m_renderView->frameView()->frame();
bool isMainFrame = !m_renderView->document()->ownerElement();
- LOG(Compositing, "\nUpdate %d of %s. Overlap testing is %s\n", m_rootLayerUpdateCount, isMainFrame ? "main frame" : frame->tree()->uniqueName().string().utf8().data(),
- m_compositingConsultsOverlap ? "on" : "off");
+ LOG(Compositing, "\nUpdate %d of %s.\n", m_rootLayerUpdateCount, isMainFrame ? "main frame" : frame->tree()->uniqueName().string().utf8().data());
}
#endif
@@ -508,6 +623,18 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
if (!hasAcceleratedCompositing())
enableCompositingMode(false);
+
+ // Inform the inspector that the layer tree has changed.
+ InspectorInstrumentation::layerTreeDidChange(page());
+}
+
+void RenderLayerCompositor::layerBecameNonComposited(const RenderLayer* renderLayer)
+{
+ // Inform the inspector that the given RenderLayer was destroyed.
+ InspectorInstrumentation::renderLayerDestroyed(page(), renderLayer);
+
+ ASSERT(m_compositedLayerCount > 0);
+ --m_compositedLayerCount;
}
#if !LOG_DISABLED
@@ -525,17 +652,36 @@ void RenderLayerCompositor::logLayerInfo(const RenderLayer* layer, int depth)
m_secondaryBackingStoreBytes += backing->backingStoreMemoryEstimate();
}
- LOG(Compositing, "%*p %dx%d %.2fKB (%s) %s\n", 12 + depth * 2, layer, backing->compositedBounds().width(), backing->compositedBounds().height(),
- backing->backingStoreMemoryEstimate() / 1024,
- reasonForCompositing(layer), layer->backing()->nameForLayer().utf8().data());
+ StringBuilder logString;
+ logString.append(String::format("%*p %dx%d %.2fKB", 12 + depth * 2, layer,
+ backing->compositedBounds().width().round(), backing->compositedBounds().height().round(),
+ backing->backingStoreMemoryEstimate() / 1024));
+
+ logString.append(" (");
+ logString.append(logReasonsForCompositing(layer));
+ logString.append(") ");
+
+ if (backing->graphicsLayer()->contentsOpaque() || backing->paintsIntoCompositedAncestor()) {
+ logString.append('[');
+ if (backing->graphicsLayer()->contentsOpaque())
+ logString.append("opaque");
+ if (backing->paintsIntoCompositedAncestor())
+ logString.append("paints into ancestor");
+ logString.append("] ");
+ }
+
+ logString.append(layer->name());
+
+ LOG(Compositing, "%s", logString.toString().utf8().data());
}
#endif
bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeRepaint shouldRepaint)
{
bool layerChanged = false;
+ RenderLayer::ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason = RenderLayer::NoNotCompositedReason;
- if (needsToBeComposited(layer)) {
+ if (needsToBeComposited(layer, &viewportConstrainedNotCompositedReason)) {
enableCompositingMode();
if (!layer->backing()) {
@@ -547,9 +693,15 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR
// At this time, the ScrollingCooridnator only supports the top-level frame.
if (layer->isRootLayer() && !m_renderView->document()->ownerElement()) {
- layer->backing()->attachToScrollingCoordinator(0);
+ layer->backing()->attachToScrollingCoordinatorWithParent(0);
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView());
+#if ENABLE(RUBBER_BANDING)
+ if (Page* page = this->page()) {
+ updateLayerForHeader(page->headerHeight());
+ updateLayerForFooter(page->footerHeight());
+ }
+#endif
}
// This layer and all of its descendants have cached repaints rects that are relative to
@@ -559,9 +711,6 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR
layerChanged = true;
}
-
- // Need to add for every compositing layer, because a composited layer may change from being non-fixed to fixed.
- updateViewportConstraintStatus(layer);
} else {
if (layer->backing()) {
// If we're removing backing on a reflection, clear the source GraphicsLayer's pointer to
@@ -607,10 +756,17 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR
if (layerChanged)
layer->clearClipRectsIncludingDescendants(PaintingClipRects);
- // If a fixed position layer gained/lost a backing, the scrolling coordinator needs to recalculate whether it can do fast scrolling.
- if (layerChanged && layer->renderer()->style()->position() == FixedPosition) {
- if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- scrollingCoordinator->frameViewFixedObjectsDidChange(m_renderView->frameView());
+ // If a fixed position layer gained/lost a backing or the reason not compositing it changed,
+ // the scrolling coordinator needs to recalculate whether it can do fast scrolling.
+ if (layer->renderer()->style()->position() == FixedPosition) {
+ if (layer->viewportConstrainedNotCompositedReason() != viewportConstrainedNotCompositedReason) {
+ layer->setViewportConstrainedNotCompositedReason(viewportConstrainedNotCompositedReason);
+ layerChanged = true;
+ }
+ if (layerChanged) {
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->frameViewFixedObjectsDidChange(m_renderView->frameView());
+ }
}
if (layer->backing())
@@ -653,7 +809,7 @@ void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer)
// This method assumes that layout is up-to-date, unlike repaintOnCompositingChange().
void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer* layer, const LayoutRect& rect)
{
- RenderLayer* compositedAncestor = layer->enclosingCompositingLayerForRepaint(false /*exclude self*/);
+ RenderLayer* compositedAncestor = layer->enclosingCompositingLayerForRepaint(ExcludeSelf);
if (compositedAncestor) {
ASSERT(compositedAncestor->backing());
@@ -674,11 +830,11 @@ void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer* layer, cons
// The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant
// RenderLayers that are rendered by the composited RenderLayer.
-IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) const
+LayoutRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) const
{
if (!canBeComposited(layer))
- return IntRect();
- return layer->calculateLayerBounds(ancestorLayer, 0, RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants);
+ return LayoutRect();
+ return layer->calculateLayerBounds(ancestorLayer, 0, RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask);
}
void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/)
@@ -701,7 +857,7 @@ void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer*
RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const
{
for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) {
- if (curr->isStackingContext())
+ if (curr->isStackingContainer())
return 0;
if (curr->renderer()->hasClipOrOverflowClip())
@@ -716,7 +872,9 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer*
return;
if (!boundsComputed) {
- layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer->localBoundingBox()));
+ // FIXME: If this layer's overlap bounds include its children, we don't need to add its
+ // children's bounds to the overlap map.
+ layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer->overlapBounds()));
// Empty rects never intersect, but we need them to for the purposes of overlap testing.
if (layerBounds.isEmpty())
layerBounds.setSize(IntSize(1, 1));
@@ -724,7 +882,9 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer*
}
IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(RenderLayer::ClipRectsContext(rootRenderLayer(), 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions.
- clipRect.scale(pageScaleFactor());
+ if (Settings* settings = m_renderView->document()->settings())
+ if (!settings->applyPageScaleFactorInCompositor())
+ clipRect.scale(pageScaleFactor());
clipRect.intersect(layerBounds);
overlapMap.add(layer, clipRect);
}
@@ -746,7 +906,7 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren
LayerListMutationDetector mutationChecker(layer);
#endif
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -764,7 +924,7 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren
}
}
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -790,20 +950,23 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren
void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestorLayer, RenderLayer* layer, OverlapMap* overlapMap, CompositingState& compositingState, bool& layersChanged, bool& descendantHas3DTransform)
{
layer->updateLayerListsIfNeeded();
-
+
+ if (layer->isOutOfFlowRenderFlowThread())
+ return;
+
if (overlapMap)
overlapMap->geometryMap().pushMappingsToAncestor(layer, ancestorLayer);
// Clear the flag
layer->setHasCompositingDescendant(false);
-
+
RenderLayer::IndirectCompositingReason compositingReason = compositingState.m_subtreeIsCompositing ? RenderLayer::IndirectCompositingForStacking : RenderLayer::NoIndirectCompositingReason;
bool haveComputedBounds = false;
IntRect absBounds;
if (overlapMap && !overlapMap->isEmpty() && compositingState.m_testingOverlap) {
// If we're testing for overlap, we only need to composite if we overlap something that is already composited.
- absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->localBoundingBox()));
+ absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds()));
// Empty rects never intersect, but we need them to for the purposes of overlap testing.
if (absBounds.isEmpty())
@@ -838,6 +1001,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
if (overlapMap)
overlapMap->pushCompositingContainer();
+ // This layer is going to be composited, so children can safely ignore the fact that there's an
+ // animation running behind this layer, meaning they can rely on the overlap map testing again.
+ childState.m_testingOverlap = true;
}
#if !ASSERT_DISABLED
@@ -846,7 +1012,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
bool anyDescendantHas3DTransform = false;
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -861,6 +1027,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
childState.m_compositingAncestor = layer;
if (overlapMap)
overlapMap->pushCompositingContainer();
+ // This layer is going to be composited, so children can safely ignore the fact that there's an
+ // animation running behind this layer, meaning they can rely on the overlap map testing again
+ childState.m_testingOverlap = true;
willBeComposited = true;
}
}
@@ -875,7 +1044,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
}
}
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -922,16 +1091,20 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
if (childState.m_subtreeIsCompositing)
compositingState.m_subtreeIsCompositing = true;
- // Turn overlap testing off for later layers if it's already off, or if we have a 3D transform or an animating transform.
- if (!childState.m_testingOverlap || layer->has3DTransform() || isRunningAcceleratedTransformAnimation(layer->renderer()))
- compositingState.m_testingOverlap = false;
-
// Set the flag to say that this SC has compositing children.
layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing);
// setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping,
// so test that again.
- if (canBeComposited(layer) && clipsCompositingDescendants(layer)) {
+ bool isCompositedClippingLayer = canBeComposited(layer) && clipsCompositingDescendants(layer);
+
+ // Turn overlap testing off for later layers if it's already off, or if we have an animating transform.
+ // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
+ // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
+ if ((!childState.m_testingOverlap && !isCompositedClippingLayer) || isRunningAcceleratedTransformAnimation(layer->renderer()))
+ compositingState.m_testingOverlap = false;
+
+ if (isCompositedClippingLayer) {
if (!willBeComposited) {
childState.m_compositingAncestor = layer;
if (overlapMap) {
@@ -940,9 +1113,6 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
}
willBeComposited = true;
}
-
- // We're done processing an element that clips. The container can keep testing overlap.
- compositingState.m_testingOverlap = true;
}
if (overlapMap && childState.m_compositingAncestor == layer && !layer->isRootLayer())
@@ -1017,6 +1187,9 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect
// Make the layer compositing if necessary, and set up clipping and content layers.
// Note that we can only do work here that is independent of whether the descendant layers
// have been processed. computeCompositingRequirements() will already have done the repaint if necessary.
+
+ if (layer->isOutOfFlowRenderFlowThread())
+ return;
RenderLayerBacking* layerBacking = layer->backing();
if (layerBacking) {
@@ -1029,7 +1202,9 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect
reflection->backing()->updateCompositedBounds();
}
- layerBacking->updateGraphicsLayerConfiguration();
+ if (layerBacking->updateGraphicsLayerConfiguration())
+ layerBacking->updateDebugIndicators(m_showDebugBorders, m_showRepaintCounter);
+
layerBacking->updateGraphicsLayerGeometry();
if (!layer->parent())
@@ -1040,6 +1215,8 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect
#else
UNUSED_PARAM(depth);
#endif
+ if (layerBacking->hasUnpositionedOverflowControlsLayers())
+ layer->positionNewlyCreatedOverflowControls();
}
// If this layer has backing, then we are collecting its children, otherwise appending
@@ -1051,7 +1228,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect
LayerListMutationDetector mutationChecker(layer);
#endif
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -1073,7 +1250,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect
}
}
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -1124,7 +1301,7 @@ void RenderLayerCompositor::frameViewDidChangeSize()
{
if (m_clipLayer) {
FrameView* frameView = m_renderView->frameView();
- m_clipLayer->setSize(frameView->visibleContentRect(false /* exclude scrollbars */).size());
+ m_clipLayer->setSize(frameView->unscaledVisibleContentSize());
frameViewDidScroll();
updateOverflowControlsLayers();
@@ -1136,6 +1313,12 @@ void RenderLayerCompositor::frameViewDidChangeSize()
}
}
+bool RenderLayerCompositor::hasCoordinatedScrolling() const
+{
+ ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator();
+ return scrollingCoordinator && scrollingCoordinator->coordinatesScrollingForFrameView(m_renderView->frameView());
+}
+
void RenderLayerCompositor::frameViewDidScroll()
{
FrameView* frameView = m_renderView->frameView();
@@ -1146,26 +1329,51 @@ void RenderLayerCompositor::frameViewDidScroll()
// If there's a scrolling coordinator that manages scrolling for this frame view,
// it will also manage updating the scroll layer position.
- if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
- if (scrollingCoordinator->coordinatesScrollingForFrameView(frameView))
- return;
+ if (hasCoordinatedScrolling())
+ return;
+
+ if (Settings* settings = m_renderView->document()->settings()) {
+ if (settings->compositedScrollingForFramesEnabled()) {
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->scrollableAreaScrollLayerDidChange(frameView);
+ }
}
m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y()));
+
+ if (GraphicsLayer* fixedBackgroundLayer = fixedRootBackgroundLayer())
+ fixedBackgroundLayer->setPosition(IntPoint(frameView->scrollOffsetForFixedPosition()));
}
void RenderLayerCompositor::frameViewDidLayout()
{
RenderLayerBacking* renderViewBacking = m_renderView->layer()->backing();
if (renderViewBacking)
- renderViewBacking->adjustTileCacheCoverage();
+ renderViewBacking->adjustTiledBackingCoverage();
+}
+
+void RenderLayerCompositor::rootFixedBackgroundsChanged()
+{
+ RenderLayerBacking* renderViewBacking = m_renderView->layer()->backing();
+ if (renderViewBacking && renderViewBacking->usingTiledBacking())
+ setCompositingLayersNeedRebuild();
}
void RenderLayerCompositor::scrollingLayerDidChange(RenderLayer* layer)
{
- RenderLayerBacking* backing = layer->backing();
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- scrollingCoordinator->scrollableAreaScrollLayerDidChange(layer, backing ? backing->scrollingContentsLayer() : 0);
+ scrollingCoordinator->scrollableAreaScrollLayerDidChange(layer);
+}
+
+void RenderLayerCompositor::fixedRootBackgroundLayerChanged()
+{
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
+ RenderLayerBacking* renderViewBacking = m_renderView->layer()->backing();
+ if (!renderViewBacking)
+ return;
+
+ scrollingCoordinator->updateScrollingNode(renderViewBacking->scrollLayerID(), scrollLayer(), fixedRootBackgroundLayer());
+ }
}
String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags)
@@ -1186,6 +1394,8 @@ String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags)
layerTreeBehavior |= LayerTreeAsTextIncludeTileCaches;
if (flags & LayerTreeFlagsIncludeRepaintRects)
layerTreeBehavior |= LayerTreeAsTextIncludeRepaintRects;
+ if (flags & LayerTreeFlagsIncludePaintingPhases)
+ layerTreeBehavior |= LayerTreeAsTextIncludePaintingPhases;
// We skip dumping the scroll and clip layers to keep layerTreeAsText output
// similar between platforms.
@@ -1207,7 +1417,7 @@ RenderLayerCompositor* RenderLayerCompositor::frameContentsCompositor(RenderPart
if (!renderer->node()->isFrameOwnerElement())
return 0;
- HTMLFrameOwnerElement* element = static_cast<HTMLFrameOwnerElement*>(renderer->node());
+ HTMLFrameOwnerElement* element = toFrameOwnerElement(renderer->node());
if (Document* contentDocument = element->contentDocument()) {
if (RenderView* view = contentDocument->renderView())
return view->compositor();
@@ -1265,7 +1475,7 @@ void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, int dept
LayerListMutationDetector mutationChecker(layer);
#endif
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i)
@@ -1279,7 +1489,7 @@ void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, int dept
updateLayerTreeGeometry(normalFlowList->at(i), depth + 1);
}
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i)
@@ -1289,7 +1499,7 @@ void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, int dept
}
// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry.
-void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, RenderLayerBacking::UpdateDepth updateDepth)
+void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, bool compositedChildrenOnly)
{
if (layer != compositingAncestor) {
if (RenderLayerBacking* layerBacking = layer->backing()) {
@@ -1301,13 +1511,13 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com
}
layerBacking->updateGraphicsLayerGeometry();
- if (updateDepth == RenderLayerBacking::CompositingChildren)
+ if (compositedChildrenOnly)
return;
}
}
if (layer->reflectionLayer())
- updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), updateDepth);
+ updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), compositedChildrenOnly);
if (!layer->hasCompositingDescendant())
return;
@@ -1316,25 +1526,25 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com
LayerListMutationDetector mutationChecker(layer);
#endif
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i)
- updateCompositingDescendantGeometry(compositingAncestor, negZOrderList->at(i), updateDepth);
+ updateCompositingDescendantGeometry(compositingAncestor, negZOrderList->at(i), compositedChildrenOnly);
}
}
if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) {
size_t listSize = normalFlowList->size();
for (size_t i = 0; i < listSize; ++i)
- updateCompositingDescendantGeometry(compositingAncestor, normalFlowList->at(i), updateDepth);
+ updateCompositingDescendantGeometry(compositingAncestor, normalFlowList->at(i), compositedChildrenOnly);
}
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i)
- updateCompositingDescendantGeometry(compositingAncestor, posZOrderList->at(i), updateDepth);
+ updateCompositingDescendantGeometry(compositingAncestor, posZOrderList->at(i), compositedChildrenOnly);
}
}
}
@@ -1417,33 +1627,44 @@ GraphicsLayer* RenderLayerCompositor::scrollLayer() const
return m_scrollLayer.get();
}
+#if ENABLE(RUBBER_BANDING)
+GraphicsLayer* RenderLayerCompositor::headerLayer() const
+{
+ return m_layerForHeader.get();
+}
+
+GraphicsLayer* RenderLayerCompositor::footerLayer() const
+{
+ return m_layerForFooter.get();
+}
+#endif
+
TiledBacking* RenderLayerCompositor::pageTiledBacking() const
{
RenderLayerBacking* renderViewBacking = m_renderView->layer()->backing();
return renderViewBacking ? renderViewBacking->tiledBacking() : 0;
}
-void RenderLayerCompositor::didMoveOnscreen()
+void RenderLayerCompositor::setIsInWindow(bool isInWindow)
{
if (TiledBacking* tiledBacking = pageTiledBacking())
- tiledBacking->setIsInWindow(true);
+ tiledBacking->setIsInWindow(isInWindow);
- if (!inCompositingMode() || m_rootLayerAttachment != RootLayerUnattached)
+ if (!inCompositingMode())
return;
- RootLayerAttachment attachment = shouldPropagateCompositingToEnclosingFrame() ? RootLayerAttachedViaEnclosingFrame : RootLayerAttachedViaChromeClient;
- attachRootLayer(attachment);
-}
-
-void RenderLayerCompositor::willMoveOffscreen()
-{
- if (TiledBacking* tiledBacking = pageTiledBacking())
- tiledBacking->setIsInWindow(false);
+ if (isInWindow) {
+ if (m_rootLayerAttachment != RootLayerUnattached)
+ return;
- if (!inCompositingMode() || m_rootLayerAttachment == RootLayerUnattached)
- return;
+ RootLayerAttachment attachment = shouldPropagateCompositingToEnclosingFrame() ? RootLayerAttachedViaEnclosingFrame : RootLayerAttachedViaChromeClient;
+ attachRootLayer(attachment);
+ } else {
+ if (m_rootLayerAttachment == RootLayerUnattached)
+ return;
- detachRootLayer();
+ detachRootLayer();
+ }
}
void RenderLayerCompositor::clearBackingForLayerIncludingDescendants(RenderLayer* layer)
@@ -1470,11 +1691,11 @@ void RenderLayerCompositor::updateRootLayerPosition()
if (m_rootContentLayer) {
const IntRect& documentRect = m_renderView->documentRect();
m_rootContentLayer->setSize(documentRect.size());
- m_rootContentLayer->setPosition(documentRect.location());
+ m_rootContentLayer->setPosition(FloatPoint(documentRect.x(), documentRect.y() + m_renderView->frameView()->headerHeight()));
}
if (m_clipLayer) {
FrameView* frameView = m_renderView->frameView();
- m_clipLayer->setSize(frameView->visibleContentRect(false /* exclude scrollbars */).size());
+ m_clipLayer->setSize(frameView->unscaledVisibleContentSize());
}
#if ENABLE(RUBBER_BANDING)
@@ -1487,6 +1708,11 @@ void RenderLayerCompositor::updateRootLayerPosition()
ScrollbarTheme::theme()->setUpContentShadowLayer(m_contentShadowLayer.get());
}
}
+
+ updateLayerForTopOverhangArea(m_layerForTopOverhangArea);
+ updateLayerForBottomOverhangArea(m_layerForBottomOverhangArea);
+ updateLayerForHeader(m_layerForHeader);
+ updateLayerForFooter(m_layerForFooter);
#endif
}
@@ -1533,7 +1759,7 @@ bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingFrame() const
RenderPart* frameRenderer = toRenderPart(renderer);
if (frameRenderer->widget()) {
ASSERT(frameRenderer->widget()->isFrameView());
- FrameView* view = static_cast<FrameView*>(frameRenderer->widget());
+ FrameView* view = toFrameView(frameRenderer->widget());
if (view->isOverlappedIncludingAncestors() || view->hasCompositingAncestor())
return true;
}
@@ -1541,18 +1767,18 @@ bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingFrame() const
return false;
}
-bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const
+bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason) const
{
if (!canBeComposited(layer))
return false;
- return requiresCompositingLayer(layer) || layer->mustCompositeForIndirectReasons() || (inCompositingMode() && layer->isRootLayer());
+ return requiresCompositingLayer(layer, viewportConstrainedNotCompositedReason) || layer->mustCompositeForIndirectReasons() || (inCompositingMode() && layer->isRootLayer());
}
// Note: this specifies whether the RL needs a compositing layer for intrinsic reasons.
// Use needsToBeComposited() to determine if a RL actually needs a compositing layer.
// static
-bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const
+bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason) const
{
RenderObject* renderer = layer->renderer();
// The compositing state of a reflection should match that of its reflected layer.
@@ -1570,7 +1796,7 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c
|| clipsCompositingDescendants(layer)
|| requiresCompositingForAnimation(renderer)
|| requiresCompositingForFilters(renderer)
- || requiresCompositingForPosition(renderer, layer)
+ || requiresCompositingForPosition(renderer, layer, viewportConstrainedNotCompositedReason)
|| requiresCompositingForOverflowScrolling(layer)
|| requiresCompositingForBlending(renderer);
}
@@ -1579,10 +1805,10 @@ bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const
{
// FIXME: We disable accelerated compositing for elements in a RenderFlowThread as it doesn't work properly.
// See http://webkit.org/b/84900 to re-enable it.
- return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer() && !layer->renderer()->inRenderFlowThread();
+ return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer() && layer->renderer()->flowThreadState() == RenderObject::NotInsideFlowThread;
}
-bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer* layer, const RenderLayer* compositingAncestorLayer) const
+bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer* layer, const RenderLayer* compositingAncestorLayer, const IntRect& layerCompositedBoundsInAncestor, const IntRect& ancestorCompositedBounds) const
{
RenderObject* renderer = layer->renderer();
if (compositingAncestorLayer
@@ -1618,12 +1844,20 @@ bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer* layer, co
|| reason == RenderLayer::IndirectCompositingForGraphicalEffect
|| reason == RenderLayer::IndirectCompositingForPreserve3D; // preserve-3d has to create backing store to ensure that 3d-transformed elements intersect.
}
+
+ if (!ancestorCompositedBounds.contains(layerCompositedBoundsInAncestor))
+ return true;
+
return false;
}
-#if !LOG_DISABLED
-const char* RenderLayerCompositor::reasonForCompositing(const RenderLayer* layer)
+CompositingReasons RenderLayerCompositor::reasonsForCompositing(const RenderLayer* layer) const
{
+ CompositingReasons reasons = CompositingReasonNone;
+
+ if (!layer || !layer->isComposited())
+ return reasons;
+
RenderObject* renderer = layer->renderer();
if (layer->isReflection()) {
renderer = renderer->parent();
@@ -1631,74 +1865,142 @@ const char* RenderLayerCompositor::reasonForCompositing(const RenderLayer* layer
}
if (requiresCompositingForTransform(renderer))
- return "3D transform";
+ reasons |= CompositingReason3DTransform;
if (requiresCompositingForVideo(renderer))
- return "video";
+ reasons |= CompositingReasonVideo;
+ else if (requiresCompositingForCanvas(renderer))
+ reasons |= CompositingReasonCanvas;
+ else if (requiresCompositingForPlugin(renderer))
+ reasons |= CompositingReasonPlugin;
+ else if (requiresCompositingForFrame(renderer))
+ reasons |= CompositingReasonIFrame;
+
+ if ((canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden))
+ reasons |= CompositingReasonBackfaceVisibilityHidden;
- if (requiresCompositingForCanvas(renderer))
- return "canvas";
+ if (clipsCompositingDescendants(layer))
+ reasons |= CompositingReasonClipsCompositingDescendants;
- if (requiresCompositingForPlugin(renderer))
- return "plugin";
+ if (requiresCompositingForAnimation(renderer))
+ reasons |= CompositingReasonAnimation;
+
+ if (requiresCompositingForFilters(renderer))
+ reasons |= CompositingReasonFilters;
+
+ if (requiresCompositingForPosition(renderer, layer))
+ reasons |= renderer->style()->position() == FixedPosition ? CompositingReasonPositionFixed : CompositingReasonPositionSticky;
+
+ if (requiresCompositingForOverflowScrolling(layer))
+ reasons |= CompositingReasonOverflowScrollingTouch;
+
+ if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForStacking)
+ reasons |= CompositingReasonStacking;
+ else if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForOverlap)
+ reasons |= CompositingReasonOverlap;
+ else if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForBackgroundLayer)
+ reasons |= CompositingReasonNegativeZIndexChildren;
+ else if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForGraphicalEffect) {
+ if (layer->transform())
+ reasons |= CompositingReasonTransformWithCompositedDescendants;
- if (requiresCompositingForFrame(renderer))
+ if (renderer->isTransparent())
+ reasons |= CompositingReasonOpacityWithCompositedDescendants;
+
+ if (renderer->hasMask())
+ reasons |= CompositingReasonMaskWithCompositedDescendants;
+
+ if (renderer->hasReflection())
+ reasons |= CompositingReasonReflectionWithCompositedDescendants;
+
+ if (renderer->hasFilter())
+ reasons |= CompositingReasonFilterWithCompositedDescendants;
+
+ if (renderer->hasBlendMode())
+ reasons |= CompositingReasonBlendingWithCompositedDescendants;
+ } else if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForPerspective)
+ reasons |= CompositingReasonPerspective;
+ else if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForPreserve3D)
+ reasons |= CompositingReasonPreserve3D;
+
+ if (inCompositingMode() && layer->isRootLayer())
+ reasons |= CompositingReasonRoot;
+
+ return reasons;
+}
+
+#if !LOG_DISABLED
+const char* RenderLayerCompositor::logReasonsForCompositing(const RenderLayer* layer)
+{
+ CompositingReasons reasons = reasonsForCompositing(layer);
+
+ if (reasons & CompositingReason3DTransform)
+ return "3D transform";
+
+ if (reasons & CompositingReasonVideo)
+ return "video";
+ else if (reasons & CompositingReasonCanvas)
+ return "canvas";
+ else if (reasons & CompositingReasonPlugin)
+ return "plugin";
+ else if (reasons & CompositingReasonIFrame)
return "iframe";
- if ((canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden))
+ if (reasons & CompositingReasonBackfaceVisibilityHidden)
return "backface-visibility: hidden";
- if (clipsCompositingDescendants(layer))
+ if (reasons & CompositingReasonClipsCompositingDescendants)
return "clips compositing descendants";
- if (requiresCompositingForAnimation(renderer))
+ if (reasons & CompositingReasonAnimation)
return "animation";
- if (requiresCompositingForFilters(renderer))
+ if (reasons & CompositingReasonFilters)
return "filters";
- if (requiresCompositingForPosition(renderer, layer))
+ if (reasons & CompositingReasonPositionFixed)
return "position: fixed";
- if (requiresCompositingForOverflowScrolling(layer))
+ if (reasons & CompositingReasonPositionSticky)
+ return "position: sticky";
+
+ if (reasons & CompositingReasonOverflowScrollingTouch)
return "-webkit-overflow-scrolling: touch";
- if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForStacking)
+ if (reasons & CompositingReasonStacking)
return "stacking";
- if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForOverlap)
+ if (reasons & CompositingReasonOverlap)
return "overlap";
- if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForBackgroundLayer)
+ if (reasons & CompositingReasonNegativeZIndexChildren)
return "negative z-index children";
- if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForGraphicalEffect) {
- if (layer->transform())
- return "transform with composited descendants";
+ if (reasons & CompositingReasonTransformWithCompositedDescendants)
+ return "transform with composited descendants";
- if (renderer->isTransparent())
- return "opacity with composited descendants";
+ if (reasons & CompositingReasonOpacityWithCompositedDescendants)
+ return "opacity with composited descendants";
- if (renderer->hasMask())
- return "mask with composited descendants";
+ if (reasons & CompositingReasonMaskWithCompositedDescendants)
+ return "mask with composited descendants";
- if (renderer->hasReflection())
- return "reflection with composited descendants";
+ if (reasons & CompositingReasonReflectionWithCompositedDescendants)
+ return "reflection with composited descendants";
- if (renderer->hasFilter())
- return "filter with composited descendants";
+ if (reasons & CompositingReasonFilterWithCompositedDescendants)
+ return "filter with composited descendants";
- if (renderer->hasBlendMode())
- return "blending with composited descendants";
- }
+ if (reasons & CompositingReasonBlendingWithCompositedDescendants)
+ return "blending with composited descendants";
- if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForPerspective)
+ if (reasons & CompositingReasonPerspective)
return "perspective";
- if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForPreserve3D)
+ if (reasons & CompositingReasonPreserve3D)
return "preserve-3d";
- if (inCompositingMode() && layer->isRootLayer())
+ if (reasons & CompositingReasonRoot)
return "root";
return "";
@@ -1747,38 +2049,19 @@ bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer
return layer->hasCompositingDescendant() && layer->renderer()->hasClipOrOverflowClip();
}
-// Return true if there is an ancestor layer that is fixed positioned to the view.
-// Note that if the ancestor has a stacking context and is fixed position then this method
-// will return false.
-bool RenderLayerCompositor::fixedPositionedByAncestor(const RenderLayer* layer) const
-{
- if (!layer->isComposited() || !layer->parent())
- return false;
-
- const RenderLayer* compositingAncestor = layer->ancestorCompositingLayer();
- if (!compositingAncestor)
- return false;
-
- const RenderLayer* curr = layer;
- while (curr) {
- const RenderLayer* next = curr->parent();
- if (next == compositingAncestor)
- return false;
-
- if (next && next->renderer()->style()->position() == FixedPosition)
- return true;
- curr = next;
- }
- return false;
-}
-
bool RenderLayerCompositor::requiresCompositingForScrollableFrame() const
{
// Need this done first to determine overflow.
ASSERT(!m_renderView->needsLayout());
+ HTMLFrameOwnerElement* ownerElement = m_renderView->document()->ownerElement();
+ if (!ownerElement)
+ return false;
+
+ if (!(m_compositingTriggers & ChromeClient::ScrollableInnerFrameTrigger))
+ return false;
- ScrollView* scrollView = m_renderView->frameView();
- return scrollView->verticalScrollbar() || scrollView->horizontalScrollbar();
+ FrameView* frameView = m_renderView->frameView();
+ return frameView->isScrollable();
}
bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer) const
@@ -1807,10 +2090,10 @@ bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer)
return false;
Node* node = renderer->node();
- if (!node || (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag)))
+ if (!node || (!node->hasTagName(HTMLNames::videoTag) && !isHTMLAudioElement(node)))
return false;
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
+ HTMLMediaElement* mediaElement = toHTMLMediaElement(node);
return mediaElement->player() ? mediaElement->player()->supportsAcceleratedRendering() : false;
}
#endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
@@ -1827,7 +2110,12 @@ bool RenderLayerCompositor::requiresCompositingForCanvas(RenderObject* renderer)
if (renderer->isCanvas()) {
HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer->node());
- return canvas->renderingContext() && canvas->renderingContext()->isAccelerated();
+#if USE(COMPOSITING_FOR_SMALL_CANVASES)
+ bool isCanvasLargeEnoughToForceCompositing = true;
+#else
+ bool isCanvasLargeEnoughToForceCompositing = canvas->size().area() >= canvasAreaThresholdRequiringCompositing;
+#endif
+ return canvas->renderingContext() && canvas->renderingContext()->isAccelerated() && (canvas->renderingContext()->is3d() || isCanvasLargeEnoughToForceCompositing);
}
return false;
}
@@ -1870,7 +2158,7 @@ bool RenderLayerCompositor::requiresCompositingForFrame(RenderObject* renderer)
return false;
// If we can't reliably know the size of the iframe yet, don't change compositing state.
- if (renderer->needsLayout())
+ if (!renderer->parent() || renderer->needsLayout())
return frameRenderer->hasLayer() && frameRenderer->layer()->isComposited();
// Don't go into compositing mode if height or width are zero.
@@ -1949,17 +2237,47 @@ bool RenderLayerCompositor::requiresCompositingForBlending(RenderObject* rendere
#endif
}
-bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer) const
+static bool isViewportConstrainedFixedOrStickyLayer(const RenderLayer* layer)
+{
+ if (layer->renderer()->isStickyPositioned())
+ return !layer->enclosingOverflowClipLayer(ExcludeSelf);
+
+ if (layer->renderer()->style()->position() != FixedPosition)
+ return false;
+
+ for (RenderLayer* stackingContainer = layer->stackingContainer(); stackingContainer; stackingContainer = stackingContainer->stackingContainer()) {
+ if (stackingContainer->isComposited() && stackingContainer->renderer()->style()->position() == FixedPosition)
+ return false;
+ }
+
+ return true;
+}
+
+bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason) const
{
// position:fixed elements that create their own stacking context (e.g. have an explicit z-index,
// opacity, transform) can get their own composited layer. A stacking context is required otherwise
// z-index and clipping will be broken.
- if (!(renderer->isOutOfFlowPositioned() && renderer->style()->position() == FixedPosition && layer->isStackingContext()))
+ if (!renderer->isPositioned())
+ return false;
+
+ EPosition position = renderer->style()->position();
+ bool isFixed = renderer->isOutOfFlowPositioned() && position == FixedPosition;
+ if (isFixed && !layer->isStackingContainer())
+ return false;
+
+ bool isSticky = renderer->isInFlowPositioned() && position == StickyPosition;
+ if (!isFixed && !isSticky)
return false;
- if (Settings* settings = m_renderView->document()->settings())
+ // FIXME: acceleratedCompositingForFixedPositionEnabled should probably be renamed acceleratedCompositingForViewportConstrainedPositionEnabled().
+ if (Settings* settings = m_renderView->document()->settings()) {
if (!settings->acceleratedCompositingForFixedPositionEnabled())
return false;
+ }
+
+ if (isSticky)
+ return hasCoordinatedScrolling() && isViewportConstrainedFixedOrStickyLayer(layer);
RenderObject* container = renderer->container();
// If the renderer is not hooked up yet then we have to wait until it is.
@@ -1968,25 +2286,45 @@ bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* rendere
return false;
}
- // Don't promote fixed position elements that are descendants of transformed elements.
- // They will stay fixed wrt the transformed element rather than the enclosing frame.
- if (container != m_renderView)
+ // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements.
+ // They will stay fixed wrt the container rather than the enclosing frame.
+ if (container != m_renderView) {
+ if (viewportConstrainedNotCompositedReason)
+ *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer;
return false;
+ }
+
+ // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done.
+ if (!m_inPostLayoutUpdate) {
+ m_reevaluateCompositingAfterLayout = true;
+ return layer->isComposited();
+ }
+
+ bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant();
+ if (!paintsContent) {
+ if (viewportConstrainedNotCompositedReason)
+ *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent;
+ return false;
+ }
// Fixed position elements that are invisible in the current view don't get their own layer.
if (FrameView* frameView = m_renderView->frameView()) {
- IntRect viewBounds = IntRect(IntPoint(frameView->scrollOffsetForFixedPosition()), frameView->layoutSize());
- IntRect layerBounds = calculateCompositedBounds(layer, rootRenderLayer());
- if (!viewBounds.intersects(layerBounds))
+ LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect();
+ LayoutRect layerBounds = layer->calculateLayerBounds(rootRenderLayer(), 0, RenderLayer::DefaultCalculateLayerBoundsFlags
+ | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask | RenderLayer::IncludeCompositedDescendants);
+ if (!viewBounds.intersects(enclosingIntRect(layerBounds))) {
+ if (viewportConstrainedNotCompositedReason)
+ *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView;
return false;
+ }
}
-
+
return true;
}
bool RenderLayerCompositor::requiresCompositingForOverflowScrolling(const RenderLayer* layer) const
{
- return layer->usesCompositedScrolling();
+ return layer->needsCompositedScrolling();
}
bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const
@@ -2047,26 +2385,34 @@ void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, Gr
transformedClip.moveBy(scrollCorner.location());
m_renderView->frameView()->paintScrollCorner(&context, transformedClip);
context.restore();
-#if PLATFORM(CHROMIUM) && ENABLE(RUBBER_BANDING)
- } else if (graphicsLayer == layerForOverhangAreas()) {
- ScrollView* view = m_renderView->frameView();
- view->calculateAndPaintOverhangAreas(&context, clip);
-#endif
}
}
-void RenderLayerCompositor::documentBackgroundColorDidChange()
+bool RenderLayerCompositor::supportsFixedRootBackgroundCompositing() const
{
- RenderLayerBacking* backing = rootRenderLayer()->backing();
- if (!backing || !backing->usingTileCache())
- return;
+ RenderLayerBacking* renderViewBacking = m_renderView->layer()->backing();
+ return renderViewBacking && renderViewBacking->usingTiledBacking();
+}
- GraphicsLayer* graphicsLayer = backing->graphicsLayer();
- Color backgroundColor = m_renderView->frameView()->documentBackgroundColor();
- if (!backgroundColor.isValid() || backgroundColor.hasAlpha())
- backgroundColor = Color::white;
+bool RenderLayerCompositor::needsFixedRootBackgroundLayer(const RenderLayer* layer) const
+{
+ if (layer != m_renderView->layer())
+ return false;
+
+ return supportsFixedRootBackgroundCompositing() && m_renderView->rootBackgroundIsEntirelyFixed();
+}
+
+GraphicsLayer* RenderLayerCompositor::fixedRootBackgroundLayer() const
+{
+ // Get the fixed root background from the RenderView layer's backing.
+ RenderLayer* viewLayer = m_renderView->layer();
+ if (!viewLayer)
+ return 0;
+
+ if (viewLayer->isComposited() && viewLayer->backing()->backgroundLayerPaintsFixedRootBackground())
+ return viewLayer->backing()->backgroundLayer();
- graphicsLayer->setBackgroundColor(backgroundColor);
+ return 0;
}
static void resetTrackedRepaintRectsRecursive(GraphicsLayer* graphicsLayer)
@@ -2125,40 +2471,38 @@ bool RenderLayerCompositor::keepLayersPixelAligned() const
return true;
}
-static bool shouldCompositeOverflowControls(FrameView* view)
+bool RenderLayerCompositor::shouldCompositeOverflowControls() const
{
+ FrameView* view = m_renderView->frameView();
+
if (view->platformWidget())
return false;
- if (Page* page = view->frame()->page()) {
- if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
- if (scrollingCoordinator->coordinatesScrollingForFrameView(view))
- return true;
- }
+ if (hasCoordinatedScrolling())
+ return true;
-#if !PLATFORM(CHROMIUM)
if (!view->hasOverlayScrollbars())
return false;
-#endif
+
return true;
}
bool RenderLayerCompositor::requiresHorizontalScrollbarLayer() const
{
FrameView* view = m_renderView->frameView();
- return shouldCompositeOverflowControls(view) && view->horizontalScrollbar();
+ return shouldCompositeOverflowControls() && view->horizontalScrollbar();
}
bool RenderLayerCompositor::requiresVerticalScrollbarLayer() const
{
FrameView* view = m_renderView->frameView();
- return shouldCompositeOverflowControls(view) && view->verticalScrollbar();
+ return shouldCompositeOverflowControls() && view->verticalScrollbar();
}
bool RenderLayerCompositor::requiresScrollCornerLayer() const
{
FrameView* view = m_renderView->frameView();
- return shouldCompositeOverflowControls(view) && view->isScrollCornerVisible();
+ return shouldCompositeOverflowControls() && view->isScrollCornerVisible();
}
#if ENABLE(RUBBER_BANDING)
@@ -2168,15 +2512,10 @@ bool RenderLayerCompositor::requiresOverhangAreasLayer() const
if (m_renderView->document()->ownerElement())
return false;
- // We do want a layer if we have a scrolling coordinator.
- if (scrollingCoordinator())
+ // We do want a layer if we have a scrolling coordinator and can scroll.
+ if (scrollingCoordinator() && m_renderView->frameView()->hasOpaqueBackground() && !m_renderView->frameView()->prohibitsScrolling())
return true;
- // Chromium always wants a layer.
-#if PLATFORM(CHROMIUM)
- return true;
-#endif
-
return false;
}
@@ -2187,14 +2526,165 @@ bool RenderLayerCompositor::requiresContentShadowLayer() const
return false;
#if PLATFORM(MAC)
- // On Mac, we want a content shadow layer if we have a scrolling coordinator.
- if (scrollingCoordinator())
+ if (viewHasTransparentBackground())
+ return false;
+
+ // On Mac, we want a content shadow layer if we have a scrolling coordinator and can scroll.
+ if (scrollingCoordinator() && !m_renderView->frameView()->prohibitsScrolling())
return true;
#endif
return false;
}
+
+GraphicsLayer* RenderLayerCompositor::updateLayerForTopOverhangArea(bool wantsLayer)
+{
+ if (m_renderView->document()->ownerElement())
+ return 0;
+
+ if (!wantsLayer) {
+ if (m_layerForTopOverhangArea) {
+ m_layerForTopOverhangArea->removeFromParent();
+ m_layerForTopOverhangArea = nullptr;
+ }
+ return 0;
+ }
+
+ if (!m_layerForTopOverhangArea) {
+ m_layerForTopOverhangArea = GraphicsLayer::create(graphicsLayerFactory(), this);
+#ifndef NDEBUG
+ m_layerForTopOverhangArea->setName("top overhang area");
+#endif
+ m_scrollLayer->addChildBelow(m_layerForTopOverhangArea.get(), m_rootContentLayer.get());
+ }
+
+ return m_layerForTopOverhangArea.get();
+}
+
+GraphicsLayer* RenderLayerCompositor::updateLayerForBottomOverhangArea(bool wantsLayer)
+{
+ if (m_renderView->document()->ownerElement())
+ return 0;
+
+ if (!wantsLayer) {
+ if (m_layerForBottomOverhangArea) {
+ m_layerForBottomOverhangArea->removeFromParent();
+ m_layerForBottomOverhangArea = nullptr;
+ }
+ return 0;
+ }
+
+ if (!m_layerForBottomOverhangArea) {
+ m_layerForBottomOverhangArea = GraphicsLayer::create(graphicsLayerFactory(), this);
+#ifndef NDEBUG
+ m_layerForBottomOverhangArea->setName("bottom overhang area");
#endif
+ m_scrollLayer->addChildBelow(m_layerForBottomOverhangArea.get(), m_rootContentLayer.get());
+ }
+
+ m_layerForBottomOverhangArea->setPosition(FloatPoint(0, m_rootContentLayer->size().height() + m_renderView->frameView()->headerHeight() + m_renderView->frameView()->footerHeight()));
+ return m_layerForBottomOverhangArea.get();
+}
+
+GraphicsLayer* RenderLayerCompositor::updateLayerForHeader(bool wantsLayer)
+{
+ if (m_renderView->document()->ownerElement())
+ return 0;
+
+ if (!wantsLayer) {
+ if (m_layerForHeader) {
+ m_layerForHeader->removeFromParent();
+ m_layerForHeader = nullptr;
+
+ // The ScrollingTree knows about the header layer, and the position of the root layer is affected
+ // by the header layer, so if we remove the header, we need to tell the scrolling tree.
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView());
+ }
+ return 0;
+ }
+
+ if (!m_layerForHeader) {
+ m_layerForHeader = GraphicsLayer::create(graphicsLayerFactory(), this);
+#ifndef NDEBUG
+ m_layerForHeader->setName("header");
+#endif
+ m_scrollLayer->addChildBelow(m_layerForHeader.get(), m_rootContentLayer.get());
+ m_renderView->frameView()->addPaintPendingMilestones(DidFirstFlushForHeaderLayer);
+ }
+
+ m_layerForHeader->setPosition(FloatPoint());
+ m_layerForHeader->setAnchorPoint(FloatPoint3D());
+ m_layerForHeader->setSize(FloatSize(m_renderView->frameView()->visibleWidth(), m_renderView->frameView()->headerHeight()));
+
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView());
+
+ if (Page* page = this->page())
+ page->chrome().client()->didAddHeaderLayer(m_layerForHeader.get());
+
+ return m_layerForHeader.get();
+}
+
+GraphicsLayer* RenderLayerCompositor::updateLayerForFooter(bool wantsLayer)
+{
+ if (m_renderView->document()->ownerElement())
+ return 0;
+
+ if (!wantsLayer) {
+ if (m_layerForFooter) {
+ m_layerForFooter->removeFromParent();
+ m_layerForFooter = nullptr;
+
+ // The ScrollingTree knows about the footer layer, and the total scrollable size is affected
+ // by the footer layer, so if we remove the footer, we need to tell the scrolling tree.
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView());
+ }
+ return 0;
+ }
+
+ if (!m_layerForFooter) {
+ m_layerForFooter = GraphicsLayer::create(graphicsLayerFactory(), this);
+#ifndef NDEBUG
+ m_layerForFooter->setName("footer");
+#endif
+ m_scrollLayer->addChildBelow(m_layerForFooter.get(), m_rootContentLayer.get());
+ }
+
+ m_layerForFooter->setPosition(FloatPoint(0, m_rootContentLayer->size().height() + m_renderView->frameView()->headerHeight()));
+ m_layerForFooter->setAnchorPoint(FloatPoint3D());
+ m_layerForFooter->setSize(FloatSize(m_renderView->frameView()->visibleWidth(), m_renderView->frameView()->footerHeight()));
+
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView());
+
+ if (Page* page = this->page())
+ page->chrome().client()->didAddFooterLayer(m_layerForFooter.get());
+
+ return m_layerForFooter.get();
+}
+
+#endif
+
+bool RenderLayerCompositor::viewHasTransparentBackground(Color* backgroundColor) const
+{
+ FrameView* frameView = m_renderView->frameView();
+ if (frameView->isTransparent()) {
+ if (backgroundColor)
+ *backgroundColor = Color(); // Return an invalid color.
+ return true;
+ }
+
+ Color documentBackgroundColor = frameView->documentBackgroundColor();
+ if (!documentBackgroundColor.isValid())
+ documentBackgroundColor = Color::white;
+
+ if (backgroundColor)
+ *backgroundColor = documentBackgroundColor;
+
+ return documentBackgroundColor.hasAlpha();
+}
void RenderLayerCompositor::updateOverflowControlsLayers()
{
@@ -2208,7 +2698,7 @@ void RenderLayerCompositor::updateOverflowControlsLayers()
m_layerForOverhangAreas->setDrawsContent(false);
m_layerForOverhangAreas->setSize(m_renderView->frameView()->frameRect().size());
- ScrollbarTheme::theme()->setUpOverhangAreasLayerContents(m_layerForOverhangAreas.get());
+ ScrollbarTheme::theme()->setUpOverhangAreasLayerContents(m_layerForOverhangAreas.get(), this->page()->chrome().client()->underlayColor());
// We want the overhang areas layer to be positioned below the frame contents,
// so insert it below the clip layer.
@@ -2250,14 +2740,14 @@ void RenderLayerCompositor::updateOverflowControlsLayers()
m_overflowControlsHostLayer->addChild(m_layerForHorizontalScrollbar.get());
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- scrollingCoordinator->frameViewHorizontalScrollbarLayerDidChange(m_renderView->frameView(), m_layerForHorizontalScrollbar.get());
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar);
}
} else if (m_layerForHorizontalScrollbar) {
m_layerForHorizontalScrollbar->removeFromParent();
m_layerForHorizontalScrollbar = nullptr;
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- scrollingCoordinator->frameViewHorizontalScrollbarLayerDidChange(m_renderView->frameView(), 0);
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar);
}
if (requiresVerticalScrollbarLayer()) {
@@ -2273,14 +2763,14 @@ void RenderLayerCompositor::updateOverflowControlsLayers()
m_overflowControlsHostLayer->addChild(m_layerForVerticalScrollbar.get());
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- scrollingCoordinator->frameViewVerticalScrollbarLayerDidChange(m_renderView->frameView(), m_layerForVerticalScrollbar.get());
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar);
}
} else if (m_layerForVerticalScrollbar) {
m_layerForVerticalScrollbar->removeFromParent();
m_layerForVerticalScrollbar = nullptr;
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- scrollingCoordinator->frameViewVerticalScrollbarLayerDidChange(m_renderView->frameView(), 0);
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar);
}
if (requiresScrollCornerLayer()) {
@@ -2387,6 +2877,8 @@ void RenderLayerCompositor::destroyRootLayer()
if (m_layerForHorizontalScrollbar) {
m_layerForHorizontalScrollbar->removeFromParent();
m_layerForHorizontalScrollbar = nullptr;
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar);
if (Scrollbar* horizontalScrollbar = m_renderView->frameView()->verticalScrollbar())
m_renderView->frameView()->invalidateScrollbar(horizontalScrollbar, IntRect(IntPoint(0, 0), horizontalScrollbar->frameRect().size()));
}
@@ -2394,6 +2886,8 @@ void RenderLayerCompositor::destroyRootLayer()
if (m_layerForVerticalScrollbar) {
m_layerForVerticalScrollbar->removeFromParent();
m_layerForVerticalScrollbar = nullptr;
+ if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar);
if (Scrollbar* verticalScrollbar = m_renderView->frameView()->verticalScrollbar())
m_renderView->frameView()->invalidateScrollbar(verticalScrollbar, IntRect(IntPoint(0, 0), verticalScrollbar->frameRect().size()));
}
@@ -2429,7 +2923,7 @@ void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment)
if (!page)
return;
- page->chrome()->client()->attachRootGraphicsLayer(frame, rootGraphicsLayer());
+ page->chrome().client()->attachRootGraphicsLayer(frame, rootGraphicsLayer());
break;
}
case RootLayerAttachedViaEnclosingFrame: {
@@ -2473,7 +2967,7 @@ void RenderLayerCompositor::detachRootLayer()
if (!page)
return;
- page->chrome()->client()->attachRootGraphicsLayer(frame, 0);
+ page->chrome().client()->attachRootGraphicsLayer(frame, 0);
}
break;
case RootLayerUnattached:
@@ -2534,7 +3028,7 @@ bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const
LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(layer));
#endif
- if (layer->isStackingContext()) {
+ if (layer->isStackingContainer()) {
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
@@ -2572,29 +3066,13 @@ void RenderLayerCompositor::deviceOrPageScaleFactorChanged()
if (!viewLayer->isComposited())
return;
- if (GraphicsLayer* rootLayer = viewLayer->backing()->graphicsLayer())
+ if (GraphicsLayer* rootLayer = viewLayer->backing()->childForSuperlayers())
rootLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
}
-static bool isRootmostFixedOrStickyLayer(RenderLayer* layer)
-{
- if (layer->renderer()->isStickyPositioned())
- return true;
-
- if (layer->renderer()->style()->position() != FixedPosition)
- return false;
-
- for (RenderLayer* stackingContext = layer->stackingContext(); stackingContext; stackingContext = stackingContext->stackingContext()) {
- if (stackingContext->isComposited() && stackingContext->renderer()->style()->position() == FixedPosition)
- return false;
- }
-
- return true;
-}
-
void RenderLayerCompositor::updateViewportConstraintStatus(RenderLayer* layer)
{
- if (isRootmostFixedOrStickyLayer(layer))
+ if (isViewportConstrainedFixedOrStickyLayer(layer))
addViewportConstrainedLayer(layer);
else
removeViewportConstrainedLayer(layer);
@@ -2613,24 +3091,23 @@ void RenderLayerCompositor::removeViewportConstrainedLayer(RenderLayer* layer)
unregisterViewportConstrainedLayer(layer);
m_viewportConstrainedLayers.remove(layer);
+ m_viewportConstrainedLayersNeedingUpdate.remove(layer);
}
-const FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewportConstraints(RenderLayer* layer)
+FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewportConstraints(RenderLayer* layer) const
{
ASSERT(layer->isComposited());
FrameView* frameView = m_renderView->frameView();
+ LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
- LayoutRect viewportRect = frameView->visibleContentRect();
- viewportRect.setLocation(toPoint(frameView->scrollOffsetForFixedPosition()));
-
- FixedPositionViewportConstraints constraints = FixedPositionViewportConstraints();
+ FixedPositionViewportConstraints constraints;
GraphicsLayer* graphicsLayer = layer->backing()->graphicsLayer();
constraints.setLayerPositionAtLastLayout(graphicsLayer->position());
constraints.setViewportRectAtLastLayout(viewportRect);
-
+
RenderStyle* style = layer->renderer()->style();
if (!style->left().isAuto())
constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
@@ -2655,17 +3132,18 @@ const FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewpo
return constraints;
}
-const StickyPositionViewportConstraints RenderLayerCompositor::computeStickyViewportConstraints(RenderLayer* layer)
+StickyPositionViewportConstraints RenderLayerCompositor::computeStickyViewportConstraints(RenderLayer* layer) const
{
ASSERT(layer->isComposited());
+ // We should never get here for stickies constrained by an enclosing clipping layer.
+ ASSERT(!layer->enclosingOverflowClipLayer(ExcludeSelf));
FrameView* frameView = m_renderView->frameView();
- LayoutRect viewportRect = frameView->visibleContentRect();
-
- StickyPositionViewportConstraints constraints = StickyPositionViewportConstraints();
+ LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
RenderBoxModelObject* renderer = toRenderBoxModelObject(layer->renderer());
+ StickyPositionViewportConstraints constraints;
renderer->computeStickyPositionConstraints(constraints, viewportRect);
GraphicsLayer* graphicsLayer = layer->backing()->graphicsLayer();
@@ -2694,17 +3172,17 @@ void RenderLayerCompositor::registerOrUpdateViewportConstrainedLayer(RenderLayer
{
// FIXME: We should support sticky position here! And we should eventuall support fixed/sticky elements
// that are inside non-main frames once we get non-main frames scrolling with the ScrollingCoordinator.
- if (layer->renderer()->isStickyPositioned() || m_renderView->document()->ownerElement())
+ if (m_renderView->document()->ownerElement())
return;
ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator();
if (!scrollingCoordinator)
return;
+ // FIXME: rename to supportsViewportConstrainedPositionLayers()?
if (!scrollingCoordinator->supportsFixedPositionLayers() || !layer->parent())
return;
- ASSERT(layer->renderer()->style()->position() == FixedPosition);
ASSERT(m_viewportConstrainedLayers.contains(layer));
ASSERT(layer->isComposited());
@@ -2713,13 +3191,13 @@ void RenderLayerCompositor::registerOrUpdateViewportConstrainedLayer(RenderLayer
return;
ScrollingNodeID nodeID = backing->scrollLayerID();
- if (!nodeID) {
- RenderLayerBacking* parent = nearestScrollingCoordinatorAncestor(layer);
- if (!parent)
- return;
- backing->attachToScrollingCoordinator(parent);
- nodeID = backing->scrollLayerID();
- }
+ RenderLayerBacking* parent = nearestScrollingCoordinatorAncestor(layer);
+ if (!parent)
+ return;
+
+ // Always call this even if the backing is already attached because the parent may have changed.
+ backing->attachToScrollingCoordinatorWithParent(parent);
+ nodeID = backing->scrollLayerID();
if (layer->renderer()->isStickyPositioned())
scrollingCoordinator->updateViewportConstrainedNode(nodeID, computeStickyViewportConstraints(layer), backing->graphicsLayer());
@@ -2752,7 +3230,7 @@ ScrollingCoordinator* RenderLayerCompositor::scrollingCoordinator() const
GraphicsLayerFactory* RenderLayerCompositor::graphicsLayerFactory() const
{
if (Page* page = this->page())
- return page->chrome()->client()->graphicsLayerFactory();
+ return page->chrome().client()->graphicsLayerFactory();
return 0;
}
@@ -2765,6 +3243,69 @@ Page* RenderLayerCompositor::page() const
return 0;
}
+void RenderLayerCompositor::setLayerFlushThrottlingEnabled(bool enabled)
+{
+ m_layerFlushThrottlingEnabled = enabled;
+ if (m_layerFlushThrottlingEnabled)
+ return;
+ m_layerFlushTimer.stop();
+ if (!m_hasPendingLayerFlush)
+ return;
+ scheduleLayerFlushNow();
+}
+
+void RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction()
+{
+ if (m_layerFlushThrottlingTemporarilyDisabledForInteraction)
+ return;
+ m_layerFlushThrottlingTemporarilyDisabledForInteraction = true;
+}
+
+bool RenderLayerCompositor::isThrottlingLayerFlushes() const
+{
+ if (!m_layerFlushThrottlingEnabled)
+ return false;
+ if (!m_layerFlushTimer.isActive())
+ return false;
+ if (m_layerFlushThrottlingTemporarilyDisabledForInteraction)
+ return false;
+ return true;
+}
+
+void RenderLayerCompositor::startLayerFlushTimerIfNeeded()
+{
+ m_layerFlushThrottlingTemporarilyDisabledForInteraction = false;
+ m_layerFlushTimer.stop();
+ if (!m_layerFlushThrottlingEnabled)
+ return;
+ m_layerFlushTimer.startOneShot(throttledLayerFlushDelay);
+}
+
+void RenderLayerCompositor::layerFlushTimerFired(Timer<RenderLayerCompositor>*)
+{
+ if (!m_hasPendingLayerFlush)
+ return;
+ scheduleLayerFlushNow();
+}
+
+void RenderLayerCompositor::paintRelatedMilestonesTimerFired(Timer<RenderLayerCompositor>*)
+{
+ FrameView* frameView = m_renderView ? m_renderView->frameView() : 0;
+ if (!frameView)
+ return;
+
+ Frame* frame = frameView->frame();
+ Page* page = frame ? frame->page() : 0;
+ if (!page)
+ return;
+
+ // If the layer tree is frozen, we'll paint when it's unfrozen and schedule the timer again.
+ if (page->chrome().client()->layerTreeStateIsFrozen())
+ return;
+
+ frameView->firePaintRelatedMilestones();
+}
+
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/rendering/RenderLayerCompositor.h b/Source/WebCore/rendering/RenderLayerCompositor.h
index 5193411a2..b0ea17d2f 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.h
+++ b/Source/WebCore/rendering/RenderLayerCompositor.h
@@ -26,11 +26,14 @@
#ifndef RenderLayerCompositor_h
#define RenderLayerCompositor_h
+#if USE(ACCELERATED_COMPOSITING)
+
#include "ChromeClient.h"
#include "Frame.h"
+#include "GraphicsLayerClient.h"
#include "GraphicsLayerUpdater.h"
#include "RenderLayer.h"
-#include "RenderLayerBacking.h"
+#include <wtf/HashMap.h>
namespace WebCore {
@@ -50,8 +53,38 @@ enum CompositingUpdateType {
CompositingUpdateAfterStyleChange,
CompositingUpdateAfterLayout,
CompositingUpdateOnHitTest,
- CompositingUpdateOnScroll
+ CompositingUpdateOnScroll,
+ CompositingUpdateOnCompositedScroll
+};
+
+enum {
+ CompositingReasonNone = 0,
+ CompositingReason3DTransform = 1 << 0,
+ CompositingReasonVideo = 1 << 1,
+ CompositingReasonCanvas = 1 << 2,
+ CompositingReasonPlugin = 1 << 3,
+ CompositingReasonIFrame = 1 << 4,
+ CompositingReasonBackfaceVisibilityHidden = 1 << 5,
+ CompositingReasonClipsCompositingDescendants = 1 << 6,
+ CompositingReasonAnimation = 1 << 7,
+ CompositingReasonFilters = 1 << 8,
+ CompositingReasonPositionFixed = 1 << 9,
+ CompositingReasonPositionSticky = 1 << 10,
+ CompositingReasonOverflowScrollingTouch = 1 << 11,
+ CompositingReasonStacking = 1 << 12,
+ CompositingReasonOverlap = 1 << 13,
+ CompositingReasonNegativeZIndexChildren = 1 << 14,
+ CompositingReasonTransformWithCompositedDescendants = 1 << 15,
+ CompositingReasonOpacityWithCompositedDescendants = 1 << 16,
+ CompositingReasonMaskWithCompositedDescendants = 1 << 17,
+ CompositingReasonReflectionWithCompositedDescendants = 1 << 18,
+ CompositingReasonFilterWithCompositedDescendants = 1 << 19,
+ CompositingReasonBlendingWithCompositedDescendants = 1 << 20,
+ CompositingReasonPerspective = 1 << 21,
+ CompositingReasonPreserve3D = 1 << 22,
+ CompositingReasonRoot = 1 << 23
};
+typedef unsigned CompositingReasons;
// RenderLayerCompositor manages the hierarchy of
// composited RenderLayers. It determines which RenderLayers
@@ -63,7 +96,7 @@ enum CompositingUpdateType {
class RenderLayerCompositor : public GraphicsLayerClient, public GraphicsLayerUpdaterClient {
WTF_MAKE_FAST_ALLOCATED;
public:
- RenderLayerCompositor(RenderView*);
+ explicit RenderLayerCompositor(RenderView*);
~RenderLayerCompositor();
// Return true if this RenderView is in "compositing mode" (i.e. has one or more
@@ -88,14 +121,9 @@ public:
void setCompositingLayersNeedRebuild(bool needRebuild = true);
bool compositingLayersNeedRebuild() const { return m_compositingLayersNeedRebuild; }
- // Controls whether or not to consult geometry when deciding which layers need
- // to be composited. Defaults to true.
- void setCompositingConsultsOverlap(bool b) { m_compositingConsultsOverlap = b; }
- bool compositingConsultsOverlap() const { return m_compositingConsultsOverlap; }
-
// GraphicsLayers buffer state, which gets pushed to the underlying platform layers
// at specific times.
- void scheduleLayerFlush();
+ void scheduleLayerFlush(bool canThrottle);
void flushPendingLayerChanges(bool isFlushRoot = true);
// flushPendingLayerChanges() flushes the entire GraphicsLayer tree, which can cross frame boundaries.
@@ -103,7 +131,10 @@ public:
RenderLayerCompositor* enclosingCompositorFlushingLayers() const;
// Called when the GraphicsLayer for the given RenderLayer has flushed changes inside of flushPendingLayerChanges().
- void didFlushChangesForLayer(RenderLayer*);
+ void didFlushChangesForLayer(RenderLayer*, const GraphicsLayer*);
+
+ // Called when something outside WebKit affects the visible rect (e.g. delegated scrolling). Might schedule a layer flush.
+ void didChangeVisibleRect();
// Rebuild the tree of compositing layers
void updateCompositingLayers(CompositingUpdateType, RenderLayer* updateRoot = 0);
@@ -116,21 +147,23 @@ public:
bool updateLayerCompositingState(RenderLayer*, CompositingChangeRepaint = CompositingChangeRepaintNow);
// Update the geometry for compositing children of compositingAncestor.
- void updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, RenderLayerBacking::UpdateDepth);
+ void updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer*, bool compositedChildrenOnly);
// Whether layer's backing needs a graphics layer to do clipping by an ancestor (non-stacking-context parent with overflow).
bool clippedByAncestor(RenderLayer*) const;
// Whether layer's backing needs a graphics layer to clip z-order children of the given layer.
bool clipsCompositingDescendants(const RenderLayer*) const;
- // Whether the layer is fixed positioned to the view by an ancestor layer.
- bool fixedPositionedByAncestor(const RenderLayer*) const;
-
// Whether the given layer needs an extra 'contents' layer.
bool needsContentsCompositingLayer(const RenderLayer*) const;
+
+ bool supportsFixedRootBackgroundCompositing() const;
+ bool needsFixedRootBackgroundLayer(const RenderLayer*) const;
+ GraphicsLayer* fixedRootBackgroundLayer() const;
+
// Return the bounding box required for compositing layer and its childern, relative to ancestorLayer.
// If layerBoundingBox is not 0, on return it contains the bounding box of this layer only.
- IntRect calculateCompositedBounds(const RenderLayer*, const RenderLayer* ancestorLayer) const;
+ LayoutRect calculateCompositedBounds(const RenderLayer*, const RenderLayer* ancestorLayer) const;
// Repaint the appropriate layers when the given RenderLayer starts or stops being composited.
void repaintOnCompositingChange(RenderLayer*);
@@ -148,12 +181,17 @@ public:
void repaintCompositedLayers(const IntRect* = 0);
// Returns true if the given layer needs it own backing store.
- bool requiresOwnBackingStore(const RenderLayer*, const RenderLayer* compositingAncestorLayer) const;
+ bool requiresOwnBackingStore(const RenderLayer*, const RenderLayer* compositingAncestorLayer, const IntRect& layerCompositedBoundsInAncestor, const IntRect& ancestorCompositedBounds) const;
RenderLayer* rootRenderLayer() const;
GraphicsLayer* rootGraphicsLayer() const;
GraphicsLayer* scrollLayer() const;
+#if ENABLE(RUBBER_BANDING)
+ GraphicsLayer* headerLayer() const;
+ GraphicsLayer* footerLayer() const;
+#endif
+
enum RootLayerAttachment {
RootLayerUnattached,
RootLayerAttachedViaChromeClient,
@@ -164,17 +202,12 @@ public:
void updateRootLayerAttachment();
void updateRootLayerPosition();
- void didMoveOnscreen();
- void willMoveOffscreen();
+ void setIsInWindow(bool);
void clearBackingForAllLayers();
void layerBecameComposited(const RenderLayer*) { ++m_compositedLayerCount; }
- void layerBecameNonComposited(const RenderLayer*)
- {
- ASSERT(m_compositedLayerCount > 0);
- --m_compositedLayerCount;
- }
+ void layerBecameNonComposited(const RenderLayer*);
#if ENABLE(VIDEO)
// Use by RenderVideo to ask if it should try to use accelerated compositing.
@@ -199,8 +232,10 @@ public:
void frameViewDidChangeSize();
void frameViewDidScroll();
void frameViewDidLayout();
+ void rootFixedBackgroundsChanged();
void scrollingLayerDidChange(RenderLayer*);
+ void fixedRootBackgroundLayerChanged();
String layerTreeAsText(LayerTreeFlags);
@@ -208,6 +243,8 @@ public:
virtual float pageScaleFactor() const OVERRIDE;
virtual void didCommitChangesForLayer(const GraphicsLayer*) const OVERRIDE;
virtual void notifyFlushBeforeDisplayRefresh(const GraphicsLayer*) OVERRIDE;
+
+ void layerTiledBackingUsageChanged(const GraphicsLayer*, bool /*usingTiledBacking*/);
bool keepLayersPixelAligned() const;
bool acceleratedDrawingEnabled() const { return m_acceleratedDrawingEnabled; }
@@ -221,9 +258,12 @@ public:
GraphicsLayer* layerForScrollCorner() const { return m_layerForScrollCorner.get(); }
#if ENABLE(RUBBER_BANDING)
GraphicsLayer* layerForOverhangAreas() const { return m_layerForOverhangAreas.get(); }
-#endif
- void documentBackgroundColorDidChange();
+ GraphicsLayer* updateLayerForTopOverhangArea(bool wantsLayer);
+ GraphicsLayer* updateLayerForBottomOverhangArea(bool wantsLayer);
+ GraphicsLayer* updateLayerForHeader(bool wantsLayer);
+ GraphicsLayer* updateLayerForFooter(bool wantsLayer);
+#endif
void updateViewportConstraintStatus(RenderLayer*);
void removeViewportConstrainedLayer(RenderLayer*);
@@ -231,23 +271,37 @@ public:
void resetTrackedRepaintRects();
void setTracksRepaints(bool);
+ void setShouldReevaluateCompositingAfterLayout() { m_reevaluateCompositingAfterLayout = true; }
+
+ bool viewHasTransparentBackground(Color* backgroundColor = 0) const;
+
+ bool hasNonMainLayersWithTiledBacking() const { return m_layersWithTiledBackingCount; }
+
+ CompositingReasons reasonsForCompositing(const RenderLayer*) const;
+
+ void setLayerFlushThrottlingEnabled(bool);
+ void disableLayerFlushThrottlingTemporarilyForInteraction();
+
+ void didPaintBacking(RenderLayerBacking*);
+
private:
class OverlapMap;
// GraphicsLayerClient implementation
virtual void notifyAnimationStarted(const GraphicsLayer*, double) OVERRIDE { }
- virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE { scheduleLayerFlush(); }
+ virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE;
virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) OVERRIDE;
virtual bool isTrackingRepaints() const OVERRIDE;
// GraphicsLayerUpdaterClient implementation
virtual void flushLayers(GraphicsLayerUpdater*) OVERRIDE;
+ virtual void customPositionForVisibleRectComputation(const GraphicsLayer*, FloatPoint&) const OVERRIDE;
// Whether the given RL needs a compositing layer.
- bool needsToBeComposited(const RenderLayer*) const;
+ bool needsToBeComposited(const RenderLayer*, RenderLayer::ViewportConstrainedNotCompositedReason* = 0) const;
// Whether the layer has an intrinsic need for compositing layer.
- bool requiresCompositingLayer(const RenderLayer*) const;
+ bool requiresCompositingLayer(const RenderLayer*, RenderLayer::ViewportConstrainedNotCompositedReason* = 0) const;
// Whether the layer could ever be composited.
bool canBeComposited(const RenderLayer*) const;
@@ -298,7 +352,7 @@ private:
Page* page() const;
TiledBacking* pageTiledBacking() const;
-
+
GraphicsLayerFactory* graphicsLayerFactory() const;
ScrollingCoordinator* scrollingCoordinator() const;
@@ -312,7 +366,7 @@ private:
bool requiresCompositingForFilters(RenderObject*) const;
bool requiresCompositingForBlending(RenderObject* renderer) const;
bool requiresCompositingForScrollableFrame() const;
- bool requiresCompositingForPosition(RenderObject*, const RenderLayer*) const;
+ bool requiresCompositingForPosition(RenderObject*, const RenderLayer*, RenderLayer::ViewportConstrainedNotCompositedReason* = 0) const;
bool requiresCompositingForOverflowScrolling(const RenderLayer*) const;
bool requiresCompositingForIndirectReason(RenderObject*, bool hasCompositedDescendants, bool has3DTransformedDescendants, RenderLayer::IndirectCompositingReason&) const;
@@ -320,8 +374,8 @@ private:
void registerOrUpdateViewportConstrainedLayer(RenderLayer*);
void unregisterViewportConstrainedLayer(RenderLayer*);
- const FixedPositionViewportConstraints computeFixedViewportConstraints(RenderLayer*);
- const StickyPositionViewportConstraints computeStickyViewportConstraints(RenderLayer*);
+ FixedPositionViewportConstraints computeFixedViewportConstraints(RenderLayer*) const;
+ StickyPositionViewportConstraints computeStickyViewportConstraints(RenderLayer*) const;
bool requiresScrollLayer(RootLayerAttachment) const;
bool requiresHorizontalScrollbarLayer() const;
@@ -332,8 +386,18 @@ private:
bool requiresContentShadowLayer() const;
#endif
+ bool hasCoordinatedScrolling() const;
+ bool shouldCompositeOverflowControls() const;
+
+ void scheduleLayerFlushNow();
+ bool isThrottlingLayerFlushes() const;
+ void startLayerFlushTimerIfNeeded();
+ void layerFlushTimerFired(Timer<RenderLayerCompositor>*);
+
+ void paintRelatedMilestonesTimerFired(Timer<RenderLayerCompositor>*);
+
#if !LOG_DISABLED
- const char* reasonForCompositing(const RenderLayer*);
+ const char* logReasonsForCompositing(const RenderLayer*);
void logLayerInfo(const RenderLayer*, int depth);
#endif
@@ -349,7 +413,6 @@ private:
bool m_showDebugBorders;
bool m_showRepaintCounter;
bool m_acceleratedDrawingEnabled;
- bool m_compositingConsultsOverlap;
// When true, we have to wait until layout has happened before we can decide whether to enter compositing mode,
// because only then do we know the final size of plugins and iframes.
@@ -360,8 +423,11 @@ private:
bool m_flushingLayers;
bool m_shouldFlushOnReattach;
bool m_forceCompositingMode;
+ bool m_inPostLayoutUpdate; // true when it's OK to trust layout information (e.g. layer sizes and positions)
bool m_isTrackingRepaints; // Used for testing.
+
+ unsigned m_layersWithTiledBackingCount;
RootLayerAttachment m_rootLayerAttachment;
@@ -382,10 +448,21 @@ private:
#if ENABLE(RUBBER_BANDING)
OwnPtr<GraphicsLayer> m_layerForOverhangAreas;
OwnPtr<GraphicsLayer> m_contentShadowLayer;
+ OwnPtr<GraphicsLayer> m_layerForTopOverhangArea;
+ OwnPtr<GraphicsLayer> m_layerForBottomOverhangArea;
+ OwnPtr<GraphicsLayer> m_layerForHeader;
+ OwnPtr<GraphicsLayer> m_layerForFooter;
#endif
OwnPtr<GraphicsLayerUpdater> m_layerUpdater; // Updates tiled layer visible area periodically while animations are running.
+ Timer<RenderLayerCompositor> m_layerFlushTimer;
+ bool m_layerFlushThrottlingEnabled;
+ bool m_layerFlushThrottlingTemporarilyDisabledForInteraction;
+ bool m_hasPendingLayerFlush;
+
+ Timer<RenderLayerCompositor> m_paintRelatedMilestonesTimer;
+
#if !LOG_DISABLED
int m_rootLayerUpdateCount;
int m_obligateCompositedLayerCount; // count of layer that have to be composited.
@@ -398,4 +475,6 @@ private:
} // namespace WebCore
+#endif // USE(ACCELERATED_COMPOSITING)
+
#endif // RenderLayerCompositor_h
diff --git a/Source/WebCore/rendering/RenderLayerFilterInfo.h b/Source/WebCore/rendering/RenderLayerFilterInfo.h
index e514a5a21..8a4d1dc54 100644
--- a/Source/WebCore/rendering/RenderLayerFilterInfo.h
+++ b/Source/WebCore/rendering/RenderLayerFilterInfo.h
@@ -32,9 +32,7 @@
#if ENABLE(CSS_FILTERS)
-#if ENABLE(SVG)
-#include "CachedSVGDocument.h"
-#endif
+#include "CachedResourceHandle.h"
#include "FilterOperation.h"
#include "LayoutRect.h"
#include <wtf/HashMap.h>
@@ -45,6 +43,11 @@
#include "CustomFilterProgramClient.h"
#endif
+#if ENABLE(SVG)
+#include "CachedSVGDocumentClient.h"
+#include "Element.h"
+#endif
+
namespace WebCore {
class FilterEffectRenderer;
diff --git a/Source/WebCore/rendering/RenderLayerModelObject.cpp b/Source/WebCore/rendering/RenderLayerModelObject.cpp
index aeb32b7a2..bf32d15fd 100644
--- a/Source/WebCore/rendering/RenderLayerModelObject.cpp
+++ b/Source/WebCore/rendering/RenderLayerModelObject.cpp
@@ -37,7 +37,7 @@ bool RenderLayerModelObject::s_hadLayer = false;
bool RenderLayerModelObject::s_hadTransform = false;
bool RenderLayerModelObject::s_layerWasSelfPainting = false;
-RenderLayerModelObject::RenderLayerModelObject(Node* node)
+RenderLayerModelObject::RenderLayerModelObject(ContainerNode* node)
: RenderObject(node)
, m_layer(0)
{
@@ -75,6 +75,16 @@ bool RenderLayerModelObject::hasSelfPaintingLayer() const
void RenderLayerModelObject::willBeDestroyed()
{
+ if (isPositioned()) {
+ // Don't use this->view() because the document's renderView has been set to 0 during destruction.
+ if (Frame* frame = this->frame()) {
+ if (FrameView* frameView = frame->view()) {
+ if (style()->hasViewportConstrainedPosition())
+ frameView->removeViewportConstrainedObject(this);
+ }
+ }
+ }
+
// RenderObject::willBeDestroyed calls back to destroyLayer() for layer destruction
RenderObject::willBeDestroyed();
}
diff --git a/Source/WebCore/rendering/RenderLayerModelObject.h b/Source/WebCore/rendering/RenderLayerModelObject.h
index c6241d377..2a7439601 100644
--- a/Source/WebCore/rendering/RenderLayerModelObject.h
+++ b/Source/WebCore/rendering/RenderLayerModelObject.h
@@ -31,7 +31,7 @@ class RenderLayer;
class RenderLayerModelObject : public RenderObject {
public:
- RenderLayerModelObject(Node*);
+ explicit RenderLayerModelObject(ContainerNode*);
virtual ~RenderLayerModelObject();
// Called by RenderObject::willBeDestroyed() and is the only way layers should ever be destroyed
@@ -46,6 +46,13 @@ public:
virtual bool requiresLayer() const = 0;
+ // Returns true if the background is painted opaque in the given rect.
+ // The query rect is given in local coordinate system.
+ virtual bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const { return false; }
+
+ // This is null for anonymous renderers.
+ ContainerNode* node() const { return toContainerNode(RenderObject::node()); }
+
protected:
void ensureLayer();
@@ -65,13 +72,13 @@ private:
inline RenderLayerModelObject* toRenderLayerModelObject(RenderObject* object)
{
- ASSERT(!object || object->isLayerModelObject());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isLayerModelObject());
return static_cast<RenderLayerModelObject*>(object);
}
inline const RenderLayerModelObject* toRenderLayerModelObject(const RenderObject* object)
{
- ASSERT(!object || object->isLayerModelObject());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isLayerModelObject());
return static_cast<const RenderLayerModelObject*>(object);
}
diff --git a/Source/WebCore/rendering/RenderLineBoxList.cpp b/Source/WebCore/rendering/RenderLineBoxList.cpp
index ea50d52e8..7b562b426 100644
--- a/Source/WebCore/rendering/RenderLineBoxList.cpp
+++ b/Source/WebCore/rendering/RenderLineBoxList.cpp
@@ -267,7 +267,7 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn
ListHashSet<RenderInline*>::iterator end = info.outlineObjects->end();
for (ListHashSet<RenderInline*>::iterator it = info.outlineObjects->begin(); it != end; ++it) {
RenderInline* flow = *it;
- flow->paintOutline(info.context, paintOffset);
+ flow->paintOutline(info, paintOffset);
}
info.outlineObjects->clear();
}
@@ -386,7 +386,11 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend
if (adjacentBox)
adjacentBox->markDirty();
adjacentBox = box->nextRootBox();
- if (adjacentBox && (adjacentBox->lineBreakObj() == child || child->isBR() || (curr && curr->isBR())))
+ // If |child| has been inserted before the first element in the linebox, but after collapsed leading
+ // space, the search for |child|'s linebox will go past the leading space to the previous linebox and select that
+ // one as |box|. If we hit that situation here, dirty the |box| actually containing the child too.
+ bool insertedAfterLeadingSpace = box->lineBreakObj() == child->previousSibling();
+ if (adjacentBox && (adjacentBox->lineBreakObj() == child || child->isBR() || (curr && curr->isBR()) || insertedAfterLeadingSpace))
adjacentBox->markDirty();
}
}
diff --git a/Source/WebCore/rendering/RenderLineBoxList.h b/Source/WebCore/rendering/RenderLineBoxList.h
index e5b085edf..0f9c65797 100644
--- a/Source/WebCore/rendering/RenderLineBoxList.h
+++ b/Source/WebCore/rendering/RenderLineBoxList.h
@@ -34,6 +34,8 @@
namespace WebCore {
+class InlineFlowBox;
+
class RenderLineBoxList {
public:
RenderLineBoxList()
diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp
index b92d9f08d..0502c6d9f 100644
--- a/Source/WebCore/rendering/RenderListBox.cpp
+++ b/Source/WebCore/rendering/RenderListBox.cpp
@@ -59,6 +59,7 @@
#include "SpatialNavigation.h"
#include "StyleResolver.h"
#include <math.h>
+#include <wtf/StackStats.h>
using namespace std;
@@ -123,14 +124,14 @@ void RenderListBox::updateFromElement()
HTMLElement* element = listItems[i];
String text;
Font itemFont = style()->font();
- if (element->hasTagName(optionTag))
+ if (isHTMLOptionElement(element))
text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
- else if (element->hasTagName(optgroupTag)) {
- text = static_cast<const HTMLOptGroupElement*>(element)->groupLabelText();
+ else if (isHTMLOptGroupElement(element)) {
+ text = toHTMLOptGroupElement(element)->groupLabelText();
FontDescription d = itemFont.fontDescription();
d.setWeight(d.bolderWeight());
itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
- itemFont.update(document()->styleResolver()->fontSelector());
+ itemFont.update(document()->ensureStyleResolver()->fontSelector());
}
if (!text.isEmpty()) {
@@ -166,8 +167,8 @@ void RenderListBox::selectionChanged()
scrollToRevealSelection();
}
- if (AXObjectCache::accessibilityEnabled())
- document()->axObjectCache()->selectedChildrenChanged(this);
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->selectedChildrenChanged(this);
}
void RenderListBox::layout()
@@ -203,6 +204,15 @@ void RenderListBox::scrollToRevealSelection()
scrollToRevealElementAtListIndex(firstIndex);
}
+void RenderListBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ maxLogicalWidth = m_optionsWidth + 2 * optionsSpacingHorizontal;
+ if (m_vBar)
+ maxLogicalWidth += m_vBar->width();
+ if (!style()->width().isPercent())
+ minLogicalWidth = maxLogicalWidth;
+}
+
void RenderListBox::computePreferredLogicalWidths()
{
ASSERT(!m_optionsChanged);
@@ -212,19 +222,13 @@ void RenderListBox::computePreferredLogicalWidths()
if (style()->width().isFixed() && style()->width().value() > 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
- else {
- m_maxPreferredLogicalWidth = m_optionsWidth + 2 * optionsSpacingHorizontal;
- if (m_vBar)
- m_maxPreferredLogicalWidth += m_vBar->width();
- }
+ else
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
- } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
- m_minPreferredLogicalWidth = 0;
- else
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
+ }
if (style()->maxWidth().isFixed()) {
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
@@ -324,10 +328,10 @@ void RenderListBox::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOf
}
}
-void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
+void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
{
if (!isSpatialNavigationEnabled(frame()))
- return RenderBlock::addFocusRingRects(rects, additionalOffset);
+ return RenderBlock::addFocusRingRects(rects, additionalOffset, paintContainer);
HTMLSelectElement* select = selectElement();
@@ -343,7 +347,8 @@ void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&
const Vector<HTMLElement*>& listItems = select->listItems();
for (int i = 0; i < size; ++i) {
HTMLElement* element = listItems[i];
- if (element->hasTagName(optionTag) && !toHTMLOptionElement(element)->disabled()) {
+ if (isHTMLOptionElement(element) && !element->isDisabledFormControl()) {
+ select->setActiveSelectionEndIndex(i);
rects.append(pixelSnappedIntRect(itemBoundingBoxRect(additionalOffset, i)));
return;
}
@@ -399,19 +404,19 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint&
return;
String itemText;
- bool isOptionElement = element->hasTagName(optionTag);
+ bool isOptionElement = isHTMLOptionElement(element);
if (isOptionElement)
itemText = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
- else if (element->hasTagName(optgroupTag))
- itemText = static_cast<const HTMLOptGroupElement*>(element)->groupLabelText();
+ else if (isHTMLOptGroupElement(element))
+ itemText = toHTMLOptGroupElement(element)->groupLabelText();
applyTextTransform(style(), itemText, ' ');
Color textColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyColor) : style()->visitedDependentColor(CSSPropertyColor);
if (isOptionElement && toHTMLOptionElement(element)->selected()) {
- if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())
+ if (frame()->selection()->isFocusedAndActive() && document()->focusedElement() == node())
textColor = theme()->activeListBoxSelectionForegroundColor();
// Honor the foreground color for disabled items
- else if (!element->disabled() && !select->disabled())
+ else if (!element->isDisabledFormControl() && !select->isDisabledFormControl())
textColor = theme()->inactiveListBoxSelectionForegroundColor();
}
@@ -423,11 +428,11 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint&
LayoutRect r = itemBoundingBoxRect(paintOffset, listIndex);
r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r));
- if (element->hasTagName(optgroupTag)) {
+ if (isHTMLOptGroupElement(element)) {
FontDescription d = itemFont.fontDescription();
d.setWeight(d.bolderWeight());
itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
- itemFont.update(document()->styleResolver()->fontSelector());
+ itemFont.update(document()->ensureStyleResolver()->fontSelector());
}
// Draw the item text
@@ -440,8 +445,8 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint&
HTMLElement* element = listItems[listIndex];
Color backColor;
- if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected()) {
- if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())
+ if (isHTMLOptionElement(element) && toHTMLOptionElement(element)->selected()) {
+ if (frame()->selection()->isFocusedAndActive() && document()->focusedElement() == node())
backColor = theme()->activeListBoxSelectionBackgroundColor();
else
backColor = theme()->inactiveListBoxSelectionBackgroundColor();
@@ -499,15 +504,15 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition)
// FIXME: This doesn't work correctly with transforms.
FloatPoint absOffset = localToAbsolute();
- IntPoint currentMousePosition = frame()->eventHandler()->currentMousePosition();
- // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
+ IntPoint lastKnownMousePosition = frame()->eventHandler()->lastKnownMousePosition();
+ // We need to check if the last known mouse position is out of the window. When the mouse is out of the window, the position is incoherent
static IntPoint previousMousePosition;
- if (currentMousePosition.y() < 0)
- currentMousePosition = previousMousePosition;
+ if (lastKnownMousePosition.y() < 0)
+ lastKnownMousePosition = previousMousePosition;
else
- previousMousePosition = currentMousePosition;
+ previousMousePosition = lastKnownMousePosition;
- int yDelta = currentMousePosition.y() - panStartMousePosition.y();
+ int yDelta = lastKnownMousePosition.y() - panStartMousePosition.y();
// If the point is too far from the center we limit the speed
yDelta = max<int>(min<int>(yDelta, maxSpeed), -maxSpeed);
@@ -554,11 +559,14 @@ int RenderListBox::scrollToward(const IntPoint& destination)
return listIndexAtOffset(positionOffset);
}
-void RenderListBox::autoscroll()
+void RenderListBox::autoscroll(const IntPoint&)
{
- IntPoint pos = frame()->view()->windowToContents(frame()->eventHandler()->currentMousePosition());
+ IntPoint pos = frame()->view()->windowToContents(frame()->eventHandler()->lastKnownMousePosition());
int endIndex = scrollToward(pos);
+ if (selectElement()->isDisabledFormControl())
+ return;
+
if (endIndex >= 0) {
HTMLSelectElement* select = selectElement();
m_inAutoscroll = true;
@@ -574,6 +582,9 @@ void RenderListBox::autoscroll()
void RenderListBox::stopAutoscroll()
{
+ if (selectElement()->isDisabledFormControl())
+ return;
+
selectElement()->listBoxOnChange();
}
@@ -803,12 +814,20 @@ int RenderListBox::visibleWidth() const
return width();
}
-IntPoint RenderListBox::currentMousePosition() const
+IntPoint RenderListBox::lastKnownMousePosition() const
{
RenderView* view = this->view();
if (!view)
return IntPoint();
- return view->frameView()->currentMousePosition();
+ return view->frameView()->lastKnownMousePosition();
+}
+
+bool RenderListBox::isHandlingWheelEvent() const
+{
+ RenderView* view = this->view();
+ if (!view)
+ return false;
+ return view->frameView()->isHandlingWheelEvent();
}
bool RenderListBox::shouldSuspendScrollAnimations() const
@@ -827,6 +846,14 @@ bool RenderListBox::scrollbarsCanBeActive() const
return view->frameView()->scrollbarsCanBeActive();
}
+bool RenderListBox::scrollbarAnimationsAreSuppressed() const
+{
+ RenderView* view = this->view();
+ if (!view)
+ return false;
+ return view->frameView()->scrollbarAnimationsAreSuppressed();
+}
+
ScrollableArea* RenderListBox::enclosingScrollableArea() const
{
// FIXME: Return a RenderLayer that's scrollable.
@@ -846,7 +873,7 @@ PassRefPtr<Scrollbar> RenderListBox::createScrollbar()
widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this->node());
else {
widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, theme()->scrollbarControlSizeForPart(ListboxPart));
- didAddVerticalScrollbar(widget.get());
+ didAddScrollbar(widget.get(), VerticalScrollbar);
}
document()->view()->addChild(widget.get());
return widget.release();
@@ -858,7 +885,7 @@ void RenderListBox::destroyScrollbar()
return;
if (!m_vBar->isCustomScrollbar())
- ScrollableArea::willRemoveVerticalScrollbar(m_vBar.get());
+ ScrollableArea::willRemoveScrollbar(m_vBar.get(), VerticalScrollbar);
m_vBar->removeFromParent();
m_vBar->disconnectFromScrollableArea();
m_vBar = 0;
diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h
index c662af27f..f4f584942 100644
--- a/Source/WebCore/rendering/RenderListBox.h
+++ b/Source/WebCore/rendering/RenderListBox.h
@@ -40,7 +40,7 @@ class HTMLSelectElement;
class RenderListBox : public RenderBlock, private ScrollableArea {
public:
- RenderListBox(Element*);
+ explicit RenderListBox(Element*);
virtual ~RenderListBox();
void selectionChanged();
@@ -75,16 +75,17 @@ private:
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
- virtual void computePreferredLogicalWidths();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
virtual void layout();
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
virtual bool canBeProgramaticallyScrolled() const { return true; }
- virtual void autoscroll();
+ virtual void autoscroll(const IntPoint&);
virtual void stopAutoscroll();
virtual bool shouldPanScroll() const { return true; }
@@ -117,9 +118,11 @@ private:
virtual IntSize contentsSize() const OVERRIDE;
virtual int visibleHeight() const OVERRIDE;
virtual int visibleWidth() const OVERRIDE;
- virtual IntPoint currentMousePosition() const OVERRIDE;
+ virtual IntPoint lastKnownMousePosition() const OVERRIDE;
+ virtual bool isHandlingWheelEvent() const OVERRIDE;
virtual bool shouldSuspendScrollAnimations() const OVERRIDE;
virtual bool scrollbarsCanBeActive() const OVERRIDE;
+ virtual bool scrollbarAnimationsAreSuppressed() const OVERRIDE;
virtual ScrollableArea* enclosingScrollableArea() const OVERRIDE;
virtual IntRect scrollableAreaBoundingBox() const OVERRIDE;
@@ -152,7 +155,7 @@ private:
inline RenderListBox* toRenderListBox(RenderObject* object)
{
- ASSERT(!object || object->isListBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isListBox());
return static_cast<RenderListBox*>(object);
}
diff --git a/Source/WebCore/rendering/RenderListItem.cpp b/Source/WebCore/rendering/RenderListItem.cpp
index 84a579460..7d8f4c842 100644
--- a/Source/WebCore/rendering/RenderListItem.cpp
+++ b/Source/WebCore/rendering/RenderListItem.cpp
@@ -24,12 +24,13 @@
#include "config.h"
#include "RenderListItem.h"
-#include "CachedImage.h"
#include "HTMLNames.h"
#include "HTMLOListElement.h"
+#include "NodeTraversal.h"
#include "RenderListMarker.h"
#include "RenderView.h"
#include "StyleInheritedData.h"
+#include <wtf/StackStats.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/StringBuilder.h>
@@ -39,8 +40,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderListItem::RenderListItem(Node* node)
- : RenderBlock(node)
+RenderListItem::RenderListItem(Element* element)
+ : RenderBlock(element)
, m_marker(0)
, m_hasExplicitValue(false)
, m_isValueUpToDate(false)
@@ -60,7 +61,7 @@ void RenderListItem::styleDidChange(StyleDifference diff, const RenderStyle* old
// up (e.g., in some deeply nested line box). See CSS3 spec.
newStyle->inheritFrom(style());
if (!m_marker)
- m_marker = new (renderArena()) RenderListMarker(this);
+ m_marker = RenderListMarker::createAnonymous(this);
m_marker->setStyle(newStyle.release());
} else if (m_marker) {
m_marker->destroy();
@@ -91,23 +92,22 @@ void RenderListItem::willBeRemovedFromTree()
updateListMarkerNumbers();
}
-static bool isList(Node* node)
+static bool isList(const Node* node)
{
return (node->hasTagName(ulTag) || node->hasTagName(olTag));
}
+// Returns the enclosing list with respect to the DOM order.
static Node* enclosingList(const RenderListItem* listItem)
{
+ Node* listItemNode = listItem->node();
Node* firstNode = 0;
-
- for (const RenderObject* renderer = listItem->parent(); renderer; renderer = renderer->parent()) {
- Node* node = renderer->node();
- if (node) {
- if (isList(node))
- return node;
- if (!firstNode)
- firstNode = node;
- }
+ // We use parentNode because the enclosing list could be a ShadowRoot that's not Element.
+ for (Node* parent = listItemNode->parentNode(); parent; parent = parent->parentNode()) {
+ if (isList(parent))
+ return parent;
+ if (!firstNode)
+ firstNode = parent;
}
// If there's no actual <ul> or <ol> list element, then the first found
@@ -116,53 +116,80 @@ static Node* enclosingList(const RenderListItem* listItem)
return firstNode;
}
-RenderListItem* RenderListItem::nextListItem(RenderObject* list, const RenderListItem* item)
+// Returns the next list item with respect to the DOM order.
+static RenderListItem* nextListItem(const Node* listNode, const RenderListItem* item = 0)
{
- if (!list)
+ if (!listNode)
return 0;
- RenderObject* renderer = item ? item->nextInPreOrder(list) : list->nextInPreOrder(list);
- while (renderer) {
- if (renderer->node() && isList(renderer->node())) {
+ const Node* current = item ? item->node() : listNode;
+ current = ElementTraversal::nextIncludingPseudo(current, listNode);
+
+ while (current) {
+ if (isList(current)) {
// We've found a nested, independent list: nothing to do here.
- renderer = renderer->nextInPreOrderAfterChildren(list);
+ current = ElementTraversal::nextIncludingPseudoSkippingChildren(current, listNode);
continue;
}
- if (renderer->isListItem())
+ RenderObject* renderer = current->renderer();
+ if (renderer && renderer->isListItem())
return toRenderListItem(renderer);
- renderer = renderer->nextInPreOrder(list);
+ // FIXME: Can this be optimized to skip the children of the elements without a renderer?
+ current = ElementTraversal::nextIncludingPseudo(current, listNode);
}
+
return 0;
}
-static RenderListItem* previousListItem(RenderObject* list, const RenderListItem* item)
+// Returns the previous list item with respect to the DOM order.
+static RenderListItem* previousListItem(const Node* listNode, const RenderListItem* item)
{
- for (RenderObject* renderer = item->previousInPreOrder(); renderer && renderer != list; renderer = renderer->previousInPreOrder()) {
- if (!renderer->isListItem())
+ Node* current = item->node();
+ for (current = ElementTraversal::previousIncludingPseudo(current, listNode); current; current = ElementTraversal::previousIncludingPseudo(current, listNode)) {
+ RenderObject* renderer = current->renderer();
+ if (!renderer || (renderer && !renderer->isListItem()))
continue;
Node* otherList = enclosingList(toRenderListItem(renderer));
// This item is part of our current list, so it's what we're looking for.
- if (list->node() == otherList)
+ if (listNode == otherList)
return toRenderListItem(renderer);
// We found ourself inside another list; lets skip the rest of it.
- // Use nextInPreOrder() here because the other list itself may actually
+ // Use nextIncludingPseudo() here because the other list itself may actually
// be a list item itself. We need to examine it, so we do this to counteract
- // the previousInPreOrder() that will be done by the loop.
+ // the previousIncludingPseudo() that will be done by the loop.
if (otherList)
- renderer = otherList->renderer()->nextInPreOrder();
+ current = ElementTraversal::nextIncludingPseudo(otherList);
}
return 0;
}
+void RenderListItem::updateItemValuesForOrderedList(const HTMLOListElement* listNode)
+{
+ ASSERT(listNode);
+
+ for (RenderListItem* listItem = nextListItem(listNode); listItem; listItem = nextListItem(listNode, listItem))
+ listItem->updateValue();
+}
+
+unsigned RenderListItem::itemCountForOrderedList(const HTMLOListElement* listNode)
+{
+ ASSERT(listNode);
+
+ unsigned itemCount = 0;
+ for (RenderListItem* listItem = nextListItem(listNode); listItem; listItem = nextListItem(listNode, listItem))
+ itemCount++;
+
+ return itemCount;
+}
+
inline int RenderListItem::calcValue() const
{
if (m_hasExplicitValue)
return m_explicitValue;
Node* list = enclosingList(this);
- RenderObject* listRenderer = list ? list->renderer() : 0;
HTMLOListElement* oListElement = (list && list->hasTagName(olTag)) ? static_cast<HTMLOListElement*>(list) : 0;
int valueStep = 1;
if (oListElement && oListElement->isReversed())
@@ -170,7 +197,7 @@ inline int RenderListItem::calcValue() const
// FIXME: This recurses to a possible depth of the length of the list.
// That's not good -- we need to change this to an iterative algorithm.
- if (RenderListItem* previousItem = previousListItem(listRenderer, this))
+ if (RenderListItem* previousItem = previousListItem(list, this))
return previousItem->value() + valueStep;
if (oListElement)
@@ -265,25 +292,14 @@ void RenderListItem::updateMarkerLocation()
if (!lineBoxParent)
lineBoxParent = this;
lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent));
- if (m_marker->preferredLogicalWidthsDirty())
- m_marker->computePreferredLogicalWidths();
+ m_marker->updateMarginsAndContent();
// If markerPar is an anonymous block that has lost all its children, destroy it.
- // Extraneous anonymous blocks can cause problems for RenderBlock::updateBeforeAfterContent.
if (markerPar && markerPar->isAnonymousBlock() && !markerPar->firstChild() && !toRenderBlock(markerPar)->continuation())
markerPar->destroy();
}
}
}
-void RenderListItem::computePreferredLogicalWidths()
-{
- ASSERT(preferredLogicalWidthsDirty());
-
- updateMarkerLocation();
-
- RenderBlock::computePreferredLogicalWidths();
-}
-
void RenderListItem::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
@@ -344,7 +360,6 @@ void RenderListItem::positionListMarker()
hitSelfPaintingLayer = true;
}
} else {
- markerLogicalLeft = m_marker->logicalLeft() + paddingStart() + borderStart() + m_marker->marginEnd();
LayoutUnit rightLineOffset = logicalRightOffsetForLine(blockOffset, logicalRightOffsetForLine(blockOffset, false), false);
markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd();
m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft);
@@ -407,8 +422,7 @@ const String& RenderListItem::markerText() const
{
if (m_marker)
return m_marker->text();
- DEFINE_STATIC_LOCAL(String, staticNullString, ());
- return staticNullString;
+ return nullAtom.string();
}
String RenderListItem::markerTextWithSuffix() const
@@ -439,10 +453,7 @@ void RenderListItem::explicitValueChanged()
if (m_marker)
m_marker->setNeedsLayoutAndPrefWidthsRecalc();
Node* listNode = enclosingList(this);
- RenderObject* listRenderer = 0;
- if (listNode)
- listRenderer = listNode->renderer();
- for (RenderListItem* item = this; item; item = nextListItem(listRenderer, item))
+ for (RenderListItem* item = this; item; item = nextListItem(listNode, item))
item->updateValue();
}
@@ -469,26 +480,26 @@ void RenderListItem::clearExplicitValue()
explicitValueChanged();
}
-static RenderListItem* previousOrNextItem(bool isListReversed, RenderObject* list, RenderListItem* item)
+static RenderListItem* previousOrNextItem(bool isListReversed, Node* list, RenderListItem* item)
{
- return isListReversed ? previousListItem(list, item) : RenderListItem::nextListItem(list, item);
+ return isListReversed ? previousListItem(list, item) : nextListItem(list, item);
}
void RenderListItem::updateListMarkerNumbers()
{
Node* listNode = enclosingList(this);
- ASSERT(listNode && listNode->renderer());
- if (!listNode || !listNode->renderer())
+ // The list node can be the shadow root which has no renderer.
+ ASSERT(listNode);
+ if (!listNode)
return;
bool isListReversed = false;
- RenderObject* list = listNode->renderer();
HTMLOListElement* oListElement = (listNode && listNode->hasTagName(olTag)) ? static_cast<HTMLOListElement*>(listNode) : 0;
if (oListElement) {
oListElement->itemCountChanged();
isListReversed = oListElement->isReversed();
}
- for (RenderListItem* item = previousOrNextItem(isListReversed, list, this); item; item = previousOrNextItem(isListReversed, list, item)) {
+ for (RenderListItem* item = previousOrNextItem(isListReversed, listNode, this); item; item = previousOrNextItem(isListReversed, listNode, item)) {
if (!item->m_isValueUpToDate) {
// If an item has been marked for update before, we can safely
// assume that all the following ones have too.
diff --git a/Source/WebCore/rendering/RenderListItem.h b/Source/WebCore/rendering/RenderListItem.h
index 65b1297f5..f319cfd70 100644
--- a/Source/WebCore/rendering/RenderListItem.h
+++ b/Source/WebCore/rendering/RenderListItem.h
@@ -27,11 +27,12 @@
namespace WebCore {
+class HTMLOListElement;
class RenderListMarker;
class RenderListItem : public RenderBlock {
public:
- explicit RenderListItem(Node*);
+ explicit RenderListItem(Element*);
int value() const { if (!m_isValueUpToDate) updateValueNow(); return m_value; }
void updateValue();
@@ -49,7 +50,8 @@ public:
void updateListMarkerNumbers();
- static RenderListItem* nextListItem(RenderObject* listRenderer, const RenderListItem* = 0);
+ static void updateItemValuesForOrderedList(const HTMLOListElement*);
+ static unsigned itemCountForOrderedList(const HTMLOListElement*);
private:
virtual const char* renderName() const { return "RenderListItem"; }
@@ -65,7 +67,6 @@ private:
virtual void paint(PaintInfo&, const LayoutPoint&);
virtual void layout();
- virtual void computePreferredLogicalWidths();
void positionListMarker();
@@ -91,7 +92,7 @@ private:
inline RenderListItem* toRenderListItem(RenderObject* object)
{
- ASSERT(!object || object->isListItem());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isListItem());
return static_cast<RenderListItem*>(object);
}
diff --git a/Source/WebCore/rendering/RenderListMarker.cpp b/Source/WebCore/rendering/RenderListMarker.cpp
index 7ccb686ff..9a37e47f9 100644
--- a/Source/WebCore/rendering/RenderListMarker.cpp
+++ b/Source/WebCore/rendering/RenderListMarker.cpp
@@ -25,13 +25,13 @@
#include "config.h"
#include "RenderListMarker.h"
-#include "CachedImage.h"
#include "Document.h"
#include "Font.h"
#include "GraphicsContext.h"
#include "RenderLayer.h"
#include "RenderListItem.h"
#include "RenderView.h"
+#include <wtf/StackStats.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/unicode/CharacterNames.h>
@@ -1054,7 +1054,7 @@ String listMarkerText(EListStyleType type, int value)
}
RenderListMarker::RenderListMarker(RenderListItem* item)
- : RenderBox(item->document())
+ : RenderBox(0)
, m_listItem(item)
{
// init RenderObject attributes
@@ -1068,6 +1068,14 @@ RenderListMarker::~RenderListMarker()
m_image->removeClient(this);
}
+RenderListMarker* RenderListMarker::createAnonymous(RenderListItem* item)
+{
+ Document* document = item->document();
+ RenderListMarker* renderer = new (document->renderArena()) RenderListMarker(item);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
void RenderListMarker::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
if (style() && (newStyle->listStylePosition() != style()->listStylePosition() || newStyle->listStyleType() != style()->listStyleType()))
@@ -1317,6 +1325,7 @@ void RenderListMarker::layout()
ASSERT(needsLayout());
if (isImage()) {
+ updateMarginsAndContent();
setWidth(m_image->imageSize(this, style()->effectiveZoom()).width());
setHeight(m_image->imageSize(this, style()->effectiveZoom()).height());
} else {
@@ -1349,20 +1358,126 @@ void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect*)
repaint();
}
-void RenderListMarker::computePreferredLogicalWidths()
+void RenderListMarker::updateMarginsAndContent()
{
- ASSERT(preferredLogicalWidthsDirty());
+ updateContent();
+ updateMargins();
+}
- m_text = "";
+void RenderListMarker::updateContent()
+{
+ // FIXME: This if-statement is just a performance optimization, but it's messy to use the preferredLogicalWidths dirty bit for this.
+ // It's unclear if this is a premature optimization.
+ if (!preferredLogicalWidthsDirty())
+ return;
- const Font& font = style()->font();
- const FontMetrics& fontMetrics = font.fontMetrics();
+ m_text = "";
if (isImage()) {
// FIXME: This is a somewhat arbitrary width. Generated images for markers really won't become particularly useful
// until we support the CSS3 marker pseudoclass to allow control over the width and height of the marker box.
- int bulletWidth = fontMetrics.ascent() / 2;
+ int bulletWidth = style()->fontMetrics().ascent() / 2;
m_image->setContainerSizeForRenderer(this, IntSize(bulletWidth, bulletWidth), style()->effectiveZoom());
+ return;
+ }
+
+ EListStyleType type = style()->listStyleType();
+ switch (type) {
+ case NoneListStyle:
+ break;
+ case Circle:
+ case Disc:
+ case Square:
+ m_text = listMarkerText(type, 0); // value is ignored for these types
+ break;
+ case Asterisks:
+ case Footnotes:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case ArabicIndic:
+ case Armenian:
+ case BinaryListStyle:
+ case Bengali:
+ case Cambodian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Devanagari:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Gujarati:
+ case Gurmukhi:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Kannada:
+ case Katakana:
+ case KatakanaIroha:
+ case Khmer:
+ case Lao:
+ case LowerAlpha:
+ case LowerArmenian:
+ case LowerGreek:
+ case LowerHexadecimal:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Malayalam:
+ case Mongolian:
+ case Myanmar:
+ case Octal:
+ case Oriya:
+ case Oromo:
+ case Persian:
+ case Sidama:
+ case Somali:
+ case Telugu:
+ case Thai:
+ case Tibetan:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperArmenian:
+ case UpperGreek:
+ case UpperHexadecimal:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
+ case Urdu:
+ m_text = listMarkerText(type, m_listItem->value());
+ break;
+ }
+}
+
+void RenderListMarker::computePreferredLogicalWidths()
+{
+ ASSERT(preferredLogicalWidthsDirty());
+ updateContent();
+
+ if (isImage()) {
LayoutSize imageSize = m_image->imageSize(this, style()->effectiveZoom());
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = style()->isHorizontalWritingMode() ? imageSize.width() : imageSize.height();
setPreferredLogicalWidthsDirty(false);
@@ -1370,6 +1485,8 @@ void RenderListMarker::computePreferredLogicalWidths()
return;
}
+ const Font& font = style()->font();
+
LayoutUnit logicalWidth = 0;
EListStyleType type = style()->listStyleType();
switch (type) {
@@ -1377,14 +1494,12 @@ void RenderListMarker::computePreferredLogicalWidths()
break;
case Asterisks:
case Footnotes:
- m_text = listMarkerText(type, m_listItem->value());
logicalWidth = font.width(m_text); // no suffix for these types
break;
case Circle:
case Disc:
case Square:
- m_text = listMarkerText(type, 0); // value is ignored for these types
- logicalWidth = (fontMetrics.ascent() * 2 / 3 + 1) / 2 + 2;
+ logicalWidth = (font.fontMetrics().ascent() * 2 / 3 + 1) / 2 + 2;
break;
case Afar:
case Amharic:
@@ -1461,7 +1576,6 @@ void RenderListMarker::computePreferredLogicalWidths()
case UpperNorwegian:
case UpperRoman:
case Urdu:
- m_text = listMarkerText(type, m_listItem->value());
if (m_text.isEmpty())
logicalWidth = 0;
else {
@@ -1477,7 +1591,7 @@ void RenderListMarker::computePreferredLogicalWidths()
m_maxPreferredLogicalWidth = logicalWidth;
setPreferredLogicalWidthsDirty(false);
-
+
updateMargins();
}
diff --git a/Source/WebCore/rendering/RenderListMarker.h b/Source/WebCore/rendering/RenderListMarker.h
index 98480ea0f..ffac4fbb7 100644
--- a/Source/WebCore/rendering/RenderListMarker.h
+++ b/Source/WebCore/rendering/RenderListMarker.h
@@ -35,18 +35,22 @@ String listMarkerText(EListStyleType, int value);
// The RenderListMarker always has to be a child of a RenderListItem.
class RenderListMarker : public RenderBox {
public:
- RenderListMarker(RenderListItem*);
- virtual ~RenderListMarker();
+ static RenderListMarker* createAnonymous(RenderListItem*);
- virtual void computePreferredLogicalWidths();
+ virtual ~RenderListMarker();
const String& text() const { return m_text; }
String suffix() const;
bool isInside() const;
+ void updateMarginsAndContent();
+
private:
+ RenderListMarker(RenderListItem*);
+
virtual const char* renderName() const { return "RenderListMarker"; }
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual bool isListMarker() const { return true; }
@@ -69,6 +73,7 @@ private:
virtual bool canBeSelectionLeaf() const { return true; }
void updateMargins();
+ void updateContent();
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -83,13 +88,13 @@ private:
inline RenderListMarker* toRenderListMarker(RenderObject* object)
{
- ASSERT(!object || object->isListMarker());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isListMarker());
return static_cast<RenderListMarker*>(object);
}
inline const RenderListMarker* toRenderListMarker(const RenderObject* object)
{
- ASSERT(!object || object->isListMarker());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isListMarker());
return static_cast<const RenderListMarker*>(object);
}
diff --git a/Source/WebCore/rendering/RenderMarquee.cpp b/Source/WebCore/rendering/RenderMarquee.cpp
index d54c90900..89b093f5a 100644
--- a/Source/WebCore/rendering/RenderMarquee.cpp
+++ b/Source/WebCore/rendering/RenderMarquee.cpp
@@ -50,6 +50,7 @@
#include "HTMLMarqueeElement.h"
#include "HTMLNames.h"
#include "RenderLayer.h"
+#include "RenderView.h"
using namespace std;
@@ -254,7 +255,7 @@ void RenderMarquee::updateMarqueeStyle()
void RenderMarquee::timerFired(Timer<RenderMarquee>*)
{
- if (m_layer->renderer()->needsLayout())
+ if (m_layer->renderer()->view()->needsLayout())
return;
if (m_reset) {
diff --git a/Source/WebCore/rendering/RenderMedia.cpp b/Source/WebCore/rendering/RenderMedia.cpp
index 385fb5068..ae488569c 100644
--- a/Source/WebCore/rendering/RenderMedia.cpp
+++ b/Source/WebCore/rendering/RenderMedia.cpp
@@ -29,7 +29,9 @@
#include "RenderMedia.h"
#include "HTMLMediaElement.h"
+#include "RenderFlowThread.h"
#include "RenderView.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -52,7 +54,7 @@ RenderMedia::~RenderMedia()
HTMLMediaElement* RenderMedia::mediaElement() const
{
- return static_cast<HTMLMediaElement*>(node());
+ return toHTMLMediaElement(node());
}
void RenderMedia::layout()
@@ -66,8 +68,17 @@ void RenderMedia::layout()
if (!controlsRenderer)
return;
+ bool controlsNeedLayout = controlsRenderer->needsLayout();
+ // If the region chain has changed we also need to relayout the controls to update the region box info.
+ // FIXME: We can do better once we compute region box info for RenderReplaced, not only for RenderBlock.
+ const RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread && !controlsNeedLayout) {
+ if (flowThread->pageLogicalSizeChanged())
+ controlsNeedLayout = true;
+ }
+
LayoutSize newSize = contentBoxRect().size();
- if (newSize == oldSize && !controlsRenderer->needsLayout())
+ if (newSize == oldSize && !controlsNeedLayout)
return;
// When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or
diff --git a/Source/WebCore/rendering/RenderMedia.h b/Source/WebCore/rendering/RenderMedia.h
index 4694cabc4..48b852edf 100644
--- a/Source/WebCore/rendering/RenderMedia.h
+++ b/Source/WebCore/rendering/RenderMedia.h
@@ -36,7 +36,7 @@ class HTMLMediaElement;
class RenderMedia : public RenderImage {
public:
- RenderMedia(HTMLMediaElement*);
+ explicit RenderMedia(HTMLMediaElement*);
RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize);
virtual ~RenderMedia();
@@ -68,7 +68,7 @@ private:
inline RenderMedia* toRenderMedia(RenderObject* object)
{
- ASSERT(!object || object->isMedia());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isMedia());
return static_cast<RenderMedia*>(object);
}
diff --git a/Source/WebCore/rendering/RenderMediaControlElements.cpp b/Source/WebCore/rendering/RenderMediaControlElements.cpp
new file mode 100644
index 000000000..215b103ce
--- /dev/null
+++ b/Source/WebCore/rendering/RenderMediaControlElements.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "RenderMediaControlElements.h"
+
+#include "RenderTheme.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Element* element)
+ : RenderBlock(element)
+{
+}
+
+void RenderMediaVolumeSliderContainer::layout()
+{
+ RenderBlock::layout();
+
+ if (style()->display() == NONE || !nextSibling() || !nextSibling()->isBox())
+ return;
+
+ RenderBox* buttonBox = toRenderBox(nextSibling());
+ int absoluteOffsetTop = buttonBox->localToAbsolute(FloatPoint(0, -size().height())).y();
+
+ LayoutStateDisabler layoutStateDisabler(view());
+
+ // If the slider would be rendered outside the page, it should be moved below the controls.
+ if (UNLIKELY(absoluteOffsetTop < 0))
+ setY(buttonBox->offsetTop() + theme()->volumeSliderOffsetFromMuteButton(buttonBox, pixelSnappedSize()).y());
+}
+
+// ----------------------------
+
+RenderMediaControlTimelineContainer::RenderMediaControlTimelineContainer(Element* element)
+ : RenderFlexibleBox(element)
+{
+}
+
+// We want the timeline slider to be at least 100 pixels wide.
+// FIXME: Eliminate hard-coded widths altogether.
+static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
+
+void RenderMediaControlTimelineContainer::layout()
+{
+ RenderFlexibleBox::layout();
+
+ LayoutStateDisabler layoutStateDisabler(view());
+ MediaControlTimelineContainerElement* container = static_cast<MediaControlTimelineContainerElement*>(node());
+ container->setTimeDisplaysHidden(width().toInt() < minWidthToDisplayTimeDisplays);
+}
+
+// ----------------------------
+
+#if ENABLE(VIDEO_TRACK)
+
+RenderTextTrackContainerElement::RenderTextTrackContainerElement(Element* element)
+ : RenderBlock(element)
+{
+}
+
+void RenderTextTrackContainerElement::layout()
+{
+ RenderBlock::layout();
+ if (style()->display() == NONE)
+ return;
+
+ ASSERT(mediaControlElementType(node()) == MediaTextTrackDisplayContainer);
+
+ LayoutStateDisabler layoutStateDisabler(view());
+ static_cast<MediaControlTextTrackContainerElement*>(node())->updateSizes();
+}
+
+#endif // ENABLE(VIDEO_TRACK)
+
+} // namespace WebCore
+
+#endif // ENABLE(VIDEO)
+
diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.h b/Source/WebCore/rendering/RenderMediaControlElements.h
index 6015cb1fc..a3df364d2 100644
--- a/Source/WebCore/rendering/RenderMediaControlsChromium.h
+++ b/Source/WebCore/rendering/RenderMediaControlElements.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2009 Apple Inc.
- * Copyright (C) 2009 Google Inc.
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,28 +25,52 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RenderMediaControlsChromium_h
-#define RenderMediaControlsChromium_h
+#ifndef RenderMediaControlElements_h
+#define RenderMediaControlElements_h
+
+#if ENABLE(VIDEO)
#include "MediaControlElements.h"
+#include "RenderBlock.h"
+#include "RenderFlexibleBox.h"
namespace WebCore {
-struct PaintInfo;
+class RenderMediaVolumeSliderContainer : public RenderBlock {
+public:
+ RenderMediaVolumeSliderContainer(Element*);
+
+private:
+ virtual void layout();
+};
+
+// ----------------------------
+
+class RenderMediaControlTimelineContainer : public RenderFlexibleBox {
+public:
+ RenderMediaControlTimelineContainer(Element*);
+
+private:
+ virtual void layout();
+};
+
+// ----------------------------
-class HTMLMediaElement;
-class IntRect;
-class RenderObject;
+#if ENABLE(VIDEO_TRACK)
-class RenderMediaControlsChromium {
+class RenderTextTrackContainerElement : public RenderBlock {
public:
- static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const PaintInfo&, const IntRect&);
- static void adjustMediaSliderThumbSize(RenderStyle*);
- static String formatMediaControlsTime(float time);
- static String formatMediaControlsCurrentTime(float currentTime, float duration);
- static String formatMediaControlsRemainingTime(float currentTime, float duration);
+ RenderTextTrackContainerElement(Element*);
+
+private:
+ virtual void layout();
};
+#endif // ENABLE(VIDEO_TRACK)
+
} // namespace WebCore
-#endif // RenderMediaControlsChromium_h
+#endif // ENABLE(VIDEO)
+
+#endif // RenderMediaControlElements_h
+
diff --git a/Source/WebCore/rendering/RenderMediaControls.cpp b/Source/WebCore/rendering/RenderMediaControls.cpp
index f17647b0b..1582fa5df 100644
--- a/Source/WebCore/rendering/RenderMediaControls.cpp
+++ b/Source/WebCore/rendering/RenderMediaControls.cpp
@@ -215,7 +215,7 @@ IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(RenderBox* muteBu
float zoomLevel = muteButtonBox->style()->effectiveZoom();
int y = yOffset * zoomLevel + muteButtonBox->pixelSnappedOffsetHeight() - size.height();
- FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), IsFixed | UseTransforms | SnapOffsetForTransforms);
+ FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), IsFixed | UseTransforms);
if (absPoint.y() < 0)
y = muteButtonBox->pixelSnappedHeight();
return IntPoint(xOffset * zoomLevel, y);
diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp
deleted file mode 100644
index 0451fbdd2..000000000
--- a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc.
- * Copyright (C) 2009 Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RenderMediaControlsChromium.h"
-
-#include "Gradient.h"
-#include "GraphicsContext.h"
-#include "HTMLMediaElement.h"
-#include "HTMLNames.h"
-#include "PaintInfo.h"
-#include "TimeRanges.h"
-
-namespace WebCore {
-
-#if ENABLE(VIDEO)
-
-typedef WTF::HashMap<const char*, Image*> MediaControlImageMap;
-static MediaControlImageMap* gMediaControlImageMap = 0;
-
-static Image* platformResource(const char* name)
-{
- if (!gMediaControlImageMap)
- gMediaControlImageMap = new MediaControlImageMap();
- if (Image* image = gMediaControlImageMap->get(name))
- return image;
- if (Image* image = Image::loadPlatformResource(name).leakRef()) {
- gMediaControlImageMap->set(name, image);
- return image;
- }
- ASSERT_NOT_REACHED();
- return 0;
-}
-
-static bool hasSource(const HTMLMediaElement* mediaElement)
-{
- return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY
- && mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE;
-}
-
-static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image)
-{
- context->drawImage(image, ColorSpaceDeviceRGB, rect);
- return true;
-}
-
-static bool paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- static Image* soundLevel3 = platformResource("mediaplayerSoundLevel3");
- static Image* soundLevel2 = platformResource("mediaplayerSoundLevel2");
- static Image* soundLevel1 = platformResource("mediaplayerSoundLevel1");
- static Image* soundLevel0 = platformResource("mediaplayerSoundLevel0");
- static Image* soundDisabled = platformResource("mediaplayerSoundDisabled");
-
- if (!hasSource(mediaElement) || !mediaElement->hasAudio())
- return paintMediaButton(paintInfo.context, rect, soundDisabled);
-
- if (mediaElement->muted() || mediaElement->volume() <= 0)
- return paintMediaButton(paintInfo.context, rect, soundLevel0);
-
- if (mediaElement->volume() <= 0.33)
- return paintMediaButton(paintInfo.context, rect, soundLevel1);
-
- if (mediaElement->volume() <= 0.66)
- return paintMediaButton(paintInfo.context, rect, soundLevel2);
-
- return paintMediaButton(paintInfo.context, rect, soundLevel3);
-}
-
-static bool paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- static Image* mediaPlay = platformResource("mediaplayerPlay");
- static Image* mediaPause = platformResource("mediaplayerPause");
- static Image* mediaPlayDisabled = platformResource("mediaplayerPlayDisabled");
-
- if (!hasSource(mediaElement))
- return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled);
-
- return paintMediaButton(paintInfo.context, rect, mediaElement->canPlay() ? mediaPlay : mediaPause);
-}
-
-static bool paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- if (!hasSource(mediaElement) || !mediaElement->canPlay())
- return false;
-
- static Image* mediaOverlayPlay = platformResource("mediaplayerOverlayPlay");
- return paintMediaButton(paintInfo.context, rect, mediaOverlayPlay);
-}
-
-static Image* getMediaSliderThumb()
-{
- static Image* mediaSliderThumb = platformResource("mediaplayerSliderThumb");
- return mediaSliderThumb;
-}
-
-static void paintRoundedSliderBackground(const IntRect& rect, const RenderStyle* style, GraphicsContext* context)
-{
- int borderRadius = rect.height() / 2;
- IntSize radii(borderRadius, borderRadius);
- Color sliderBackgroundColor = Color(11, 11, 11);
- context->save();
- context->fillRoundedRect(rect, radii, radii, radii, radii, sliderBackgroundColor, ColorSpaceDeviceRGB);
- context->restore();
-}
-
-static void paintSliderRangeHighlight(const IntRect& rect, const RenderStyle* style, GraphicsContext* context, int startPosition, int endPosition, Color startColor, Color endColor)
-{
- // Calculate border radius; need to avoid being smaller than half the slider height
- // because of https://bugs.webkit.org/show_bug.cgi?id=30143.
- int borderRadius = rect.height() / 2;
- IntSize radii(borderRadius, borderRadius);
-
- // Calculate highlight rectangle and edge dimensions.
- int startOffset = startPosition;
- int endOffset = rect.width() - endPosition;
- int rangeWidth = endPosition - startPosition;
-
- if (rangeWidth <= 0)
- return;
-
- // Make sure the range width is bigger than border radius at the edges to retain rounded corners.
- if (startOffset < borderRadius && rangeWidth < borderRadius)
- rangeWidth = borderRadius;
- if (endOffset < borderRadius && rangeWidth < borderRadius) {
- startPosition -= borderRadius - rangeWidth;
- rangeWidth = borderRadius;
- }
-
- // Set rectangle to highlight range.
- IntRect highlightRect = rect;
- highlightRect.move(startOffset, 0);
- highlightRect.setWidth(rangeWidth);
-
- // Don't bother drawing an empty area.
- if (highlightRect.isEmpty())
- return;
-
- // Calculate white-grey gradient.
- IntPoint sliderTopLeft = highlightRect.location();
- IntPoint sliderBottomLeft = sliderTopLeft;
- sliderBottomLeft.move(0, highlightRect.height());
- RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderBottomLeft);
- gradient->addColorStop(0.0, startColor);
- gradient->addColorStop(1.0, endColor);
-
- // Fill highlight rectangle with gradient, potentially rounded if on left or right edge.
- context->save();
- context->setFillGradient(gradient);
-
- if (startOffset < borderRadius && endOffset < borderRadius)
- context->fillRoundedRect(highlightRect, radii, radii, radii, radii, startColor, ColorSpaceDeviceRGB);
- else if (startOffset < borderRadius)
- context->fillRoundedRect(highlightRect, radii, IntSize(0, 0), radii, IntSize(0, 0), startColor, ColorSpaceDeviceRGB);
- else if (endOffset < borderRadius)
- context->fillRoundedRect(highlightRect, IntSize(0, 0), radii, IntSize(0, 0), radii, startColor, ColorSpaceDeviceRGB);
- else
- context->fillRect(highlightRect);
-
- context->restore();
-}
-
-const int mediaSliderThumbWidth = 32;
-
-static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- RenderStyle* style = object->style();
- GraphicsContext* context = paintInfo.context;
-
- paintRoundedSliderBackground(rect, style, context);
-
- // Draw the buffered range. Since the element may have multiple buffered ranges and it'd be
- // distracting/'busy' to show all of them, show only the buffered range containing the current play head.
- RefPtr<TimeRanges> bufferedTimeRanges = mediaElement->buffered();
- float duration = mediaElement->duration();
- float currentTime = mediaElement->currentTime();
- if (isnan(duration) || isinf(duration) || !duration || isnan(currentTime))
- return true;
-
- for (unsigned i = 0; i < bufferedTimeRanges->length(); ++i) {
- float start = bufferedTimeRanges->start(i, ASSERT_NO_EXCEPTION);
- float end = bufferedTimeRanges->end(i, ASSERT_NO_EXCEPTION);
- if (isnan(start) || isnan(end) || start > currentTime || end < currentTime)
- continue;
- int startPosition = int(start * rect.width() / duration);
- int currentPosition = int(currentTime * rect.width() / duration);
- int endPosition = int(end * rect.width() / duration);
-
- // Add half the thumb width proportionally adjusted to the current painting position.
- int thumbCenter = mediaSliderThumbWidth / 2;
- int addWidth = thumbCenter * (1.0 - 2.0 * currentPosition / rect.width());
- currentPosition += addWidth;
-
- // Draw white-ish highlight before current time.
- Color startColor = Color(195, 195, 195);
- Color endColor = Color(217, 217, 217);
- if (currentPosition > startPosition)
- paintSliderRangeHighlight(rect, style, context, startPosition, currentPosition, startColor, endColor);
-
- // Draw grey-ish highlight after current time.
- startColor = Color(60, 60, 60);
- endColor = Color(76, 76, 76);
-
- if (endPosition > currentPosition)
- paintSliderRangeHighlight(rect, style, context, currentPosition, endPosition, startColor, endColor);
-
- return true;
- }
-
- return true;
-}
-
-static bool paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- ASSERT(object->node());
- HTMLMediaElement* mediaElement = toParentMediaElement(object->node()->shadowHost());
- if (!mediaElement)
- return false;
-
- if (!hasSource(mediaElement))
- return true;
-
- Image* mediaSliderThumb = getMediaSliderThumb();
- return paintMediaButton(paintInfo.context, rect, mediaSliderThumb);
-}
-
-const int mediaVolumeSliderThumbWidth = 24;
-
-static bool paintMediaVolumeSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- GraphicsContext* context = paintInfo.context;
- RenderStyle* style = object->style();
-
- paintRoundedSliderBackground(rect, style, context);
-
- // Calculate volume position for white background rectangle.
- float volume = mediaElement->volume();
- if (isnan(volume) || volume < 0)
- return true;
- if (volume > 1)
- volume = 1;
- if (!hasSource(mediaElement) || !mediaElement->hasAudio() || mediaElement->muted())
- volume = 0;
-
- // Calculate the position relative to the center of the thumb.
- float fillWidth = 0;
- if (volume > 0) {
- float thumbCenter = mediaVolumeSliderThumbWidth / 2;
- float zoomLevel = style->effectiveZoom();
- float positionWidth = volume * (rect.width() - (zoomLevel * thumbCenter));
- fillWidth = positionWidth + (zoomLevel * thumbCenter / 2);
- }
-
- Color startColor = Color(195, 195, 195);
- Color endColor = Color(217, 217, 217);
-
- paintSliderRangeHighlight(rect, style, context, 0.0, fillWidth, startColor, endColor);
-
- return true;
-}
-
-static bool paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- ASSERT(object->node());
- HTMLMediaElement* mediaElement = toParentMediaElement(object->node()->shadowHost());
- if (!mediaElement)
- return false;
-
- if (!hasSource(mediaElement) || !mediaElement->hasAudio())
- return true;
-
- static Image* mediaVolumeSliderThumb = platformResource("mediaplayerVolumeSliderThumb");
- return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb);
-}
-
-static bool paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- static Image* mediaFullscreenButton = platformResource("mediaplayerFullscreen");
- return paintMediaButton(paintInfo.context, rect, mediaFullscreenButton);
-}
-
-static bool paintMediaClosedCaptionsButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- HTMLMediaElement* mediaElement = toParentMediaElement(object);
- if (!mediaElement)
- return false;
-
- static Image* mediaClosedCaptionButton = platformResource("mediaplayerClosedCaption");
- static Image* mediaClosedCaptionButtonDisabled = platformResource("mediaplayerClosedCaptionDisabled");
-
- if (mediaElement->webkitClosedCaptionsVisible())
- return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButton);
-
- return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButtonDisabled);
-}
-
-
-bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- switch (part) {
- case MediaMuteButton:
- case MediaUnMuteButton:
- return paintMediaMuteButton(object, paintInfo, rect);
- case MediaPauseButton:
- case MediaPlayButton:
- return paintMediaPlayButton(object, paintInfo, rect);
- case MediaShowClosedCaptionsButton:
- return paintMediaClosedCaptionsButton(object, paintInfo, rect);
- case MediaSlider:
- return paintMediaSlider(object, paintInfo, rect);
- case MediaSliderThumb:
- return paintMediaSliderThumb(object, paintInfo, rect);
- case MediaVolumeSlider:
- return paintMediaVolumeSlider(object, paintInfo, rect);
- case MediaVolumeSliderThumb:
- return paintMediaVolumeSliderThumb(object, paintInfo, rect);
- case MediaEnterFullscreenButton:
- case MediaExitFullscreenButton:
- return paintMediaFullscreenButton(object, paintInfo, rect);
- case MediaOverlayPlayButton:
- return paintMediaOverlayPlayButton(object, paintInfo, rect);
- case MediaVolumeSliderMuteButton:
- case MediaSeekBackButton:
- case MediaSeekForwardButton:
- case MediaVolumeSliderContainer:
- case MediaTimelineContainer:
- case MediaCurrentTimeDisplay:
- case MediaTimeRemainingDisplay:
- case MediaControlsPanel:
- case MediaRewindButton:
- case MediaReturnToRealtimeButton:
- case MediaStatusDisplay:
- case MediaHideClosedCaptionsButton:
- case MediaTextTrackDisplayContainer:
- case MediaTextTrackDisplay:
- case MediaFullScreenVolumeSlider:
- case MediaFullScreenVolumeSliderThumb:
- case MediaClosedCaptionsContainer:
- case MediaClosedCaptionsTrackList:
- ASSERT_NOT_REACHED();
- break;
- }
- return false;
-}
-
-const int mediaSliderThumbHeight = 24;
-const int mediaVolumeSliderThumbHeight = 24;
-
-void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderStyle* style)
-{
- static Image* mediaSliderThumb = platformResource("mediaplayerSliderThumb");
- static Image* mediaVolumeSliderThumb = platformResource("mediaplayerVolumeSliderThumb");
- int width = 0;
- int height = 0;
-
- Image* thumbImage = 0;
- if (style->appearance() == MediaSliderThumbPart) {
- thumbImage = mediaSliderThumb;
- width = mediaSliderThumbWidth;
- height = mediaSliderThumbHeight;
- } else if (style->appearance() == MediaVolumeSliderThumbPart) {
- thumbImage = mediaVolumeSliderThumb;
- width = mediaVolumeSliderThumbWidth;
- height = mediaVolumeSliderThumbHeight;
- }
-
- float zoomLevel = style->effectiveZoom();
- if (thumbImage) {
- style->setWidth(Length(static_cast<int>(width * zoomLevel), Fixed));
- style->setHeight(Length(static_cast<int>(height * zoomLevel), Fixed));
- }
-}
-
-static String formatChromiumMediaControlsTime(float time, float duration)
-{
- if (!isfinite(time))
- time = 0;
- if (!isfinite(duration))
- duration = 0;
- int seconds = static_cast<int>(fabsf(time));
- int hours = seconds / (60 * 60);
- int minutes = (seconds / 60) % 60;
- seconds %= 60;
-
- // duration defines the format of how the time is rendered
- int durationSecs = static_cast<int>(fabsf(duration));
- int durationHours = durationSecs / (60 * 60);
- int durationMins = (durationSecs / 60) % 60;
-
- if (durationHours || hours)
- return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
- if (durationMins > 9)
- return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
-
- return String::format("%s%01d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
-}
-
-String RenderMediaControlsChromium::formatMediaControlsTime(float time)
-{
- return formatChromiumMediaControlsTime(time, time);
-}
-
-String RenderMediaControlsChromium::formatMediaControlsCurrentTime(float currentTime, float duration)
-{
- return formatChromiumMediaControlsTime(currentTime, duration);
-}
-
-String RenderMediaControlsChromium::formatMediaControlsRemainingTime(float currentTime, float duration)
-{
- return formatChromiumMediaControlsTime(currentTime - duration, duration);
-}
-
-#endif // #if ENABLE(VIDEO)
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp
index b721742e1..47a74fce8 100644
--- a/Source/WebCore/rendering/RenderMenuList.cpp
+++ b/Source/WebCore/rendering/RenderMenuList.cpp
@@ -54,10 +54,10 @@ namespace WebCore {
using namespace HTMLNames;
RenderMenuList::RenderMenuList(Element* element)
- : RenderDeprecatedFlexibleBox(element)
+ : RenderFlexibleBox(element)
, m_buttonText(0)
, m_innerBlock(0)
- , m_optionsChanged(true)
+ , m_needsOptionsWidthUpdate(true)
, m_optionsWidth(0)
, m_lastActiveIndex(-1)
, m_popupIsVisible(false)
@@ -91,26 +91,38 @@ void RenderMenuList::createInnerBlock()
ASSERT(!firstChild());
m_innerBlock = createAnonymousBlock();
adjustInnerStyle();
- RenderDeprecatedFlexibleBox::addChild(m_innerBlock);
+ RenderFlexibleBox::addChild(m_innerBlock);
}
void RenderMenuList::adjustInnerStyle()
{
RenderStyle* innerStyle = m_innerBlock->style();
- innerStyle->setBoxFlex(1);
-
+ innerStyle->setFlexGrow(1);
+ innerStyle->setFlexShrink(1);
+ // min-width: 0; is needed for correct shrinking.
+ // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
+ innerStyle->setMinWidth(Length(0, Fixed));
+ // Use margin:auto instead of align-items:center to get safe centering, i.e.
+ // when the content overflows, treat it the same as align-items: flex-start.
+ // But we only do that for the cases where html.css would otherwise use center.
+ if (style()->alignItems() == AlignCenter) {
+ innerStyle->setMarginTop(Length());
+ innerStyle->setMarginBottom(Length());
+ innerStyle->setAlignSelf(AlignFlexStart);
+ }
+
innerStyle->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed));
innerStyle->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed));
innerStyle->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed));
innerStyle->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed));
- if (document()->page()->chrome()->selectItemWritingDirectionIsNatural()) {
+ if (document()->page()->chrome().selectItemWritingDirectionIsNatural()) {
// Items in the popup will not respect the CSS text-align and direction properties,
// so we must adjust our own style to match.
innerStyle->setTextAlign(LEFT);
TextDirection direction = (m_buttonText && m_buttonText->text()->defaultWritingDirection() == WTF::Unicode::RightToLeft) ? RTL : LTR;
innerStyle->setDirection(direction);
- } else if (m_optionStyle && document()->page()->chrome()->selectItemAlignmentFollowsMenuWritingDirection()) {
+ } else if (m_optionStyle && document()->page()->chrome().selectItemAlignmentFollowsMenuWritingDirection()) {
if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi()))
m_innerBlock->setNeedsLayoutAndPrefWidthsRecalc();
innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT);
@@ -130,14 +142,14 @@ void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild)
m_innerBlock->addChild(newChild, beforeChild);
ASSERT(m_innerBlock == firstChild());
- if (AXObjectCache::accessibilityEnabled())
- document()->axObjectCache()->childrenChanged(this);
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->childrenChanged(this);
}
void RenderMenuList::removeChild(RenderObject* oldChild)
{
if (oldChild == m_innerBlock || !m_innerBlock) {
- RenderDeprecatedFlexibleBox::removeChild(oldChild);
+ RenderFlexibleBox::removeChild(oldChild);
m_innerBlock = 0;
} else
m_innerBlock->removeChild(oldChild);
@@ -153,8 +165,10 @@ void RenderMenuList::styleDidChange(StyleDifference diff, const RenderStyle* old
adjustInnerStyle();
bool fontChanged = !oldStyle || oldStyle->font() != style()->font();
- if (fontChanged)
+ if (fontChanged) {
updateOptionsWidth();
+ m_needsOptionsWidthUpdate = false;
+ }
}
void RenderMenuList::updateOptionsWidth()
@@ -166,7 +180,7 @@ void RenderMenuList::updateOptionsWidth()
for (int i = 0; i < size; ++i) {
HTMLElement* element = listItems[i];
- if (!element->hasTagName(optionTag))
+ if (!isHTMLOptionElement(element))
continue;
String text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
@@ -194,9 +208,9 @@ void RenderMenuList::updateOptionsWidth()
void RenderMenuList::updateFromElement()
{
- if (m_optionsChanged) {
+ if (m_needsOptionsWidthUpdate) {
updateOptionsWidth();
- m_optionsChanged = false;
+ m_needsOptionsWidthUpdate = false;
}
if (m_popupIsVisible)
@@ -215,7 +229,7 @@ void RenderMenuList::setTextFromOption(int optionIndex)
String text = emptyString();
if (i >= 0 && i < size) {
Element* element = listItems[i];
- if (element->hasTagName(optionTag)) {
+ if (isHTMLOptionElement(element)) {
text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
m_optionStyle = element->renderStyle();
}
@@ -272,6 +286,13 @@ LayoutRect RenderMenuList::controlClipRect(const LayoutPoint& additionalOffset)
return intersection(outerBox, innerBox);
}
+void RenderMenuList::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ maxLogicalWidth = max(m_optionsWidth, theme()->minimumMenuListSize(style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight();
+ if (!style()->width().isPercent())
+ minLogicalWidth = maxLogicalWidth;
+}
+
void RenderMenuList::computePreferredLogicalWidths()
{
m_minPreferredLogicalWidth = 0;
@@ -280,15 +301,12 @@ void RenderMenuList::computePreferredLogicalWidths()
if (style()->width().isFixed() && style()->width().value() > 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
else
- m_maxPreferredLogicalWidth = max(m_optionsWidth, theme()->minimumMenuListSize(style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight();
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
- } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
- m_minPreferredLogicalWidth = 0;
- else
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
+ }
if (style()->maxWidth().isFixed()) {
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
@@ -307,7 +325,7 @@ void RenderMenuList::showPopup()
if (m_popupIsVisible)
return;
- if (document()->page()->chrome()->hasOpenedPopup())
+ if (document()->page()->chrome().hasOpenedPopup())
return;
// Create m_innerBlock here so it ends up as the first child.
@@ -315,12 +333,12 @@ void RenderMenuList::showPopup()
// inside the showPopup call and it would fail.
createInnerBlock();
if (!m_popup)
- m_popup = document()->page()->chrome()->createPopupMenu(this);
+ m_popup = document()->page()->chrome().createPopupMenu(this);
m_popupIsVisible = true;
// Compute the top left taking transforms into account, but use
// the actual width of the element to size the popup.
- FloatPoint absTopLeft = localToAbsolute(FloatPoint(), UseTransforms | SnapOffsetForTransforms);
+ FloatPoint absTopLeft = localToAbsolute(FloatPoint(), UseTransforms);
IntRect absBounds = absoluteBoundingBoxRectIgnoringTransforms();
absBounds.setLocation(roundedIntPoint(absTopLeft));
HTMLSelectElement* select = selectElement();
@@ -337,7 +355,7 @@ void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
{
// Check to ensure a page navigation has not occurred while
// the popup was up.
- Document* doc = static_cast<Element*>(node())->document();
+ Document* doc = toElement(node())->document();
if (!doc || doc != doc->frame()->document())
return;
@@ -362,7 +380,7 @@ void RenderMenuList::didSetSelectedIndex(int listIndex)
void RenderMenuList::didUpdateActiveOption(int optionIndex)
{
- if (!AXObjectCache::accessibilityEnabled())
+ if (!AXObjectCache::accessibilityEnabled() || !document()->existingAXObjectCache())
return;
if (m_lastActiveIndex == optionIndex)
@@ -389,9 +407,9 @@ String RenderMenuList::itemText(unsigned listIndex) const
String itemString;
Element* element = listItems[listIndex];
- if (element->hasTagName(optgroupTag))
- itemString = static_cast<const HTMLOptGroupElement*>(element)->groupLabelText();
- else if (element->hasTagName(optionTag))
+ if (isHTMLOptGroupElement(element))
+ itemString = toHTMLOptGroupElement(element)->groupLabelText();
+ else if (isHTMLOptionElement(element))
itemString = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
applyTextTransform(style(), itemString, ' ');
@@ -431,18 +449,18 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
if (listIndex >= listItems.size())
return false;
HTMLElement* element = listItems[listIndex];
- if (!element->hasTagName(optionTag))
+ if (!isHTMLOptionElement(element))
return false;
bool groupEnabled = true;
if (Element* parentElement = element->parentElement()) {
- if (parentElement->hasTagName(optgroupTag))
- groupEnabled = !static_cast<HTMLOptGroupElement*>(parentElement)->disabled();
+ if (isHTMLOptGroupElement(parentElement))
+ groupEnabled = !parentElement->isDisabledFormControl();
}
if (!groupEnabled)
return false;
- return element->isEnabledFormControl();
+ return !element->isDisabledFormControl();
}
PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
@@ -459,33 +477,46 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
listIndex = 0;
}
HTMLElement* element = listItems[listIndex];
-
+
+ Color itemBackgroundColor;
+ bool itemHasCustomBackgroundColor;
+ getItemBackgroundColor(listIndex, itemBackgroundColor, itemHasCustomBackgroundColor);
+
RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle();
- return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE,
- style->display() == NONE, style->textIndent(), style->direction(), isOverride(style->unicodeBidi())) : menuStyle();
+ return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor, style->font(), style->visibility() == VISIBLE,
+ style->display() == NONE, style->textIndent(), style->direction(), isOverride(style->unicodeBidi()),
+ itemHasCustomBackgroundColor ? PopupMenuStyle::CustomBackgroundColor : PopupMenuStyle::DefaultBackgroundColor) : menuStyle();
}
-Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
+void RenderMenuList::getItemBackgroundColor(unsigned listIndex, Color& itemBackgroundColor, bool& itemHasCustomBackgroundColor) const
{
const Vector<HTMLElement*>& listItems = selectElement()->listItems();
- if (listIndex >= listItems.size())
- return style()->visitedDependentColor(CSSPropertyBackgroundColor);
+ if (listIndex >= listItems.size()) {
+ itemBackgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
+ itemHasCustomBackgroundColor = false;
+ return;
+ }
HTMLElement* element = listItems[listIndex];
Color backgroundColor;
if (element->renderStyle())
backgroundColor = element->renderStyle()->visitedDependentColor(CSSPropertyBackgroundColor);
+ itemHasCustomBackgroundColor = backgroundColor.isValid() && backgroundColor.alpha();
// If the item has an opaque background color, return that.
- if (!backgroundColor.hasAlpha())
- return backgroundColor;
+ if (!backgroundColor.hasAlpha()) {
+ itemBackgroundColor = backgroundColor;
+ return;
+ }
// Otherwise, the item's background is overlayed on top of the menu background.
backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor).blend(backgroundColor);
- if (!backgroundColor.hasAlpha())
- return backgroundColor;
+ if (!backgroundColor.hasAlpha()) {
+ itemBackgroundColor = backgroundColor;
+ return;
+ }
// If the menu background is not opaque, then add an opaque white background behind.
- return Color(Color::white).blend(backgroundColor);
+ itemBackgroundColor = Color(Color::white).blend(backgroundColor);
}
PopupMenuStyle RenderMenuList::menuStyle() const
@@ -567,7 +598,7 @@ bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
bool RenderMenuList::itemIsLabel(unsigned listIndex) const
{
const Vector<HTMLElement*>& listItems = selectElement()->listItems();
- return listIndex < listItems.size() && listItems[listIndex]->hasTagName(optgroupTag);
+ return listIndex < listItems.size() && isHTMLOptGroupElement(listItems[listIndex]);
}
bool RenderMenuList::itemIsSelected(unsigned listIndex) const
@@ -576,7 +607,7 @@ bool RenderMenuList::itemIsSelected(unsigned listIndex) const
if (listIndex >= listItems.size())
return false;
HTMLElement* element = listItems[listIndex];
- return element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected();
+ return isHTMLOptionElement(element) && toHTMLOptionElement(element)->selected();
}
void RenderMenuList::setTextFromItem(unsigned listIndex)
@@ -586,7 +617,7 @@ void RenderMenuList::setTextFromItem(unsigned listIndex)
FontSelector* RenderMenuList::fontSelector() const
{
- return document()->styleResolver()->fontSelector();
+ return document()->ensureStyleResolver()->fontSelector();
}
}
diff --git a/Source/WebCore/rendering/RenderMenuList.h b/Source/WebCore/rendering/RenderMenuList.h
index df42f1696..7287ac300 100644
--- a/Source/WebCore/rendering/RenderMenuList.h
+++ b/Source/WebCore/rendering/RenderMenuList.h
@@ -27,7 +27,7 @@
#include "LayoutRect.h"
#include "PopupMenu.h"
#include "PopupMenuClient.h"
-#include "RenderDeprecatedFlexibleBox.h"
+#include "RenderFlexibleBox.h"
#if PLATFORM(MAC)
#define POPUP_MENU_PULLS_DOWN 0
@@ -40,7 +40,7 @@ namespace WebCore {
class HTMLSelectElement;
class RenderText;
-class RenderMenuList : public RenderDeprecatedFlexibleBox, private PopupMenuClient {
+class RenderMenuList : public RenderFlexibleBox, private PopupMenuClient {
public:
RenderMenuList(Element*);
@@ -51,7 +51,7 @@ public:
void showPopup();
void hidePopup();
- void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
+ void setOptionsChanged(bool changed) { m_needsOptionsWidthUpdate = changed; }
void didSetSelectedIndex(int listIndex);
@@ -75,7 +75,8 @@ private:
virtual const char* renderName() const { return "RenderMenuList"; }
- virtual void computePreferredLogicalWidths();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -114,7 +115,16 @@ private:
virtual bool hasLineIfEmpty() const { return true; }
- Color itemBackgroundColor(unsigned listIndex) const;
+ // Flexbox defines baselines differently than regular blocks.
+ // For backwards compatibility, menulists need to do the regular block behavior.
+ virtual int baselinePosition(FontBaseline baseline, bool firstLine, LineDirectionMode direction, LinePositionMode position) const OVERRIDE
+ {
+ return RenderBlock::baselinePosition(baseline, firstLine, direction, position);
+ }
+ virtual int firstLineBoxBaseline() const OVERRIDE { return RenderBlock::firstLineBoxBaseline(); }
+ virtual int inlineBlockBaseline(LineDirectionMode direction) const OVERRIDE { return RenderBlock::inlineBlockBaseline(direction); }
+
+ void getItemBackgroundColor(unsigned listIndex, Color&, bool& itemHasCustomBackgroundColor) const;
void createInnerBlock();
void adjustInnerStyle();
@@ -127,7 +137,7 @@ private:
RenderText* m_buttonText;
RenderBlock* m_innerBlock;
- bool m_optionsChanged;
+ bool m_needsOptionsWidthUpdate;
int m_optionsWidth;
int m_lastActiveIndex;
@@ -140,7 +150,7 @@ private:
inline RenderMenuList* toRenderMenuList(RenderObject* object)
{
- ASSERT(!object || object->isMenuList());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isMenuList());
return static_cast<RenderMenuList*>(object);
}
diff --git a/Source/WebCore/rendering/RenderMeter.cpp b/Source/WebCore/rendering/RenderMeter.cpp
index a4b3eca35..a2ea96890 100644
--- a/Source/WebCore/rendering/RenderMeter.cpp
+++ b/Source/WebCore/rendering/RenderMeter.cpp
@@ -19,9 +19,9 @@
*/
#include "config.h"
+#if ENABLE(METER_ELEMENT)
#include "RenderMeter.h"
-#if ENABLE(METER_ELEMENT)
#include "HTMLMeterElement.h"
#include "HTMLNames.h"
#include "RenderTheme.h"
@@ -73,11 +73,6 @@ void RenderMeter::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logi
computedValues.m_extent = isHorizontalWritingMode() ? frameSize.height() : frameSize.width();
}
-double RenderMeter::valueRatio() const
-{
- return meterElement()->valueRatio();
-}
-
void RenderMeter::updateFromElement()
{
repaint();
diff --git a/Source/WebCore/rendering/RenderMeter.h b/Source/WebCore/rendering/RenderMeter.h
index b7c3ecee7..bc09d3fd6 100644
--- a/Source/WebCore/rendering/RenderMeter.h
+++ b/Source/WebCore/rendering/RenderMeter.h
@@ -32,26 +32,24 @@ class HTMLMeterElement;
class RenderMeter : public RenderBlock {
public:
- RenderMeter(HTMLElement*);
+ explicit RenderMeter(HTMLElement*);
virtual ~RenderMeter();
HTMLMeterElement* meterElement() const;
virtual void updateFromElement();
-private:
+private:
virtual void updateLogicalWidth() OVERRIDE;
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
virtual const char* renderName() const { return "RenderMeter"; }
virtual bool isMeter() const { return true; }
virtual bool requiresForcedStyleRecalcPropagation() const { return true; }
-
- double valueRatio() const;
};
inline RenderMeter* toRenderMeter(RenderObject* object)
{
- ASSERT(!object || object->isMeter());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isMeter());
return static_cast<RenderMeter*>(object);
}
diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp
index ba3ccd9b2..33d5c873b 100644
--- a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp
+++ b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp
@@ -25,21 +25,31 @@
#include "config.h"
#include "RenderMultiColumnBlock.h"
+
#include "RenderMultiColumnFlowThread.h"
#include "RenderMultiColumnSet.h"
+#include "RenderView.h"
#include "StyleInheritedData.h"
using namespace std;
namespace WebCore {
-RenderMultiColumnBlock::RenderMultiColumnBlock(Node* node)
- : RenderBlock(node)
+RenderMultiColumnBlock::RenderMultiColumnBlock(Element* element)
+ : RenderBlock(element)
, m_flowThread(0)
, m_columnCount(1)
, m_columnWidth(0)
- , m_columnHeight(0)
+ , m_columnHeightAvailable(0)
+ , m_inBalancingPass(false)
+{
+}
+
+void RenderMultiColumnBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
+ RenderBlock::styleDidChange(diff, oldStyle);
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox())
+ child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
}
void RenderMultiColumnBlock::computeColumnCountAndWidth()
@@ -82,76 +92,104 @@ void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& /
{
// We don't actually update any of the variables. We just subclassed to adjust our column height.
updateLogicalHeight();
- LayoutUnit newContentLogicalHeight = contentLogicalHeight();
- if (newContentLogicalHeight > 0) {
- // The regions will be invalidated when we lay them out and they change size to
- // the new column height.
- if (columnHeight() != newContentLogicalHeight)
- setColumnHeight(newContentLogicalHeight);
- }
+ m_columnHeightAvailable = max<LayoutUnit>(contentLogicalHeight(), 0);
setLogicalHeight(0);
-
- // Set up our column sets.
- ensureColumnSets();
}
-bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutStateMaintainer&)
+bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutStateMaintainer& statePusher)
{
- // FIXME: Implement.
- return false;
+ if (m_inBalancingPass || !requiresBalancing())
+ return false;
+ m_inBalancingPass = true; // Prevent re-entering this method (and recursion into layout).
+
+ bool needsRelayout;
+ bool neededRelayout = false;
+ bool firstPass = true;
+ do {
+ // Column heights may change here because of balancing. We may have to do multiple layout
+ // passes, depending on how the contents is fitted to the changed column heights. In most
+ // cases, laying out again twice or even just once will suffice. Sometimes we need more
+ // passes than that, though, but the number of retries should not exceed the number of
+ // columns, unless we have a bug.
+ needsRelayout = false;
+ for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox())
+ if (childBox != m_flowThread && childBox->isRenderMultiColumnSet()) {
+ RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(childBox);
+ if (multicolSet->calculateBalancedHeight(firstPass)) {
+ multicolSet->setChildNeedsLayout(true, MarkOnlyThis);
+ needsRelayout = true;
+ }
+ }
+
+ if (needsRelayout) {
+ // Layout again. Column balancing resulted in a new height.
+ neededRelayout = true;
+ m_flowThread->setChildNeedsLayout(true, MarkOnlyThis);
+ setChildNeedsLayout(true, MarkOnlyThis);
+ if (firstPass)
+ statePusher.pop();
+ layoutBlock(false);
+ }
+ firstPass = false;
+ } while (needsRelayout);
+ m_inBalancingPass = false;
+ return neededRelayout;
}
void RenderMultiColumnBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
if (!m_flowThread) {
- m_flowThread = new (renderArena()) RenderMultiColumnFlowThread(document());
+ m_flowThread = RenderMultiColumnFlowThread::createAnonymous(document());
m_flowThread->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
- RenderBlock::addChild(m_flowThread); // Always put the flow thread at the end.
+ RenderBlock::addChild(m_flowThread);
}
-
- // Column sets are siblings of the flow thread. All children designed to be in the columns, however, are part
- // of the flow thread itself.
- if (newChild->isRenderMultiColumnSet())
- RenderBlock::addChild(newChild, beforeChild);
- else
- m_flowThread->addChild(newChild, beforeChild);
+ m_flowThread->addChild(newChild, beforeChild);
}
-
-void RenderMultiColumnBlock::ensureColumnSets()
+
+RenderObject* RenderMultiColumnBlock::layoutSpecialExcludedChild(bool relayoutChildren)
{
- // This function ensures we have the correct column set information before we get into layout.
- // For a simple multi-column layout in continuous media, only one column set child is required.
- // Once a column is nested inside an enclosing pagination context, the number of column sets
- // required becomes 2n-1, where n is the total number of nested pagination contexts. For example:
- //
- // Column layout with no enclosing pagination model = 2 * 1 - 1 = 1 column set.
- // Columns inside pages = 2 * 2 - 1 = 3 column sets (bottom of first page, all the subsequent pages, then the last page).
- // Columns inside columns inside pages = 2 * 3 - 1 = 5 column sets.
- //
- // In addition, column spans will force a column set to "split" into before/after sets around the spanning region.
- //
- // Finally, we will need to deal with columns inside regions. If regions have variable widths, then there will need
- // to be unique column sets created inside any region whose width is different from its surrounding regions. This is
- // actually pretty similar to the spanning case, in that we break up the column sets whenever the width varies.
- //
- // FIXME: For now just make one column set. This matches the old multi-column code.
- // Right now our goal is just feature parity with the old multi-column code so that we can switch over to the
- // new code as soon as possible.
- if (flowThread() && !firstChild()->isRenderMultiColumnSet()) {
- RenderMultiColumnSet* columnSet = new (renderArena()) RenderMultiColumnSet(document(), flowThread());
- columnSet->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
- RenderBlock::addChild(columnSet, firstChild());
+ if (!m_flowThread)
+ return 0;
+
+ // Update the dimensions of our regions before we lay out the flow thread.
+ // FIXME: Eventually this is going to get way more complicated, and we will be destroying regions
+ // instead of trying to keep them around.
+ bool shouldInvalidateRegions = false;
+ for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
+ if (childBox == m_flowThread)
+ continue;
+
+ if (relayoutChildren || childBox->needsLayout()) {
+ if (!m_inBalancingPass && childBox->isRenderMultiColumnSet())
+ toRenderMultiColumnSet(childBox)->prepareForLayout();
+ shouldInvalidateRegions = true;
+ }
}
+
+ if (shouldInvalidateRegions)
+ m_flowThread->invalidateRegions();
+
+ if (relayoutChildren)
+ m_flowThread->setChildNeedsLayout(true, MarkOnlyThis);
+
+ setLogicalTopForChild(m_flowThread, borderAndPaddingBefore());
+ m_flowThread->layoutIfNeeded();
+ determineLogicalLeftPositionForChild(m_flowThread);
+
+ return m_flowThread;
}
const char* RenderMultiColumnBlock::renderName() const
-{
+{
if (isFloating())
return "RenderMultiColumnBlock (floating)";
if (isOutOfFlowPositioned())
return "RenderMultiColumnBlock (positioned)";
if (isAnonymousBlock())
return "RenderMultiColumnBlock (anonymous)";
+ // FIXME: Temporary hack while the new generated content system is being implemented.
+ if (isPseudoElement())
+ return "RenderMultiColumnBlock (generated)";
if (isAnonymous())
return "RenderMultiColumnBlock (generated)";
if (isRelPositioned())
diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.h b/Source/WebCore/rendering/RenderMultiColumnBlock.h
index 58850c334..f4408ae98 100644
--- a/Source/WebCore/rendering/RenderMultiColumnBlock.h
+++ b/Source/WebCore/rendering/RenderMultiColumnBlock.h
@@ -35,21 +35,26 @@ class RenderMultiColumnFlowThread;
class RenderMultiColumnBlock : public RenderBlock {
public:
- RenderMultiColumnBlock(Node*);
-
- LayoutUnit columnHeight() const { return m_columnHeight; }
- void setColumnHeight(LayoutUnit columnHeight) { m_columnHeight = columnHeight; }
+ RenderMultiColumnBlock(Element*);
+
+ LayoutUnit columnHeightAvailable() const { return m_columnHeightAvailable; }
LayoutUnit columnWidth() const { return m_columnWidth; }
unsigned columnCount() const { return m_columnCount; }
RenderMultiColumnFlowThread* flowThread() const { return m_flowThread; }
+ bool requiresBalancing() const { return !m_columnHeightAvailable; }
+
private:
virtual bool isRenderMultiColumnBlock() const { return true; }
virtual const char* renderName() const;
+ virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren) OVERRIDE;
+
+ virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE;
+
virtual bool updateLogicalWidthAndColumnWidth() OVERRIDE;
virtual void checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) OVERRIDE;
virtual bool relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer&) OVERRIDE;
@@ -64,18 +69,19 @@ private:
unsigned m_columnCount; // The default column count/width that are based off our containing block width. These values represent only the default,
LayoutUnit m_columnWidth; // since a multi-column block that is split across variable width pages or regions will have different column counts and widths in each.
// These values will be cached (eventually) for multi-column blocks.
- LayoutUnit m_columnHeight; // The current column height.
+ LayoutUnit m_columnHeightAvailable; // Total height available to columns, or 0 if auto.
+ bool m_inBalancingPass; // Set when relayouting for column balancing.
};
inline RenderMultiColumnBlock* toRenderMultiColumnBlock(RenderObject* object)
{
- ASSERT(!object || object->isRenderMultiColumnBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderMultiColumnBlock());
return static_cast<RenderMultiColumnBlock*>(object);
}
inline const RenderMultiColumnBlock* toRenderMultiColumnBlock(const RenderObject* object)
{
- ASSERT(!object || object->isRenderMultiColumnBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderMultiColumnBlock());
return static_cast<const RenderMultiColumnBlock*>(object);
}
diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp b/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp
index 562506842..dfa017dcd 100644
--- a/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp
+++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp
@@ -26,17 +26,27 @@
#include "config.h"
#include "RenderMultiColumnFlowThread.h"
+#include "RenderMultiColumnBlock.h"
+#include "RenderMultiColumnSet.h"
+
namespace WebCore {
-RenderMultiColumnFlowThread::RenderMultiColumnFlowThread(Node* node)
- : RenderFlowThread(node)
+RenderMultiColumnFlowThread::RenderMultiColumnFlowThread()
{
+ setFlowThreadState(InsideInFlowThread);
}
RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread()
{
}
+RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Document* document)
+{
+ RenderMultiColumnFlowThread* renderer = new (document->renderArena()) RenderMultiColumnFlowThread();
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
const char* RenderMultiColumnFlowThread::renderName() const
{
return "RenderMultiColumnFlowThread";
@@ -49,4 +59,61 @@ void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight,
computedValues.m_position = logicalTop;
}
+LayoutUnit RenderMultiColumnFlowThread::initialLogicalWidth() const
+{
+ RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
+ return parentBlock->columnWidth();
+}
+
+void RenderMultiColumnFlowThread::autoGenerateRegionsToBlockOffset(LayoutUnit /*offset*/)
+{
+ // This function ensures we have the correct column set information at all times.
+ // For a simple multi-column layout in continuous media, only one column set child is required.
+ // Once a column is nested inside an enclosing pagination context, the number of column sets
+ // required becomes 2n-1, where n is the total number of nested pagination contexts. For example:
+ //
+ // Column layout with no enclosing pagination model = 2 * 1 - 1 = 1 column set.
+ // Columns inside pages = 2 * 2 - 1 = 3 column sets (bottom of first page, all the subsequent pages, then the last page).
+ // Columns inside columns inside pages = 2 * 3 - 1 = 5 column sets.
+ //
+ // In addition, column spans will force a column set to "split" into before/after sets around the spanning element.
+ //
+ // Finally, we will need to deal with columns inside regions. If regions have variable widths, then there will need
+ // to be unique column sets created inside any region whose width is different from its surrounding regions. This is
+ // actually pretty similar to the spanning case, in that we break up the column sets whenever the width varies.
+ //
+ // FIXME: For now just make one column set. This matches the old multi-column code.
+ // Right now our goal is just feature parity with the old multi-column code so that we can switch over to the
+ // new code as soon as possible.
+ RenderMultiColumnSet* firstSet = toRenderMultiColumnSet(firstRegion());
+ if (firstSet)
+ return;
+
+ invalidateRegions();
+
+ RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
+ firstSet = RenderMultiColumnSet::createAnonymous(this);
+ firstSet->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentBlock->style(), BLOCK));
+ parentBlock->RenderBlock::addChild(firstSet);
+
+ // Even though we aren't placed yet, we can go ahead and set up our size. At this point we're
+ // typically in the middle of laying out the thread, attempting to paginate, and we need to do
+ // some rudimentary "layout" of the set now, so that pagination will work.
+ firstSet->prepareForLayout();
+
+ validateRegions();
+}
+
+void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
+{
+ if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlockOffset(offset)))
+ multicolSet->recordSpaceShortage(spaceShortage);
+}
+
+void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
+{
+ if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlockOffset(offset)))
+ multicolSet->updateMinimumColumnHeight(minHeight);
+}
+
}
diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h
index 595222784..dfa9280f4 100644
--- a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h
+++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h
@@ -33,13 +33,19 @@ namespace WebCore {
class RenderMultiColumnFlowThread : public RenderFlowThread {
public:
- RenderMultiColumnFlowThread(Node*);
~RenderMultiColumnFlowThread();
+ static RenderMultiColumnFlowThread* createAnonymous(Document*);
+
private:
+ RenderMultiColumnFlowThread();
+
virtual const char* renderName() const OVERRIDE;
-
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
+ virtual void autoGenerateRegionsToBlockOffset(LayoutUnit) OVERRIDE;
+ virtual LayoutUnit initialLogicalWidth() const OVERRIDE;
+ virtual void setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) OVERRIDE;
+ virtual void updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight) OVERRIDE;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.cpp b/Source/WebCore/rendering/RenderMultiColumnSet.cpp
index 21bf10fe7..9642b5394 100644
--- a/Source/WebCore/rendering/RenderMultiColumnSet.cpp
+++ b/Source/WebCore/rendering/RenderMultiColumnSet.cpp
@@ -26,21 +26,22 @@
#include "config.h"
#include "RenderMultiColumnSet.h"
-#include "HitTestResult.h"
#include "PaintInfo.h"
-#include "RenderMultiColumnFlowThread.h"
+#include "RenderLayer.h"
#include "RenderMultiColumnBlock.h"
+#include "RenderMultiColumnFlowThread.h"
-using std::min;
-using std::max;
+using namespace std;
namespace WebCore {
-RenderMultiColumnSet::RenderMultiColumnSet(Node* node, RenderFlowThread* flowThread)
- : RenderRegionSet(node, flowThread)
+RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread)
+ : RenderRegionSet(0, flowThread)
, m_computedColumnCount(1)
, m_computedColumnWidth(0)
, m_computedColumnHeight(0)
+ , m_maxColumnHeight(LayoutUnit::max())
+ , m_minSpaceShortage(LayoutUnit::max())
, m_minimumColumnHeight(0)
, m_forcedBreaksCount(0)
, m_maximumDistanceBetweenForcedBreaks(0)
@@ -48,69 +49,181 @@ RenderMultiColumnSet::RenderMultiColumnSet(Node* node, RenderFlowThread* flowThr
{
}
+RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* flowThread)
+{
+ Document* document = flowThread->document();
+ RenderMultiColumnSet* renderer = new (document->renderArena()) RenderMultiColumnSet(flowThread);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
+LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const
+{
+ RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent());
+ LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPaddingBefore();
+
+ height -= contentLogicalTop;
+ return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
+}
+
LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) const
{
LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x());
- unsigned columnIndex = (offset - portionLogicalTop) / computedColumnHeight();
+ unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns);
return portionLogicalTop + columnIndex * computedColumnHeight();
}
+void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight)
+{
+ m_computedColumnHeight = newHeight;
+ if (m_computedColumnHeight > m_maxColumnHeight)
+ m_computedColumnHeight = m_maxColumnHeight;
+ // FIXME: the height may also be affected by the enclosing pagination context, if any.
+}
+
+bool RenderMultiColumnSet::calculateBalancedHeight(bool initial)
+{
+ ASSERT(toRenderMultiColumnBlock(parent())->requiresBalancing());
+ LayoutUnit oldColumnHeight = m_computedColumnHeight;
+ LayoutUnit currentMinSpaceShortage = m_minSpaceShortage;
+ m_minSpaceShortage = LayoutUnit::max();
+
+ if (initial) {
+ // Start with the lowest imaginable column height.
+ LayoutUnit logicalHeightGuess = ceilf(float(flowThread()->logicalHeight()) / float(m_computedColumnCount));
+ logicalHeightGuess = max(logicalHeightGuess, m_minimumColumnHeight);
+ setAndConstrainColumnHeight(logicalHeightGuess);
+
+ // The multicol container now typically needs at least one more layout pass with a new
+ // column height, but if height was specified, we only need to do this if we found that we
+ // might need less space than that. On the other hand, if we determined that the columns
+ // need to be as tall as the specified height of the container, we have already laid it out
+ // correctly, and there's no need for another pass.
+ return m_computedColumnHeight != oldColumnHeight;
+ }
+
+ if (columnCount() <= computedColumnCount())
+ // With the current column height, the content fits without creating overflowing columns. We're done.
+ return false;
+
+ // If the initial guessed column height wasn't enough, stretch it now. Stretch by the lowest
+ // amount of space shortage found during layout.
+
+ ASSERT(currentMinSpaceShortage != LayoutUnit::max()); // If this can actually happen, we probably have a bug.
+ if (currentMinSpaceShortage == LayoutUnit::max())
+ return false; // So bail out rather than looping infinitely.
+
+ setAndConstrainColumnHeight(m_computedColumnHeight + currentMinSpaceShortage);
+
+ // If we reach the maximum column height (typically set by the height or max-height property),
+ // we may not be allowed to stretch further. Return true only if stretching
+ // succeeded. Otherwise, we're done.
+ ASSERT(m_computedColumnHeight >= oldColumnHeight); // We shouldn't be able to shrink the height!
+ return m_computedColumnHeight > oldColumnHeight;
+}
+
+void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage)
+{
+ if (spaceShortage >= m_minSpaceShortage)
+ return;
+
+ // The space shortage is what we use as our stretch amount. We need a positive number here in
+ // order to get anywhere.
+ ASSERT(spaceShortage > 0);
+
+ m_minSpaceShortage = spaceShortage;
+}
+
void RenderMultiColumnSet::updateLogicalWidth()
{
- // Our logical width starts off matching the column block itself.
- // This width will be fixed up after the flow thread lays out once it is determined exactly how many
- // columns we ended up holding.
+ RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
+ setComputedColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->columnCount()); // FIXME: This will eventually vary if we are contained inside regions.
+
// FIXME: When we add regions support, we'll start it off at the width of the multi-column
// block in that particular region.
setLogicalWidth(parentBox()->contentLogicalWidth());
-
- RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
- setComputedColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->columnCount()); // FIXME: This will eventually vary if we are contained inside regions.
+
+ // If we overflow, increase our logical width.
+ unsigned colCount = columnCount();
+ LayoutUnit colGap = columnGap();
+ LayoutUnit minimumContentLogicalWidth = colCount * computedColumnWidth() + (colCount - 1) * colGap;
+ LayoutUnit currentContentLogicalWidth = contentLogicalWidth();
+ LayoutUnit delta = max(LayoutUnit(), minimumContentLogicalWidth - currentContentLogicalWidth);
+ if (!delta)
+ return;
+
+ // Increase our logical width by the delta.
+ setLogicalWidth(logicalWidth() + delta);
}
-void RenderMultiColumnSet::updateLogicalHeight()
+void RenderMultiColumnSet::prepareForLayout()
{
- // FIXME: This is the only class that overrides updateLogicalHeight. If we didn't have to set computedColumnHeight,
- // we could remove this and make updateLogicalHeight non-virtual. https://bugs.webkit.org/show_bug.cgi?id=96804
- // Make sure our column height is up to date.
- LogicalExtentComputedValues computedValues;
- computeLogicalHeight(0, 0, computedValues);
- setComputedColumnHeight(computedValues.m_extent); // FIXME: Once we make more than one column set, this will become variable.
-
- // Our logical height is always just the height of our columns.
- setLogicalHeight(computedColumnHeight());
+ RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent());
+ RenderStyle* multicolStyle = multicolBlock->style();
+
+ // Set box logical top.
+ ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSet()); // FIXME: multiple set not implemented; need to examine previous set to calculate the correct logical top.
+ setLogicalTop(multicolBlock->borderAndPaddingBefore());
+
+ // Set box width.
+ updateLogicalWidth();
+
+ if (multicolBlock->requiresBalancing()) {
+ // Set maximum column height. We will not stretch beyond this.
+ m_maxColumnHeight = LayoutUnit::max();
+ if (!multicolStyle->logicalHeight().isAuto())
+ m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalHeight());
+ if (!multicolStyle->logicalMaxHeight().isUndefined()) {
+ LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight());
+ if (m_maxColumnHeight > logicalMaxHeight)
+ m_maxColumnHeight = logicalMaxHeight;
+ }
+ m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight);
+ m_computedColumnHeight = 0; // Restart balancing.
+ } else
+ setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->columnHeightAvailable()));
+
+ // Nuke previously stored minimum column height. Contents may have changed for all we know.
+ m_minimumColumnHeight = 0;
}
-void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit, LogicalExtentComputedValues& computedValues) const
+void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
{
- RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
- computedValues.m_extent = parentBlock->columnHeight();
+ computedValues.m_extent = m_computedColumnHeight;
+ computedValues.m_position = logicalTop;
}
LayoutUnit RenderMultiColumnSet::columnGap() const
{
- if (style()->hasNormalColumnGap())
- return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
- return static_cast<int>(style()->columnGap());
+ // FIXME: Eventually we will cache the column gap when the widths of columns start varying, but for now we just
+ // go to the parent block to get the gap.
+ RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
+ if (parentBlock->style()->hasNormalColumnGap())
+ return parentBlock->style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
+ return parentBlock->style()->columnGap();
}
unsigned RenderMultiColumnSet::columnCount() const
{
+ // We must always return a value of 1 or greater. Column count = 0 is a meaningless situation,
+ // and will confuse and cause problems in other parts of the code.
if (!computedColumnHeight())
- return 0;
-
- // Our region rect determines our column count. We have as many columns as needed to fit all the content.
+ return 1;
+
+ // Our portion rect determines our column count. We have as many columns as needed to fit all the content.
LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width();
- return ceil(static_cast<float>(logicalHeightInColumns) / computedColumnHeight());
+ unsigned count = ceil(static_cast<float>(logicalHeightInColumns) / computedColumnHeight());
+ ASSERT(count >= 1);
+ return count;
}
LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const
{
LayoutUnit colLogicalWidth = computedColumnWidth();
LayoutUnit colLogicalHeight = computedColumnHeight();
- LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
+ LayoutUnit colLogicalTop = borderAndPaddingBefore();
LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft();
- int colGap = columnGap();
+ LayoutUnit colGap = columnGap();
if (style()->isLeftToRightDirection())
colLogicalLeft += index * (colLogicalWidth + colGap);
else
@@ -121,18 +234,22 @@ LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const
return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
}
-unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset) const
+unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnIndexCalculationMode mode) const
{
LayoutRect portionRect(flowThreadPortionRect());
- LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y() : portionRect.x();
- LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX();
-
+
// Handle the offset being out of range.
+ LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y() : portionRect.x();
if (offset < flowThreadLogicalTop)
return 0;
- if (offset >= flowThreadLogicalBottom)
- return columnCount() - 1;
-
+ // If we're laying out right now, we cannot constrain against some logical bottom, since it
+ // isn't known yet. Otherwise, just return the last column if we're past the logical bottom.
+ if (mode == ClampToExistingColumns) {
+ LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX();
+ if (offset >= flowThreadLogicalBottom)
+ return columnCount() - 1;
+ }
+
// Just divide by the column height to determine the correct column.
return static_cast<float>(offset - flowThreadLogicalTop) / computedColumnHeight();
}
@@ -147,7 +264,7 @@ LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const
return portionRect;
}
-LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, int colGap) const
+LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const
{
// This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are
// unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
@@ -161,16 +278,18 @@ LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect&
// This problem applies to regions and pages as well and is not unique to columns.
bool isFirstColumn = !index;
bool isLastColumn = index == colCount - 1;
+ bool isLeftmostColumn = style()->isLeftToRightDirection() ? isFirstColumn : isLastColumn;
+ bool isRightmostColumn = style()->isLeftToRightDirection() ? isLastColumn : isFirstColumn;
LayoutRect overflowRect(portionRect);
if (isHorizontalWritingMode()) {
- if (isFirstColumn) {
+ if (isLeftmostColumn) {
// Shift to the logical left overflow of the flow thread to make sure it's all covered.
overflowRect.shiftXEdgeTo(min(flowThread()->visualOverflowRect().x(), portionRect.x()));
} else {
// Expand into half of the logical left column gap.
overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2);
}
- if (isLastColumn) {
+ if (isRightmostColumn) {
// Shift to the logical right overflow of the flow thread to ensure content can spill out of the column.
overflowRect.shiftMaxXEdgeTo(max(flowThread()->visualOverflowRect().maxX(), portionRect.maxX()));
} else {
@@ -178,14 +297,14 @@ LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect&
overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap / 2);
}
} else {
- if (isFirstColumn) {
+ if (isLeftmostColumn) {
// Shift to the logical left overflow of the flow thread to make sure it's all covered.
overflowRect.shiftYEdgeTo(min(flowThread()->visualOverflowRect().y(), portionRect.y()));
} else {
// Expand into half of the logical left column gap.
overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2);
}
- if (isLastColumn) {
+ if (isRightmostColumn) {
// Shift to the logical right overflow of the flow thread to ensure content can spill out of the column.
overflowRect.shiftMaxYEdgeTo(max(flowThread()->visualOverflowRect().maxY(), portionRect.maxY()));
} else {
@@ -196,18 +315,22 @@ LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect&
return overflowRectForFlowThreadPortion(overflowRect, isFirstRegion() && isFirstColumn, isLastRegion() && isLastColumn);
}
-void RenderMultiColumnSet::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+void RenderMultiColumnSet::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
- // FIXME: RenderRegions are replaced elements right now and so they only paint in the foreground phase.
+ if (style()->visibility() != VISIBLE)
+ return;
+
+ RenderBlock::paintObject(paintInfo, paintOffset);
+
+ // FIXME: Right now we're only painting in the foreground phase.
// Columns should technically respect phases and allow for background/float/foreground overlap etc., just like
- // RenderBlocks do. We can't correct this, however, until RenderRegions are changed to actually be
- // RenderBlocks. Note this is a pretty minor issue, since the old column implementation clipped columns
+ // RenderBlocks do. Note this is a pretty minor issue, since the old column implementation clipped columns
// anyway, thus making it impossible for them to overlap one another. It's also really unlikely that the columns
// would overlap another block.
- setRegionObjectsRegionStyle();
+ if (!m_flowThread || !isValid() || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
+ return;
+
paintColumnRules(paintInfo, paintOffset);
- paintColumnContents(paintInfo, paintOffset);
- restoreRegionObjectsOriginalStyle();
}
void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
@@ -221,7 +344,7 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo
EBorderStyle ruleStyle = blockStyle->columnRuleStyle();
LayoutUnit ruleThickness = blockStyle->columnRuleWidth();
LayoutUnit colGap = columnGap();
- bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleThickness <= colGap;
+ bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
if (!renderRule)
return;
@@ -249,7 +372,7 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo
ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
currLogicalLeftOffset -= (inlineDirectionSize + colGap);
}
-
+
// Now paint the column rule.
if (i < colCount - 1) {
LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
@@ -264,76 +387,6 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo
}
}
-void RenderMultiColumnSet::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
-{
- // For each rectangle, set it as the region rectangle and then let flow thread painting do the rest.
- // We make multiple calls to paintFlowThreadPortionInRegion, changing the rectangles each time.
- unsigned colCount = columnCount();
- if (!colCount)
- return;
-
- LayoutUnit colGap = columnGap();
- for (unsigned i = 0; i < colCount; i++) {
- // First we get the column rect, which is in our local coordinate space, and we make it physical and apply
- // the paint offset to it. That gives us the physical location that we want to paint the column at.
- LayoutRect colRect = columnRectAt(i);
- flipForWritingMode(colRect);
- colRect.moveBy(paintOffset);
-
- // Next we get the portion of the flow thread that corresponds to this column.
- LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
-
- // Now get the overflow rect that corresponds to the column.
- LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);
-
- // Do the paint with the computed rects.
- flowThread()->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortion, flowThreadOverflowPortion, colRect.location());
- }
-}
-
-bool RenderMultiColumnSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
-{
- LayoutPoint adjustedLocation = accumulatedOffset + location();
-
- // Check our bounds next. For this purpose always assume that we can only be hit in the
- // foreground phase (which is true for replaced elements like images).
- // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect.
- LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
- boundsRect.moveBy(adjustedLocation);
- if (!visibleToHitTesting() || action != HitTestForeground || !locationInContainer.intersects(boundsRect))
- return false;
-
- // The point is in one specific column. Since columns can't overlap, we don't ever have to test
- // multiple columns. Put the
-
- // FIXME: It would be nice to jump right to the specific column by just doing math on the point. Since columns
- // can't overlap, we shouldn't have to walk every column like this. The old column code walked all the columns, though,
- // so this is no worse. We'd have to watch out for rect-based hit testing, though, which actually could overlap
- // multiple columns.
- LayoutUnit colGap = columnGap();
- unsigned colCount = columnCount();
- for (unsigned i = 0; i < colCount; i++) {
- // First we get the column rect, which is in our local coordinate space, and we make it physical and apply
- // the hit test offset to it. That gives us the physical location that we want to paint the column at.
- LayoutRect colRect = columnRectAt(i);
- flipForWritingMode(colRect);
- colRect.moveBy(adjustedLocation);
-
- // Next we get the portion of the flow thread that corresponds to this column.
- LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
-
- // Now get the overflow rect that corresponds to the column.
- LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);
-
- // Do the hit test with the computed rects.
- if (flowThread()->hitTestFlowThreadPortionInRegion(this, flowThreadPortion, flowThreadOverflowPortion, request, result, locationInContainer, colRect.location()))
- return true;
- }
-
- updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
- return !result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect);
-}
-
void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const
{
// Figure out the start and end columns and only check within that range so that we don't walk the
@@ -372,6 +425,88 @@ void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRec
}
}
+void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
+{
+ // Put the layer bounds into flow thread-local coordinates by flipping it first.
+ LayoutRect layerBoundsInFlowThread(layerBoundingBox);
+ flowThread()->flipForWritingMode(layerBoundsInFlowThread);
+
+ // Do the same for the dirty rect.
+ LayoutRect dirtyRectInFlowThread(dirtyRect);
+ flowThread()->flipForWritingMode(dirtyRectInFlowThread);
+
+ // Now we can compare with the flow thread portions owned by each column. First let's
+ // see if the rect intersects our flow thread portion at all.
+ LayoutRect clippedRect(layerBoundsInFlowThread);
+ clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
+ if (clippedRect.isEmpty())
+ return;
+
+ // Now we know we intersect at least one column. Let's figure out the logical top and logical
+ // bottom of the area we're checking.
+ LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
+ LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;
+
+ // Figure out the start and end columns and only check within that range so that we don't walk the
+ // entire column set.
+ unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
+ unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);
+
+ LayoutUnit colLogicalWidth = computedColumnWidth();
+ LayoutUnit colGap = columnGap();
+ unsigned colCount = columnCount();
+
+ for (unsigned i = startColumn; i <= endColumn; i++) {
+ // Get the portion of the flow thread that corresponds to this column.
+ LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
+
+ // Now get the overflow rect that corresponds to the column.
+ LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);
+
+ // In order to create a fragment we must intersect the portion painted by this column.
+ LayoutRect clippedRect(layerBoundsInFlowThread);
+ clippedRect.intersect(flowThreadOverflowPortion);
+ if (clippedRect.isEmpty())
+ continue;
+
+ // We also need to intersect the dirty rect. We have to apply a translation and shift based off
+ // our column index.
+ LayoutPoint translationOffset;
+ LayoutUnit inlineOffset = i * (colLogicalWidth + colGap);
+ if (!style()->isLeftToRightDirection())
+ inlineOffset = -inlineOffset;
+ translationOffset.setX(inlineOffset);
+ LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x();
+ if (isFlippedBlocksWritingMode(style()->writingMode()))
+ blockOffset = -blockOffset;
+ translationOffset.setY(blockOffset);
+ if (!isHorizontalWritingMode())
+ translationOffset = translationOffset.transposedPoint();
+ // FIXME: The translation needs to include the multicolumn set's content offset within the
+ // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.
+
+ // Shift the dirty rect to be in flow thread coordinates with this translation applied.
+ LayoutRect translatedDirtyRect(dirtyRectInFlowThread);
+ translatedDirtyRect.moveBy(-translationOffset);
+
+ // See if we intersect the dirty rect.
+ clippedRect = layerBoundsInFlowThread;
+ clippedRect.intersect(translatedDirtyRect);
+ if (clippedRect.isEmpty())
+ continue;
+
+ // Something does need to paint in this column. Make a fragment now and supply the physical translation
+ // offset and the clip rect for the column with that offset applied.
+ LayerFragment fragment;
+ fragment.paginationOffset = translationOffset;
+
+ LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
+ flipForWritingMode(flippedFlowThreadOverflowPortion);
+ fragment.paginationClip = flippedFlowThreadOverflowPortion;
+ fragments.append(fragment);
+ }
+}
+
const char* RenderMultiColumnSet::renderName() const
{
return "RenderMultiColumnSet";
diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.h b/Source/WebCore/rendering/RenderMultiColumnSet.h
index 88653035c..5f597f7ee 100644
--- a/Source/WebCore/rendering/RenderMultiColumnSet.h
+++ b/Source/WebCore/rendering/RenderMultiColumnSet.h
@@ -43,8 +43,8 @@ namespace WebCore {
// come before and after the span.
class RenderMultiColumnSet : public RenderRegionSet {
public:
- RenderMultiColumnSet(Node*, RenderFlowThread*);
-
+ static RenderMultiColumnSet* createAnonymous(RenderFlowThread*);
+
virtual bool isRenderMultiColumnSet() const OVERRIDE { return true; }
unsigned computedColumnCount() const { return m_computedColumnCount; }
@@ -56,10 +56,8 @@ public:
m_computedColumnWidth = width;
m_computedColumnCount = count;
}
- void setComputedColumnHeight(LayoutUnit height)
- {
- m_computedColumnHeight = height;
- }
+
+ LayoutUnit heightAdjustedForSetOffset(LayoutUnit height) const;
void updateMinimumColumnHeight(LayoutUnit height) { m_minimumColumnHeight = std::max(height, m_minimumColumnHeight); }
LayoutUnit minimumColumnHeight() const { return m_minimumColumnHeight; }
@@ -84,13 +82,27 @@ public:
m_forcedBreakOffset = offsetFromFirstPage;
}
-private:
+ // Calculate the column height when contents are supposed to be balanced. If 'initial' is set,
+ // guess an initial column height; otherwise, stretch the column height a tad. Return true if
+ // column height changed and another layout pass is required.
+ bool calculateBalancedHeight(bool initial);
+
+ // Record space shortage (the amount of space that would have been enough to prevent some
+ // element from being moved to the next column) at a column break. The smallest amount of space
+ // shortage we find is the amount with which we will stretch the column height, if it turns out
+ // after layout that the columns weren't tall enough.
+ void recordSpaceShortage(LayoutUnit spaceShortage);
+
virtual void updateLogicalWidth() OVERRIDE;
- virtual void updateLogicalHeight() OVERRIDE;
+
+ void prepareForLayout();
+
+private:
+ RenderMultiColumnSet(RenderFlowThread*);
+
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
- virtual void paintReplaced(PaintInfo&, const LayoutPoint& paintOffset) OVERRIDE;
- virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
+ virtual void paintObject(PaintInfo&, const LayoutPoint& paintOffset) OVERRIDE;
virtual LayoutUnit pageLogicalWidth() const OVERRIDE { return m_computedColumnWidth; }
virtual LayoutUnit pageLogicalHeight() const OVERRIDE { return m_computedColumnHeight; }
@@ -99,34 +111,62 @@ private:
// FIXME: This will change once we have column sets constrained by enclosing pages, etc.
virtual LayoutUnit logicalHeightOfAllFlowThreadContent() const OVERRIDE { return m_computedColumnHeight; }
+
+ // FIXME: For now we return false, but it's likely we will leverage the auto height region code to do column
+ // balancing. That's why we have an override of this function that is distinct from RenderRegionSet's override.
+ virtual bool shouldHaveAutoLogicalHeight() const OVERRIDE { return false; }
virtual void repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const OVERRIDE;
+ virtual void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) OVERRIDE;
+
virtual const char* renderName() const;
void paintColumnRules(PaintInfo&, const LayoutPoint& paintOffset);
- void paintColumnContents(PaintInfo&, const LayoutPoint& paintOffset);
LayoutUnit columnGap() const;
LayoutRect columnRectAt(unsigned index) const;
unsigned columnCount() const;
LayoutRect flowThreadPortionRectAt(unsigned index) const;
- LayoutRect flowThreadPortionOverflowRect(const LayoutRect& flowThreadPortion, unsigned index, unsigned colCount, int colGap) const;
-
- unsigned columnIndexAtOffset(LayoutUnit) const;
-
+ LayoutRect flowThreadPortionOverflowRect(const LayoutRect& flowThreadPortion, unsigned index, unsigned colCount, LayoutUnit colGap) const;
+
+ enum ColumnIndexCalculationMode {
+ ClampToExistingColumns, // Stay within the range of already existing columns.
+ AssumeNewColumns // Allow column indices outside the range of already existing columns.
+ };
+ unsigned columnIndexAtOffset(LayoutUnit, ColumnIndexCalculationMode = ClampToExistingColumns) const;
+
+ void setAndConstrainColumnHeight(LayoutUnit);
+
unsigned m_computedColumnCount;
LayoutUnit m_computedColumnWidth;
LayoutUnit m_computedColumnHeight;
// The following variables are used when balancing the column set.
+ LayoutUnit m_maxColumnHeight; // Maximum column height allowed.
+ LayoutUnit m_minSpaceShortage; // The smallest amout of space shortage that caused a column break.
LayoutUnit m_minimumColumnHeight;
unsigned m_forcedBreaksCount; // FIXME: We will ultimately need to cache more information to balance around forced breaks properly.
LayoutUnit m_maximumDistanceBetweenForcedBreaks;
LayoutUnit m_forcedBreakOffset;
};
+inline RenderMultiColumnSet* toRenderMultiColumnSet(RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderMultiColumnSet());
+ return static_cast<RenderMultiColumnSet*>(object);
+}
+
+inline const RenderMultiColumnSet* toRenderMultiColumnSet(const RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderMultiColumnSet());
+ return static_cast<const RenderMultiColumnSet*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderMultiColumnSet(const RenderMultiColumnSet*);
+
} // namespace WebCore
#endif // RenderMultiColumnSet_h
diff --git a/Source/WebCore/rendering/RenderNamedFlowThread.cpp b/Source/WebCore/rendering/RenderNamedFlowThread.cpp
index d4b9ae5f8..89e4a3156 100644
--- a/Source/WebCore/rendering/RenderNamedFlowThread.cpp
+++ b/Source/WebCore/rendering/RenderNamedFlowThread.cpp
@@ -26,10 +26,14 @@
#include "config.h"
#include "RenderNamedFlowThread.h"
+#include "ExceptionCodePlaceholder.h"
#include "FlowThreadController.h"
#include "InlineTextBox.h"
#include "InspectorInstrumentation.h"
+#include "NodeRenderingContext.h"
+#include "NodeTraversal.h"
#include "Position.h"
+#include "Range.h"
#include "RenderInline.h"
#include "RenderRegion.h"
#include "RenderText.h"
@@ -39,10 +43,19 @@
namespace WebCore {
-RenderNamedFlowThread::RenderNamedFlowThread(Node* node, PassRefPtr<WebKitNamedFlow> namedFlow)
- : RenderFlowThread(node)
+RenderNamedFlowThread* RenderNamedFlowThread::createAnonymous(Document* document, PassRefPtr<WebKitNamedFlow> namedFlow)
+{
+ ASSERT(document->cssRegionsEnabled());
+ RenderNamedFlowThread* renderer = new (document->renderArena()) RenderNamedFlowThread(namedFlow);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
+RenderNamedFlowThread::RenderNamedFlowThread(PassRefPtr<WebKitNamedFlow> namedFlow)
+ : m_overset(true)
, m_namedFlow(namedFlow)
, m_regionLayoutUpdateEventTimer(this, &RenderNamedFlowThread::regionLayoutUpdateEventTimerFired)
+ , m_regionOversetChangeEventTimer(this, &RenderNamedFlowThread::regionOversetChangeEventTimerFired)
{
}
@@ -220,27 +233,34 @@ static void addRegionToList(RenderRegionList& regionList, RenderRegion* renderRe
}
}
-void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
+void RenderNamedFlowThread::addRegionToNamedFlowThread(RenderRegion* renderRegion)
{
ASSERT(renderRegion);
-
- resetMarkForDestruction();
-
ASSERT(!renderRegion->isValid());
- if (renderRegion->parentNamedFlowThread()) {
- if (renderRegion->parentNamedFlowThread()->dependsOn(this)) {
- // The order of invalid regions is irrelevant.
- m_invalidRegionList.add(renderRegion);
- // Register ourself to get a notification when the state changes.
- renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this);
- return;
- }
+ if (renderRegion->parentNamedFlowThread())
addDependencyOnFlowThread(renderRegion->parentNamedFlowThread());
- }
renderRegion->setIsValid(true);
addRegionToList(m_regionList, renderRegion);
+}
+
+void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
+{
+ ASSERT(renderRegion);
+ ASSERT(!renderRegion->isValid());
+
+ resetMarkForDestruction();
+
+ if (renderRegion->parentNamedFlowThread() && renderRegion->parentNamedFlowThread()->dependsOn(this)) {
+ // The order of invalid regions is irrelevant.
+ m_invalidRegionList.add(renderRegion);
+ // Register ourself to get a notification when the state changes.
+ renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this);
+ return;
+ }
+
+ addRegionToNamedFlowThread(renderRegion);
invalidateRegions();
}
@@ -248,7 +268,6 @@ void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
{
ASSERT(renderRegion);
- m_regionRangeMap.clear();
if (renderRegion->parentNamedFlowThread()) {
if (!renderRegion->isValid()) {
@@ -275,6 +294,54 @@ void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
invalidateRegions();
}
+void RenderNamedFlowThread::computeOversetStateForRegions(LayoutUnit oldClientAfterEdge)
+{
+ LayoutUnit height = oldClientAfterEdge;
+
+ // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread)
+ // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow
+ // because of how computeLogicalHeight is implemented for RenderNamedFlowThread (as a sum of all regions height).
+ // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region)
+ if (hasRenderOverflow()
+ && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY())
+ || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX())))
+ height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX();
+
+ RenderRegion* lastReg = lastRegion();
+ for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
+ RenderRegion* region = *iter;
+ LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x());
+ LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX());
+ RegionOversetState previousState = region->regionOversetState();
+ RegionOversetState state = RegionFit;
+ if (flowMin <= 0)
+ state = RegionEmpty;
+ if (flowMax > 0 && region == lastReg)
+ state = RegionOverset;
+ region->setRegionOversetState(state);
+ // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event
+ // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually
+ // changed, so it just assumes that the NamedFlow should dispatch the event
+ if (previousState != state
+ || state == RegionFit
+ || state == RegionOverset)
+ setDispatchRegionLayoutUpdateEvent(true);
+
+ if (previousState != state)
+ setDispatchRegionOversetChangeEvent(true);
+ }
+
+ // If the number of regions has changed since we last computed the overset property, schedule the regionOversetChange event.
+ if (previousRegionCountChanged()) {
+ setDispatchRegionOversetChangeEvent(true);
+ updatePreviousRegionCount();
+ }
+
+ // With the regions overflow state computed we can also set the overset flag for the named flow.
+ // If there are no valid regions in the chain, overset is true.
+ m_overset = lastReg ? lastReg->regionOversetState() == RegionOverset : true;
+}
+
void RenderNamedFlowThread::checkInvalidRegions()
{
Vector<RenderRegion*> newValidRegions;
@@ -292,9 +359,7 @@ void RenderNamedFlowThread::checkInvalidRegions()
RenderRegion* region = *iter;
m_invalidRegionList.remove(region);
region->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
- region->setIsValid(true);
- addDependencyOnFlowThread(region->parentNamedFlowThread());
- addRegionToList(m_regionList, region);
+ addRegionToNamedFlowThread(region);
}
if (!newValidRegions.isEmpty())
@@ -387,6 +452,22 @@ const AtomicString& RenderNamedFlowThread::flowThreadName() const
return m_namedFlow->name();
}
+bool RenderNamedFlowThread::isChildAllowed(RenderObject* child, RenderStyle* style) const
+{
+ ASSERT(child);
+ ASSERT(style);
+
+ if (!child->node())
+ return true;
+
+ ASSERT(child->node()->isElementNode());
+ RenderObject* parentRenderer = NodeRenderingContext(child->node()).parentRenderer();
+ if (!parentRenderer)
+ return true;
+
+ return parentRenderer->isChildAllowed(child, style);
+}
+
void RenderNamedFlowThread::dispatchRegionLayoutUpdateEvent()
{
RenderFlowThread::dispatchRegionLayoutUpdateEvent();
@@ -396,6 +477,15 @@ void RenderNamedFlowThread::dispatchRegionLayoutUpdateEvent()
m_regionLayoutUpdateEventTimer.startOneShot(0);
}
+void RenderNamedFlowThread::dispatchRegionOversetChangeEvent()
+{
+ RenderFlowThread::dispatchRegionOversetChangeEvent();
+ InspectorInstrumentation::didChangeRegionOverset(document(), m_namedFlow.get());
+
+ if (!m_regionOversetChangeEventTimer.isActive() && m_namedFlow->hasEventListeners())
+ m_regionOversetChangeEventTimer.startOneShot(0);
+}
+
void RenderNamedFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*)
{
ASSERT(m_namedFlow);
@@ -403,6 +493,13 @@ void RenderNamedFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderNamedF
m_namedFlow->dispatchRegionLayoutUpdateEvent();
}
+void RenderNamedFlowThread::regionOversetChangeEventTimerFired(Timer<RenderNamedFlowThread>*)
+{
+ ASSERT(m_namedFlow);
+
+ m_namedFlow->dispatchRegionOversetChangeEvent();
+}
+
void RenderNamedFlowThread::setMarkForDestruction()
{
if (m_namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
@@ -476,7 +573,6 @@ void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, cons
if (!contentNode->renderer())
continue;
- ExceptionCode ignoredException;
RefPtr<Range> range = Range::create(contentNode->document());
bool foundStartPosition = false;
bool startsAboveRegion = true;
@@ -484,7 +580,7 @@ void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, cons
bool skipOverOutsideNodes = false;
Node* lastEndNode = 0;
- for (Node* node = contentNode; node; node = node->traverseNextNode(contentNode)) {
+ for (Node* node = contentNode; node; node = NodeTraversal::next(node, contentNode)) {
RenderObject* renderer = node->renderer();
if (!renderer)
continue;
@@ -515,16 +611,16 @@ void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, cons
if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) {
if (foundStartPosition) {
if (!startsAboveRegion) {
- if (range->intersectsNode(node, ignoredException))
- range->setEndBefore(node, ignoredException);
- rangeObjects.append(range->cloneRange(ignoredException));
+ if (range->intersectsNode(node, IGNORE_EXCEPTION))
+ range->setEndBefore(node, IGNORE_EXCEPTION);
+ rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION));
range = Range::create(contentNode->document());
startsAboveRegion = true;
} else
skipOverOutsideNodes = true;
}
if (skipOverOutsideNodes)
- range->setStartAfter(node, ignoredException);
+ range->setStartAfter(node, IGNORE_EXCEPTION);
foundStartPosition = false;
continue;
}
@@ -551,7 +647,7 @@ void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, cons
// the range is closed.
if (startsAboveRegion) {
startsAboveRegion = false;
- range->setStartBefore(node, ignoredException);
+ range->setStartBefore(node, IGNORE_EXCEPTION);
}
}
skipOverOutsideNodes = false;
@@ -585,7 +681,7 @@ void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, cons
// for elements that ends inside the region, set the end position to be after them
// allow this end position to be changed only by other elements that are not descendants of the current end node
if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) {
- range->setEndAfter(node, ignoredException);
+ range->setEndAfter(node, IGNORE_EXCEPTION);
endsBelowRegion = false;
lastEndNode = node;
}
diff --git a/Source/WebCore/rendering/RenderNamedFlowThread.h b/Source/WebCore/rendering/RenderNamedFlowThread.h
index 2bd438bbc..c0c493ec8 100644
--- a/Source/WebCore/rendering/RenderNamedFlowThread.h
+++ b/Source/WebCore/rendering/RenderNamedFlowThread.h
@@ -45,9 +45,10 @@ typedef ListHashSet<Node*> NamedFlowContentNodes;
class RenderNamedFlowThread : public RenderFlowThread {
public:
- RenderNamedFlowThread(Node*, PassRefPtr<WebKitNamedFlow>);
virtual ~RenderNamedFlowThread();
+ static RenderNamedFlowThread* createAnonymous(Document*, PassRefPtr<WebKitNamedFlow>);
+
const AtomicString& flowThreadName() const;
const RenderRegionList& invalidRenderRegionList() const { return m_invalidRegionList; }
@@ -67,6 +68,9 @@ public:
virtual void addRegionToThread(RenderRegion*) OVERRIDE;
virtual void removeRegionFromThread(RenderRegion*) OVERRIDE;
+ bool overset() const { return m_overset; }
+ void computeOversetStateForRegions(LayoutUnit oldClientAfterEdge);
+
void registerNamedFlowContentNode(Node*);
void unregisterNamedFlowContentNode(Node*);
const NamedFlowContentNodes& contentNodes() const { return m_contentNodes; }
@@ -79,17 +83,26 @@ protected:
void resetMarkForDestruction();
private:
+ RenderNamedFlowThread(PassRefPtr<WebKitNamedFlow>);
+
virtual const char* renderName() const OVERRIDE;
virtual bool isRenderNamedFlowThread() const OVERRIDE { return true; }
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE;
virtual void dispatchRegionLayoutUpdateEvent() OVERRIDE;
+ virtual void dispatchRegionOversetChangeEvent() OVERRIDE;
bool dependsOn(RenderNamedFlowThread* otherRenderFlowThread) const;
void addDependencyOnFlowThread(RenderNamedFlowThread*);
void removeDependencyOnFlowThread(RenderNamedFlowThread*);
+
+ void addRegionToNamedFlowThread(RenderRegion*);
+
void checkInvalidRegions();
+
bool canBeDestroyed() const { return m_invalidRegionList.isEmpty() && m_regionList.isEmpty() && m_contentNodes.isEmpty(); }
void regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*);
+ void regionOversetChangeEventTimerFired(Timer<RenderNamedFlowThread>*);
void clearContentNodes();
private:
@@ -111,21 +124,24 @@ private:
RenderRegionList m_invalidRegionList;
+ bool m_overset : 1;
+
// The DOM Object that represents a named flow.
RefPtr<WebKitNamedFlow> m_namedFlow;
Timer<RenderNamedFlowThread> m_regionLayoutUpdateEventTimer;
+ Timer<RenderNamedFlowThread> m_regionOversetChangeEventTimer;
};
inline RenderNamedFlowThread* toRenderNamedFlowThread(RenderObject* object)
{
- ASSERT(!object || object->isRenderNamedFlowThread());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderNamedFlowThread());
return static_cast<RenderNamedFlowThread*>(object);
}
inline const RenderNamedFlowThread* toRenderNamedFlowThread(const RenderObject* object)
{
- ASSERT(!object || object->isRenderNamedFlowThread());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderNamedFlowThread());
return static_cast<const RenderNamedFlowThread*>(object);
}
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index 17bdafb54..b93764828 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -28,19 +28,23 @@
#include "RenderObject.h"
#include "AXObjectCache.h"
-#include "Chrome.h"
+#include "AnimationController.h"
#include "ContentData.h"
#include "CursorList.h"
-#include "DashArray.h"
-#include "EditingBoundary.h"
+#include "EventHandler.h"
#include "FloatQuad.h"
#include "FlowThreadController.h"
#include "Frame.h"
+#include "FrameSelection.h"
#include "FrameView.h"
#include "GraphicsContext.h"
+#include "HTMLAnchorElement.h"
#include "HTMLElement.h"
+#include "HTMLImageElement.h"
#include "HTMLNames.h"
+#include "HTMLTableElement.h"
#include "HitTestResult.h"
+#include "LogicalSelectionOffsetCaches.h"
#include "Page.h"
#include "RenderArena.h"
#include "RenderCounter.h"
@@ -52,6 +56,7 @@
#include "RenderImageResourceStyleImage.h"
#include "RenderInline.h"
#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
#include "RenderListItem.h"
#include "RenderMultiColumnBlock.h"
#include "RenderNamedFlowThread.h"
@@ -70,9 +75,8 @@
#include "TransformState.h"
#include "htmlediting.h"
#include <algorithm>
-#include <stdio.h>
#include <wtf/RefCountedLeakCounter.h>
-#include <wtf/UnusedParam.h>
+#include <wtf/StackStats.h>
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerCompositor.h"
@@ -92,11 +96,11 @@ using namespace HTMLNames;
#ifndef NDEBUG
static void* baseOfRenderObjectBeingDeleted;
-RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject)
+RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject, bool isForbidden)
: m_renderObject(renderObject)
, m_preexistingForbidden(m_renderObject->isSetNeedsLayoutForbidden())
{
- m_renderObject->setNeedsLayoutIsForbidden(true);
+ m_renderObject->setNeedsLayoutIsForbidden(isForbidden);
}
RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope()
@@ -116,7 +120,30 @@ struct SameSizeAsRenderObject {
COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
+// On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
+// when scrolling a page with a fixed background image. As an optimization, assuming there are
+// no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
+// ignore the CSS property "background-attachment: fixed".
+static bool shouldRepaintFixedBackgroundsOnScroll(FrameView* frameView)
+{
+#if !ENABLE(FAST_MOBILE_SCROLLING) && !PLATFORM(QT)
+ UNUSED_PARAM(frameView);
+#endif
+
+ bool repaintFixedBackgroundsOnScroll = true;
+#if ENABLE(FAST_MOBILE_SCROLLING)
+#if PLATFORM(QT)
+ if (frameView->delegatesScrolling())
+ repaintFixedBackgroundsOnScroll = false;
+#else
+ repaintFixedBackgroundsOnScroll = false;
+#endif
+#endif
+ return repaintFixedBackgroundsOnScroll;
+}
+
bool RenderObject::s_affectsParentBlock = false;
+bool RenderObject::s_noLongerAffectsParentBlock = false;
RenderObjectAncestorLineboxDirtySet* RenderObject::s_ancestorLineboxDirtySet = 0;
@@ -133,17 +160,17 @@ void RenderObject::operator delete(void* ptr, size_t sz)
*(size_t *)ptr = sz;
}
-RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
+RenderObject* RenderObject::createObject(Element* element, RenderStyle* style)
{
- Document* doc = node->document();
+ Document* doc = element->document();
RenderArena* arena = doc->renderArena();
// Minimal support for content properties replacing an entire element.
// Works only if we have exactly one piece of content and it's a URL.
// Otherwise acts as if we didn't support this feature.
const ContentData* contentData = style->contentData();
- if (contentData && !contentData->next() && contentData->isImage() && doc != node) {
- RenderImage* image = new (arena) RenderImage(node);
+ if (contentData && !contentData->next() && contentData->isImage() && !element->isPseudoElement()) {
+ RenderImage* image = new (arena) RenderImage(element);
// RenderImageResourceStyleImage requires a style being present on the image but we don't want to
// trigger a style change now as the node is not fully attached. Moving this code to style change
// doesn't make sense as it should be run once at renderer creation.
@@ -157,56 +184,56 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
return image;
}
- if (node->hasTagName(rubyTag)) {
+ if (element->hasTagName(rubyTag)) {
if (style->display() == INLINE)
- return new (arena) RenderRubyAsInline(node);
+ return new (arena) RenderRubyAsInline(element);
else if (style->display() == BLOCK)
- return new (arena) RenderRubyAsBlock(node);
+ return new (arena) RenderRubyAsBlock(element);
}
// treat <rt> as ruby text ONLY if it still has its default treatment of block
- if (node->hasTagName(rtTag) && style->display() == BLOCK)
- return new (arena) RenderRubyText(node);
+ if (element->hasTagName(rtTag) && style->display() == BLOCK)
+ return new (arena) RenderRubyText(element);
if (doc->cssRegionsEnabled() && style->isDisplayRegionType() && !style->regionThread().isEmpty() && doc->renderView())
- return new (arena) RenderRegion(node, 0);
+ return new (arena) RenderRegion(element, 0);
switch (style->display()) {
case NONE:
return 0;
case INLINE:
- return new (arena) RenderInline(node);
+ return new (arena) RenderInline(element);
case BLOCK:
case INLINE_BLOCK:
case RUN_IN:
case COMPACT:
if ((!style->hasAutoColumnCount() || !style->hasAutoColumnWidth()) && doc->regionBasedColumnsEnabled())
- return new (arena) RenderMultiColumnBlock(node);
- return new (arena) RenderBlock(node);
+ return new (arena) RenderMultiColumnBlock(element);
+ return new (arena) RenderBlock(element);
case LIST_ITEM:
- return new (arena) RenderListItem(node);
+ return new (arena) RenderListItem(element);
case TABLE:
case INLINE_TABLE:
- return new (arena) RenderTable(node);
+ return new (arena) RenderTable(element);
case TABLE_ROW_GROUP:
case TABLE_HEADER_GROUP:
case TABLE_FOOTER_GROUP:
- return new (arena) RenderTableSection(node);
+ return new (arena) RenderTableSection(element);
case TABLE_ROW:
- return new (arena) RenderTableRow(node);
+ return new (arena) RenderTableRow(element);
case TABLE_COLUMN_GROUP:
case TABLE_COLUMN:
- return new (arena) RenderTableCol(node);
+ return new (arena) RenderTableCol(element);
case TABLE_CELL:
- return new (arena) RenderTableCell(node);
+ return new (arena) RenderTableCell(element);
case TABLE_CAPTION:
- return new (arena) RenderTableCaption(node);
+ return new (arena) RenderTableCaption(element);
case BOX:
case INLINE_BOX:
- return new (arena) RenderDeprecatedFlexibleBox(node);
+ return new (arena) RenderDeprecatedFlexibleBox(element);
case FLEX:
case INLINE_FLEX:
- return new (arena) RenderFlexibleBox(node);
+ return new (arena) RenderFlexibleBox(element);
case GRID:
case INLINE_GRID:
- return new (arena) RenderGrid(node);
+ return new (arena) RenderGrid(element);
}
return 0;
@@ -230,7 +257,6 @@ RenderObject::RenderObject(Node* node)
#ifndef NDEBUG
renderObjectCounter.increment();
#endif
- ASSERT(node);
}
RenderObject::~RenderObject()
@@ -277,6 +303,19 @@ bool RenderObject::isHTMLMarquee() const
return node() && node()->renderer() == this && node()->hasTagName(marqueeTag);
}
+void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state)
+{
+ setFlowThreadState(state);
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ // If the child is a fragmentation context it already updated the descendants flag accordingly.
+ if (child->isRenderFlowThread())
+ continue;
+ ASSERT(state != child->flowThreadState());
+ child->setFlowThreadStateIncludingDescendants(state);
+ }
+}
+
void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
RenderObjectChildList* children = virtualChildren();
@@ -444,7 +483,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*
{
if (obj->hasLayer()) {
if (!beforeChild && newObject) {
- // We need to figure out the layer that follows newObject. We only do
+ // We need to figure out the layer that follows newObject. We only do
// this the first time we find a child layer, and then we update the
// pointer values for newObject and beforeChild used by everyone else.
beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
@@ -503,7 +542,7 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
bool checkParent)
{
- // Error check the parent layer passed in. If it's null, we can't find anything.
+ // Error check the parent layer passed in. If it's null, we can't find anything.
if (!parentLayer)
return 0;
@@ -523,7 +562,7 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject*
}
}
- // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
+ // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
// find anything.
if (parentLayer == ourLayer)
return 0;
@@ -584,11 +623,10 @@ RenderBoxModelObject* RenderObject::enclosingBoxModelObject() const
return 0;
}
-RenderFlowThread* RenderObject::enclosingRenderFlowThread() const
-{
- if (!inRenderFlowThread())
- return 0;
-
+RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const
+{
+ ASSERT(flowThreadState() != NotInsideFlowThread);
+
// See if we have the thread cached because we're in the middle of layout.
RenderFlowThread* flowThread = view()->flowThreadController()->currentRenderFlowThread();
if (flowThread)
@@ -599,7 +637,7 @@ RenderFlowThread* RenderObject::enclosingRenderFlowThread() const
while (curr) {
if (curr->isRenderFlowThread())
return toRenderFlowThread(curr);
- curr = curr->parent();
+ curr = curr->containingBlock();
}
return 0;
}
@@ -645,6 +683,7 @@ static inline bool objectIsRelayoutBoundary(const RenderObject* object)
void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot)
{
ASSERT(!scheduleRelayout || !newRoot);
+ ASSERT(!isSetNeedsLayoutForbidden());
RenderObject* object = container();
RenderObject* last = this;
@@ -652,6 +691,11 @@ void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderOb
bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout();
while (object) {
+#ifndef NDEBUG
+ // FIXME: Remove this once we remove the special cases for counters, quotes and mathml
+ // calling setNeedsLayout during preferred width computation.
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(object, isSetNeedsLayoutForbidden());
+#endif
// Don't mark the outermost object of an unrooted subtree. That object will be
// marked when the subtree is added to the document.
RenderObject* container = object->container();
@@ -750,56 +794,13 @@ RenderBlock* RenderObject::containingBlock() const
RenderObject* o = parent();
if (!o && isRenderScrollbarPart())
o = toRenderScrollbarPart(this)->rendererOwningScrollbar();
- if (!isText() && m_style->position() == FixedPosition) {
- while (o) {
- if (o->isRenderView())
- break;
- if (o->hasTransform() && o->isRenderBlock())
- break;
- // The render flow thread is the top most containing block
- // for the fixed positioned elements.
- if (o->isRenderFlowThread())
- break;
-#if ENABLE(SVG)
- // foreignObject is the containing block for its contents.
- if (o->isSVGForeignObject())
- break;
-#endif
- o = o->parent();
- }
- ASSERT(!o->isAnonymousBlock());
- } else if (!isText() && m_style->position() == AbsolutePosition) {
- while (o) {
- // For relpositioned inlines, we return the nearest non-anonymous enclosing block. We don't try
- // to return the inline itself. This allows us to avoid having a positioned objects
- // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
- // from this method. The container() method can actually be used to obtain the
- // inline directly.
- if (!o->style()->position() == StaticPosition && !(o->isInline() && !o->isReplaced()))
- break;
- if (o->isRenderView())
- break;
- if (o->hasTransform() && o->isRenderBlock())
- break;
- if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) {
- o = o->containingBlock();
- break;
- }
-#if ENABLE(SVG)
- if (o->isSVGForeignObject()) //foreignObject is the containing block for contents inside it
- break;
-#endif
-
- o = o->parent();
- }
-
- while (o && o->isAnonymousBlock())
- o = o->containingBlock();
- } else {
- while (o && ((o->isInline() && !o->isReplaced()) || !o->isRenderBlock()))
- o = o->parent();
- }
+ if (!isText() && m_style->position() == FixedPosition)
+ o = containingBlockForFixedPosition(o);
+ else if (!isText() && m_style->position() == AbsolutePosition)
+ o = containingBlockForAbsolutePosition(o);
+ else
+ o = containingBlockForObjectInFlow(o);
if (!o || !o->isRenderBlock())
return 0; // This can still happen in case of an orphaned tree
@@ -821,10 +822,19 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer*
if (!layer->xPosition().isZero() || !layer->yPosition().isZero())
return true;
- if (layer->size().type == SizeLength) {
- if (layer->size().size.width().isPercent() || layer->size().size.height().isPercent())
+ EFillSizeType sizeType = layer->sizeType();
+
+ if (sizeType == Contain || sizeType == Cover)
+ return true;
+
+ if (sizeType == SizeLength) {
+ LengthSize size = layer->sizeLength();
+ if (size.width().isPercent() || size.height().isPercent())
return true;
- } else if (layer->size().type == Contain || layer->size().type == Cover || img->usesImageContainerSize())
+ // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
+ if ((size.width().isAuto() || size.height().isAuto()) && img->isGeneratedImage())
+ return true;
+ } else if (img->usesImageContainerSize())
return true;
return false;
@@ -885,14 +895,13 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
return;
case DOTTED:
case DASHED: {
- graphicsContext->setStrokeColor(color, m_style->colorSpace());
- graphicsContext->setStrokeThickness(thickness);
- StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
- graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
-
if (thickness > 0) {
bool wasAntialiased = graphicsContext->shouldAntialias();
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
graphicsContext->setShouldAntialias(antialias);
+ graphicsContext->setStrokeColor(color, m_style->colorSpace());
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
switch (side) {
case BSBottom:
@@ -1086,14 +1095,14 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
}
}
-void RenderObject::paintFocusRing(GraphicsContext* context, const LayoutPoint& paintOffset, RenderStyle* style)
+void RenderObject::paintFocusRing(PaintInfo& paintInfo, const LayoutPoint& paintOffset, RenderStyle* style)
{
Vector<IntRect> focusRingRects;
- addFocusRingRects(focusRingRects, paintOffset);
+ addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer);
if (style->outlineStyleIsAuto())
- context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), style->visitedDependentColor(CSSPropertyOutlineColor));
+ paintInfo.context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), style->visitedDependentColor(CSSPropertyOutlineColor));
else
- addPDFURLRect(context, unionRect(focusRingRects));
+ addPDFURLRect(paintInfo.context, unionRect(focusRingRects));
}
void RenderObject::addPDFURLRect(GraphicsContext* context, const LayoutRect& rect)
@@ -1103,29 +1112,26 @@ void RenderObject::addPDFURLRect(GraphicsContext* context, const LayoutRect& rec
Node* n = node();
if (!n || !n->isLink() || !n->isElementNode())
return;
- const AtomicString& href = static_cast<Element*>(n)->getAttribute(hrefAttr);
+ const AtomicString& href = toElement(n)->getAttribute(hrefAttr);
if (href.isNull())
return;
context->setURLForRect(n->document()->completeURL(href), pixelSnappedIntRect(rect));
}
-void RenderObject::paintOutline(GraphicsContext* graphicsContext, const LayoutRect& paintRect)
+void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
{
if (!hasOutline())
return;
RenderStyle* styleToUse = style();
LayoutUnit outlineWidth = styleToUse->outlineWidth();
- EBorderStyle outlineStyle = styleToUse->outlineStyle();
-
- Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
int outlineOffset = styleToUse->outlineOffset();
if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
if (!theme()->supportsFocusRing(styleToUse)) {
// Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
- paintFocusRing(graphicsContext, paintRect.location(), styleToUse);
+ paintFocusRing(paintInfo, paintRect.location(), styleToUse);
}
}
@@ -1142,6 +1148,10 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, const LayoutRe
if (outer.isEmpty())
return;
+ EBorderStyle outlineStyle = styleToUse->outlineStyle();
+ Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
+
+ GraphicsContext* graphicsContext = paintInfo.context;
bool useTransparencyLayer = outlineColor.hasAlpha();
if (useTransparencyLayer) {
if (outlineStyle == SOLID) {
@@ -1214,11 +1224,11 @@ void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
// descendants.
FloatPoint absolutePoint = localToAbsolute();
addFocusRingRects(rects, flooredLayoutPoint(absolutePoint));
- size_t count = rects.size();
+ size_t count = rects.size();
for (size_t i = 0; i < count; ++i) {
IntRect rect = rects[i];
rect.move(-absolutePoint.x(), -absolutePoint.y());
- quads.append(localToAbsoluteQuad(FloatQuad(rect), SnapOffsetForTransforms));
+ quads.append(localToAbsoluteQuad(FloatQuad(rect)));
}
}
@@ -1233,9 +1243,12 @@ FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
Vector<FloatQuad> quads;
range->textQuads(quads);
- FloatRect result;
- for (size_t i = 0; i < quads.size(); ++i)
- result.unite(quads[i].boundingBox());
+ if (quads.isEmpty())
+ return FloatRect();
+
+ FloatRect result = quads[0].boundingBox();
+ for (size_t i = 1; i < quads.size(); ++i)
+ result.uniteEvenIfEmpty(quads[i].boundingBox());
return result;
}
@@ -1248,6 +1261,7 @@ void RenderObject::addAbsoluteRectForLayer(LayoutRect& result)
current->addAbsoluteRectForLayer(result);
}
+// FIXME: change this to use the subtreePaint terminology
LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
{
LayoutRect result = absoluteBoundingBoxRectIgnoringTransforms();
@@ -1292,11 +1306,16 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
// If we have a flow thread, then we need to do individual repaints within the RenderRegions instead.
// Return the flow thread as a repaint container in order to create a chokepoint that allows us to change
// repainting to do individual region repaints.
- if (inRenderFlowThread()) {
- RenderFlowThread* parentRenderFlowThread = enclosingRenderFlowThread();
+ RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock();
+ if (parentRenderFlowThread) {
+ // The ancestor document will do the reparenting when the repaint propagates further up.
+ // We're just a seamless child document, and we don't need to do the hacking.
+ if (parentRenderFlowThread && parentRenderFlowThread->document() != document())
+ return repaintContainer;
// If we have already found a repaint container then we will repaint into that container only if it is part of the same
// flow thread. Otherwise we will need to catch the repaint call and send it to the flow thread.
- if (!(repaintContainer && repaintContainer->inRenderFlowThread() && repaintContainer->enclosingRenderFlowThread() == parentRenderFlowThread))
+ RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : 0;
+ if (!repaintContainerFlowThread || repaintContainerFlowThread != parentRenderFlowThread)
repaintContainer = parentRenderFlowThread;
}
return repaintContainer;
@@ -1327,10 +1346,7 @@ void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintCo
ASSERT(repaintContainer == v);
bool viewHasCompositedLayer = v->hasLayer() && v->layer()->isComposited();
if (!viewHasCompositedLayer || v->layer()->backing()->paintsIntoWindow()) {
- LayoutRect repaintRectangle = r;
- if (viewHasCompositedLayer && v->layer()->transform())
- repaintRectangle = enclosingIntRect(v->layer()->transform()->mapRect(r));
- v->repaintViewRectangle(repaintRectangle, immediate);
+ v->repaintViewRectangle(viewHasCompositedLayer && v->layer()->transform() ? v->layer()->transform()->mapRect(r) : r, immediate);
return;
}
}
@@ -1496,14 +1512,6 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repa
return false;
}
-void RenderObject::repaintDuringLayoutIfMoved(const LayoutRect&)
-{
-}
-
-void RenderObject::repaintOverhangingFloats(bool)
-{
-}
-
bool RenderObject::checkForRepaintDuringLayout() const
{
return !document()->view()->needsFullRepaint() && !hasLayer() && everHadLayout();
@@ -1623,13 +1631,15 @@ Color RenderObject::selectionBackgroundColor() const
{
Color color;
if (style()->userSelect() != SELECT_NONE) {
- RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION);
- if (pseudoStyle && pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
- color = pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).blendWithWhite();
- else
- color = frame()->selection()->isFocusedAndActive() ?
- theme()->activeSelectionBackgroundColor() :
- theme()->inactiveSelectionBackgroundColor();
+ if (frame()->selection()->shouldShowBlockCursor() && frame()->selection()->isCaret())
+ color = style()->visitedDependentColor(CSSPropertyColor).blendWithWhite();
+ else {
+ RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
+ if (pseudoStyle && pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
+ color = pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).blendWithWhite();
+ else
+ color = frame()->selection()->isFocusedAndActive() ? theme()->activeSelectionBackgroundColor() : theme()->inactiveSelectionBackgroundColor();
+ }
}
return color;
@@ -1644,7 +1654,7 @@ Color RenderObject::selectionColor(int colorProperty) const
|| (frame()->view()->paintBehavior() & PaintBehaviorSelectionOnly))
return color;
- if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION)) {
+ if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION))) {
color = pseudoStyle->visitedDependentColor(colorProperty);
if (!color.isValid())
color = pseudoStyle->visitedDependentColor(CSSPropertyColor);
@@ -1690,6 +1700,30 @@ void RenderObject::handleDynamicFloatPositionChange()
}
}
+void RenderObject::removeAnonymousWrappersForInlinesIfNecessary()
+{
+ // We have changed to floated or out-of-flow positioning so maybe all our parent's
+ // children can be inline now. Bail if there are any block children left on the line,
+ // otherwise we can proceed to stripping solitary anonymous wrappers from the inlines.
+ // FIXME: We should also handle split inlines here - we exclude them at the moment by returning
+ // if we find a continuation.
+ RenderObject* curr = parent()->firstChild();
+ while (curr && ((curr->isAnonymousBlock() && !toRenderBlock(curr)->isAnonymousBlockContinuation()) || curr->style()->isFloating() || curr->style()->hasOutOfFlowPosition()))
+ curr = curr->nextSibling();
+
+ if (curr)
+ return;
+
+ curr = parent()->firstChild();
+ RenderBlock* parentBlock = toRenderBlock(parent());
+ while (curr) {
+ RenderObject* next = curr->nextSibling();
+ if (curr->isAnonymousBlock())
+ parentBlock->collapseAnonymousBoxChild(parentBlock, toRenderBlock(curr));
+ curr = next;
+ }
+}
+
void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style)
{
if (!isText() && style)
@@ -1756,6 +1790,37 @@ StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsign
return diff;
}
+void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)
+{
+ ASSERT(pseudoStyle->styleType() == BEFORE || pseudoStyle->styleType() == AFTER);
+
+ // Images are special and must inherit the pseudoStyle so the width and height of
+ // the pseudo element doesn't change the size of the image. In all other cases we
+ // can just share the style.
+ if (isImage()) {
+ RefPtr<RenderStyle> style = RenderStyle::create();
+ style->inheritFrom(pseudoStyle.get());
+ setStyle(style.release());
+ return;
+ }
+
+ setStyle(pseudoStyle);
+}
+
+inline bool RenderObject::hasImmediateNonWhitespaceTextChild() const
+{
+ for (const RenderObject* r = firstChild(); r; r = r->nextSibling()) {
+ if (r->isText() && !toRenderText(r)->isAllCollapsibleWhitespace())
+ return true;
+ }
+ return false;
+}
+
+inline bool RenderObject::shouldRepaintForStyleDifference(StyleDifference diff) const
+{
+ return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfText && hasImmediateNonWhitespaceTextChild());
+}
+
void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
{
if (m_style == style) {
@@ -1809,21 +1874,26 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
if (updatedDiff == StyleDifferenceLayout)
setNeedsLayoutAndPrefWidthsRecalc();
else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly)
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle.get());
else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle.get());
setNeedsSimplifiedNormalFlowLayout();
} else if (updatedDiff == StyleDifferenceSimplifiedLayout)
setNeedsSimplifiedNormalFlowLayout();
}
-
- if (updatedDiff == StyleDifferenceRepaintLayer || updatedDiff == StyleDifferenceRepaint) {
+
+ if (updatedDiff == StyleDifferenceRepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) {
// Do a repaint with the new style now, e.g., for example if we go from
// not having an outline to having an outline.
repaint();
}
}
+static inline bool rendererHasBackground(const RenderObject* renderer)
+{
+ return renderer && renderer->hasBackground();
+}
+
void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
if (m_style) {
@@ -1837,8 +1907,10 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
if (visibilityChanged)
document()->setAnnotatedRegionsDirty(true);
#endif
- if (visibilityChanged && AXObjectCache::accessibilityEnabled())
- document()->axObjectCache()->childrenChanged(parent());
+ if (visibilityChanged) {
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->childrenChanged(parent());
+ }
// Keep layer hierarchy visibility bits up to date if visibility changes.
if (m_style->visibility() != newStyle->visibility()) {
@@ -1854,7 +1926,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
}
}
- if (m_parent && (diff == StyleDifferenceRepaint || newStyle->outlineSize() < m_style->outlineSize()))
+ if (m_parent && (newStyle->outlineSize() < m_style->outlineSize() || shouldRepaintForStyleDifference(diff)))
repaint();
if (isFloating() && (m_style->floating() != newStyle->floating()))
// For changes in float styles, we need to conceivably remove ourselves
@@ -1869,41 +1941,48 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
&& (!newStyle->isFloating() && !newStyle->hasOutOfFlowPosition())
&& parent() && (parent()->isBlockFlow() || parent()->isRenderInline());
+ s_noLongerAffectsParentBlock = ((!isFloating() && newStyle->isFloating()) || (!isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition()))
+ && parent() && parent()->isRenderBlock();
+
// reset style flags
if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) {
setFloating(false);
- setPositioned(false);
- setRelPositioned(false);
- setStickyPositioned(false);
+ clearPositionedState();
}
setHorizontalWritingMode(true);
- setPaintBackground(false);
+ setHasBoxDecorations(false);
setHasOverflowClip(false);
setHasTransform(false);
setHasReflection(false);
- } else
+ } else {
s_affectsParentBlock = false;
+ s_noLongerAffectsParentBlock = false;
+ }
- if (view()->frameView()) {
- bool shouldBlitOnFixedBackgroundImage = false;
-#if ENABLE(FAST_MOBILE_SCROLLING)
- // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
- // when scrolling a page with a fixed background image. As an optimization, assuming there are
- // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
- // ignore the CSS property "background-attachment: fixed".
-#if PLATFORM(QT)
- if (view()->frameView()->delegatesScrolling())
-#endif
- shouldBlitOnFixedBackgroundImage = true;
-#endif
+ if (FrameView* frameView = view()->frameView()) {
+ bool repaintFixedBackgroundsOnScroll = shouldRepaintFixedBackgroundsOnScroll(frameView);
- bool newStyleSlowScroll = newStyle && !shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage();
- bool oldStyleSlowScroll = m_style && !shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage();
+ bool newStyleSlowScroll = newStyle && repaintFixedBackgroundsOnScroll && newStyle->hasFixedBackgroundImage();
+ bool oldStyleSlowScroll = m_style && repaintFixedBackgroundsOnScroll && m_style->hasFixedBackgroundImage();
+
+#if USE(ACCELERATED_COMPOSITING)
+ bool drawsRootBackground = isRoot() || (isBody() && !rendererHasBackground(document()->documentElement()->renderer()));
+ if (drawsRootBackground && repaintFixedBackgroundsOnScroll) {
+ if (view()->compositor()->supportsFixedRootBackgroundCompositing()) {
+ if (newStyleSlowScroll && newStyle->hasEntirelyFixedBackground())
+ newStyleSlowScroll = false;
+
+ if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground())
+ oldStyleSlowScroll = false;
+ }
+ }
+#endif
if (oldStyleSlowScroll != newStyleSlowScroll) {
if (oldStyleSlowScroll)
- view()->frameView()->removeSlowRepaintObject();
+ frameView->removeSlowRepaintObject(this);
+
if (newStyleSlowScroll)
- view()->frameView()->addSlowRepaintObject();
+ frameView->addSlowRepaintObject(this);
}
}
}
@@ -1924,6 +2003,8 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
if (s_affectsParentBlock)
handleDynamicFloatPositionChange();
+ if (s_noLongerAffectsParentBlock)
+ removeAnonymousWrappersForInlinesIfNecessary();
#if ENABLE(SVG)
SVGRenderSupport::styleChanged(this);
#endif
@@ -1947,17 +2028,17 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
else
setNeedsSimplifiedNormalFlowLayout();
} else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle);
setNeedsSimplifiedNormalFlowLayout();
} else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle);
// Don't check for repaint here; we need to wait until the layer has been
// updated by subclasses before we know if we have to repaint (in setStyle()).
if (oldStyle && !areCursorsEqual(oldStyle, style())) {
if (Frame* frame = this->frame())
- frame->eventHandler()->dispatchFakeMouseMoveEventSoon();
+ frame->eventHandler()->scheduleCursorUpdate();
}
}
@@ -2044,6 +2125,14 @@ FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, MapCo
return transformState.lastPlanarPoint();
}
+FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinatesFlags mode) const
+{
+ TransformState transformState(TransformState::UnapplyInverseTransformDirection, quad.boundingBox().center(), quad);
+ mapAbsoluteToLocalPoint(mode, transformState);
+ transformState.flatten();
+ return transformState.lastPlanarQuad();
+}
+
void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
{
if (repaintContainer == this)
@@ -2170,7 +2259,7 @@ LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint&
offset -= toRenderBox(o)->scrolledContentOffset();
if (offsetDependsOnPoint)
- *offsetDependsOnPoint = hasColumns();
+ *offsetDependsOnPoint = hasColumns() || o->isRenderFlowThread();
return offset;
}
@@ -2240,11 +2329,11 @@ RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
// Respect the image's orientation if it's being used as a full-page image or it's
// an <img> and the setting to respect it everywhere is set.
return
-#if USE(CG) || PLATFORM(CHROMIUM) || USE(CAIRO)
+#if USE(CG) || USE(CAIRO) || PLATFORM(BLACKBERRY)
// This can only be enabled for ports which honor the orientation flag in their drawing code.
document()->isImageDocument() ||
#endif
- (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && (node()->hasTagName(HTMLNames::imgTag) || node()->hasTagName(HTMLNames::webkitInnerImageTag))) ? RespectImageOrientation : DoNotRespectImageOrientation;
+ (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
}
bool RenderObject::hasOutlineAnnotation() const
@@ -2252,6 +2341,11 @@ bool RenderObject::hasOutlineAnnotation() const
return node() && node()->isLink() && document()->printing();
}
+bool RenderObject::hasEntirelyFixedBackground() const
+{
+ return m_style->hasEntirelyFixedBackground();
+}
+
RenderObject* RenderObject::container(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const
{
if (repaintContainerSkipped)
@@ -2289,7 +2383,7 @@ RenderObject* RenderObject::container(const RenderLayerModelObject* repaintConta
#endif
// The render flow thread is the top most containing block
// for the fixed positioned elements.
- if (o->isRenderFlowThread())
+ if (o->isOutOfFlowRenderFlowThread())
break;
if (repaintContainerSkipped && o == repaintContainer)
@@ -2353,14 +2447,22 @@ void RenderObject::willBeDestroyed()
if (frame() && frame()->eventHandler()->autoscrollRenderer() == this)
frame()->eventHandler()->stopAutoscrollTimer(true);
- if (AXObjectCache::accessibilityEnabled()) {
- document()->axObjectCache()->childrenChanged(this->parent());
- document()->axObjectCache()->remove(this);
- }
animation()->cancelAnimations(this);
+ // For accessibility management, notify the parent of the imminent change to its child set.
+ // We do it now, before remove(), while the parent pointer is still available.
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->childrenChanged(this->parent());
+
remove();
+ ASSERT(documentBeingDestroyed() || !frame()->view()->hasSlowRepaintObject(this));
+
+ // The remove() call above may invoke axObjectCache()->childrenChanged() on the parent, which may require the AX render
+ // object for this renderer. So we remove the AX render object now, after the renderer is removed.
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->remove(this);
+
#ifndef NDEBUG
if (!documentBeingDestroyed() && view() && view()->hasRenderNamedFlowThreads()) {
// After remove, the object and the associated information should not be in any flow thread.
@@ -2425,6 +2527,14 @@ void RenderObject::willBeRemovedFromTree()
{
// FIXME: We should ASSERT(isRooted()) but we have some out-of-order removals which would need to be fixed first.
+ if (!isText()) {
+ if (FrameView* frameView = view()->frameView()) {
+ bool repaintFixedBackgroundsOnScroll = shouldRepaintFixedBackgroundsOnScroll(frameView);
+ if (repaintFixedBackgroundsOnScroll && m_style && m_style->hasFixedBackgroundImage())
+ frameView->removeSlowRepaintObject(this);
+ }
+ }
+
// If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
RenderLayer* layer = 0;
if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
@@ -2442,8 +2552,7 @@ void RenderObject::willBeRemovedFromTree()
if (isOutOfFlowPositioned() && parent()->childrenInline())
parent()->dirtyLinesFromChangedChild(this);
- if (inRenderFlowThread())
- removeFromRenderFlowThread();
+ removeFromRenderFlowThread();
if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
containerFlowThread->removeFlowChild(this);
@@ -2456,13 +2565,14 @@ void RenderObject::willBeRemovedFromTree()
void RenderObject::removeFromRenderFlowThread()
{
- RenderFlowThread* renderFlowThread = enclosingRenderFlowThread();
- ASSERT(renderFlowThread);
- // Sometimes we remove the element from the flow, but it's not destroyed at that time.
+ if (flowThreadState() == NotInsideFlowThread)
+ return;
+
+ // Sometimes we remove the element from the flow, but it's not destroyed at that time.
// It's only until later when we actually destroy it and remove all the children from it.
// Currently, that happens for firstLetter elements and list markers.
// Pass in the flow thread so that we don't have to look it up for all the children.
- removeFromRenderFlowThreadRecursive(renderFlowThread);
+ removeFromRenderFlowThreadRecursive(flowThreadContainingBlock());
}
void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderFlowThread)
@@ -2471,8 +2581,13 @@ void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderF
for (RenderObject* child = children->firstChild(); child; child = child->nextSibling())
child->removeFromRenderFlowThreadRecursive(renderFlowThread);
}
- renderFlowThread->removeFlowChildInfo(this);
- setInRenderFlowThread(false);
+
+ RenderFlowThread* localFlowThread = renderFlowThread;
+ if (flowThreadState() == InsideInFlowThread)
+ localFlowThread = flowThreadContainingBlock(); // We have to ask. We can't just assume we are in the same flow thread.
+ if (localFlowThread)
+ localFlowThread->removeFlowChildInfo(this);
+ setFlowThreadState(NotInsideFlowThread);
}
void RenderObject::destroyAndCleanupAnonymousWrappers()
@@ -2485,9 +2600,9 @@ void RenderObject::destroyAndCleanupAnonymousWrappers()
RenderObject* destroyRoot = this;
for (RenderObject* destroyRootParent = destroyRoot->parent(); destroyRootParent && destroyRootParent->isAnonymous(); destroyRoot = destroyRootParent, destroyRootParent = destroyRootParent->parent()) {
- // Currently we only remove anonymous cells' wrapper but we should remove all unneeded
+ // Currently we only remove anonymous cells' and table sections' wrappers but we should remove all unneeded
// wrappers. See http://webkit.org/b/52123 as an example where this is needed.
- if (!destroyRootParent->isTableCell())
+ if (!destroyRootParent->isTableCell() && !destroyRootParent->isTableSection())
break;
if (destroyRootParent->firstChild() != this || destroyRootParent->lastChild() != this)
@@ -2586,11 +2701,19 @@ void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint&
if (result.innerNode())
return;
- Node* n = node();
- if (n) {
- result.setInnerNode(n);
+ Node* node = this->node();
+
+ // If we hit the anonymous renderers inside generated content we should
+ // actually hit the generated content so walk up to the PseudoElement.
+ if (!node && parent() && parent()->isBeforeOrAfterContent()) {
+ for (RenderObject* renderer = parent(); renderer && !node; renderer = renderer->parent())
+ node = renderer->node();
+ }
+
+ if (node) {
+ result.setInnerNode(node);
if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(n);
+ result.setInnerNonSharedNode(node);
result.setLocalPoint(point);
}
}
@@ -2644,7 +2767,7 @@ static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheSta
if (RenderBlock* firstLineBlock = rendererForFirstLineStyle->firstLineBlock()) {
if (type == Cached)
return firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style);
- return firstLineBlock->getUncachedPseudoStyle(FIRST_LINE, style, firstLineBlock == renderer ? style : 0);
+ return firstLineBlock->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE), style, firstLineBlock == renderer ? style : 0);
}
} else if (!rendererForFirstLineStyle->isAnonymous() && rendererForFirstLineStyle->isRenderInline()) {
RenderStyle* parentStyle = rendererForFirstLineStyle->parent()->firstLineStyle();
@@ -2654,7 +2777,7 @@ static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheSta
rendererForFirstLineStyle->style()->setHasPseudoStyle(FIRST_LINE_INHERITED);
return rendererForFirstLineStyle->getCachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle);
}
- return rendererForFirstLineStyle->getUncachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle, style);
+ return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style);
}
}
return 0;
@@ -2689,15 +2812,15 @@ RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* pa
if (cachedStyle)
return cachedStyle;
- RefPtr<RenderStyle> result = getUncachedPseudoStyle(pseudo, parentStyle);
+ RefPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
if (result)
return style()->addCachedPseudoStyle(result.release());
return 0;
}
-PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle, RenderStyle* ownStyle) const
+PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const
{
- if (pseudo < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudo))
+ if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId))
return 0;
if (!parentStyle) {
@@ -2713,17 +2836,24 @@ PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, Re
return 0;
Element* element = toElement(n);
- if (pseudo == FIRST_LINE_INHERITED) {
- RefPtr<RenderStyle> result = document()->styleResolver()->styleForElement(element, parentStyle, DisallowStyleSharing);
+ if (pseudoStyleRequest.pseudoId == FIRST_LINE_INHERITED) {
+ RefPtr<RenderStyle> result = document()->ensureStyleResolver()->styleForElement(element, parentStyle, DisallowStyleSharing);
result->setStyleType(FIRST_LINE_INHERITED);
return result.release();
}
- return document()->styleResolver()->pseudoStyleForElement(pseudo, element, parentStyle);
+
+ return document()->ensureStyleResolver()->pseudoStyleForElement(element, pseudoStyleRequest, parentStyle);
}
static Color decorationColor(RenderStyle* style)
{
Color result;
+#if ENABLE(CSS3_TEXT)
+ // Check for text decoration color first.
+ result = style->visitedDependentColor(CSSPropertyWebkitTextDecorationColor);
+ if (result.isValid())
+ return result;
+#endif // CSS3_TEXT
if (style->textStrokeWidth() > 0) {
// Prefer stroke color if possible but not if it's fully transparent.
result = style->visitedDependentColor(CSSPropertyWebkitTextStrokeColor);
@@ -2740,21 +2870,25 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co
{
RenderObject* curr = this;
RenderStyle* styleToUse = 0;
+ TextDecoration currDecs = TextDecorationNone;
+ Color resultColor;
do {
styleToUse = curr->style(firstlineStyle);
- int currDecs = styleToUse->textDecoration();
+ currDecs = styleToUse->textDecoration();
+ resultColor = decorationColor(styleToUse);
+ // Parameter 'decorations' is cast as an int to enable the bitwise operations below.
if (currDecs) {
- if (currDecs & UNDERLINE) {
- decorations &= ~UNDERLINE;
- underline = decorationColor(styleToUse);
+ if (currDecs & TextDecorationUnderline) {
+ decorations &= ~TextDecorationUnderline;
+ underline = resultColor;
}
- if (currDecs & OVERLINE) {
- decorations &= ~OVERLINE;
- overline = decorationColor(styleToUse);
+ if (currDecs & TextDecorationOverline) {
+ decorations &= ~TextDecorationOverline;
+ overline = resultColor;
}
- if (currDecs & LINE_THROUGH) {
- decorations &= ~LINE_THROUGH;
- linethrough = decorationColor(styleToUse);
+ if (currDecs & TextDecorationLineThrough) {
+ decorations &= ~TextDecorationLineThrough;
+ linethrough = resultColor;
}
}
if (curr->isRubyText())
@@ -2762,18 +2896,18 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co
curr = curr->parent();
if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation())
curr = toRenderBlock(curr)->continuation();
- } while (curr && decorations && (!quirksMode || !curr->node() ||
- (!curr->node()->hasTagName(aTag) && !curr->node()->hasTagName(fontTag))));
+ } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(curr->node()) && !curr->node()->hasTagName(fontTag))));
// If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
if (decorations && curr) {
styleToUse = curr->style(firstlineStyle);
- if (decorations & UNDERLINE)
- underline = decorationColor(styleToUse);
- if (decorations & OVERLINE)
- overline = decorationColor(styleToUse);
- if (decorations & LINE_THROUGH)
- linethrough = decorationColor(styleToUse);
+ resultColor = decorationColor(styleToUse);
+ if (decorations & TextDecorationUnderline)
+ underline = resultColor;
+ if (decorations & TextDecorationOverline)
+ overline = resultColor;
+ if (decorations & TextDecorationLineThrough)
+ linethrough = resultColor;
}
}
@@ -2910,6 +3044,33 @@ void RenderObject::imageChanged(CachedImage* image, const IntRect* rect)
{
imageChanged(static_cast<WrappedImagePtr>(image), rect);
}
+
+RenderObject* RenderObject::hoverAncestor() const
+{
+ // When searching for the hover ancestor and encountering a named flow thread,
+ // the search will continue with the DOM ancestor of the top-most element
+ // in the named flow thread.
+ // See https://bugs.webkit.org/show_bug.cgi?id=111749
+ RenderObject* hoverAncestor = parent();
+
+ // Skip anonymous blocks directly flowed into flow threads as it would
+ // prevent us from continuing the search on the DOM tree when reaching the named flow thread.
+ if (hoverAncestor && hoverAncestor->isAnonymousBlock() && hoverAncestor->parent() && hoverAncestor->parent()->isRenderNamedFlowThread())
+ hoverAncestor = hoverAncestor->parent();
+
+ if (hoverAncestor && hoverAncestor->isRenderNamedFlowThread()) {
+ hoverAncestor = 0;
+
+ Node* node = this->node();
+ if (node) {
+ Node* domAncestorNode = node->parentNode();
+ if (domAncestorNode)
+ hoverAncestor = domAncestorNode->renderer();
+ }
+ }
+
+ return hoverAncestor;
+}
RenderBoxModelObject* RenderObject::offsetParent() const
{
@@ -2935,24 +3096,29 @@ RenderBoxModelObject* RenderObject::offsetParent() const
bool skipTables = isPositioned();
float currZoom = style()->effectiveZoom();
RenderObject* curr = parent();
- while (curr && (!curr->node() || (!curr->isPositioned() && !curr->isBody()))) {
+ while (curr && (!curr->node() || (!curr->isPositioned() && !curr->isBody())) && !curr->isRenderNamedFlowThread()) {
Node* element = curr->node();
- if (!skipTables && element && (element->hasTagName(tableTag) || element->hasTagName(tdTag) || element->hasTagName(thTag)))
+ if (!skipTables && element && (isHTMLTableElement(element) || element->hasTagName(tdTag) || element->hasTagName(thTag)))
break;
-
+
float newZoom = curr->style()->effectiveZoom();
if (currZoom != newZoom)
break;
currZoom = newZoom;
curr = curr->parent();
}
+
+ // CSS regions specification says that region flows should return the body element as their offsetParent.
+ if (curr && curr->isRenderNamedFlowThread())
+ curr = document()->body() ? document()->body()->renderer() : 0;
+
return curr && curr->isBoxModelObject() ? toRenderBoxModelObject(curr) : 0;
}
VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
{
// If this is a non-anonymous renderer in an editable area, then it's simple.
- if (Node* node = this->node()) {
+ if (Node* node = nonPseudoNode()) {
if (!node->rendererIsEditable()) {
// If it can be found, we prefer a visually equivalent position that is editable.
Position position = createLegacyEditingPosition(node, offset);
@@ -2978,7 +3144,7 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
// Find non-anonymous content after.
RenderObject* renderer = child;
while ((renderer = renderer->nextInPreOrder(parent))) {
- if (Node* node = renderer->node())
+ if (Node* node = renderer->nonPseudoNode())
return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
}
@@ -2987,12 +3153,12 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
while ((renderer = renderer->previousInPreOrder())) {
if (renderer == parent)
break;
- if (Node* node = renderer->node())
+ if (Node* node = renderer->nonPseudoNode())
return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
}
// Use the parent itself unless it too is anonymous.
- if (Node* node = parent->node())
+ if (Node* node = parent->nonPseudoNode())
return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
// Repeat at the next level up.
diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h
index 258276b36..ac83e84f4 100644
--- a/Source/WebCore/rendering/RenderObject.h
+++ b/Source/WebCore/rendering/RenderObject.h
@@ -37,10 +37,7 @@
#include "ScrollBehavior.h"
#include "StyleInheritedData.h"
#include "TextAffinity.h"
-#include "TransformationMatrix.h"
#include <wtf/HashSet.h>
-#include <wtf/StackStats.h>
-#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -51,10 +48,9 @@ class Document;
class HitTestLocation;
class HitTestResult;
class InlineBox;
-class InlineFlowBox;
-class OverlapTestRequestClient;
class Path;
class Position;
+class PseudoStyleRequest;
class RenderBoxModelObject;
class RenderInline;
class RenderBlock;
@@ -63,7 +59,6 @@ class RenderGeometryMap;
class RenderLayer;
class RenderLayerModelObject;
class RenderNamedFlowThread;
-class RenderTable;
class RenderTheme;
class TransformState;
class VisiblePosition;
@@ -106,16 +101,10 @@ enum MarkingBehavior {
MarkContainingBlockChain,
};
-enum PlaceGeneratedRunInFlag {
- PlaceGeneratedRunIn,
- DoNotPlaceGeneratedRunIn
-};
-
enum MapCoordinatesMode {
IsFixed = 1 << 0,
UseTransforms = 1 << 1,
- ApplyContainerFlip = 1 << 2,
- SnapOffsetForTransforms = 1 << 3
+ ApplyContainerFlip = 1 << 2
};
typedef unsigned MapCoordinatesFlags;
@@ -161,7 +150,7 @@ class RenderObject : public CachedImageClient {
public:
// Anonymous objects should pass the document as their node, and they will then automatically be
// marked as anonymous in the constructor.
- RenderObject(Node*);
+ explicit RenderObject(Node*);
virtual ~RenderObject();
RenderTheme* theme() const;
@@ -191,22 +180,6 @@ public:
return children->lastChild();
return 0;
}
- RenderObject* beforePseudoElementRenderer() const
- {
- if (const RenderObjectChildList* children = virtualChildren())
- return children->beforePseudoElementRenderer(this);
- return 0;
- }
-
- // This function only returns the renderer of the "after" pseudoElement if it is a child of
- // this renderer. If "continuations" exist, the function returns 0 even if the element that
- // generated this renderer has an "after" pseudo-element.
- RenderObject* afterPseudoElementRenderer() const
- {
- if (const RenderObjectChildList* children = virtualChildren())
- return children->afterPseudoElementRenderer(this);
- return 0;
- }
virtual RenderObjectChildList* virtualChildren() { return 0; }
virtual const RenderObjectChildList* virtualChildren() const { return 0; }
@@ -238,8 +211,14 @@ public:
RenderBox* enclosingBox() const;
RenderBoxModelObject* enclosingBoxModelObject() const;
- // Function to return our enclosing flow thread if we are contained inside one.
- RenderFlowThread* enclosingRenderFlowThread() const;
+ // Function to return our enclosing flow thread if we are contained inside one. This
+ // function follows the containing block chain.
+ RenderFlowThread* flowThreadContainingBlock() const
+ {
+ if (flowThreadState() == NotInsideFlowThread)
+ return 0;
+ return locateFlowThreadContainingBlock();
+ }
RenderNamedFlowThread* renderNamedFlowThreadWrapper() const;
@@ -248,13 +227,11 @@ public:
#ifndef NDEBUG
void setHasAXObject(bool flag) { m_hasAXObject = flag; }
bool hasAXObject() const { return m_hasAXObject; }
- bool isSetNeedsLayoutForbidden() const { return m_setNeedsLayoutForbidden; }
- void setNeedsLayoutIsForbidden(bool flag) { m_setNeedsLayoutForbidden = flag; }
// Helper class forbidding calls to setNeedsLayout() during its lifetime.
class SetLayoutNeededForbiddenScope {
public:
- explicit SetLayoutNeededForbiddenScope(RenderObject*);
+ explicit SetLayoutNeededForbiddenScope(RenderObject*, bool isForbidden = true);
~SetLayoutNeededForbiddenScope();
private:
RenderObject* m_renderObject;
@@ -270,6 +247,7 @@ public:
// again. We have to make sure the render tree updates as needed to accommodate the new
// normal flow object.
void handleDynamicFloatPositionChange();
+ void removeAnonymousWrappersForInlinesIfNecessary();
// RenderObject tree manipulation
//////////////////////////////////////////
@@ -290,13 +268,22 @@ protected:
void setParent(RenderObject* parent)
{
m_parent = parent;
- if (parent && parent->inRenderFlowThread())
- setInRenderFlowThread(true);
- else if (!parent && inRenderFlowThread())
- setInRenderFlowThread(false);
+
+ // Only update if our flow thread state is different from our new parent and if we're not a RenderFlowThread.
+ // A RenderFlowThread is always considered to be inside itself, so it never has to change its state
+ // in response to parent changes.
+ FlowThreadState newState = parent ? parent->flowThreadState() : NotInsideFlowThread;
+ if (newState != flowThreadState() && !isRenderFlowThread())
+ setFlowThreadStateIncludingDescendants(newState);
}
+
//////////////////////////////////////////
private:
+#ifndef NDEBUG
+ bool isSetNeedsLayoutForbidden() const { return m_setNeedsLayoutForbidden; }
+ void setNeedsLayoutIsForbidden(bool flag) { m_setNeedsLayoutForbidden = flag; }
+#endif
+
void addAbsoluteRectForLayer(LayoutRect& result);
void setLayerNeedsFullRepaint();
void setLayerNeedsFullRepaintForPositionedMovementLayout();
@@ -314,7 +301,7 @@ public:
void showRenderTreeAndMark(const RenderObject* markedObject1 = 0, const char* markedLabel1 = 0, const RenderObject* markedObject2 = 0, const char* markedLabel2 = 0, int depth = 0) const;
#endif
- static RenderObject* createObject(Node*, RenderStyle*);
+ static RenderObject* createObject(Element*, RenderStyle*);
// Overloaded new operator. Derived classes must override operator new
// in order to allocate out of the RenderArena.
@@ -330,6 +317,8 @@ private:
public:
RenderArena* renderArena() const { return document()->renderArena(); }
+ bool isPseudoElement() const { return node() && node()->isPseudoElement(); }
+
virtual bool isBR() const { return false; }
virtual bool isBlockFlow() const { return false; }
virtual bool isBoxModelObject() const { return false; }
@@ -363,6 +352,7 @@ public:
virtual bool isProgress() const { return false; }
#endif
virtual bool isRenderBlock() const { return false; }
+ virtual bool isRenderSVGBlock() const { return false; };
virtual bool isRenderButton() const { return false; }
virtual bool isRenderIFrame() const { return false; }
virtual bool isRenderImage() const { return false; }
@@ -396,14 +386,17 @@ public:
virtual bool isRenderFullScreenPlaceholder() const { return false; }
#endif
+ virtual bool isRenderGrid() const { return false; }
+
virtual bool isRenderFlowThread() const { return false; }
virtual bool isRenderNamedFlowThread() const { return false; }
-
+ bool isInFlowRenderFlowThread() const { return isRenderFlowThread() && !isOutOfFlowPositioned(); }
+ bool isOutOfFlowRenderFlowThread() const { return isRenderFlowThread() && isOutOfFlowPositioned(); }
+
virtual bool isRenderMultiColumnBlock() const { return false; }
virtual bool isRenderMultiColumnSet() const { return false; }
virtual bool isRenderScrollbarPart() const { return false; }
- bool canHaveRegionStyle() const { return isRenderBlock() && !isAnonymous() && !isRenderFlowThread(); }
bool isRoot() const { return document()->documentElement() == m_node; }
bool isBody() const;
@@ -447,8 +440,16 @@ public:
}
}
- bool inRenderFlowThread() const { return m_bitfields.inRenderFlowThread(); }
- void setInRenderFlowThread(bool b = true) { m_bitfields.setInRenderFlowThread(b); }
+ enum FlowThreadState {
+ NotInsideFlowThread = 0,
+ InsideOutOfFlowThread = 1,
+ InsideInFlowThread = 2,
+ };
+
+ void setFlowThreadStateIncludingDescendants(FlowThreadState);
+
+ FlowThreadState flowThreadState() const { return m_bitfields.flowThreadState(); }
+ void setFlowThreadState(FlowThreadState state) { m_bitfields.setFlowThreadState(state); }
virtual bool requiresForcedStyleRecalcPropagation() const { return false; }
@@ -484,6 +485,7 @@ public:
// to inherit from RenderSVGObject -> RenderObject (some need RenderBlock inheritance for instance)
virtual void setNeedsTransformUpdate() { }
virtual void setNeedsBoundariesUpdate();
+ virtual bool needsBoundariesUpdate() { return false; }
// Per SVG 1.1 objectBoundingBox ignores clipping, masking, filter effects, opacity and stroke-width.
// This is used for all computation of objectBoundingBox relative units and by SVGLocatable::getBBox().
@@ -512,15 +514,15 @@ public:
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
#endif
+ bool hasAspectRatio() const { return isReplaced() && (isImage() || isVideo() || isCanvas()); }
bool isAnonymous() const { return m_bitfields.isAnonymous(); }
- void setIsAnonymous(bool b) { m_bitfields.setIsAnonymous(b); }
bool isAnonymousBlock() const
{
// This function is kept in sync with anonymous block creation conditions in
// RenderBlock::createAnonymousBlock(). This includes creating an anonymous
// RenderBlock having a BLOCK or BOX display. Other classes such as RenderTextFragment
// are not RenderBlocks and will return false. See https://bugs.webkit.org/show_bug.cgi?id=56709.
- return isAnonymous() && (style()->display() == BLOCK || style()->display() == BOX) && style()->styleType() == NOPSEUDO && isRenderBlock() && !isListMarker()
+ return isAnonymous() && (style()->display() == BLOCK || style()->display() == BOX) && style()->styleType() == NOPSEUDO && isRenderBlock() && !isListMarker() && !isRenderFlowThread()
#if ENABLE(FULLSCREEN_API)
&& !isRenderFullScreen()
&& !isRenderFullScreenPlaceholder()
@@ -539,11 +541,11 @@ public:
bool isFloating() const { return m_bitfields.floating(); }
- bool isOutOfFlowPositioned() const { return m_bitfields.positioned(); } // absolute or fixed positioning
- bool isInFlowPositioned() const { return m_bitfields.relPositioned() || m_bitfields.stickyPositioned(); } // relative or sticky positioning
- bool isRelPositioned() const { return m_bitfields.relPositioned(); } // relative positioning
- bool isStickyPositioned() const { return m_bitfields.stickyPositioned(); }
- bool isPositioned() const { return m_bitfields.positioned() || m_bitfields.relPositioned() || m_bitfields.stickyPositioned(); }
+ bool isOutOfFlowPositioned() const { return m_bitfields.isOutOfFlowPositioned(); } // absolute or fixed positioning
+ bool isInFlowPositioned() const { return m_bitfields.isRelPositioned() || m_bitfields.isStickyPositioned(); } // relative or sticky positioning
+ bool isRelPositioned() const { return m_bitfields.isRelPositioned(); } // relative positioning
+ bool isStickyPositioned() const { return m_bitfields.isStickyPositioned(); }
+ bool isPositioned() const { return m_bitfields.isPositioned(); }
bool isText() const { return m_bitfields.isText(); }
bool isBox() const { return m_bitfields.isBox(); }
@@ -554,11 +556,20 @@ public:
bool isHorizontalWritingMode() const { return m_bitfields.horizontalWritingMode(); }
bool hasLayer() const { return m_bitfields.hasLayer(); }
-
- bool hasBoxDecorations() const { return m_bitfields.paintBackground(); }
+
+ enum BoxDecorationState {
+ NoBoxDecorations,
+ HasBoxDecorationsAndBackgroundObscurationStatusInvalid,
+ HasBoxDecorationsAndBackgroundIsKnownToBeObscured,
+ HasBoxDecorationsAndBackgroundMayBeVisible,
+ };
+ bool hasBoxDecorations() const { return m_bitfields.boxDecorationState() != NoBoxDecorations; }
+ bool backgroundIsKnownToBeObscured();
bool borderImageIsLoadedAndCanBeRendered() const;
bool mustRepaintBackgroundOrBorder() const;
bool hasBackground() const { return style()->hasBackground(); }
+ bool hasEntirelyFixedBackground() const;
+
bool needsLayout() const
{
return m_bitfields.needsLayout() || m_bitfields.normalChildNeedsLayout() || m_bitfields.posChildNeedsLayout()
@@ -607,7 +618,7 @@ public:
// The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect
// any pseudo classes (and therefore has no concept of changing state).
RenderStyle* getCachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0) const;
- PassRefPtr<RenderStyle> getUncachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0, RenderStyle* ownStyle = 0) const;
+ PassRefPtr<RenderStyle> getUncachedPseudoStyle(const PseudoStyleRequest&, RenderStyle* parentStyle = 0, RenderStyle* ownStyle = 0) const;
virtual void updateDragState(bool dragOn);
@@ -617,12 +628,15 @@ public:
bool isRooted(RenderView** = 0) const;
Node* node() const { return isAnonymous() ? 0 : m_node; }
+ Node* nonPseudoNode() const { return isPseudoElement() ? 0 : node(); }
+
+ // FIXME: Why does RenderWidget need this?
+ void clearNode() { m_node = 0; }
// Returns the styled node that caused the generation of this renderer.
// This is the same as node() except for renderers of :before and :after
// pseudo elements for which their parent node is returned.
- Node* generatingNode() const { return m_node == document() ? 0 : m_node; }
- void setNode(Node* node) { m_node = node; }
+ Node* generatingNode() const { return isPseudoElement() ? node()->parentOrShadowHostNode() : node(); }
Document* document() const { return m_node->document(); }
Frame* frame() const { return document()->frame(); }
@@ -635,15 +649,14 @@ public:
// is true if the renderer returned is an ancestor of repaintContainer.
RenderObject* container(const RenderLayerModelObject* repaintContainer = 0, bool* repaintContainerSkipped = 0) const;
- virtual RenderObject* hoverAncestor() const { return parent(); }
+ virtual RenderObject* hoverAncestor() const;
- // IE Extension that can be called on any RenderObject. See the implementation for the details.
RenderBoxModelObject* offsetParent() const;
void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0);
void setNeedsLayout(bool needsLayout, MarkingBehavior = MarkContainingBlockChain);
void setChildNeedsLayout(bool childNeedsLayout, MarkingBehavior = MarkContainingBlockChain);
- void setNeedsPositionedMovementLayout();
+ void setNeedsPositionedMovementLayout(const RenderStyle* oldStyle);
void setNeedsSimplifiedNormalFlowLayout();
void setPreferredLogicalWidthsDirty(bool, MarkingBehavior = MarkContainingBlockChain);
void invalidateContainerPreferredLogicalWidths();
@@ -654,12 +667,20 @@ public:
setPreferredLogicalWidthsDirty(true);
}
- void setPositioned(bool b = true) { m_bitfields.setPositioned(b); }
- void setRelPositioned(bool b = true) { m_bitfields.setRelPositioned(b); }
- void setStickyPositioned(bool b = true) { m_bitfields.setStickyPositioned(b); }
+ void setPositionState(EPosition position)
+ {
+ ASSERT((position != AbsolutePosition && position != FixedPosition) || isBox());
+ m_bitfields.setPositionedState(position);
+ }
+ void clearPositionedState() { m_bitfields.clearPositionedState(); }
+
void setFloating(bool b = true) { m_bitfields.setFloating(b); }
void setInline(bool b = true) { m_bitfields.setIsInline(b); }
- void setHasBoxDecorations(bool b = true) { m_bitfields.setPaintBackground(b); }
+
+ void setHasBoxDecorations(bool = true);
+ void invalidateBackgroundObscurationStatus();
+ virtual bool computeBackgroundIsKnownToBeObscured() { return false; }
+
void setIsText() { m_bitfields.setIsText(true); }
void setIsBox() { m_bitfields.setIsBox(true); }
void setReplaced(bool b = true) { m_bitfields.setIsReplaced(b); }
@@ -711,6 +732,9 @@ public:
// Set the style of the object and update the state of the object accordingly.
virtual void setStyle(PassRefPtr<RenderStyle>);
+ // Set the style of the object if it's generated content.
+ void setPseudoStyle(PassRefPtr<RenderStyle>);
+
// Updates only the local style ptr of the object. Does not update the state of the object,
// and so only should be called when the style is known not to have changed (or from setStyle).
void setStyleInternal(PassRefPtr<RenderStyle> style) { m_style = style; }
@@ -718,6 +742,15 @@ public:
// returns the containing block level element for this element.
RenderBlock* containingBlock() const;
+ bool canContainFixedPositionObjects() const
+ {
+ return isRenderView() || (hasTransform() && isRenderBlock())
+#if ENABLE(SVG)
+ || isSVGForeignObject()
+#endif
+ || isOutOfFlowRenderFlowThread();
+ }
+
// Convert the given local point to absolute coordinates
// FIXME: Temporary. If UseTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware.
FloatPoint localToAbsolute(const FloatPoint& localPoint = FloatPoint(), MapCoordinatesFlags = 0) const;
@@ -728,6 +761,8 @@ public:
{
return localToContainerQuad(quad, 0, mode, wasFixed);
}
+ // Convert an absolute quad to local coordinates.
+ FloatQuad absoluteToLocalQuad(const FloatQuad&, MapCoordinatesFlags mode = 0) const;
// Convert a local quad into the coordinate system of container, taking transforms into account.
FloatQuad localToContainerQuad(const FloatQuad&, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags = 0, bool* wasFixed = 0) const;
@@ -792,12 +827,6 @@ public:
// Repaint only if our old bounds and new bounds are different. The caller may pass in newBounds and newOutlineBox if they are known.
bool repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr = 0, const LayoutRect* newOutlineBoxPtr = 0);
- // Repaint only if the object moved.
- virtual void repaintDuringLayoutIfMoved(const LayoutRect&);
-
- // Called to repaint a block's floats.
- virtual void repaintOverhangingFloats(bool paintAllDescendants = false);
-
bool checkForRepaintDuringLayout() const;
// Returns the rect that should be repainted whenever this object changes. The rect is in the view's
@@ -835,6 +864,7 @@ public:
virtual unsigned int length() const { return 1; }
bool isFloatingOrOutOfFlowPositioned() const { return (isFloating() || isOutOfFlowPositioned()); }
+ bool isFloatingWithShapeOutside() const { return isBox() && isFloating() && style()->shapeOutside(); }
bool isTransparent() const { return style()->opacity() < 1.0f; }
float opacity() const { return style()->opacity(); }
@@ -883,11 +913,6 @@ public:
*/
virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0);
- bool isMarginBeforeQuirk() const { return m_bitfields.marginBeforeQuirk(); }
- bool isMarginAfterQuirk() const { return m_bitfields.marginAfterQuirk(); }
- void setMarginBeforeQuirk(bool b = true) { m_bitfields.setMarginBeforeQuirk(b); }
- void setMarginAfterQuirk(bool b = true) { m_bitfields.setMarginAfterQuirk(b); }
-
// When performing a global document tear-down, the renderer of the document is cleared. We use this
// as a hook to detect the case of document destruction and don't waste time doing unnecessary work.
bool documentBeingDestroyed() const;
@@ -943,7 +968,7 @@ public:
// return true if this object requires a new stacking context
bool createsGroup() const { return isTransparent() || hasMask() || hasFilter() || hasBlendMode(); }
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&) { };
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& /* additionalOffset */, const RenderLayerModelObject* /* paintContainer */ = 0) { };
LayoutRect absoluteOutlineBounds() const
{
@@ -967,8 +992,8 @@ protected:
void drawLineForBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, BoxSide,
Color, EBorderStyle, int adjbw1, int adjbw2, bool antialias = false);
- void paintFocusRing(GraphicsContext*, const LayoutPoint&, RenderStyle*);
- void paintOutline(GraphicsContext*, const LayoutRect&);
+ void paintFocusRing(PaintInfo&, const LayoutPoint&, RenderStyle*);
+ void paintOutline(PaintInfo&, const LayoutRect&);
void addPDFURLRect(GraphicsContext*, const LayoutRect&);
virtual LayoutRect viewRect() const;
@@ -984,10 +1009,16 @@ protected:
virtual void insertedIntoTree();
virtual void willBeRemovedFromTree();
+ void setDocumentForAnonymous(Document* document) { ASSERT(isAnonymous()); m_node = document; }
+
private:
+ RenderFlowThread* locateFlowThreadContainingBlock() const;
void removeFromRenderFlowThread();
void removeFromRenderFlowThreadRecursive(RenderFlowThread*);
+ bool shouldRepaintForStyleDifference(StyleDifference) const;
+ bool hasImmediateNonWhitespaceTextChild() const;
+
RenderStyle* cachedFirstLineStyle() const;
StyleDifference adjustStyleDifference(StyleDifference, unsigned contextSensitiveProperties) const;
@@ -1020,6 +1051,13 @@ private:
void set##Name(bool name) { m_##name = name; }\
class RenderObjectBitfields {
+ enum PositionedState {
+ IsStaticallyPositioned = 0,
+ IsRelativelyPositioned = 1,
+ IsOutOfFlowPositioned = 2,
+ IsStickyPositioned = 3
+ };
+
public:
RenderObjectBitfields(Node* node)
: m_needsLayout(false)
@@ -1029,11 +1067,7 @@ private:
, m_needsSimplifiedNormalFlowLayout(false)
, m_preferredLogicalWidthsDirty(false)
, m_floating(false)
- , m_positioned(false)
- , m_relPositioned(false)
- , m_stickyPositioned(false)
- , m_paintBackground(false)
- , m_isAnonymous(node == node->document())
+ , m_isAnonymous(!node)
, m_isText(false)
, m_isBox(false)
, m_isInline(true)
@@ -1046,16 +1080,16 @@ private:
, m_hasReflection(false)
, m_hasCounterNodeMap(false)
, m_everHadLayout(false)
- , m_inRenderFlowThread(false)
, m_childrenInline(false)
- , m_marginBeforeQuirk(false)
- , m_marginAfterQuirk(false)
, m_hasColumns(false)
+ , m_positionedState(IsStaticallyPositioned)
, m_selectionState(SelectionNone)
+ , m_flowThreadState(NotInsideFlowThread)
+ , m_boxDecorationState(NoBoxDecorations)
{
}
- // 32 bits have been used here. THERE ARE NO FREE BITS AVAILABLE.
+ // 31 bits have been used here. There is one bit available.
ADD_BOOLEAN_BITFIELD(needsLayout, NeedsLayout);
ADD_BOOLEAN_BITFIELD(needsPositionedMovementLayout, NeedsPositionedMovementLayout);
ADD_BOOLEAN_BITFIELD(normalChildNeedsLayout, NormalChildNeedsLayout);
@@ -1064,12 +1098,6 @@ private:
ADD_BOOLEAN_BITFIELD(preferredLogicalWidthsDirty, PreferredLogicalWidthsDirty);
ADD_BOOLEAN_BITFIELD(floating, Floating);
- ADD_BOOLEAN_BITFIELD(positioned, Positioned);
- ADD_BOOLEAN_BITFIELD(relPositioned, RelPositioned);
- ADD_BOOLEAN_BITFIELD(stickyPositioned, StickyPositioned);
- ADD_BOOLEAN_BITFIELD(paintBackground, PaintBackground); // if the box has something to paint in the
- // background painting phase (background, border, etc)
-
ADD_BOOLEAN_BITFIELD(isAnonymous, IsAnonymous);
ADD_BOOLEAN_BITFIELD(isText, IsText);
ADD_BOOLEAN_BITFIELD(isBox, IsBox);
@@ -1086,22 +1114,37 @@ private:
ADD_BOOLEAN_BITFIELD(hasCounterNodeMap, HasCounterNodeMap);
ADD_BOOLEAN_BITFIELD(everHadLayout, EverHadLayout);
- // These bitfields are moved here from subclasses to pack them together.
- // from RenderFlowThread
- ADD_BOOLEAN_BITFIELD(inRenderFlowThread, InRenderFlowThread);
-
// from RenderBlock
ADD_BOOLEAN_BITFIELD(childrenInline, ChildrenInline);
- ADD_BOOLEAN_BITFIELD(marginBeforeQuirk, MarginBeforeQuirk);
- ADD_BOOLEAN_BITFIELD(marginAfterQuirk, MarginAfterQuirk);
ADD_BOOLEAN_BITFIELD(hasColumns, HasColumns);
private:
+ unsigned m_positionedState : 2; // PositionedState
unsigned m_selectionState : 3; // SelectionState
+ unsigned m_flowThreadState : 2; // FlowThreadState
+ unsigned m_boxDecorationState : 2; // BoxDecorationState
public:
+ bool isOutOfFlowPositioned() const { return m_positionedState == IsOutOfFlowPositioned; }
+ bool isRelPositioned() const { return m_positionedState == IsRelativelyPositioned; }
+ bool isStickyPositioned() const { return m_positionedState == IsStickyPositioned; }
+ bool isPositioned() const { return m_positionedState != IsStaticallyPositioned; }
+
+ void setPositionedState(int positionState)
+ {
+ // This mask maps FixedPosition and AbsolutePosition to IsOutOfFlowPositioned, saving one bit.
+ m_positionedState = static_cast<PositionedState>(positionState & 0x3);
+ }
+ void clearPositionedState() { m_positionedState = StaticPosition; }
+
ALWAYS_INLINE SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); }
ALWAYS_INLINE void setSelectionState(SelectionState selectionState) { m_selectionState = selectionState; }
+
+ ALWAYS_INLINE FlowThreadState flowThreadState() const { return static_cast<FlowThreadState>(m_flowThreadState); }
+ ALWAYS_INLINE void setFlowThreadState(FlowThreadState flowThreadState) { m_flowThreadState = flowThreadState; }
+
+ ALWAYS_INLINE BoxDecorationState boxDecorationState() const { return static_cast<BoxDecorationState>(m_boxDecorationState); }
+ ALWAYS_INLINE void setBoxDecorationState(BoxDecorationState boxDecorationState) { m_boxDecorationState = boxDecorationState; }
};
#undef ADD_BOOLEAN_BITFIELD
@@ -1112,13 +1155,13 @@ private:
void setNormalChildNeedsLayout(bool b) { m_bitfields.setNormalChildNeedsLayout(b); }
void setPosChildNeedsLayout(bool b) { m_bitfields.setPosChildNeedsLayout(b); }
void setNeedsSimplifiedNormalFlowLayout(bool b) { m_bitfields.setNeedsSimplifiedNormalFlowLayout(b); }
- void setPaintBackground(bool b) { m_bitfields.setPaintBackground(b); }
void setIsDragging(bool b) { m_bitfields.setIsDragging(b); }
void setEverHadLayout(bool b) { m_bitfields.setEverHadLayout(b); }
private:
// Store state between styleWillChange and styleDidChange
static bool s_affectsParentBlock;
+ static bool s_noLongerAffectsParentBlock;
};
inline bool RenderObject::documentBeingDestroyed() const
@@ -1192,15 +1235,19 @@ inline void RenderObject::setChildNeedsLayout(bool childNeedsLayout, MarkingBeha
}
}
-inline void RenderObject::setNeedsPositionedMovementLayout()
+inline void RenderObject::setNeedsPositionedMovementLayout(const RenderStyle* oldStyle)
{
bool alreadyNeededLayout = needsPositionedMovementLayout();
setNeedsPositionedMovementLayout(true);
ASSERT(!isSetNeedsLayoutForbidden());
if (!alreadyNeededLayout) {
markContainingBlocksForLayout();
- if (hasLayer())
- setLayerNeedsFullRepaintForPositionedMovementLayout();
+ if (hasLayer()) {
+ if (oldStyle && m_style->diffRequiresRepaint(oldStyle))
+ setLayerNeedsFullRepaint();
+ else
+ setLayerNeedsFullRepaintForPositionedMovementLayout();
+ }
}
}
@@ -1248,15 +1295,31 @@ inline void RenderObject::setSelectionStateIfNeeded(SelectionState state)
setSelectionState(state);
}
-inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
+inline void RenderObject::setHasBoxDecorations(bool b)
{
-#if !ENABLE(3D_RENDERING)
- UNUSED_PARAM(has3DRendering);
- matrix.makeAffine();
-#else
- if (!has3DRendering)
- matrix.makeAffine();
-#endif
+ if (!b) {
+ m_bitfields.setBoxDecorationState(NoBoxDecorations);
+ return;
+ }
+ if (hasBoxDecorations())
+ return;
+ m_bitfields.setBoxDecorationState(HasBoxDecorationsAndBackgroundObscurationStatusInvalid);
+}
+
+inline void RenderObject::invalidateBackgroundObscurationStatus()
+{
+ if (!hasBoxDecorations())
+ return;
+ m_bitfields.setBoxDecorationState(HasBoxDecorationsAndBackgroundObscurationStatusInvalid);
+}
+
+inline bool RenderObject::backgroundIsKnownToBeObscured()
+{
+ if (m_bitfields.boxDecorationState() == HasBoxDecorationsAndBackgroundObscurationStatusInvalid) {
+ BoxDecorationState boxDecorationState = computeBackgroundIsKnownToBeObscured() ? HasBoxDecorationsAndBackgroundIsKnownToBeObscured : HasBoxDecorationsAndBackgroundMayBeVisible;
+ m_bitfields.setBoxDecorationState(boxDecorationState);
+ }
+ return m_bitfields.boxDecorationState() == HasBoxDecorationsAndBackgroundIsKnownToBeObscured;
}
inline int adjustForAbsoluteZoom(int value, RenderObject* renderer)
@@ -1264,6 +1327,13 @@ inline int adjustForAbsoluteZoom(int value, RenderObject* renderer)
return adjustForAbsoluteZoom(value, renderer->style());
}
+#if ENABLE(SUBPIXEL_LAYOUT)
+inline LayoutUnit adjustLayoutUnitForAbsoluteZoom(LayoutUnit value, RenderObject* renderer)
+{
+ return adjustLayoutUnitForAbsoluteZoom(value, renderer->style());
+}
+#endif
+
inline void adjustFloatQuadForAbsoluteZoom(FloatQuad& quad, RenderObject* renderer)
{
float zoom = renderer->style()->effectiveZoom();
diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp
index e2a95a207..9445df88f 100644
--- a/Source/WebCore/rendering/RenderObjectChildList.cpp
+++ b/Source/WebCore/rendering/RenderObjectChildList.cpp
@@ -28,20 +28,13 @@
#include "RenderObjectChildList.h"
#include "AXObjectCache.h"
-#include "ContentData.h"
-#include "RenderBlock.h"
#include "RenderCounter.h"
-#include "RenderLayer.h"
-#include "RenderListItem.h"
-#include "RenderNamedFlowThread.h"
-#include "RenderRegion.h"
+#include "RenderObject.h"
#include "RenderStyle.h"
#include "RenderView.h"
namespace WebCore {
-bool RenderObjectChildList::s_enableUpdateBeforeAfterContent = true;
-
void RenderObjectChildList::destroyLeftoverChildren()
{
while (firstChild()) {
@@ -113,346 +106,64 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render
// rendererRemovedFromTree walks the whole subtree. We can improve performance
// by skipping this step when destroying the entire tree.
- if (!owner->documentBeingDestroyed()) {
+ if (!owner->documentBeingDestroyed())
RenderCounter::rendererRemovedFromTree(oldChild);
- }
- if (AXObjectCache::accessibilityEnabled())
- owner->document()->axObjectCache()->childrenChanged(owner);
+ if (AXObjectCache* cache = owner->document()->existingAXObjectCache())
+ cache->childrenChanged(owner);
return oldChild;
}
-void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool notifyRenderer)
+void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* newChild, RenderObject* beforeChild, bool notifyRenderer)
{
- ASSERT(newChild->parent() == 0);
+ ASSERT(!newChild->parent());
ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
- newChild->setParent(owner);
- RenderObject* lChild = lastChild();
-
- if (lChild) {
- newChild->setPreviousSibling(lChild);
- lChild->setNextSibling(newChild);
- } else
- setFirstChild(newChild);
-
- setLastChild(newChild);
-
- if (!owner->documentBeingDestroyed() && notifyRenderer)
- newChild->insertedIntoTree();
-
- if (!owner->documentBeingDestroyed()) {
- RenderCounter::rendererSubtreeAttached(newChild);
- }
- newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
- if (!owner->normalChildNeedsLayout())
- owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
-
- if (AXObjectCache::accessibilityEnabled())
- owner->document()->axObjectCache()->childrenChanged(owner);
-}
-
-void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool notifyRenderer)
-{
- if (!beforeChild) {
- appendChildNode(owner, child, notifyRenderer);
- return;
- }
-
- ASSERT(!child->parent());
- while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
+ while (beforeChild && beforeChild->parent() && beforeChild->parent() != owner)
beforeChild = beforeChild->parent();
- ASSERT(beforeChild->parent() == owner);
-
- ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
-
- if (beforeChild == firstChild())
- setFirstChild(child);
-
- RenderObject* prev = beforeChild->previousSibling();
- child->setNextSibling(beforeChild);
- beforeChild->setPreviousSibling(child);
- if (prev)
- prev->setNextSibling(child);
- child->setPreviousSibling(prev);
-
- child->setParent(owner);
-
- if (!owner->documentBeingDestroyed() && notifyRenderer)
- child->insertedIntoTree();
-
- if (!owner->documentBeingDestroyed()) {
- RenderCounter::rendererSubtreeAttached(child);
- }
- child->setNeedsLayoutAndPrefWidthsRecalc();
- if (!owner->normalChildNeedsLayout())
- owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
-
- if (AXObjectCache::accessibilityEnabled())
- owner->document()->axObjectCache()->childrenChanged(owner);
-}
-
-static RenderObject* findBeforeAfterParent(RenderObject* object)
-{
- // Only table parts and flex-boxes need to search for the :before or :after parent
- // FIXME: We could likely get away without this check and always look for the right parent.
- if (!(object->isTable() || object->isTableSection() || object->isTableRow() || object->isFlexibleBoxIncludingDeprecated()))
- return object;
-
- // If there is a :first-letter style applied on the :before or :after content,
- // then we want the parent of the first-letter block
- RenderObject* beforeAfterParent = object;
- while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())
- && (beforeAfterParent->style()->styleType() != FIRST_LETTER))
- beforeAfterParent = beforeAfterParent->firstChild();
-
- return beforeAfterParent ? beforeAfterParent->parent() : 0;
-}
-
-RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
-{
- // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
- // Therefore we should skip these generated run-ins when checking our immediate children.
- // If we don't find our :before child immediately, then we should check if we own a
- // generated inline run-in in the next level of children.
- RenderObject* first = const_cast<RenderObject*>(owner);
- do {
- first = first->firstChild();
- // Skip list markers and generated run-ins.
- while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn())))
- first = first->nextInPreOrderAfterChildren(owner);
- } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
-
- if (!first)
- return 0;
-
- if (first->isBeforeContent())
- return first;
-
- // Check for a possible generated run-in, using run-in positioning rules.
- first = owner->firstChild();
- if (!first->isRenderBlock())
- return 0;
-
- first = first->firstChild();
- // We still need to skip any list markers that could exist before the run-in.
- while (first && first->isListMarker())
- first = first->nextSibling();
- if (first && first->isBeforeContent() && first->isRenderInline() && first->isRunIn())
- return first;
-
- return 0;
-}
-
-RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const
-{
- RenderObject* last = const_cast<RenderObject*>(owner);
- do {
- last = last->lastChild();
- } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
- if (last && !last->isAfterContent())
- return 0;
- return last;
-}
-void RenderObjectChildList::updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle)
-{
- if (!child || child->style()->styleType() != type)
- return;
-
- // We have generated content present still. We want to walk this content and update our
- // style information with the new pseudo-element style.
- child->setStyle(pseudoElementStyle);
-
- RenderObject* beforeAfterParent = findBeforeAfterParent(child);
- if (!beforeAfterParent)
- return;
-
- // When beforeAfterParent is not equal to child (e.g. in tables),
- // we need to create new styles inheriting from pseudoElementStyle
- // on all the intermediate parents (leaving their display same).
- if (beforeAfterParent != child) {
- RenderObject* curr = beforeAfterParent;
- while (curr && curr != child) {
- ASSERT(curr->isAnonymous());
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(pseudoElementStyle);
- newStyle->setDisplay(curr->style()->display());
- newStyle->setStyleType(curr->style()->styleType());
- curr->setStyle(newStyle);
- curr = curr->parent();
- }
- }
-
- // Note that if we ever support additional types of generated content (which should be way off
- // in the future), this code will need to be patched.
- for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
- if (genChild->isText())
- // Generated text content is a child whose style also needs to be set to the pseudo-element style.
- genChild->setStyle(pseudoElementStyle);
- else if (genChild->isImage()) {
- // Images get an empty style that inherits from the pseudo.
- RefPtr<RenderStyle> style = RenderStyle::create();
- style->inheritFrom(pseudoElementStyle);
- genChild->setStyle(style.release());
- } else {
- // RenderListItem may insert a list marker here. We do not need to care about this case.
- // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
- ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
- }
- }
-}
-
-static RenderObject* ensureBeforeAfterContainer(RenderObject* owner, PseudoId type, RenderStyle* pseudoElementStyle, Node* generatingNode, RenderObject* insertBefore)
-{
- // Make a generated box that might be any display type now that we are able to drill down into children
- // to find the original content properly.
- RenderObject* generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
- ASSERT(generatingNode); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements.
- generatedContentContainer->setNode(generatingNode); // This allows access to the generatingNode.
- generatedContentContainer->setStyle(pseudoElementStyle);
- if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
- // The generated content container is not allowed here -> abort.
- generatedContentContainer->destroy();
- return 0;
- }
-
- // When we don't have a first child and are part of a continuation chain,
- // insertBefore is incorrectly set to zero above, which causes the :before
- // child to end up at the end of continuation chain.
- // See https://bugs.webkit.org/show_bug.cgi?id=78380.
- if (!insertBefore && type == BEFORE && owner->virtualContinuation())
- owner->addChildIgnoringContinuation(generatedContentContainer, 0);
- else
- owner->addChild(generatedContentContainer, insertBefore);
-
- return generatedContentContainer;
-}
-
-void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
-{
- // Double check that the document did in fact use generated content rules. Otherwise we should not have been called.
- ASSERT(owner->document()->styleSheetCollection()->usesBeforeAfterRules());
-
- // In CSS2, before/after pseudo-content cannot nest. Check this first.
- if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
- return;
- if (!s_enableUpdateBeforeAfterContent)
- return;
-
- if (!styledObject)
- styledObject = owner;
-
- RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
- RenderObject* child;
- switch (type) {
- case BEFORE:
- child = beforePseudoElementRenderer(owner);
- break;
- case AFTER:
- child = afterPseudoElementRenderer(owner);
- break;
- default:
+ // This should never happen, but if it does prevent render tree corruption
+ // where child->parent() ends up being owner but child->nextSibling()->parent()
+ // is not owner.
+ if (beforeChild && beforeChild->parent() != owner) {
ASSERT_NOT_REACHED();
return;
}
- // Whether or not we currently have generated content attached.
- bool oldContentPresent = child;
-
- // Whether or not we now want generated content.
- bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
-
- // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
- // :after content and not :before content.
- if (newContentWanted && type == BEFORE && owner->isElementContinuation())
- newContentWanted = false;
-
- // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
- // then we don't generate the :after content.
- if (newContentWanted && type == AFTER && owner->virtualContinuation())
- newContentWanted = false;
-
- // If we don't want generated content any longer, or if we have generated content, but it's no longer
- // identical to the new content data we want to build render objects for, then we nuke all
- // of the old generated content.
- if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) {
- // Nuke the child.
- if (child->style()->styleType() == type) {
- oldContentPresent = false;
- child->destroy();
- child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
- }
- }
-
- // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
- // have no generated content and can now return.
- if (!newContentWanted)
- return;
+ newChild->setParent(owner);
- if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && !pseudoElementStyle->isFloating() &&
- !pseudoElementStyle->hasOutOfFlowPosition())
- // According to the CSS2 spec (the end of section 12.1), the only allowed
- // display values for the pseudo style are NONE and INLINE for inline flows.
- // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
- // For now we at least relax the restriction to allow all inline types like inline-block
- // and inline-table.
- pseudoElementStyle->setDisplay(INLINE);
+ if (firstChild() == beforeChild)
+ setFirstChild(newChild);
- if (oldContentPresent) {
- updateBeforeAfterStyle(child, type, pseudoElementStyle);
- return; // We've updated the generated content. That's all we needed to do.
+ if (beforeChild) {
+ RenderObject* previousSibling = beforeChild->previousSibling();
+ if (previousSibling)
+ previousSibling->setNextSibling(newChild);
+ newChild->setPreviousSibling(previousSibling);
+ newChild->setNextSibling(beforeChild);
+ beforeChild->setPreviousSibling(newChild);
+ } else {
+ if (lastChild())
+ lastChild()->setNextSibling(newChild);
+ newChild->setPreviousSibling(lastChild());
+ setLastChild(newChild);
}
-
- RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
- if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) {
- // We are going to add the "before" element. We have to check whether the "insertBefore" element
- // is an anonymous block with inline children. If it is, then we should insert the "before" element
- // before the first inline child of the anonymous block, otherwise we will end up with the "before"
- // element in a different block. We do this only when the anonymous block has children, otherwise
- // we end up with the before element in a wrong block.
- insertBefore = insertBefore->firstChild();
- }
-
- // Nothing goes before the intruded run-in, not even generated content.
- if (insertBefore && insertBefore->isRunIn() && owner->isRenderBlock()
- && toRenderBlock(owner)->runInIsPlacedIntoSiblingBlock(insertBefore))
- insertBefore = insertBefore->nextSibling();
-
- // Generated content consists of a single container that houses multiple children (specified
- // by the content property). This generated content container gets the pseudo-element style set on it.
- // For pseudo-elements that are regions, the container is the RenderRegion.
- RenderObject* generatedContentContainer = 0;
- if (!pseudoElementStyle->regionThread().isEmpty())
- generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore);
- else {
- // Walk our list of generated content and create render objects for each.
- for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
- RenderObject* renderer = content->createRenderer(owner->document(), pseudoElementStyle);
+ if (!owner->documentBeingDestroyed() && notifyRenderer)
+ newChild->insertedIntoTree();
- if (!generatedContentContainer) {
- generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore);
- if (!generatedContentContainer) {
- renderer->destroy();
- return;
- }
- }
- if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
- generatedContentContainer->addChild(renderer);
- else
- renderer->destroy();
- }
+ if (!owner->documentBeingDestroyed()) {
+ RenderCounter::rendererSubtreeAttached(newChild);
}
- if (!generatedContentContainer)
- return;
+ newChild->setNeedsLayoutAndPrefWidthsRecalc();
+ owner->setPreferredLogicalWidthsDirty(true);
+ if (!owner->normalChildNeedsLayout())
+ owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
- // Handle placement of run-ins. We do the run-in placement at the end since generatedContentContainer can get destroyed.
- RenderObject* generatedContentContainerImmediateParent = generatedContentContainer->parent();
- if (generatedContentContainerImmediateParent->isRenderBlock())
- toRenderBlock(generatedContentContainerImmediateParent)->placeRunInIfNeeded(generatedContentContainer, PlaceGeneratedRunIn);
+ if (AXObjectCache* cache = owner->document()->axObjectCache())
+ cache->childrenChanged(owner);
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderObjectChildList.h b/Source/WebCore/rendering/RenderObjectChildList.h
index 3f606db8d..b2804ec56 100644
--- a/Source/WebCore/rendering/RenderObjectChildList.h
+++ b/Source/WebCore/rendering/RenderObjectChildList.h
@@ -26,13 +26,11 @@
#ifndef RenderObjectChildList_h
#define RenderObjectChildList_h
-#include "RenderStyleConstants.h"
#include <wtf/Forward.h>
namespace WebCore {
class RenderObject;
-class RenderStyle;
class RenderObjectChildList {
public:
@@ -44,28 +42,22 @@ public:
RenderObject* firstChild() const { return m_firstChild; }
RenderObject* lastChild() const { return m_lastChild; }
-
+
// FIXME: Temporary while RenderBox still exists. Eventually this will just happen during insert/append/remove methods on the child list, and nobody
// will need to manipulate firstChild or lastChild directly.
void setFirstChild(RenderObject* child) { m_firstChild = child; }
void setLastChild(RenderObject* child) { m_lastChild = child; }
-
+
void destroyLeftoverChildren();
RenderObject* removeChildNode(RenderObject* owner, RenderObject*, bool notifyRenderer = true);
- void appendChildNode(RenderObject* owner, RenderObject*, bool notifyRenderer = true);
- void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool notifyRenderer = true);
-
- void updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject = 0);
- RenderObject* beforePseudoElementRenderer(const RenderObject* owner) const;
- RenderObject* afterPseudoElementRenderer(const RenderObject* owner) const;
-
-public:
- static bool s_enableUpdateBeforeAfterContent;
+ void insertChildNode(RenderObject* owner, RenderObject* newChild, RenderObject* beforeChild, bool notifyRenderer = true);
+ void appendChildNode(RenderObject* owner, RenderObject* newChild, bool notifyRenderer = true)
+ {
+ insertChildNode(owner, newChild, 0, notifyRenderer);
+ }
private:
- void updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle);
-
RenderObject* m_firstChild;
RenderObject* m_lastChild;
};
diff --git a/Source/WebCore/rendering/RenderOverflow.h b/Source/WebCore/rendering/RenderOverflow.h
index e6b85e9f4..2430b882d 100644
--- a/Source/WebCore/rendering/RenderOverflow.h
+++ b/Source/WebCore/rendering/RenderOverflow.h
@@ -48,16 +48,6 @@ public:
const LayoutRect layoutOverflowRect() const { return m_layoutOverflow; }
const LayoutRect visualOverflowRect() const { return m_visualOverflow; }
-
- void setMinYLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setY(overflow); }
- void setMaxYLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setHeight(overflow - m_layoutOverflow.y()); }
- void setMinXLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setX(overflow); }
- void setMaxXLayoutOverflow(LayoutUnit overflow) { m_layoutOverflow.setWidth(overflow - m_layoutOverflow.x()); }
-
- void setMinYVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setY(overflow); }
- void setMaxYVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setHeight(overflow - m_layoutOverflow.y()); }
- void setMinXVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setX(overflow); }
- void setMaxXVisualOverflow(LayoutUnit overflow) { m_visualOverflow.setWidth(overflow - m_layoutOverflow.x()); }
void move(LayoutUnit dx, LayoutUnit dy);
@@ -67,9 +57,14 @@ public:
void setLayoutOverflow(const LayoutRect&);
void setVisualOverflow(const LayoutRect&);
+ LayoutUnit layoutClientAfterEdge() const { return m_layoutClientAfterEdge; }
+ void setLayoutClientAfterEdge(LayoutUnit clientAfterEdge) { m_layoutClientAfterEdge = clientAfterEdge; }
+
private:
LayoutRect m_layoutOverflow;
LayoutRect m_visualOverflow;
+
+ LayoutUnit m_layoutClientAfterEdge;
};
inline void RenderOverflow::move(LayoutUnit dx, LayoutUnit dy)
diff --git a/Source/WebCore/rendering/RenderPart.cpp b/Source/WebCore/rendering/RenderPart.cpp
index 92fcf5d85..6a269efb1 100644
--- a/Source/WebCore/rendering/RenderPart.cpp
+++ b/Source/WebCore/rendering/RenderPart.cpp
@@ -28,7 +28,9 @@
#include "Frame.h"
#include "FrameView.h"
#include "HTMLFrameElementBase.h"
+#include "HitTestResult.h"
#include "PluginViewBase.h"
+#include "RenderLayer.h"
#include "RenderSVGRoot.h"
#include "RenderView.h"
@@ -78,13 +80,13 @@ bool RenderPart::requiresAcceleratedCompositing() const
// renderer and the plugin has a layer, then we need a layer. Second, if this is
// a renderer with a contentDocument and that document needs a layer, then we need
// a layer.
- if (widget() && widget()->isPluginViewBase() && static_cast<PluginViewBase*>(widget())->platformLayer())
+ if (widget() && widget()->isPluginViewBase() && toPluginViewBase(widget())->platformLayer())
return true;
if (!node() || !node()->isFrameOwnerElement())
return false;
- HTMLFrameOwnerElement* element = static_cast<HTMLFrameOwnerElement*>(node());
+ HTMLFrameOwnerElement* element = toFrameOwnerElement(node());
if (Document* contentDocument = element->contentDocument()) {
if (RenderView* view = contentDocument->renderView())
return view->usesCompositing();
@@ -105,7 +107,36 @@ RenderBox* RenderPart::embeddedContentBox() const
{
if (!node() || !widget() || !widget()->isFrameView())
return 0;
- return static_cast<FrameView*>(widget())->embeddedContentBox();
+ return toFrameView(widget())->embeddedContentBox();
+}
+
+bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
+{
+ if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameContent())
+ return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
+
+ FrameView* childFrameView = toFrameView(widget());
+ RenderView* childRoot = childFrameView->renderView();
+
+ if (childRoot) {
+ LayoutPoint adjustedLocation = accumulatedOffset + location();
+ LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - childFrameView->scrollOffset();
+ HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
+ HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildFrameHitTest);
+ HitTestResult childFrameResult(newHitTestLocation);
+
+ bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTestLocation, childFrameResult);
+
+ if (newHitTestLocation.isRectBasedTest())
+ result.append(childFrameResult);
+ else if (isInsideChildFrame)
+ result = childFrameResult;
+
+ if (isInsideChildFrame)
+ return true;
+ }
+
+ return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
}
}
diff --git a/Source/WebCore/rendering/RenderPart.h b/Source/WebCore/rendering/RenderPart.h
index dffbbd54c..538b0f973 100644
--- a/Source/WebCore/rendering/RenderPart.h
+++ b/Source/WebCore/rendering/RenderPart.h
@@ -30,7 +30,7 @@ namespace WebCore {
// Renderer for frames via RenderFrameBase, and plug-ins via RenderEmbeddedObject.
class RenderPart : public RenderWidget {
public:
- RenderPart(Element*);
+ explicit RenderPart(Element*);
virtual ~RenderPart();
virtual void setWidget(PassRefPtr<Widget>);
@@ -43,6 +43,8 @@ public:
virtual bool needsPreferredWidthsRecalculation() const;
virtual RenderBox* embeddedContentBox() const;
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
+
protected:
#if USE(ACCELERATED_COMPOSITING)
virtual bool requiresLayer() const;
@@ -55,7 +57,7 @@ private:
inline RenderPart* toRenderPart(RenderObject* object)
{
- ASSERT(!object || object->isRenderPart());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderPart());
return static_cast<RenderPart*>(object);
}
diff --git a/Source/WebCore/rendering/RenderProgress.cpp b/Source/WebCore/rendering/RenderProgress.cpp
index 7243e96dc..ad1b338ad 100644
--- a/Source/WebCore/rendering/RenderProgress.cpp
+++ b/Source/WebCore/rendering/RenderProgress.cpp
@@ -19,9 +19,9 @@
*/
#include "config.h"
+#if ENABLE(PROGRESS_ELEMENT)
#include "RenderProgress.h"
-#if ENABLE(PROGRESS_ELEMENT)
#include "HTMLNames.h"
#include "HTMLProgressElement.h"
#include "PaintInfo.h"
@@ -56,6 +56,7 @@ void RenderProgress::updateFromElement()
m_position = element->position();
updateAnimationState();
+ repaint();
RenderBlock::updateFromElement();
}
@@ -91,7 +92,6 @@ void RenderProgress::updateAnimationState()
if (animating == m_animating)
return;
- repaint();
m_animating = animating;
if (m_animating) {
m_animationStartTime = currentTime();
diff --git a/Source/WebCore/rendering/RenderProgress.h b/Source/WebCore/rendering/RenderProgress.h
index 6835e48c8..1428d838b 100644
--- a/Source/WebCore/rendering/RenderProgress.h
+++ b/Source/WebCore/rendering/RenderProgress.h
@@ -30,7 +30,7 @@ class HTMLProgressElement;
class RenderProgress : public RenderBlock {
public:
- RenderProgress(HTMLElement*);
+ explicit RenderProgress(HTMLElement*);
virtual ~RenderProgress();
double position() const { return m_position; }
@@ -61,7 +61,7 @@ private:
inline RenderProgress* toRenderProgress(RenderObject* object)
{
- ASSERT(!object || object->isProgress());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isProgress());
return static_cast<RenderProgress*>(object);
}
diff --git a/Source/WebCore/rendering/RenderQuote.cpp b/Source/WebCore/rendering/RenderQuote.cpp
index da16df5aa..48f1f097e 100644
--- a/Source/WebCore/rendering/RenderQuote.cpp
+++ b/Source/WebCore/rendering/RenderQuote.cpp
@@ -1,6 +1,7 @@
-/**
+/*
* Copyright (C) 2011 Nokia Inc. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -22,27 +23,27 @@
#include "config.h"
#include "RenderQuote.h"
-#include "RenderView.h"
-#include <wtf/text/AtomicString.h>
+#include "QuotesData.h"
-#define U(x) ((const UChar*)L##x)
+using namespace WTF::Unicode;
namespace WebCore {
RenderQuote::RenderQuote(Document* node, QuoteType quote)
: RenderText(node, StringImpl::empty())
, m_type(quote)
- , m_depth(0)
+ , m_depth(-1)
, m_next(0)
, m_previous(0)
- , m_attached(false)
+ , m_isAttached(false)
{
}
RenderQuote::~RenderQuote()
{
- ASSERT(!m_attached);
- ASSERT(!m_next && !m_previous);
+ ASSERT(!m_isAttached);
+ ASSERT(!m_next);
+ ASSERT(!m_previous);
}
void RenderQuote::willBeDestroyed()
@@ -54,252 +55,332 @@ void RenderQuote::willBeDestroyed()
void RenderQuote::willBeRemovedFromTree()
{
RenderText::willBeRemovedFromTree();
-
detachQuote();
}
-typedef HashMap<AtomicString, const QuotesData*, CaseFoldingHash> QuotesMap;
+void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderText::styleDidChange(diff, oldStyle);
+ setText(originalText());
+}
+
+const unsigned maxDistinctQuoteCharacters = 16;
+
+#if !ASSERT_DISABLED
-static const QuotesMap& quotesDataLanguageMap()
+static void checkNumberOfDistinctQuoteCharacters(UChar character)
{
- DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ());
- if (staticQuotesMap.size())
- return staticQuotesMap;
+ ASSERT(character);
+ static UChar distinctQuoteCharacters[maxDistinctQuoteCharacters];
+ for (unsigned i = 0; i < maxDistinctQuoteCharacters; ++i) {
+ if (distinctQuoteCharacters[i] == character)
+ return;
+ if (!distinctQuoteCharacters[i]) {
+ distinctQuoteCharacters[i] = character;
+ return;
+ }
+ }
+ ASSERT_NOT_REACHED();
+}
- // Table of quotes from http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#quotes
- #define QUOTES_LANG(lang, o1, c1, o2, c2) staticQuotesMap.set(lang, QuotesData::create(U(o1), U(c1), U(o2), U(c2)).leakRef())
- QUOTES_LANG("af", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("agq", "\x201e", "\x201d", "\x201a", "\x2019");
- QUOTES_LANG("ak", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("am", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("ar", "\x201d", "\x201c", "\x2019", "\x2018");
- QUOTES_LANG("asa", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("az-Cyrl", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("bas", "\x00ab", "\x00bb", "\x201e", "\x201c");
- QUOTES_LANG("bem", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("bez", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("bg", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("bm", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("bn", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("br", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("brx", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("bs-Cyrl", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("ca", "\x201c", "\x201d", "\x00ab", "\x00bb");
- QUOTES_LANG("cgg", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("chr", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("cs", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("da", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("dav", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("de", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("de-CH", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("dje", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("dua", "\x00ab", "\x00bb", "\x2018", "\x2019");
- QUOTES_LANG("dyo", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("dz", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ebu", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ee", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("el", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("en", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("en-GB", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("es", "\x201c", "\x201d", "\x00ab", "\x00bb");
- QUOTES_LANG("et", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("eu", "\x201c", "\x201d", "\x00ab", "\x00bb");
- QUOTES_LANG("ewo", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("fa", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("ff", "\x201e", "\x201d", "\x201a", "\x2019");
- QUOTES_LANG("fi", "\x201d", "\x201d", "\x2019", "\x2019");
- QUOTES_LANG("fr", "\x00ab", "\x00bb", "\x00ab", "\x00bb");
- QUOTES_LANG("fr-CA", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("fr-CH", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("gsw", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("gu", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("guz", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ha", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("he", "\x0022", "\x0022", "\x0027", "\x0027");
- QUOTES_LANG("hi", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("hr", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("hu", "\x201e", "\x201d", "\x00bb", "\x00ab");
- QUOTES_LANG("id", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ig", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("it", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("ja", "\x300c", "\x300d", "\x300e", "\x300f");
- QUOTES_LANG("jgo", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("jmc", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("kab", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("kam", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("kde", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("kea", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("khq", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ki", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("kkj", "\x00ab", "\x00bb", "\x2039", "\x203a");
- QUOTES_LANG("kln", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("km", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("kn", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ko", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ksb", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ksf", "\x00ab", "\x00bb", "\x2018", "\x2019");
- QUOTES_LANG("lag", "\x201d", "\x201d", "\x2019", "\x2019");
- QUOTES_LANG("lg", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ln", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("lo", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("lt", "\x201e", "\x201c", "\x201e", "\x201c");
- QUOTES_LANG("lu", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("luo", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("luy", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("lv", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mas", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mer", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mfe", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mg", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("mgo", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mk", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("ml", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mr", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ms", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("mua", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("my", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("naq", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("nb", "\x00ab", "\x00bb", "\x2018", "\x2019");
- QUOTES_LANG("nd", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("nl", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("nmg", "\x201e", "\x201d", "\x00ab", "\x00bb");
- QUOTES_LANG("nn", "\x00ab", "\x00bb", "\x2018", "\x2019");
- QUOTES_LANG("nnh", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("nus", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("nyn", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("pl", "\x201e", "\x201d", "\x00ab", "\x00bb");
- QUOTES_LANG("pt", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("pt-PT", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("rn", "\x201d", "\x201d", "\x2019", "\x2019");
- QUOTES_LANG("ro", "\x201e", "\x201d", "\x00ab", "\x00bb");
- QUOTES_LANG("rof", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ru", "\x00ab", "\x00bb", "\x201e", "\x201c");
- QUOTES_LANG("rw", "\x00ab", "\x00bb", "\x2018", "\x2019");
- QUOTES_LANG("rwk", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("saq", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("sbp", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("seh", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ses", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("sg", "\x00ab", "\x00bb", "\x201c", "\x201d");
- QUOTES_LANG("shi", "\x00ab", "\x00bb", "\x201e", "\x201d");
- QUOTES_LANG("shi-Tfng", "\x00ab", "\x00bb", "\x201e", "\x201d");
- QUOTES_LANG("si", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("sk", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("sl", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("sn", "\x201d", "\x201d", "\x2019", "\x2019");
- QUOTES_LANG("so", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("sq", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("sr", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("sr-Latn", "\x201e", "\x201c", "\x201a", "\x2018");
- QUOTES_LANG("sv", "\x201d", "\x201d", "\x2019", "\x2019");
- QUOTES_LANG("sw", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("swc", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ta", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("te", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("teo", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("th", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("ti-ER", "\x2018", "\x2019", "\x201c", "\x201d");
- QUOTES_LANG("to", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("tr", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("twq", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("tzm", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("uk", "\x00ab", "\x00bb", "\x201e", "\x201c");
- QUOTES_LANG("ur", "\x201d", "\x201c", "\x2019", "\x2018");
- QUOTES_LANG("vai", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("vai-Latn", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("vi", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("vun", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("xh", "\x2018", "\x2019", "\x201c", "\x201d");
- QUOTES_LANG("xog", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("yav", "\x00ab", "\x00bb", "\x00ab", "\x00bb");
- QUOTES_LANG("yo", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("zh", "\x201c", "\x201d", "\x2018", "\x2019");
- QUOTES_LANG("zh-Hant", "\x300c", "\x300d", "\x300e", "\x300f");
- QUOTES_LANG("zu", "\x201c", "\x201d", "\x2018", "\x2019");
- #undef QUOTES_LANG
-
- return staticQuotesMap;
+#endif
+
+struct QuotesForLanguage {
+ const char* language;
+ UChar open1;
+ UChar close1;
+ UChar open2;
+ UChar close2;
+};
+
+static int quoteTableLanguageComparisonFunction(const void* a, const void* b)
+{
+ return strcmp(static_cast<const QuotesForLanguage*>(a)->language,
+ static_cast<const QuotesForLanguage*>(b)->language);
}
-static const QuotesData* basicQuotesData()
+static const QuotesForLanguage* quotesForLanguage(const String& language)
{
- // FIXME: The default quotes should be the fancy quotes for "en".
- static const QuotesData* staticBasicQuotes = QuotesData::create(U("\""), U("\""), U("'"), U("'")).leakRef();
- return staticBasicQuotes;
+ // Table of quotes from http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#quotes
+ static const QuotesForLanguage quoteTable[] = {
+ { "af", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "agq", 0x201e, 0x201d, 0x201a, 0x2019 },
+ { "ak", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "am", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "ar", 0x201d, 0x201c, 0x2019, 0x2018 },
+ { "asa", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "az-cyrl", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "bas", 0x00ab, 0x00bb, 0x201e, 0x201c },
+ { "bem", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "bez", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "bg", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "bm", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "bn", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "br", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "brx", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "bs-cyrl", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "ca", 0x201c, 0x201d, 0x00ab, 0x00bb },
+ { "cgg", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "chr", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "cs", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "da", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "dav", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "de", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "de-ch", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "dje", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "dua", 0x00ab, 0x00bb, 0x2018, 0x2019 },
+ { "dyo", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "dz", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ebu", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ee", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "el", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "en", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "en-gb", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "es", 0x201c, 0x201d, 0x00ab, 0x00bb },
+ { "et", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "eu", 0x201c, 0x201d, 0x00ab, 0x00bb },
+ { "ewo", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "fa", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "ff", 0x201e, 0x201d, 0x201a, 0x2019 },
+ { "fi", 0x201d, 0x201d, 0x2019, 0x2019 },
+ { "fr", 0x00ab, 0x00bb, 0x00ab, 0x00bb },
+ { "fr-ca", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "fr-ch", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "gsw", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "gu", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "guz", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ha", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "he", 0x0022, 0x0022, 0x0027, 0x0027 },
+ { "hi", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "hr", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "hu", 0x201e, 0x201d, 0x00bb, 0x00ab },
+ { "id", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ig", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "it", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "ja", 0x300c, 0x300d, 0x300e, 0x300f },
+ { "jgo", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "jmc", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "kab", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "kam", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "kde", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "kea", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "khq", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ki", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "kkj", 0x00ab, 0x00bb, 0x2039, 0x203a },
+ { "kln", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "km", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "kn", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ko", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ksb", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ksf", 0x00ab, 0x00bb, 0x2018, 0x2019 },
+ { "lag", 0x201d, 0x201d, 0x2019, 0x2019 },
+ { "lg", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ln", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "lo", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "lt", 0x201e, 0x201c, 0x201e, 0x201c },
+ { "lu", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "luo", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "luy", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "lv", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mas", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mer", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mfe", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mg", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "mgo", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mk", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "ml", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mr", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ms", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "mua", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "my", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "naq", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "nb", 0x00ab, 0x00bb, 0x2018, 0x2019 },
+ { "nd", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "nl", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "nmg", 0x201e, 0x201d, 0x00ab, 0x00bb },
+ { "nn", 0x00ab, 0x00bb, 0x2018, 0x2019 },
+ { "nnh", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "nus", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "nyn", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "pl", 0x201e, 0x201d, 0x00ab, 0x00bb },
+ { "pt", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "pt-pt", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "rn", 0x201d, 0x201d, 0x2019, 0x2019 },
+ { "ro", 0x201e, 0x201d, 0x00ab, 0x00bb },
+ { "rof", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ru", 0x00ab, 0x00bb, 0x201e, 0x201c },
+ { "rw", 0x00ab, 0x00bb, 0x2018, 0x2019 },
+ { "rwk", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "saq", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "sbp", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "seh", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ses", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "sg", 0x00ab, 0x00bb, 0x201c, 0x201d },
+ { "shi", 0x00ab, 0x00bb, 0x201e, 0x201d },
+ { "shi-tfng", 0x00ab, 0x00bb, 0x201e, 0x201d },
+ { "si", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "sk", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "sl", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "sn", 0x201d, 0x201d, 0x2019, 0x2019 },
+ { "so", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "sq", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "sr", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "sr-latn", 0x201e, 0x201c, 0x201a, 0x2018 },
+ { "sv", 0x201d, 0x201d, 0x2019, 0x2019 },
+ { "sw", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "swc", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ta", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "te", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "teo", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "th", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "ti-er", 0x2018, 0x2019, 0x201c, 0x201d },
+ { "to", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "tr", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "twq", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "tzm", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "uk", 0x00ab, 0x00bb, 0x201e, 0x201c },
+ { "ur", 0x201d, 0x201c, 0x2019, 0x2018 },
+ { "vai", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "vai-latn", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "vi", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "vun", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "xh", 0x2018, 0x2019, 0x201c, 0x201d },
+ { "xog", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "yav", 0x00ab, 0x00bb, 0x00ab, 0x00bb },
+ { "yo", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "zh", 0x201c, 0x201d, 0x2018, 0x2019 },
+ { "zh-hant", 0x300c, 0x300d, 0x300e, 0x300f },
+ { "zu", 0x201c, 0x201d, 0x2018, 0x2019 },
+ };
+
+ const unsigned maxLanguageLength = 8;
+
+#if !ASSERT_DISABLED
+ // One time check that the table meets the constraints that the code below relies on.
+
+ static bool didOneTimeCheck = false;
+ if (!didOneTimeCheck) {
+ didOneTimeCheck = true;
+
+ checkNumberOfDistinctQuoteCharacters(quotationMark);
+ checkNumberOfDistinctQuoteCharacters(apostrophe);
+
+ for (unsigned i = 0; i < WTF_ARRAY_LENGTH(quoteTable); ++i) {
+ ASSERT(strlen(quoteTable[i].language) <= maxLanguageLength);
+
+ if (i)
+ ASSERT(strcmp(quoteTable[i - 1].language, quoteTable[i].language) < 0);
+
+ for (unsigned j = 0; UChar character = quoteTable[i].language[j]; ++j)
+ ASSERT(isASCIILower(character) || character == '-');
+
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].open1);
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].close1);
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].open2);
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].close2);
+ }
+ }
+#endif
+
+ unsigned length = language.length();
+ if (!length || length > maxLanguageLength)
+ return 0;
+
+ char languageKeyBuffer[maxLanguageLength + 1];
+ for (unsigned i = 0; i < length; ++i) {
+ UChar character = toASCIILower(language[i]);
+ if (!(isASCIILower(character) || character == '-'))
+ return 0;
+ languageKeyBuffer[i] = static_cast<char>(character);
+ }
+ languageKeyBuffer[length] = 0;
+
+ QuotesForLanguage languageKey = { languageKeyBuffer, 0, 0, 0, 0 };
+
+ return static_cast<const QuotesForLanguage*>(bsearch(&languageKey,
+ quoteTable, WTF_ARRAY_LENGTH(quoteTable), sizeof(quoteTable[0]), quoteTableLanguageComparisonFunction));
}
-PassRefPtr<StringImpl> RenderQuote::originalText() const
+static StringImpl* stringForQuoteCharacter(UChar character)
{
- switch (m_type) {
- case NO_OPEN_QUOTE:
- case NO_CLOSE_QUOTE:
- return StringImpl::empty();
- case CLOSE_QUOTE:
- return quotesData()->getCloseQuote(m_depth - 1).impl();
- case OPEN_QUOTE:
- return quotesData()->getOpenQuote(m_depth).impl();
+ // Use linear search because there is a small number of distinct characters, thus binary search is unneeded.
+ ASSERT(character);
+ struct StringForCharacter {
+ UChar character;
+ StringImpl* string;
+ };
+ static StringForCharacter strings[maxDistinctQuoteCharacters];
+ for (unsigned i = 0; i < maxDistinctQuoteCharacters; ++i) {
+ if (strings[i].character == character)
+ return strings[i].string;
+ if (!strings[i].character) {
+ strings[i].character = character;
+ strings[i].string = StringImpl::create8BitIfPossible(&character, 1).leakRef();
+ return strings[i].string;
+ }
}
ASSERT_NOT_REACHED();
return StringImpl::empty();
}
-void RenderQuote::updateText()
+static inline StringImpl* quotationMarkString()
{
- computePreferredLogicalWidths(0);
+ static StringImpl* quotationMarkString = stringForQuoteCharacter(quotationMark);
+ return quotationMarkString;
}
-void RenderQuote::computePreferredLogicalWidths(float lead)
+static inline StringImpl* apostropheString()
{
- if (!m_attached)
- attachQuote();
- setTextInternal(originalText());
- RenderText::computePreferredLogicalWidths(lead);
+ static StringImpl* apostropheString = stringForQuoteCharacter(apostrophe);
+ return apostropheString;
}
-const QuotesData* RenderQuote::quotesData() const
+PassRefPtr<StringImpl> RenderQuote::originalText() const
{
- if (QuotesData* customQuotes = style()->quotes())
- return customQuotes;
-
- AtomicString language = style()->locale();
- if (language.isNull())
- return basicQuotesData();
- const QuotesData* quotes = quotesDataLanguageMap().get(language);
- if (!quotes)
- return basicQuotesData();
- return quotes;
+ if (m_depth < 0)
+ return StringImpl::empty();
+ bool isOpenQuote = false;
+ switch (m_type) {
+ case NO_OPEN_QUOTE:
+ case NO_CLOSE_QUOTE:
+ return StringImpl::empty();
+ case OPEN_QUOTE:
+ isOpenQuote = true;
+ // fall through
+ case CLOSE_QUOTE:
+ if (const QuotesData* quotes = style()->quotes())
+ return isOpenQuote ? quotes->openQuote(m_depth).impl() : quotes->closeQuote(m_depth).impl();
+ if (const QuotesForLanguage* quotes = quotesForLanguage(style()->locale()))
+ return stringForQuoteCharacter(isOpenQuote ? (m_depth ? quotes->open2 : quotes->open1) : (m_depth ? quotes->close2 : quotes->close1));
+ // FIXME: Should the default be the quotes for "en" rather than straight quotes?
+ return m_depth ? apostropheString() : quotationMarkString();
+ }
+ ASSERT_NOT_REACHED();
+ return StringImpl::empty();
}
void RenderQuote::attachQuote()
{
ASSERT(view());
- ASSERT(!m_attached);
- ASSERT(!m_next && !m_previous);
+ ASSERT(!m_isAttached);
+ ASSERT(!m_next);
+ ASSERT(!m_previous);
+ ASSERT(isRooted());
- // FIXME: Don't set pref widths dirty during layout. See updateDepth() for
- // more detail.
- if (!isRooted()) {
- setNeedsLayoutAndPrefWidthsRecalc();
- return;
- }
-
- if (!view()->renderQuoteHead()) {
- view()->setRenderQuoteHead(this);
- m_attached = true;
- return;
- }
-
- for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) {
- // Skip unattached predecessors to avoid having stale m_previous pointers
- // if the previous node is never attached and is then destroyed.
- if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached())
- continue;
- m_previous = toRenderQuote(predecessor);
- m_next = m_previous->m_next;
- m_previous->m_next = this;
- if (m_next)
- m_next->m_previous = this;
- break;
+ // Optimize case where this is the first quote in a RenderView by not searching for predecessors in that case.
+ if (view()->renderQuoteHead()) {
+ for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) {
+ // Skip unattached predecessors to avoid having stale m_previous pointers
+ // if the previous node is never attached and is then destroyed.
+ if (!predecessor->isQuote() || !toRenderQuote(predecessor)->m_isAttached)
+ continue;
+ m_previous = toRenderQuote(predecessor);
+ m_next = m_previous->m_next;
+ m_previous->m_next = this;
+ if (m_next)
+ m_next->m_previous = this;
+ break;
+ }
}
if (!m_previous) {
@@ -308,22 +389,23 @@ void RenderQuote::attachQuote()
if (m_next)
m_next->m_previous = this;
}
- m_attached = true;
+
+ m_isAttached = true;
for (RenderQuote* quote = this; quote; quote = quote->m_next)
quote->updateDepth();
- ASSERT(!m_next || m_next->m_attached);
+ ASSERT(!m_next || m_next->m_isAttached);
ASSERT(!m_next || m_next->m_previous == this);
- ASSERT(!m_previous || m_previous->m_attached);
+ ASSERT(!m_previous || m_previous->m_isAttached);
ASSERT(!m_previous || m_previous->m_next == this);
}
void RenderQuote::detachQuote()
{
- ASSERT(!m_next || m_next->m_attached);
- ASSERT(!m_previous || m_previous->m_attached);
- if (!m_attached)
+ ASSERT(!m_next || m_next->m_isAttached);
+ ASSERT(!m_previous || m_previous->m_isAttached);
+ if (!m_isAttached)
return;
if (m_previous)
m_previous->m_next = m_next;
@@ -335,37 +417,42 @@ void RenderQuote::detachQuote()
for (RenderQuote* quote = m_next; quote; quote = quote->m_next)
quote->updateDepth();
}
- m_attached = false;
+ m_isAttached = false;
m_next = 0;
m_previous = 0;
- m_depth = 0;
}
void RenderQuote::updateDepth()
{
- ASSERT(m_attached);
- int oldDepth = m_depth;
- m_depth = 0;
+ ASSERT(m_isAttached);
+ int depth = 0;
if (m_previous) {
- m_depth = m_previous->m_depth;
+ depth = m_previous->m_depth;
+ if (depth < 0)
+ depth = 0;
switch (m_previous->m_type) {
case OPEN_QUOTE:
case NO_OPEN_QUOTE:
- m_depth++;
+ depth++;
break;
case CLOSE_QUOTE:
case NO_CLOSE_QUOTE:
- if (m_depth)
- m_depth--;
break;
}
}
- // FIXME: Don't call setNeedsLayout or dirty our preferred widths during layout.
- // This is likely to fail anyway as one of our ancestor will call setNeedsLayout(false),
- // preventing the future layout to occur on |this|. The solution is to move that to a
- // pre-layout phase.
- if (oldDepth != m_depth)
- setNeedsLayoutAndPrefWidthsRecalc();
+ switch (m_type) {
+ case OPEN_QUOTE:
+ case NO_OPEN_QUOTE:
+ break;
+ case CLOSE_QUOTE:
+ case NO_CLOSE_QUOTE:
+ depth--;
+ break;
+ }
+ if (m_depth == depth)
+ return;
+ m_depth = depth;
+ setText(originalText());
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderQuote.h b/Source/WebCore/rendering/RenderQuote.h
index 947f3a6f5..55b9d44db 100644
--- a/Source/WebCore/rendering/RenderQuote.h
+++ b/Source/WebCore/rendering/RenderQuote.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2011 Nokia Inc. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -22,52 +23,39 @@
#ifndef RenderQuote_h
#define RenderQuote_h
-#include "QuotesData.h"
-#include "RenderStyle.h"
-#include "RenderStyleConstants.h"
#include "RenderText.h"
namespace WebCore {
-class Document;
-
-class RenderQuote : public RenderText {
+class RenderQuote FINAL : public RenderText {
public:
- RenderQuote(Document*, const QuoteType);
+ RenderQuote(Document*, QuoteType);
virtual ~RenderQuote();
+
void attachQuote();
- void detachQuote();
private:
+ void detachQuote();
+
virtual void willBeDestroyed() OVERRIDE;
- virtual const char* renderName() const OVERRIDE { return "RenderQuote"; };
+ virtual const char* renderName() const OVERRIDE { return "RenderQuote"; }
virtual bool isQuote() const OVERRIDE { return true; };
virtual PassRefPtr<StringImpl> originalText() const OVERRIDE;
-
- virtual void updateText() OVERRIDE;
- virtual void computePreferredLogicalWidths(float leadWidth) OVERRIDE;
-
- // We don't override insertedIntoTree to call attachQuote() as it would be attached
- // too early and get the wrong depth since generated content is inserted into anonymous
- // renderers before going into the main render tree. Once we can ensure that insertIntoTree,
- // is called on an attached tree, we should override it here.
-
+ virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE;
virtual void willBeRemovedFromTree() OVERRIDE;
- const QuotesData* quotesData() const;
void updateDepth();
- bool isAttached() { return m_attached; }
QuoteType m_type;
int m_depth;
RenderQuote* m_next;
RenderQuote* m_previous;
- bool m_attached;
+ bool m_isAttached;
};
inline RenderQuote* toRenderQuote(RenderObject* object)
{
- ASSERT(!object || object->isQuote());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isQuote());
return static_cast<RenderQuote*>(object);
}
diff --git a/Source/WebCore/rendering/RenderRegion.cpp b/Source/WebCore/rendering/RenderRegion.cpp
index ce0b9d4f9..acd7f5ccf 100644
--- a/Source/WebCore/rendering/RenderRegion.cpp
+++ b/Source/WebCore/rendering/RenderRegion.cpp
@@ -34,42 +34,63 @@
#include "GraphicsContext.h"
#include "HitTestResult.h"
#include "IntRect.h"
+#include "LayoutRepainter.h"
#include "PaintInfo.h"
#include "Range.h"
#include "RenderBoxRegionInfo.h"
#include "RenderNamedFlowThread.h"
#include "RenderView.h"
#include "StyleResolver.h"
+#include <wtf/StackStats.h>
+
+using namespace std;
namespace WebCore {
-RenderRegion::RenderRegion(Node* node, RenderFlowThread* flowThread)
- : RenderReplaced(node, IntSize())
+RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread)
+ : RenderBlock(element)
, m_flowThread(flowThread)
, m_parentNamedFlowThread(0)
, m_isValid(false)
, m_hasCustomRegionStyle(false)
, m_hasAutoLogicalHeight(false)
- , m_regionState(RegionUndefined)
+ , m_hasComputedAutoHeight(false)
+ , m_computedAutoHeight(0)
{
}
LayoutUnit RenderRegion::pageLogicalWidth() const
{
+ ASSERT(m_flowThread);
return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHeight();
}
LayoutUnit RenderRegion::pageLogicalHeight() const
{
- if (hasOverrideHeight() && view()->normalLayoutPhase())
- return overrideLogicalContentHeight() + borderAndPaddingLogicalHeight();
+ ASSERT(m_flowThread);
+ if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) {
+ ASSERT(hasAutoLogicalHeight());
+ return computedAutoHeight();
+ }
return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth();
}
+// This method returns the maximum page size of a region with auto-height. This is the initial
+// height value for auto-height regions in the first layout phase of the parent named flow.
+LayoutUnit RenderRegion::maxPageLogicalHeight() const
+{
+ ASSERT(m_flowThread);
+ ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase());
+ return style()->logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
+}
+
LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const
{
- if (hasOverrideHeight() && view()->normalLayoutPhase())
- return overrideLogicalContentHeight() + borderAndPaddingLogicalHeight();
+ ASSERT(m_flowThread);
+ if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) {
+ ASSERT(hasAutoLogicalHeight());
+ return computedAutoHeight();
+ }
return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth();
}
@@ -78,14 +99,16 @@ LayoutRect RenderRegion::flowThreadPortionOverflowRect() const
return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion());
}
-LayoutRect RenderRegion::overflowRectForFlowThreadPortion(LayoutRect flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const
+LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const
{
+ ASSERT(isValid());
+
// FIXME: Would like to just use hasOverflowClip() but we aren't a block yet. When RenderRegion is eliminated and
// folded into RenderBlock, switch to hasOverflowClip().
bool clipX = style()->overflowX() != OVISIBLE;
bool clipY = style()->overflowY() != OVISIBLE;
- bool isLastRegionWithRegionOverflowBreak = (isLastPortion && (style()->regionOverflow() == BreakRegionOverflow));
- if ((clipX && clipY) || !isValid() || !m_flowThread || isLastRegionWithRegionOverflowBreak)
+ bool isLastRegionWithRegionFragmentBreak = (isLastPortion && (style()->regionFragment() == BreakRegionFragment));
+ if ((clipX && clipY) || isLastRegionWithRegionFragmentBreak)
return flowThreadPortionRect;
LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect();
@@ -96,20 +119,41 @@ LayoutRect RenderRegion::overflowRectForFlowThreadPortion(LayoutRect flowThreadP
if (m_flowThread->isHorizontalWritingMode()) {
LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize) : flowThreadPortionRect.y();
LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY();
- LayoutUnit minX = clipX ? flowThreadPortionRect.x() : (flowThreadOverflow.x() - outlineSize);
- LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : (flowThreadOverflow.maxX() + outlineSize);
+ LayoutUnit minX = clipX ? flowThreadPortionRect.x() : min(flowThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize);
+ LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : max(flowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize));
clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
} else {
LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize) : flowThreadPortionRect.x();
LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX();
- LayoutUnit minY = clipY ? flowThreadPortionRect.y() : (flowThreadOverflow.y() - outlineSize);
- LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : (flowThreadOverflow.maxY() + outlineSize);
+ LayoutUnit minY = clipY ? flowThreadPortionRect.y() : min(flowThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize));
+ LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize));
clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
}
return clipRect;
}
+RegionOversetState RenderRegion::regionOversetState() const
+{
+ ASSERT(node());
+
+ if (!isValid())
+ return RegionUndefined;
+
+ if (Element* element = toElement(node()))
+ return element->regionOversetState();
+
+ return RegionUndefined;
+}
+
+void RenderRegion::setRegionOversetState(RegionOversetState state)
+{
+ ASSERT(node());
+
+ if (Element* element = toElement(node()))
+ element->setRegionOversetState(state);
+}
+
LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const
{
return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x();
@@ -117,46 +161,60 @@ LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const
bool RenderRegion::isFirstRegion() const
{
- ASSERT(isValid() && m_flowThread);
+ ASSERT(isValid());
+
return m_flowThread->firstRegion() == this;
}
bool RenderRegion::isLastRegion() const
{
- ASSERT(isValid() && m_flowThread);
+ ASSERT(isValid());
+
return m_flowThread->lastRegion() == this;
}
-void RenderRegion::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+static bool shouldPaintRegionContentsInPhase(PaintPhase phase)
+{
+ return phase == PaintPhaseBlockBackground
+ || phase == PaintPhaseChildBlockBackground
+ || phase == PaintPhaseSelection
+ || phase == PaintPhaseTextClip;
+}
+
+void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
- // Delegate painting of content in region to RenderFlowThread.
- if (!m_flowThread || !isValid())
+ if (style()->visibility() != VISIBLE)
return;
+ RenderBlock::paintObject(paintInfo, paintOffset);
+
+ if (!isValid())
+ return;
+
+ // We do not want to paint a region's contents multiple times (for each paint phase of the region object).
+ // Thus, we only paint the region's contents in certain phases.
+ if (!shouldPaintRegionContentsInPhase(paintInfo.phase))
+ return;
+
+ // Delegate the painting of a region's contents to RenderFlowThread.
+ // RenderFlowThread is a self painting layer because it's a positioned object.
+ // RenderFlowThread paints its children, the collected objects.
setRegionObjectsRegionStyle();
m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop()));
restoreRegionObjectsOriginalStyle();
}
// Hit Testing
-bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
+bool RenderRegion::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
- if (!isValid())
+ if (!isValid() || action != HitTestForeground)
return false;
- LayoutPoint adjustedLocation = accumulatedOffset + location();
-
- // Check our bounds next. For this purpose always assume that we can only be hit in the
- // foreground phase (which is true for replaced elements like images).
- // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect.
LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
- boundsRect.moveBy(adjustedLocation);
- if (visibleToHitTesting() && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
- // Check the contents of the RenderFlowThread.
- if (m_flowThread && m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, locationInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop())))
- return true;
- updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
- if (!result.addNodeToRectBasedTestResult(generatingNode(), request, locationInContainer, boundsRect))
+ boundsRect.moveBy(accumulatedOffset);
+ if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) {
+ if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result,
+ locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft() + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop())))
return true;
}
@@ -170,13 +228,28 @@ void RenderRegion::checkRegionStyle()
// FIXME: Region styling doesn't work for pseudo elements.
if (node()) {
- Element* regionElement = static_cast<Element*>(node());
- customRegionStyle = view()->document()->styleResolver()->checkRegionStyle(regionElement);
+ Element* regionElement = toElement(node());
+ customRegionStyle = view()->document()->ensureStyleResolver()->checkRegionStyle(regionElement);
}
setHasCustomRegionStyle(customRegionStyle);
m_flowThread->checkRegionsWithStyling();
}
+void RenderRegion::incrementAutoLogicalHeightCount()
+{
+ ASSERT(isValid());
+ ASSERT(m_hasAutoLogicalHeight);
+
+ m_flowThread->incrementAutoLogicalHeightRegions();
+}
+
+void RenderRegion::decrementAutoLogicalHeightCount()
+{
+ ASSERT(isValid());
+
+ m_flowThread->decrementAutoLogicalHeightRegions();
+}
+
void RenderRegion::updateRegionHasAutoLogicalHeightFlag()
{
ASSERT(m_flowThread);
@@ -188,17 +261,24 @@ void RenderRegion::updateRegionHasAutoLogicalHeightFlag()
m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight();
if (m_hasAutoLogicalHeight != didHaveAutoLogicalHeight) {
if (m_hasAutoLogicalHeight)
- view()->flowThreadController()->incrementAutoLogicalHeightRegions();
+ incrementAutoLogicalHeightCount();
else {
- clearOverrideLogicalContentHeight();
- view()->flowThreadController()->decrementAutoLogicalHeightRegions();
+ clearComputedAutoHeight();
+ decrementAutoLogicalHeightCount();
}
}
}
+bool RenderRegion::shouldHaveAutoLogicalHeight() const
+{
+ bool hasSpecifiedEndpointsForHeight = style()->logicalTop().isSpecified() && style()->logicalBottom().isSpecified();
+ bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecifiedEndpointsForHeight;
+ return style()->logicalHeight().isAuto() && !hasAnchoredEndpointsForHeight;
+}
+
void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
- RenderReplaced::styleDidChange(diff, oldStyle);
+ RenderBlock::styleDidChange(diff, oldStyle);
// If the region is not attached to any thread, there is no need to check
// whether the region has region styling since no content will be displayed
@@ -212,15 +292,24 @@ void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
updateRegionHasAutoLogicalHeightFlag();
}
-void RenderRegion::layout()
+void RenderRegion::layoutBlock(bool relayoutChildren, LayoutUnit)
{
StackStats::LayoutCheckPoint layoutCheckPoint;
- RenderReplaced::layout();
- if (m_flowThread && isValid()) {
+ RenderBlock::layoutBlock(relayoutChildren);
+
+ if (isValid()) {
LayoutRect oldRegionRect(flowThreadPortionRect());
if (!isHorizontalWritingMode())
oldRegionRect = oldRegionRect.transposedRect();
- if (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight())
+
+ if (hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()) {
+ m_flowThread->invalidateRegions();
+ clearComputedAutoHeight();
+ return;
+ }
+
+ if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()))
+ // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread.
m_flowThread->invalidateRegions();
}
@@ -243,6 +332,8 @@ void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect, bool
void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, bool immediate, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const
{
+ ASSERT(isValid());
+
// We only have to issue a repaint in this region if the region rect intersects the repaint rect.
LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
LayoutRect flippedFlowThreadPortionOverflowRect(flowThreadPortionOverflowRect);
@@ -303,6 +394,7 @@ void RenderRegion::attachRegion()
if (!m_flowThread)
return;
+ // Only after adding the region to the thread, the region is marked to be valid.
m_flowThread->addRegionToThread(this);
// The region just got attached to the flow thread, lets check whether
@@ -314,34 +406,29 @@ void RenderRegion::attachRegion()
m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight();
if (hasAutoLogicalHeight())
- view()->flowThreadController()->incrementAutoLogicalHeightRegions();
+ incrementAutoLogicalHeightCount();
}
void RenderRegion::detachRegion()
{
if (m_flowThread) {
m_flowThread->removeRegionFromThread(this);
- if (hasAutoLogicalHeight()) {
- ASSERT(isValid());
- view()->flowThreadController()->decrementAutoLogicalHeightRegions();
- }
+ if (hasAutoLogicalHeight())
+ decrementAutoLogicalHeightCount();
}
m_flowThread = 0;
}
RenderBoxRegionInfo* RenderRegion::renderBoxRegionInfo(const RenderBox* box) const
{
- if (!m_isValid || !m_flowThread)
- return 0;
+ ASSERT(isValid());
return m_renderBoxRegionInfo.get(box);
}
RenderBoxRegionInfo* RenderRegion::setRenderBoxRegionInfo(const RenderBox* box, LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset,
bool containingBlockChainIsInset)
{
- ASSERT(m_isValid && m_flowThread);
- if (!m_isValid || !m_flowThread)
- return 0;
+ ASSERT(isValid());
OwnPtr<RenderBoxRegionInfo>& boxInfo = m_renderBoxRegionInfo.add(box, nullptr).iterator->value;
if (boxInfo)
@@ -369,15 +456,13 @@ void RenderRegion::deleteAllRenderBoxRegionInfo()
LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rect) const
{
- if (!m_isValid || !flowThread())
- return 0;
+ ASSERT(isValid());
return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x();
}
LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect& rect) const
{
- if (!m_isValid || !flowThread())
- return 0;
+ ASSERT(isValid());
return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX();
}
@@ -453,14 +538,14 @@ void RenderRegion::restoreRegionObjectsOriginalStyle()
void RenderRegion::insertedIntoTree()
{
- RenderReplaced::insertedIntoTree();
+ RenderBlock::insertedIntoTree();
attachRegion();
}
void RenderRegion::willBeRemovedFromTree()
{
- RenderReplaced::willBeRemovedFromTree();
+ RenderBlock::willBeRemovedFromTree();
detachRegion();
}
@@ -475,7 +560,7 @@ PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* o
// FIXME: Region styling fails for pseudo-elements because the renderers don't have a node.
Element* element = toElement(object->node());
- RefPtr<RenderStyle> renderObjectRegionStyle = object->view()->document()->styleResolver()->styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this);
+ RefPtr<RenderStyle> renderObjectRegionStyle = object->view()->document()->ensureStyleResolver()->styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this);
return renderObjectRegionStyle.release();
}
@@ -492,7 +577,7 @@ void RenderRegion::computeChildrenStyleInRegion(const RenderObject* object)
childStyleInRegion = it->value.style;
objectRegionStyleCached = true;
} else {
- if (child->isAnonymous())
+ if (child->isAnonymous() || child->isInFlowRenderFlowThread())
childStyleInRegion = RenderStyle::createAnonymousStyleWithDisplay(object->style(), child->style()->display());
else if (child->isText())
childStyleInRegion = RenderStyle::clone(object->style());
@@ -508,9 +593,7 @@ void RenderRegion::computeChildrenStyleInRegion(const RenderObject* object)
void RenderRegion::setObjectStyleInRegion(RenderObject* object, PassRefPtr<RenderStyle> styleInRegion, bool objectRegionStyleCached)
{
- ASSERT(object->inRenderFlowThread());
- if (!object->inRenderFlowThread())
- return;
+ ASSERT(object->flowThreadContainingBlock());
RefPtr<RenderStyle> objectOriginalStyle = object->style();
object->setStyleInternal(styleInRegion);
@@ -540,44 +623,50 @@ void RenderRegion::clearObjectStyleInRegion(const RenderObject* object)
clearObjectStyleInRegion(child);
}
-// FIXME: when RenderRegion will inherit from RenderBlock instead of RenderReplaced,
-// we should overwrite computePreferredLogicalWidths ( see https://bugs.webkit.org/show_bug.cgi?id=74132 )
-LayoutUnit RenderRegion::minPreferredLogicalWidth() const
+void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
- if (!m_flowThread || !m_isValid)
- return RenderReplaced::minPreferredLogicalWidth();
-
- // FIXME: Currently, the code handles only the <length> case for min-width. It should also support other values, like percentage, calc
- // or viewport relative.
- RenderStyle* styleToUse = style();
- LayoutUnit minPreferredLogicalWidth = m_flowThread->minPreferredLogicalWidth();
-
- if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0)
- minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
-
- if (styleToUse->logicalMaxWidth().isFixed())
- minPreferredLogicalWidth = std::min(minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ if (!isValid()) {
+ RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
+ return;
+ }
- return minPreferredLogicalWidth + borderAndPaddingLogicalWidth();
+ minLogicalWidth = m_flowThread->minPreferredLogicalWidth();
+ maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth();
}
-LayoutUnit RenderRegion::maxPreferredLogicalWidth() const
+void RenderRegion::computePreferredLogicalWidths()
{
- if (!m_flowThread || !m_isValid)
- return RenderReplaced::maxPreferredLogicalWidth();
+ ASSERT(preferredLogicalWidthsDirty());
+
+ if (!isValid()) {
+ RenderBlock::computePreferredLogicalWidths();
+ return;
+ }
+
+ // FIXME: Currently, the code handles only the <length> case for min-width/max-width.
+ // It should also support other values, like percentage, calc or viewport relative.
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
- // FIXME: Currently, the code handles only the <length> case for max-width. It should also support other values, like percentage, calc
- // or viewport relative.
RenderStyle* styleToUse = style();
- LayoutUnit maxPreferredLogicalWidth = m_flowThread->maxPreferredLogicalWidth();
+ if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
+ else
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
- if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0)
- maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
+ m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ }
- if (styleToUse->logicalMaxWidth().isFixed())
- maxPreferredLogicalWidth = std::min(maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ if (styleToUse->logicalMaxWidth().isFixed()) {
+ m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ }
- return maxPreferredLogicalWidth + borderAndPaddingLogicalWidth();
+ LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
+ m_minPreferredLogicalWidth += borderAndPadding;
+ m_maxPreferredLogicalWidth += borderAndPadding;
+ setPreferredLogicalWidthsDirty(false);
}
void RenderRegion::getRanges(Vector<RefPtr<Range> >& rangeObjects) const
@@ -588,33 +677,32 @@ void RenderRegion::getRanges(Vector<RefPtr<Range> >& rangeObjects) const
void RenderRegion::updateLogicalHeight()
{
- RenderReplaced::updateLogicalHeight();
+ RenderBlock::updateLogicalHeight();
if (!hasAutoLogicalHeight())
return;
- // We want to update the logical height based on the computed override logical
- // content height only if the view is in the layout phase
- // in which all the auto logical height regions have their override logical height set.
- if (view()->normalLayoutPhase())
+ // We want to update the logical height based on the computed auto-height
+ // only if the view is in the layout phase in which all the
+ // auto logical height regions have a computed auto-height.
+ if (!m_flowThread->inConstrainedLayoutPhase())
return;
// There may be regions with auto logical height that during the prerequisite layout phase
// did not have the chance to layout flow thread content. Because of that, these regions do not
- // have an overrideLogicalContentHeight computed and they will not be able to fragment any flow
+ // have a computedAutoHeight and they will not be able to fragment any flow
// thread content.
- if (!hasOverrideHeight())
+ if (!hasComputedAutoHeight())
return;
- LayoutUnit newLogicalHeight = overrideLogicalContentHeight() + borderAndPaddingLogicalHeight();
+ LayoutUnit newLogicalHeight = computedAutoHeight() + borderAndPaddingLogicalHeight();
ASSERT(newLogicalHeight < LayoutUnit::max() / 2);
- if (newLogicalHeight > logicalHeight())
+ if (newLogicalHeight > logicalHeight()) {
setLogicalHeight(newLogicalHeight);
-}
-
-bool RenderRegion::needsOverrideLogicalContentHeightComputation() const
-{
- return hasAutoLogicalHeight() && view()->normalLayoutPhase() && !hasOverrideHeight();
+ // Recalculate position of the render block after new logical height is set.
+ // (needed in absolute positioning case with bottom alignment for example)
+ RenderBlock::updateLogicalHeight();
+ }
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderRegion.h b/Source/WebCore/rendering/RenderRegion.h
index 5617ae802..770816231 100644
--- a/Source/WebCore/rendering/RenderRegion.h
+++ b/Source/WebCore/rendering/RenderRegion.h
@@ -30,24 +30,25 @@
#ifndef RenderRegion_h
#define RenderRegion_h
-#include "RenderReplaced.h"
+#include "RenderBlock.h"
#include "StyleInheritedData.h"
namespace WebCore {
+struct LayerFragment;
+typedef Vector<LayerFragment, 1> LayerFragments;
class RenderBox;
class RenderBoxRegionInfo;
class RenderFlowThread;
class RenderNamedFlowThread;
-class RenderRegion : public RenderReplaced {
+class RenderRegion : public RenderBlock {
public:
- explicit RenderRegion(Node*, RenderFlowThread*);
+ explicit RenderRegion(Element*, RenderFlowThread*);
virtual bool isRenderRegion() const { return true; }
- virtual void paintReplaced(PaintInfo&, const LayoutPoint&);
- virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
+ virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -68,8 +69,6 @@ public:
bool hasCustomRegionStyle() const { return m_hasCustomRegionStyle; }
void setHasCustomRegionStyle(bool hasCustomRegionStyle) { m_hasCustomRegionStyle = hasCustomRegionStyle; }
- virtual void layout();
-
RenderBoxRegionInfo* renderBoxRegionInfo(const RenderBox*) const;
RenderBoxRegionInfo* setRenderBoxRegionInfo(const RenderBox*, LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset,
bool containingBlockChainIsInset);
@@ -83,25 +82,16 @@ public:
void clearObjectStyleInRegion(const RenderObject*);
- enum RegionState {
- RegionUndefined,
- RegionEmpty,
- RegionFit,
- RegionOverset
- };
+ RegionOversetState regionOversetState() const;
+ void setRegionOversetState(RegionOversetState);
- RegionState regionState() const { return isValid() ? m_regionState : RegionUndefined; }
- void setRegionState(RegionState regionState) { m_regionState = regionState; }
-
// These methods represent the width and height of a "page" and for a RenderRegion they are just the
// content width and content height of a region. For RenderRegionSets, however, they will be the width and
// height of a single column or page in the set.
virtual LayoutUnit pageLogicalWidth() const;
virtual LayoutUnit pageLogicalHeight() const;
+ LayoutUnit maxPageLogicalHeight() const;
- virtual LayoutUnit minPreferredLogicalWidth() const OVERRIDE;
- virtual LayoutUnit maxPreferredLogicalWidth() const OVERRIDE;
-
LayoutUnit logicalTopOfFlowThreadContentRect(const LayoutRect&) const;
LayoutUnit logicalBottomOfFlowThreadContentRect(const LayoutRect&) const;
LayoutUnit logicalTopForFlowThreadContent() const { return logicalTopOfFlowThreadContentRect(flowThreadPortionRect()); };
@@ -116,7 +106,21 @@ public:
bool hasAutoLogicalHeight() const { return m_hasAutoLogicalHeight; }
- bool needsOverrideLogicalContentHeightComputation() const;
+ LayoutUnit computedAutoHeight() const { return m_computedAutoHeight; }
+
+ void setComputedAutoHeight(LayoutUnit computedAutoHeight)
+ {
+ m_hasComputedAutoHeight = true;
+ m_computedAutoHeight = computedAutoHeight;
+ }
+
+ void clearComputedAutoHeight()
+ {
+ m_hasComputedAutoHeight = false;
+ m_computedAutoHeight = 0;
+ }
+
+ bool hasComputedAutoHeight() const { return m_hasComputedAutoHeight; }
virtual void updateLogicalHeight() OVERRIDE;
@@ -132,43 +136,45 @@ public:
virtual void repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const;
+ virtual void collectLayerFragments(LayerFragments&, const LayoutRect&, const LayoutRect&) { }
+
protected:
void setRegionObjectsRegionStyle();
void restoreRegionObjectsOriginalStyle();
- LayoutRect overflowRectForFlowThreadPortion(LayoutRect flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+
+ LayoutRect overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const;
void repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, bool immediate, const LayoutRect& flowThreadPortionRect,
const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const;
+ virtual bool shouldHaveAutoLogicalHeight() const;
+
private:
virtual const char* renderName() const { return "RenderRegion"; }
- // FIXME: these functions should be revisited once RenderRegion inherits from RenderBlock
- // instead of RenderReplaced (see https://bugs.webkit.org/show_bug.cgi?id=74132 )
- // When width is auto, use normal block/box sizing code except when inline.
- virtual bool isInlineBlockOrInlineTable() const OVERRIDE { return isInline() && !shouldComputeSizeAsReplaced(); }
- virtual bool shouldComputeSizeAsReplaced() const OVERRIDE { return !style()->logicalWidth().isAuto() && !style()->logicalHeight().isAuto(); }
-
- bool shouldHaveAutoLogicalHeight() const
- {
- bool hasSpecifiedEndpointsForHeight = style()->logicalTop().isSpecified() && style()->logicalBottom().isSpecified();
- bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecifiedEndpointsForHeight;
- return style()->logicalHeight().isAuto() && !hasAnchoredEndpointsForHeight;
- }
+ virtual bool canHaveChildren() const OVERRIDE { return false; }
+ virtual bool canHaveGeneratedChildren() const OVERRIDE { return true; }
virtual void insertedIntoTree() OVERRIDE;
virtual void willBeRemovedFromTree() OVERRIDE;
+ virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE;
+ virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE;
+
virtual void installFlowThread();
PassRefPtr<RenderStyle> computeStyleInRegion(const RenderObject*);
void computeChildrenStyleInRegion(const RenderObject*);
void setObjectStyleInRegion(RenderObject*, PassRefPtr<RenderStyle>, bool objectRegionStyleCached);
- void printRegionObjectsStyles();
void checkRegionStyle();
void updateRegionHasAutoLogicalHeightFlag();
+ void incrementAutoLogicalHeightCount();
+ void decrementAutoLogicalHeightCount();
+
protected:
RenderFlowThread* m_flowThread;
@@ -202,18 +208,20 @@ private:
bool m_isValid : 1;
bool m_hasCustomRegionStyle : 1;
bool m_hasAutoLogicalHeight : 1;
- RegionState m_regionState;
+ bool m_hasComputedAutoHeight : 1;
+
+ LayoutUnit m_computedAutoHeight;
};
inline RenderRegion* toRenderRegion(RenderObject* object)
{
- ASSERT(!object || object->isRenderRegion());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderRegion());
return static_cast<RenderRegion*>(object);
}
inline const RenderRegion* toRenderRegion(const RenderObject* object)
{
- ASSERT(!object || object->isRenderRegion());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderRegion());
return static_cast<const RenderRegion*>(object);
}
diff --git a/Source/WebCore/rendering/RenderRegionSet.cpp b/Source/WebCore/rendering/RenderRegionSet.cpp
index 25b5cfa9c..e205bcb1e 100644
--- a/Source/WebCore/rendering/RenderRegionSet.cpp
+++ b/Source/WebCore/rendering/RenderRegionSet.cpp
@@ -30,8 +30,8 @@
namespace WebCore {
-RenderRegionSet::RenderRegionSet(Node* node, RenderFlowThread* flowThread)
- : RenderRegion(node, flowThread)
+RenderRegionSet::RenderRegionSet(Element* element, RenderFlowThread* flowThread)
+ : RenderRegion(element, flowThread)
{
}
diff --git a/Source/WebCore/rendering/RenderRegionSet.h b/Source/WebCore/rendering/RenderRegionSet.h
index e91eceecc..aa8969d67 100644
--- a/Source/WebCore/rendering/RenderRegionSet.h
+++ b/Source/WebCore/rendering/RenderRegionSet.h
@@ -47,8 +47,11 @@ class RenderFlowThread;
class RenderRegionSet : public RenderRegion {
public:
- RenderRegionSet(Node*, RenderFlowThread*);
+ RenderRegionSet(Element*, RenderFlowThread*);
+protected:
+ virtual bool shouldHaveAutoLogicalHeight() const OVERRIDE { return false; }
+
private:
virtual void installFlowThread() OVERRIDE;
diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp
index 47c239ab5..1df9e19c5 100644
--- a/Source/WebCore/rendering/RenderReplaced.cpp
+++ b/Source/WebCore/rendering/RenderReplaced.cpp
@@ -33,6 +33,7 @@
#include "RenderTheme.h"
#include "RenderView.h"
#include "VisiblePosition.h"
+#include <wtf/StackStats.h>
using namespace std;
@@ -41,15 +42,15 @@ namespace WebCore {
const int cDefaultWidth = 300;
const int cDefaultHeight = 150;
-RenderReplaced::RenderReplaced(Node* node)
- : RenderBox(node)
+RenderReplaced::RenderReplaced(Element* element)
+ : RenderBox(element)
, m_intrinsicSize(cDefaultWidth, cDefaultHeight)
{
setReplaced(true);
}
-RenderReplaced::RenderReplaced(Node* node, const LayoutSize& intrinsicSize)
- : RenderBox(node)
+RenderReplaced::RenderReplaced(Element* element, const LayoutSize& intrinsicSize)
+ : RenderBox(element)
, m_intrinsicSize(intrinsicSize)
{
setReplaced(true);
@@ -92,11 +93,12 @@ void RenderReplaced::layout()
m_overflow.clear();
addVisualEffectOverflow();
updateLayerTransform();
-
+ invalidateBackgroundObscurationStatus();
+
repainter.repaintAfterLayout();
setNeedsLayout(false);
}
-
+
void RenderReplaced::intrinsicSizeChanged()
{
int scaledWidth = static_cast<int>(cDefaultWidth * style()->effectiveZoom());
@@ -122,7 +124,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size());
if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
- paintOutline(paintInfo.context, paintRect);
+ paintOutline(paintInfo, paintRect);
if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren())
return;
@@ -232,33 +234,13 @@ bool RenderReplaced::hasReplacedLogicalWidth() const
return firstContainingBlockWithLogicalWidth(this);
}
-static inline bool hasAutoHeightOrContainingBlockWithAutoHeight(const RenderReplaced* replaced)
-{
- Length logicalHeightLength = replaced->style()->logicalHeight();
- if (logicalHeightLength.isAuto())
- return true;
-
- // For percentage heights: The percentage is calculated with respect to the height of the generated box's
- // containing block. If the height of the containing block is not specified explicitly (i.e., it depends
- // on content height), and this element is not absolutely positioned, the value computes to 'auto'.
- if (!logicalHeightLength.isPercent() || replaced->isOutOfFlowPositioned() || replaced->document()->inQuirksMode())
- return false;
-
- for (RenderBlock* cb = replaced->containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
- if (cb->isTableCell() || (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto())))
- return false;
- }
-
- return true;
-}
-
bool RenderReplaced::hasReplacedLogicalHeight() const
{
if (style()->logicalHeight().isAuto())
return false;
if (style()->logicalHeight().isSpecified()) {
- if (hasAutoHeightOrContainingBlockWithAutoHeight(this))
+ if (hasAutoHeightOrContainingBlockWithAutoHeight())
return false;
return true;
}
@@ -266,12 +248,6 @@ bool RenderReplaced::hasReplacedLogicalHeight() const
return false;
}
-static inline bool rendererHasAspectRatio(const RenderObject* renderer)
-{
- ASSERT(renderer);
- return renderer->isImage() || renderer->isCanvas() || renderer->isVideo();
-}
-
void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
{
FloatSize intrinsicSize;
@@ -284,7 +260,7 @@ void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* conten
if (!isPercentageIntrinsicSize)
intrinsicSize.scale(style()->effectiveZoom());
- if (rendererHasAspectRatio(this) && isPercentageIntrinsicSize)
+ if (hasAspectRatio() && isPercentageIntrinsicSize)
intrinsicRatio = 1;
// Update our intrinsic size to match what the content renderer has computed, so that when we
@@ -330,16 +306,16 @@ void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize,
intrinsicSize = FloatSize(intrinsicLogicalWidth(), intrinsicLogicalHeight());
// Figure out if we need to compute an intrinsic ratio.
- if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this))
+ if (intrinsicSize.isEmpty() || !hasAspectRatio())
return;
intrinsicRatio = intrinsicSize.width() / intrinsicSize.height();
}
-LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) const
+LayoutUnit RenderReplaced::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
{
- if (style()->logicalWidth().isSpecified())
- return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth()), includeMaxWidth);
+ if (style()->logicalWidth().isSpecified() || style()->logicalWidth().isIntrinsic())
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
RenderBox* contentRenderer = embeddedContentBox();
@@ -355,7 +331,7 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
// If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, then that intrinsic width is the used value of 'width'.
if (heightIsAuto && hasIntrinsicWidth)
- return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), includeMaxWidth);
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred);
bool hasIntrinsicHeight = !isPercentageIntrinsicSize && constrainedSize.height() > 0;
if (intrinsicRatio || isPercentageIntrinsicSize) {
@@ -363,8 +339,8 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
// or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value
// of 'width' is: (used height) * (intrinsic ratio)
if (intrinsicRatio && ((heightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !heightIsAuto)) {
- LayoutUnit logicalHeight = computeReplacedLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight());
- return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio)));
+ LayoutUnit logicalHeight = computeReplacedLogicalHeight();
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio)), shouldComputePreferred);
}
// If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width, then the used value of
@@ -375,7 +351,7 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
// 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
LayoutUnit logicalWidth;
if (RenderBlock* blockWithWidth = firstContainingBlockWithLogicalWidth(this))
- logicalWidth = blockWithWidth->computeReplacedLogicalWidthRespectingMinMaxWidth(blockWithWidth->computeReplacedLogicalWidthUsing(MainOrPreferredSize, blockWithWidth->style()->logicalWidth()), false);
+ logicalWidth = blockWithWidth->computeReplacedLogicalWidthRespectingMinMaxWidth(blockWithWidth->computeReplacedLogicalWidthUsing(blockWithWidth->style()->logicalWidth()), shouldComputePreferred);
else
logicalWidth = containingBlock()->availableLogicalWidth();
@@ -385,13 +361,13 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
logicalWidth = max<LayoutUnit>(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth())));
if (isPercentageIntrinsicSize)
logicalWidth = logicalWidth * constrainedSize.width() / 100;
- return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, includeMaxWidth);
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, shouldComputePreferred);
}
}
// Otherwise, if 'width' has a computed value of 'auto', and the element has an intrinsic width, then that intrinsic width is the used value of 'width'.
if (hasIntrinsicWidth)
- return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), includeMaxWidth);
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(constrainedSize.width(), shouldComputePreferred);
// Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px. If 300px is too
// wide to fit the device, UAs should use the width of the largest rectangle that has a 2:1 ratio and fits the device instead.
@@ -400,14 +376,14 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
// has no intrinsic size, which is wrong per CSS 2.1, but matches our behavior since a long time.
}
- return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), includeMaxWidth);
+ return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), shouldComputePreferred);
}
LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const
{
// 10.5 Content height: the 'height' property: http://www.w3.org/TR/CSS21/visudet.html#propdef-height
if (hasReplacedLogicalHeight())
- return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight()));
+ return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
RenderBox* contentRenderer = embeddedContentBox();
@@ -438,34 +414,39 @@ LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const
return computeReplacedLogicalHeightRespectingMinMaxHeight(intrinsicLogicalHeight());
}
-LayoutUnit RenderReplaced::computeMaxPreferredLogicalWidth() const
+void RenderReplaced::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
- Length logicalWidth = style()->logicalWidth();
-
- // We cannot resolve any percent logical width here as the available logical
- // width may not be set on our containing block.
- if (logicalWidth.isPercent())
- return intrinsicLogicalWidth();
-
- // FIXME: We shouldn't be calling a logical width computing function in preferred
- // logical widths computation as the layout information is probably invalid.
- return computeReplacedLogicalWidth(false);
+ minLogicalWidth = maxLogicalWidth = intrinsicLogicalWidth();
}
void RenderReplaced::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
- LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
- m_maxPreferredLogicalWidth = computeMaxPreferredLogicalWidth() + borderAndPadding;
-
- if (style()->maxWidth().isFixed())
- m_maxPreferredLogicalWidth = min<LayoutUnit>(m_maxPreferredLogicalWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : LayoutUnit()));
+ // We cannot resolve any percent logical width here as the available logical
+ // width may not be set on our containing block.
+ if (style()->logicalWidth().isPercent())
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
+ else
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeReplacedLogicalWidth(ComputePreferred);
- if (hasRelativeDimensions())
+ RenderStyle* styleToUse = style();
+ if (styleToUse->logicalWidth().isPercent() || styleToUse->logicalMaxWidth().isPercent() || hasRelativeIntrinsicLogicalWidth())
m_minPreferredLogicalWidth = 0;
- else
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
+
+ if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
+ m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ }
+
+ if (styleToUse->logicalMaxWidth().isFixed()) {
+ m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ }
+
+ LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
+ m_minPreferredLogicalWidth += borderAndPadding;
+ m_maxPreferredLogicalWidth += borderAndPadding;
setPreferredLogicalWidthsDirty(false);
}
diff --git a/Source/WebCore/rendering/RenderReplaced.h b/Source/WebCore/rendering/RenderReplaced.h
index a6dee443e..ae85e44b7 100644
--- a/Source/WebCore/rendering/RenderReplaced.h
+++ b/Source/WebCore/rendering/RenderReplaced.h
@@ -28,11 +28,11 @@ namespace WebCore {
class RenderReplaced : public RenderBox {
public:
- RenderReplaced(Node*);
- RenderReplaced(Node*, const LayoutSize& intrinsicSize);
+ RenderReplaced(Element*);
+ RenderReplaced(Element*, const LayoutSize& intrinsicSize);
virtual ~RenderReplaced();
- virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE;
virtual LayoutUnit computeReplacedLogicalHeight() const;
bool hasReplacedLogicalWidth() const;
@@ -46,6 +46,8 @@ protected:
virtual LayoutSize intrinsicSize() const OVERRIDE { return m_intrinsicSize; }
virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const;
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+
virtual LayoutUnit minimumReplacedHeight() const { return LayoutUnit(); }
virtual void setSelectionState(SelectionState);
@@ -56,6 +58,7 @@ protected:
void setIntrinsicSize(const LayoutSize& intrinsicSize) { m_intrinsicSize = intrinsicSize; }
virtual void intrinsicSizeChanged();
+ virtual bool hasRelativeIntrinsicLogicalWidth() const { return false; }
virtual void paint(PaintInfo&, const LayoutPoint&);
bool shouldPaint(PaintInfo&, const LayoutPoint&);
@@ -67,7 +70,6 @@ private:
virtual bool canHaveChildren() const { return false; }
- LayoutUnit computeMaxPreferredLogicalWidth() const;
virtual void computePreferredLogicalWidths();
virtual void paintReplaced(PaintInfo&, const LayoutPoint&) { }
diff --git a/Source/WebCore/rendering/RenderReplica.cpp b/Source/WebCore/rendering/RenderReplica.cpp
index c10bdcaf3..e0f4ad245 100644
--- a/Source/WebCore/rendering/RenderReplica.cpp
+++ b/Source/WebCore/rendering/RenderReplica.cpp
@@ -30,11 +30,12 @@
#include "RenderReplica.h"
#include "RenderLayer.h"
+#include <wtf/StackStats.h>
namespace WebCore {
-RenderReplica::RenderReplica(Node* n)
-: RenderBox(n)
+RenderReplica::RenderReplica()
+ : RenderBox(0)
{
// This is a hack. Replicas are synthetic, and don't pick up the attributes of the
// renderers being replicated, so they always report that they are inline, non-replaced.
@@ -43,8 +44,16 @@ RenderReplica::RenderReplica(Node* n)
setReplaced(true);
}
+RenderReplica* RenderReplica::createAnonymous(Document* document)
+{
+ RenderReplica* renderer = new (document->renderArena()) RenderReplica();
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
RenderReplica::~RenderReplica()
-{}
+{
+}
void RenderReplica::layout()
{
diff --git a/Source/WebCore/rendering/RenderReplica.h b/Source/WebCore/rendering/RenderReplica.h
index de694439e..4665e13f1 100644
--- a/Source/WebCore/rendering/RenderReplica.h
+++ b/Source/WebCore/rendering/RenderReplica.h
@@ -35,7 +35,8 @@ namespace WebCore {
class RenderReplica : public RenderBox {
public:
- RenderReplica(Node*);
+ static RenderReplica* createAnonymous(Document*);
+
virtual ~RenderReplica();
virtual const char* renderName() const { return "RenderReplica"; }
@@ -43,12 +44,14 @@ public:
virtual bool requiresLayer() const { return true; }
virtual void layout();
- virtual void computePreferredLogicalWidths();
virtual void paint(PaintInfo&, const LayoutPoint&);
private:
+ RenderReplica();
+
virtual bool isReplica() const { return true; }
+ virtual void computePreferredLogicalWidths();
};
diff --git a/Source/WebCore/rendering/RenderRuby.cpp b/Source/WebCore/rendering/RenderRuby.cpp
index e7b859f70..076744e16 100644
--- a/Source/WebCore/rendering/RenderRuby.cpp
+++ b/Source/WebCore/rendering/RenderRuby.cpp
@@ -74,19 +74,19 @@ static inline bool isRubyAfterBlock(const RenderObject* object)
static inline RenderBlock* rubyBeforeBlock(const RenderObject* ruby)
{
RenderObject* child = ruby->firstChild();
- return isRubyBeforeBlock(child) ? static_cast<RenderBlock*>(child) : 0;
+ return isRubyBeforeBlock(child) ? toRenderBlock(child) : 0;
}
static inline RenderBlock* rubyAfterBlock(const RenderObject* ruby)
{
RenderObject* child = ruby->lastChild();
- return isRubyAfterBlock(child) ? static_cast<RenderBlock*>(child) : 0;
+ return isRubyAfterBlock(child) ? toRenderBlock(child) : 0;
}
static RenderBlock* createAnonymousRubyInlineBlock(RenderObject* ruby)
{
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(ruby->style(), INLINE_BLOCK);
- RenderBlock* newBlock = new (ruby->renderArena()) RenderBlock(ruby->document() /* anonymous box */);
+ RenderBlock* newBlock = RenderBlock::createAnonymous(ruby->document());
newBlock->setStyle(newStyle.release());
return newBlock;
}
@@ -97,20 +97,20 @@ static RenderRubyRun* lastRubyRun(const RenderObject* ruby)
if (child && !child->isRubyRun())
child = child->previousSibling();
ASSERT(!child || child->isRubyRun() || child->isBeforeContent() || child == rubyBeforeBlock(ruby));
- return child && child->isRubyRun() ? static_cast<RenderRubyRun*>(child) : 0;
+ return child && child->isRubyRun() ? toRenderRubyRun(child) : 0;
}
static inline RenderRubyRun* findRubyRunParent(RenderObject* child)
{
while (child && !child->isRubyRun())
child = child->parent();
- return static_cast<RenderRubyRun*>(child);
+ return toRenderRubyRun(child);
}
//=== ruby as inline object ===
-RenderRubyAsInline::RenderRubyAsInline(Node* node)
- : RenderInline(node)
+RenderRubyAsInline::RenderRubyAsInline(Element* element)
+ : RenderInline(element)
{
}
@@ -184,7 +184,7 @@ void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild
RenderRubyRun* lastRun = lastRubyRun(this);
if (!lastRun || lastRun->hasRubyText()) {
lastRun = RenderRubyRun::staticCreateRubyRun(this);
- RenderInline::addChild(lastRun);
+ RenderInline::addChild(lastRun, beforeChild);
}
lastRun->addChild(child);
}
@@ -213,11 +213,10 @@ void RenderRubyAsInline::removeChild(RenderObject* child)
run->removeChild(child);
}
-
//=== ruby as block object ===
-RenderRubyAsBlock::RenderRubyAsBlock(Node* node)
- : RenderBlock(node)
+RenderRubyAsBlock::RenderRubyAsBlock(Element* element)
+ : RenderBlock(element)
{
}
@@ -291,7 +290,7 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
RenderRubyRun* lastRun = lastRubyRun(this);
if (!lastRun || lastRun->hasRubyText()) {
lastRun = RenderRubyRun::staticCreateRubyRun(this);
- RenderBlock::addChild(lastRun);
+ RenderBlock::addChild(lastRun, beforeChild);
}
lastRun->addChild(child);
}
diff --git a/Source/WebCore/rendering/RenderRuby.h b/Source/WebCore/rendering/RenderRuby.h
index 2ab964ca0..2494639f9 100644
--- a/Source/WebCore/rendering/RenderRuby.h
+++ b/Source/WebCore/rendering/RenderRuby.h
@@ -53,7 +53,7 @@ namespace WebCore {
// <ruby> when used as 'display:inline'
class RenderRubyAsInline : public RenderInline {
public:
- RenderRubyAsInline(Node*);
+ RenderRubyAsInline(Element*);
virtual ~RenderRubyAsInline();
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
@@ -72,7 +72,7 @@ private:
// <ruby> when used as 'display:block' or 'display:inline-block'
class RenderRubyAsBlock : public RenderBlock {
public:
- RenderRubyAsBlock(Node*);
+ RenderRubyAsBlock(Element*);
virtual ~RenderRubyAsBlock();
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
diff --git a/Source/WebCore/rendering/RenderRubyBase.cpp b/Source/WebCore/rendering/RenderRubyBase.cpp
index 87402f713..adc2f0d44 100644
--- a/Source/WebCore/rendering/RenderRubyBase.cpp
+++ b/Source/WebCore/rendering/RenderRubyBase.cpp
@@ -38,8 +38,8 @@ using namespace std;
namespace WebCore {
-RenderRubyBase::RenderRubyBase(Node* node)
- : RenderBlock(node)
+RenderRubyBase::RenderRubyBase()
+ : RenderBlock(0)
{
setInline(false);
}
@@ -48,6 +48,13 @@ RenderRubyBase::~RenderRubyBase()
{
}
+RenderRubyBase* RenderRubyBase::createAnonymous(Document* document)
+{
+ RenderRubyBase* renderer = new (document->renderArena()) RenderRubyBase();
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
bool RenderRubyBase::isChildAllowed(RenderObject* child, RenderStyle*) const
{
return child->isInline();
diff --git a/Source/WebCore/rendering/RenderRubyBase.h b/Source/WebCore/rendering/RenderRubyBase.h
index 993892005..3888606b4 100644
--- a/Source/WebCore/rendering/RenderRubyBase.h
+++ b/Source/WebCore/rendering/RenderRubyBase.h
@@ -39,8 +39,9 @@ class RenderRubyRun;
class RenderRubyBase : public RenderBlock {
public:
- RenderRubyBase(Node*);
virtual ~RenderRubyBase();
+
+ static RenderRubyBase* createAnonymous(Document*);
virtual const char* renderName() const { return "RenderRubyBase (anonymous)"; }
@@ -49,6 +50,8 @@ public:
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
private:
+ RenderRubyBase();
+
virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const;
virtual void adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const;
diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp
index 498d17d10..874821f1b 100644
--- a/Source/WebCore/rendering/RenderRubyRun.cpp
+++ b/Source/WebCore/rendering/RenderRubyRun.cpp
@@ -37,13 +37,14 @@
#include "RenderText.h"
#include "RenderView.h"
#include "StyleInheritedData.h"
+#include <wtf/StackStats.h>
using namespace std;
namespace WebCore {
-RenderRubyRun::RenderRubyRun(Node* node)
- : RenderBlock(node)
+RenderRubyRun::RenderRubyRun()
+ : RenderBlock(0)
{
setReplaced(true);
setInline(true);
@@ -199,17 +200,18 @@ void RenderRubyRun::removeChild(RenderObject* child)
RenderRubyBase* RenderRubyRun::createRubyBase() const
{
- RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */);
+ RenderRubyBase* renderer = RenderRubyBase::createAnonymous(document());
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
- rb->setStyle(newStyle.release());
- return rb;
+ renderer->setStyle(newStyle.release());
+ return renderer;
}
RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
{
ASSERT(parentRuby && parentRuby->isRuby());
- RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */);
+ RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun();
+ rr->setDocumentForAnonymous(parentRuby->document());
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parentRuby->style(), INLINE_BLOCK);
rr->setStyle(newStyle.release());
return rr;
@@ -232,11 +234,13 @@ void RenderRubyRun::layout()
{
RenderBlock::layout();
- // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
RenderRubyText* rt = rubyText();
if (!rt)
return;
+
+ rt->setLogicalLeft(0);
+ // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
LayoutUnit lastLineRubyTextBottom = rt->logicalHeight();
LayoutUnit firstLineRubyTextTop = 0;
RootInlineBox* rootBox = rt->lastRootBox();
@@ -269,7 +273,6 @@ void RenderRubyRun::layout()
}
// Update our overflow to account for the new RenderRubyText position.
- m_overflow.clear();
computeOverflow(clientLogicalBottom());
}
diff --git a/Source/WebCore/rendering/RenderRubyRun.h b/Source/WebCore/rendering/RenderRubyRun.h
index f65ad86c6..1e553a6a0 100644
--- a/Source/WebCore/rendering/RenderRubyRun.h
+++ b/Source/WebCore/rendering/RenderRubyRun.h
@@ -43,7 +43,6 @@ class RenderRubyText;
class RenderRubyRun : public RenderBlock {
public:
- RenderRubyRun(Node*);
virtual ~RenderRubyRun();
bool hasRubyText() const;
@@ -71,6 +70,8 @@ protected:
RenderRubyBase* createRubyBase() const;
private:
+ RenderRubyRun();
+
virtual bool isRubyRun() const { return true; }
virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; }
virtual bool createsAnonymousWrapper() const { return true; }
@@ -79,13 +80,13 @@ private:
inline RenderRubyRun* toRenderRubyRun(RenderObject* object)
{
- ASSERT(!object || object->isRubyRun());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRubyRun());
return static_cast<RenderRubyRun*>(object);
}
inline const RenderRubyRun* toRenderRubyRun(const RenderObject* object)
{
- ASSERT(!object || object->isBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isBox());
return static_cast<const RenderRubyRun*>(object);
}
diff --git a/Source/WebCore/rendering/RenderRubyText.cpp b/Source/WebCore/rendering/RenderRubyText.cpp
index e9765f28d..497c8b71d 100644
--- a/Source/WebCore/rendering/RenderRubyText.cpp
+++ b/Source/WebCore/rendering/RenderRubyText.cpp
@@ -37,8 +37,8 @@ using namespace std;
namespace WebCore {
-RenderRubyText::RenderRubyText(Node* node)
- : RenderBlock(node)
+RenderRubyText::RenderRubyText(Element* element)
+ : RenderBlock(element)
{
}
@@ -88,15 +88,4 @@ bool RenderRubyText::avoidsFloats() const
return true;
}
-void RenderRubyText::updateBeforeAfterContent(PseudoId pseudoId)
-{
- // RenderRubyText manages its own :before and :after content
- // and is not handled by its anonymous wrappers RenderRubyRun
- // and RenderRuby. This contrasts with other ruby children, which
- // are enclosed in RenderRubyBase and hence they are able to
- // update their :before, :after content (since RenderRubyBase
- // is not a anonymous wrapper).
- return children()->updateBeforeAfterContent(this, pseudoId);
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderRubyText.h b/Source/WebCore/rendering/RenderRubyText.h
index f47304ccd..0b0bae582 100644
--- a/Source/WebCore/rendering/RenderRubyText.h
+++ b/Source/WebCore/rendering/RenderRubyText.h
@@ -37,7 +37,7 @@ namespace WebCore {
class RenderRubyText : public RenderBlock {
public:
- RenderRubyText(Node*);
+ RenderRubyText(Element*);
virtual ~RenderRubyText();
virtual const char* renderName() const { return "RenderRubyText"; }
@@ -46,8 +46,6 @@ public:
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
- virtual void updateBeforeAfterContent(PseudoId);
-
private:
virtual bool avoidsFloats() const;
diff --git a/Source/WebCore/rendering/RenderScrollbar.cpp b/Source/WebCore/rendering/RenderScrollbar.cpp
index 216c5f8d8..0699502c6 100644
--- a/Source/WebCore/rendering/RenderScrollbar.cpp
+++ b/Source/WebCore/rendering/RenderScrollbar.cpp
@@ -32,6 +32,7 @@
#include "RenderScrollbarPart.h"
#include "RenderScrollbarTheme.h"
#include "StyleInheritedData.h"
+#include "StyleResolver.h"
namespace WebCore {
@@ -145,30 +146,12 @@ void RenderScrollbar::setPressedPart(ScrollbarPart part)
updateScrollbarPart(TrackBGPart);
}
-static ScrollbarPart s_styleResolvePart;
-static RenderScrollbar* s_styleResolveScrollbar;
-
-RenderScrollbar* RenderScrollbar::scrollbarForStyleResolve()
-{
- return s_styleResolveScrollbar;
-}
-
-ScrollbarPart RenderScrollbar::partForStyleResolve()
-{
- return s_styleResolvePart;
-}
-
PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart partType, PseudoId pseudoId)
{
if (!owningRenderer())
return 0;
- s_styleResolvePart = partType;
- s_styleResolveScrollbar = this;
- RefPtr<RenderStyle> result = owningRenderer()->getUncachedPseudoStyle(pseudoId, owningRenderer()->style());
- s_styleResolvePart = NoPart;
- s_styleResolveScrollbar = 0;
-
+ RefPtr<RenderStyle> result = owningRenderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId, this, partType), owningRenderer()->style());
// Scrollbars for root frames should always have background color
// unless explicitly specified as transparent. So we force it.
// This is because WebKit assumes scrollbar to be always painted and missing background
@@ -270,7 +253,7 @@ void RenderScrollbar::updateScrollbarPart(ScrollbarPart partType, bool destroy)
RenderScrollbarPart* partRenderer = m_parts.get(partType);
if (!partRenderer && needRenderer) {
- partRenderer = new (owningRenderer()->renderArena()) RenderScrollbarPart(owningRenderer()->document(), this, partType);
+ partRenderer = RenderScrollbarPart::createAnonymous(owningRenderer()->document(), this, partType);
m_parts.set(partType, partRenderer);
} else if (partRenderer && !needRenderer) {
m_parts.remove(partType);
diff --git a/Source/WebCore/rendering/RenderScrollbar.h b/Source/WebCore/rendering/RenderScrollbar.h
index 918eee0a9..685c0072f 100644
--- a/Source/WebCore/rendering/RenderScrollbar.h
+++ b/Source/WebCore/rendering/RenderScrollbar.h
@@ -47,9 +47,6 @@ public:
static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollableArea*, ScrollbarOrientation, Node*, Frame* owningFrame = 0);
virtual ~RenderScrollbar();
- static ScrollbarPart partForStyleResolve();
- static RenderScrollbar* scrollbarForStyleResolve();
-
RenderBox* owningRenderer() const;
void paintPart(GraphicsContext*, ScrollbarPart, const IntRect&);
@@ -92,7 +89,7 @@ private:
inline RenderScrollbar* toRenderScrollbar(ScrollbarThemeClient* scrollbar)
{
- ASSERT(!scrollbar || scrollbar->isCustomScrollbar());
+ ASSERT_WITH_SECURITY_IMPLICATION(!scrollbar || scrollbar->isCustomScrollbar());
return static_cast<RenderScrollbar*>(scrollbar);
}
diff --git a/Source/WebCore/rendering/RenderScrollbarPart.cpp b/Source/WebCore/rendering/RenderScrollbarPart.cpp
index 3eeb1d89f..af8ac3c12 100644
--- a/Source/WebCore/rendering/RenderScrollbarPart.cpp
+++ b/Source/WebCore/rendering/RenderScrollbarPart.cpp
@@ -30,13 +30,14 @@
#include "RenderScrollbar.h"
#include "RenderScrollbarTheme.h"
#include "RenderView.h"
+#include <wtf/StackStats.h>
using namespace std;
namespace WebCore {
-RenderScrollbarPart::RenderScrollbarPart(Node* node, RenderScrollbar* scrollbar, ScrollbarPart part)
- : RenderBlock(node)
+RenderScrollbarPart::RenderScrollbarPart(RenderScrollbar* scrollbar, ScrollbarPart part)
+ : RenderBlock(0)
, m_scrollbar(scrollbar)
, m_part(part)
{
@@ -46,6 +47,13 @@ RenderScrollbarPart::~RenderScrollbarPart()
{
}
+RenderScrollbarPart* RenderScrollbarPart::createAnonymous(Document* document, RenderScrollbar* scrollbar, ScrollbarPart part)
+{
+ RenderScrollbarPart* renderer = new (document->renderArena()) RenderScrollbarPart(scrollbar, part);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
void RenderScrollbarPart::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
@@ -143,7 +151,7 @@ void RenderScrollbarPart::styleDidChange(StyleDifference diff, const RenderStyle
{
RenderBlock::styleDidChange(diff, oldStyle);
setInline(false);
- setPositioned(false);
+ clearPositionedState();
setFloating(false);
setHasOverflowClip(false);
if (oldStyle && m_scrollbar && m_part != NoPart && diff >= StyleDifferenceRepaint)
@@ -177,7 +185,7 @@ void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, const
return;
// Now do the paint.
- PaintInfo paintInfo(graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, false, 0, 0, 0);
+ PaintInfo paintInfo(graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, PaintBehaviorNormal);
paint(paintInfo, paintOffset);
paintInfo.phase = PaintPhaseChildBlockBackgrounds;
paint(paintInfo, paintOffset);
diff --git a/Source/WebCore/rendering/RenderScrollbarPart.h b/Source/WebCore/rendering/RenderScrollbarPart.h
index 2d8a36c4a..75b7b5106 100644
--- a/Source/WebCore/rendering/RenderScrollbarPart.h
+++ b/Source/WebCore/rendering/RenderScrollbarPart.h
@@ -35,7 +35,8 @@ class RenderScrollbar;
class RenderScrollbarPart : public RenderBlock {
public:
- RenderScrollbarPart(Node*, RenderScrollbar* = 0, ScrollbarPart = NoPart);
+ static RenderScrollbarPart* createAnonymous(Document*, RenderScrollbar* = 0, ScrollbarPart = NoPart);
+
virtual ~RenderScrollbarPart();
virtual const char* renderName() const { return "RenderScrollbarPart"; }
@@ -43,7 +44,6 @@ public:
virtual bool requiresLayer() const { return false; }
virtual void layout();
- virtual void computePreferredLogicalWidths();
void paintIntoRect(GraphicsContext*, const LayoutPoint&, const LayoutRect&);
@@ -62,6 +62,10 @@ protected:
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
private:
+ RenderScrollbarPart(RenderScrollbar*, ScrollbarPart);
+
+ virtual void computePreferredLogicalWidths();
+
void layoutHorizontalPart();
void layoutVerticalPart();
@@ -74,13 +78,13 @@ private:
inline RenderScrollbarPart* toRenderScrollbarPart(RenderObject* object)
{
- ASSERT(!object || object->isRenderScrollbarPart());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderScrollbarPart());
return static_cast<RenderScrollbarPart*>(object);
}
inline const RenderScrollbarPart* toRenderScrollbarPart(const RenderObject* object)
{
- ASSERT(!object || object->isRenderScrollbarPart());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderScrollbarPart());
return static_cast<const RenderScrollbarPart*>(object);
}
diff --git a/Source/WebCore/rendering/RenderSearchField.cpp b/Source/WebCore/rendering/RenderSearchField.cpp
index 4ad458ab7..50d29a784 100644
--- a/Source/WebCore/rendering/RenderSearchField.cpp
+++ b/Source/WebCore/rendering/RenderSearchField.cpp
@@ -53,14 +53,14 @@ using namespace HTMLNames;
// ----------------------------
-RenderSearchField::RenderSearchField(Node* node)
- : RenderTextControlSingleLine(node)
+RenderSearchField::RenderSearchField(Element* element)
+ : RenderTextControlSingleLine(element)
, m_searchPopupIsVisible(false)
, m_searchPopup(0)
{
- ASSERT(node->isHTMLElement());
- ASSERT(node->toInputElement());
- ASSERT(node->toInputElement()->isSearchField());
+ ASSERT(element->isHTMLElement());
+ ASSERT(element->toInputElement());
+ ASSERT(element->toInputElement()->isSearchField());
}
RenderSearchField::~RenderSearchField()
@@ -107,7 +107,7 @@ void RenderSearchField::addSearchResult()
const AtomicString& name = autosaveName();
if (!m_searchPopup)
- m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
+ m_searchPopup = document()->page()->chrome().createSearchPopupMenu(this);
m_searchPopup->saveRecentSearches(name, m_recentSearches);
}
@@ -118,7 +118,7 @@ void RenderSearchField::showPopup()
return;
if (!m_searchPopup)
- m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
+ m_searchPopup = document()->page()->chrome().createSearchPopupMenu(this);
if (!m_searchPopup->enabled())
return;
@@ -147,19 +147,19 @@ void RenderSearchField::hidePopup()
m_searchPopup->popupMenu()->hide();
}
-LayoutUnit RenderSearchField::computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
+LayoutUnit RenderSearchField::computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
{
HTMLElement* resultsButton = resultsButtonElement();
if (RenderBox* resultsRenderer = resultsButton ? resultsButton->renderBox() : 0) {
resultsRenderer->updateLogicalHeight();
- nonContentHeight = max(nonContentHeight, resultsRenderer->borderAndPaddingHeight() + resultsRenderer->marginHeight());
- lineHeight = max(lineHeight, resultsRenderer->height());
+ nonContentHeight = max(nonContentHeight, resultsRenderer->borderAndPaddingLogicalHeight() + resultsRenderer->marginLogicalHeight());
+ lineHeight = max(lineHeight, resultsRenderer->logicalHeight());
}
HTMLElement* cancelButton = cancelButtonElement();
if (RenderBox* cancelRenderer = cancelButton ? cancelButton->renderBox() : 0) {
cancelRenderer->updateLogicalHeight();
- nonContentHeight = max(nonContentHeight, cancelRenderer->borderAndPaddingHeight() + cancelRenderer->marginHeight());
- lineHeight = max(lineHeight, cancelRenderer->height());
+ nonContentHeight = max(nonContentHeight, cancelRenderer->borderAndPaddingLogicalHeight() + cancelRenderer->marginLogicalHeight());
+ lineHeight = max(lineHeight, cancelRenderer->logicalHeight());
}
return lineHeight + nonContentHeight;
@@ -199,7 +199,7 @@ EVisibility RenderSearchField::visibilityForCancelButton() const
const AtomicString& RenderSearchField::autosaveName() const
{
- return static_cast<Element*>(node())->getAttribute(autosaveAttr);
+ return toElement(node())->getAttribute(autosaveAttr);
}
// PopupMenuClient methods
@@ -213,7 +213,7 @@ void RenderSearchField::valueChanged(unsigned listIndex, bool fireEvents)
const AtomicString& name = autosaveName();
if (!name.isEmpty()) {
if (!m_searchPopup)
- m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
+ m_searchPopup = document()->page()->chrome().createSearchPopupMenu(this);
m_searchPopup->saveRecentSearches(name, m_recentSearches);
}
}
@@ -266,7 +266,7 @@ PopupMenuStyle RenderSearchField::itemStyle(unsigned) const
PopupMenuStyle RenderSearchField::menuStyle() const
{
return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE,
- style()->display() == NONE, style()->textIndent(), style()->direction(), isOverride(style()->unicodeBidi()));
+ style()->display() == NONE, style()->textIndent(), style()->direction(), isOverride(style()->unicodeBidi()), PopupMenuStyle::CustomBackgroundColor);
}
int RenderSearchField::clientInsetLeft() const
@@ -344,7 +344,7 @@ void RenderSearchField::setTextFromItem(unsigned listIndex)
FontSelector* RenderSearchField::fontSelector() const
{
- return document()->styleResolver()->fontSelector();
+ return document()->ensureStyleResolver()->fontSelector();
}
HostWindow* RenderSearchField::hostWindow() const
@@ -363,9 +363,9 @@ PassRefPtr<Scrollbar> RenderSearchField::createScrollbar(ScrollableArea* scrolla
return widget.release();
}
-LayoutUnit RenderSearchField::computeHeightLimit() const
+LayoutUnit RenderSearchField::computeLogicalHeightLimit() const
{
- return height();
+ return logicalHeight();
}
void RenderSearchField::centerContainerIfNeeded(RenderBox* containerRenderer) const
@@ -373,13 +373,13 @@ void RenderSearchField::centerContainerIfNeeded(RenderBox* containerRenderer) co
if (!containerRenderer)
return;
- if (containerRenderer->height() <= contentHeight())
+ if (containerRenderer->logicalHeight() <= contentLogicalHeight())
return;
// A quirk for find-in-page box on Safari Windows.
// http://webkit.org/b/63157
- LayoutUnit heightDiff = containerRenderer->height() - contentHeight();
- containerRenderer->setY(containerRenderer->y() - (heightDiff / 2 + layoutMod(heightDiff, 2)));
+ LayoutUnit logicalHeightDiff = containerRenderer->logicalHeight() - contentLogicalHeight();
+ containerRenderer->setLogicalTop(containerRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2)));
}
}
diff --git a/Source/WebCore/rendering/RenderSearchField.h b/Source/WebCore/rendering/RenderSearchField.h
index 967335d34..b0ffaa8c3 100644
--- a/Source/WebCore/rendering/RenderSearchField.h
+++ b/Source/WebCore/rendering/RenderSearchField.h
@@ -33,7 +33,7 @@ class SearchPopupMenu;
class RenderSearchField : public RenderTextControlSingleLine, private PopupMenuClient {
public:
- RenderSearchField(Node*);
+ RenderSearchField(Element*);
virtual ~RenderSearchField();
void updateCancelButtonVisibility() const;
@@ -47,8 +47,8 @@ public:
private:
virtual void centerContainerIfNeeded(RenderBox*) const OVERRIDE;
- virtual LayoutUnit computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE;
- virtual LayoutUnit computeHeightLimit() const OVERRIDE;
+ virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE;
+ virtual LayoutUnit computeLogicalHeightLimit() const OVERRIDE;
virtual void updateFromElement() OVERRIDE;
EVisibility visibilityForCancelButton() const;
const AtomicString& autosaveName() const;
@@ -92,7 +92,7 @@ private:
inline RenderSearchField* toRenderSearchField(RenderObject* object)
{
- ASSERT(!object || object->isTextField());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTextField());
return static_cast<RenderSearchField*>(object);
}
diff --git a/Source/WebCore/rendering/RenderSlider.cpp b/Source/WebCore/rendering/RenderSlider.cpp
index d5b90cad6..55df4fdea 100644
--- a/Source/WebCore/rendering/RenderSlider.cpp
+++ b/Source/WebCore/rendering/RenderSlider.cpp
@@ -41,6 +41,7 @@
#include "StepRange.h"
#include "StyleResolver.h"
#include <wtf/MathExtras.h>
+#include <wtf/StackStats.h>
using std::min;
@@ -70,6 +71,13 @@ int RenderSlider::baselinePosition(FontBaseline, bool /*firstLine*/, LineDirecti
return height() + marginTop();
}
+void RenderSlider::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ maxLogicalWidth = defaultTrackLength * style()->effectiveZoom();
+ if (!style()->width().isPercent())
+ minLogicalWidth = maxLogicalWidth;
+}
+
void RenderSlider::computePreferredLogicalWidths()
{
m_minPreferredLogicalWidth = 0;
@@ -78,16 +86,13 @@ void RenderSlider::computePreferredLogicalWidths()
if (style()->width().isFixed() && style()->width().value() > 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
else
- m_maxPreferredLogicalWidth = defaultTrackLength * style()->effectiveZoom();
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
- } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
- m_minPreferredLogicalWidth = 0;
- else
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
-
+ }
+
if (style()->maxWidth().isFixed()) {
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
@@ -109,7 +114,7 @@ void RenderSlider::layout()
if (thumbBox && thumbBox->isSliderThumb())
static_cast<RenderSliderThumb*>(thumbBox)->updateAppearance(style());
- RenderBlock::layout();
+ RenderFlexibleBox::layout();
}
bool RenderSlider::inDragMode() const
diff --git a/Source/WebCore/rendering/RenderSlider.h b/Source/WebCore/rendering/RenderSlider.h
index 252cd080c..8603a90e8 100644
--- a/Source/WebCore/rendering/RenderSlider.h
+++ b/Source/WebCore/rendering/RenderSlider.h
@@ -33,7 +33,7 @@ class RenderSlider : public RenderFlexibleBox {
public:
static const int defaultTrackLength;
- RenderSlider(HTMLInputElement*);
+ explicit RenderSlider(HTMLInputElement*);
virtual ~RenderSlider();
bool inDragMode() const;
@@ -44,14 +44,15 @@ private:
virtual bool canBeReplacedWithInlineRunIn() const OVERRIDE;
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
- virtual void computePreferredLogicalWidths();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual bool requiresForcedStyleRecalcPropagation() const { return true; }
virtual void layout();
};
inline RenderSlider* toRenderSlider(RenderObject* object)
{
- ASSERT(!object || object->isSlider());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSlider());
return static_cast<RenderSlider*>(object);
}
diff --git a/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp b/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
index 972b2bf90..075910abe 100644
--- a/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
+++ b/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
@@ -26,25 +26,30 @@
#include "config.h"
#include "RenderSnapshottedPlugIn.h"
+#include "CachedImage.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
#include "Cursor.h"
+#include "Filter.h"
#include "FrameLoaderClient.h"
#include "FrameView.h"
#include "Gradient.h"
#include "HTMLPlugInImageElement.h"
+#include "ImageBuffer.h"
#include "MouseEvent.h"
+#include "Page.h"
#include "PaintInfo.h"
#include "Path.h"
+#include "PlatformMouseEvent.h"
+#include "RenderView.h"
+#include <wtf/StackStats.h>
namespace WebCore {
-static const int autoStartPlugInSizeThresholdWidth = 1;
-static const int autoStartPlugInSizeThresholdHeight = 1;
-static const int startButtonPadding = 10;
-
RenderSnapshottedPlugIn::RenderSnapshottedPlugIn(HTMLPlugInImageElement* element)
: RenderEmbeddedObject(element)
, m_snapshotResource(RenderImageResource::create())
- , m_isMouseInButtonRect(false)
+ , m_isPotentialMouseActivation(false)
{
m_snapshotResource->initialize(this);
}
@@ -57,7 +62,22 @@ RenderSnapshottedPlugIn::~RenderSnapshottedPlugIn()
HTMLPlugInImageElement* RenderSnapshottedPlugIn::plugInImageElement() const
{
- return static_cast<HTMLPlugInImageElement*>(node());
+ return toHTMLPlugInImageElement(node());
+}
+
+void RenderSnapshottedPlugIn::layout()
+{
+ StackStats::LayoutCheckPoint layoutCheckPoint;
+ LayoutSize oldSize = contentBoxRect().size();
+
+ RenderEmbeddedObject::layout();
+
+ LayoutSize newSize = contentBoxRect().size();
+ if (newSize == oldSize)
+ return;
+
+ if (document()->view())
+ document()->view()->addWidgetToUpdate(this);
}
void RenderSnapshottedPlugIn::updateSnapshot(PassRefPtr<Image> image)
@@ -72,37 +92,37 @@ void RenderSnapshottedPlugIn::updateSnapshot(PassRefPtr<Image> image)
void RenderSnapshottedPlugIn::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
- if (plugInImageElement()->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick) {
- RenderReplaced::paint(paintInfo, paintOffset);
- return;
+ if (paintInfo.phase == PaintPhaseForeground && plugInImageElement()->displayState() < HTMLPlugInElement::Restarting) {
+ paintSnapshot(paintInfo, paintOffset);
}
- RenderEmbeddedObject::paint(paintInfo, paintOffset);
-}
+ PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
+ newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
-void RenderSnapshottedPlugIn::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
-{
- if (plugInImageElement()->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick) {
- paintReplacedSnapshot(paintInfo, paintOffset);
- paintButton(paintInfo, paintOffset);
- return;
+ PaintInfo paintInfoForChild(paintInfo);
+ paintInfoForChild.phase = newPhase;
+ paintInfoForChild.updateSubtreePaintRootForChildren(this);
+
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
+ if (!child->hasSelfPaintingLayer() && !child->isFloating())
+ child->paint(paintInfoForChild, childPoint);
}
- RenderEmbeddedObject::paintReplaced(paintInfo, paintOffset);
+ RenderEmbeddedObject::paint(paintInfo, paintOffset);
}
-void RenderSnapshottedPlugIn::paintReplacedSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
- // This code should be similar to RenderImage::paintReplaced() and RenderImage::paintIntoRect().
+ Image* image = m_snapshotResource->image().get();
+ if (!image || image->isNull())
+ return;
+
LayoutUnit cWidth = contentWidth();
LayoutUnit cHeight = contentHeight();
if (!cWidth || !cHeight)
return;
- RefPtr<Image> image = m_snapshotResource->image();
- if (!image || image->isNull())
- return;
-
GraphicsContext* context = paintInfo.context;
#if PLATFORM(MAC)
if (style()->highlight() != nullAtom && !context->paintingDisabled())
@@ -110,7 +130,7 @@ void RenderSnapshottedPlugIn::paintReplacedSnapshot(PaintInfo& paintInfo, const
#endif
LayoutSize contentSize(cWidth, cHeight);
- LayoutPoint contentLocation = paintOffset;
+ LayoutPoint contentLocation = location() + paintOffset;
contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
LayoutRect rect(contentLocation, contentSize);
@@ -118,48 +138,13 @@ void RenderSnapshottedPlugIn::paintReplacedSnapshot(PaintInfo& paintInfo, const
if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
return;
- bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), image.get(), alignedRect.size());
- context->drawImage(image.get(), style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling);
-}
-
-static Image* startButtonImage()
-{
- static Image* buttonImage = Image::loadPlatformResource("startButton").leakRef();
- return buttonImage;
-}
-
-static Image* startButtonPressedImage()
-{
- static Image* buttonImage = Image::loadPlatformResource("startButtonPressed").leakRef();
- return buttonImage;
-}
-
-void RenderSnapshottedPlugIn::paintButton(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
-{
- LayoutRect contentRect = contentBoxRect();
- if (contentRect.isEmpty())
- return;
-
- Image* buttonImage = startButtonImage();
- if (plugInImageElement()->active()) {
- if (m_isMouseInButtonRect)
- buttonImage = startButtonPressedImage();
- } else if (!plugInImageElement()->hovered())
- return;
-
- LayoutPoint contentLocation = paintOffset + contentRect.maxXMaxYCorner() - buttonImage->size() - LayoutSize(startButtonPadding, startButtonPadding);
- paintInfo.context->drawImage(buttonImage, ColorSpaceDeviceRGB, roundedIntPoint(contentLocation), buttonImage->rect());
-}
-
-void RenderSnapshottedPlugIn::repaintButton()
-{
- // FIXME: This is unfortunate. We should just repaint the button.
- repaint();
+ bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size());
+ context->drawImage(image, style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling);
}
CursorDirective RenderSnapshottedPlugIn::getCursor(const LayoutPoint& point, Cursor& overrideCursor) const
{
- if (plugInImageElement()->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick) {
+ if (plugInImageElement()->displayState() < HTMLPlugInElement::Restarting) {
overrideCursor = handCursor();
return SetCursor;
}
@@ -173,43 +158,29 @@ void RenderSnapshottedPlugIn::handleEvent(Event* event)
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
- if (event->type() == eventNames().clickEvent && mouseEvent->button() == LeftButton) {
- if (m_isMouseInButtonRect)
- plugInImageElement()->setDisplayState(HTMLPlugInElement::Playing);
- else {
- plugInImageElement()->setDisplayState(HTMLPlugInElement::PlayingWithPendingMouseClick);
- plugInImageElement()->setPendingClickEvent(mouseEvent);
- }
- if (widget()) {
- if (Frame* frame = document()->frame())
- frame->loader()->client()->recreatePlugin(widget());
- repaint();
- }
- event->setDefaultHandled();
- } else if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent)
- repaintButton();
- else if (event->type() == eventNames().mousedownEvent) {
- bool isMouseInButtonRect = m_buttonRect.contains(IntPoint(mouseEvent->offsetX(), mouseEvent->offsetY()));
- if (isMouseInButtonRect != m_isMouseInButtonRect) {
- m_isMouseInButtonRect = isMouseInButtonRect;
- repaintButton();
- }
- }
-}
+ // If we're a snapshotted plugin, we want to make sure we activate on
+ // clicks even if the page is preventing our default behaviour. Otherwise
+ // we can never restart. One we do restart, then the page will happily
+ // block the new plugin in the normal renderer. All this means we have to
+ // be on the lookout for a mouseup event that comes after a mousedown
+ // event. The code below is not completely foolproof, but the worst that
+ // could happen is that a snapshotted plugin restarts.
-void RenderSnapshottedPlugIn::layout()
-{
- RenderEmbeddedObject::layout();
- if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) {
- LayoutRect rect = contentBoxRect();
- int width = rect.width();
- int height = rect.height();
- if (!width || !height || (width <= autoStartPlugInSizeThresholdWidth && height <= autoStartPlugInSizeThresholdHeight))
- plugInImageElement()->setDisplayState(HTMLPlugInElement::Playing);
- }
+ if (event->type() == eventNames().mouseoutEvent)
+ m_isPotentialMouseActivation = false;
+
+ if (mouseEvent->button() != LeftButton)
+ return;
- LayoutSize buttonSize = startButtonImage()->size();
- m_buttonRect = LayoutRect(contentBoxRect().maxXMaxYCorner() - LayoutSize(startButtonPadding, startButtonPadding) - buttonSize, buttonSize);
+ if (event->type() == eventNames().clickEvent || (m_isPotentialMouseActivation && event->type() == eventNames().mouseupEvent)) {
+ m_isPotentialMouseActivation = false;
+ bool clickWasOnOverlay = plugInImageElement()->partOfSnapshotOverlay(event->target()->toNode());
+ plugInImageElement()->userDidClickSnapshot(mouseEvent, !clickWasOnOverlay);
+ event->setDefaultHandled();
+ } else if (event->type() == eventNames().mousedownEvent) {
+ m_isPotentialMouseActivation = true;
+ event->setDefaultHandled();
+ }
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderSnapshottedPlugIn.h b/Source/WebCore/rendering/RenderSnapshottedPlugIn.h
index 2a1f896c7..beae256fa 100644
--- a/Source/WebCore/rendering/RenderSnapshottedPlugIn.h
+++ b/Source/WebCore/rendering/RenderSnapshottedPlugIn.h
@@ -27,9 +27,8 @@
#define RenderSnapshottedPlugIn_h
#include "RenderEmbeddedObject.h"
-
#include "RenderImageResource.h"
-#include "RenderTheme.h"
+#include "Timer.h"
namespace WebCore {
@@ -37,7 +36,7 @@ class HTMLPlugInImageElement;
class RenderSnapshottedPlugIn : public RenderEmbeddedObject {
public:
- RenderSnapshottedPlugIn(HTMLPlugInImageElement*);
+ explicit RenderSnapshottedPlugIn(HTMLPlugInImageElement*);
virtual ~RenderSnapshottedPlugIn();
void updateSnapshot(PassRefPtr<Image>);
@@ -51,22 +50,20 @@ private:
virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const OVERRIDE;
virtual bool isSnapshottedPlugIn() const OVERRIDE { return true; }
virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE;
- virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE;
+
+ virtual bool canHaveWidget() const OVERRIDE { return false; }
- void paintReplacedSnapshot(PaintInfo&, const LayoutPoint&);
- void paintButton(PaintInfo&, const LayoutPoint&);
- void repaintButton();
+ void paintSnapshot(PaintInfo&, const LayoutPoint&);
virtual void layout() OVERRIDE;
OwnPtr<RenderImageResource> m_snapshotResource;
- LayoutRect m_buttonRect;
- bool m_isMouseInButtonRect;
+ bool m_isPotentialMouseActivation;
};
inline RenderSnapshottedPlugIn* toRenderSnapshottedPlugIn(RenderObject* object)
{
- ASSERT(!object || object->isSnapshottedPlugIn());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSnapshottedPlugIn());
return static_cast<RenderSnapshottedPlugIn*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp
index 7d5cfe94f..3249afb8a 100644
--- a/Source/WebCore/rendering/RenderTable.cpp
+++ b/Source/WebCore/rendering/RenderTable.cpp
@@ -28,12 +28,12 @@
#include "AutoTableLayout.h"
#include "CollapsedBorderValue.h"
-#include "DeleteButtonController.h"
#include "Document.h"
#include "FixedTableLayout.h"
#include "FrameView.h"
#include "HitTestResult.h"
#include "HTMLNames.h"
+#include "HTMLTableElement.h"
#include "LayoutRepainter.h"
#include "RenderLayer.h"
#include "RenderTableCaption.h"
@@ -42,6 +42,7 @@
#include "RenderTableSection.h"
#include "RenderView.h"
#include "StyleInheritedData.h"
+#include <wtf/StackStats.h>
using namespace std;
@@ -49,8 +50,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderTable::RenderTable(Node* node)
- : RenderBlock(node)
+RenderTable::RenderTable(Element* element)
+ : RenderBlock(element)
, m_head(0)
, m_foot(0)
, m_firstBody(0)
@@ -113,10 +114,6 @@ static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, Rend
void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
{
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild)
- beforeChild = afterPseudoElementRenderer();
-
bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
if (child->isTableCaption())
@@ -159,6 +156,9 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
else
wrapInAnonymousSection = true;
+ if (child->isTableSection())
+ setNeedsSectionRecalc();
+
if (!wrapInAnonymousSection) {
if (beforeChild && beforeChild->parent() != this)
beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
@@ -255,7 +255,7 @@ void RenderTable::updateLogicalWidth()
LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
Length styleLogicalWidth = style()->logicalWidth();
- if (styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive())
+ if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic())
setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
else {
// Subtract out any fixed margins from our available width for auto width tables.
@@ -267,7 +267,7 @@ void RenderTable::updateLogicalWidth()
LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) {
// FIXME: Work with regions someday.
- availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, 0, 0);
+ availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, 0);
}
// Ensure we aren't bigger than our available width.
@@ -280,14 +280,14 @@ void RenderTable::updateLogicalWidth()
// Ensure we aren't bigger than our max-width style.
Length styleMaxLogicalWidth = style()->logicalMaxWidth();
- if (styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) {
+ if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) {
LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth);
setLogicalWidth(min<int>(logicalWidth(), computedMaxLogicalWidth));
}
// Ensure we aren't smaller than our min-width style.
Length styleMinLogicalWidth = style()->logicalMinWidth();
- if (styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) {
+ if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) {
LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth);
setLogicalWidth(max<int>(logicalWidth(), computedMinLogicalWidth));
}
@@ -298,7 +298,7 @@ void RenderTable::updateLogicalWidth()
if (!hasPerpendicularContainingBlock) {
LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth;
if (avoidsFloats() && cb->containsFloats())
- containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0, 0); // FIXME: Work with regions someday.
+ containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0); // FIXME: Work with regions someday.
ComputedMarginValues marginValues;
bool hasInvertedDirection = cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection();
computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(),
@@ -315,14 +315,15 @@ void RenderTable::updateLogicalWidth()
// This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
{
+ if (styleLogicalWidth.isIntrinsic())
+ return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection());
+
// HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
LayoutUnit borders = 0;
- bool isCSSTable = !node() || !node()->hasTagName(tableTag);
- if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) {
- recalcBordersInRowDirection();
- if (style()->boxSizing() == CONTENT_BOX)
- borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
- }
+ bool isCSSTable = !node() || !isHTMLTableElement(node());
+ if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX)
+ borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
+
return minimumValueForLength(styleLogicalWidth, availableWidth, view()) + borders;
}
@@ -333,7 +334,7 @@ LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length&
// HTML tables size as though CSS height includes border/padding, CSS tables do not.
LayoutUnit borders = LayoutUnit();
// FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
- if ((node() && node()->hasTagName(tableTag)) || style()->boxSizing() == BORDER_BOX) {
+ if ((node() && isHTMLTableElement(node())) || style()->boxSizing() == BORDER_BOX) {
LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
borders = borderAndPaddingBefore + borderAndPaddingAfter;
@@ -382,6 +383,14 @@ void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
// ASSERT(!topSection() || !extraLogicalHeight);
}
+void RenderTable::simplifiedNormalFlowLayout()
+{
+ for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
+ section->layoutIfNeeded();
+ section->computeOverflowFromCells();
+ }
+}
+
void RenderTable::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
@@ -391,12 +400,14 @@ void RenderTable::layout()
return;
recalcSectionsIfNeeded();
+ // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
+ // to call this before we call borderStart/borderEnd to avoid getting a stale value.
+ recalcBordersInRowDirection();
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
- LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
+ LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
setLogicalHeight(0);
- m_overflow.clear();
initMaxMarginValues();
@@ -643,7 +654,7 @@ void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
PaintInfo info(paintInfo);
info.phase = paintPhase;
- info.updatePaintingRootForChildren(this);
+ info.updateSubtreePaintRootForChildren(this);
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
@@ -670,7 +681,7 @@ void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
// Paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
- paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
+ paintOutline(paintInfo, LayoutRect(paintOffset, size()));
}
void RenderTable::subtractCaptionRect(LayoutRect& rect) const
@@ -698,9 +709,10 @@ void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& p
LayoutRect rect(paintOffset, size());
subtractCaptionRect(rect);
- if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context)))
+ BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
+ if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
paintBoxShadow(paintInfo, rect, style(), Normal);
- paintBackground(paintInfo, rect);
+ paintBackground(paintInfo, rect, bleedAvoidance);
paintBoxShadow(paintInfo, rect, style(), Inset);
if (style()->hasBorder() && !collapseBorders())
@@ -718,18 +730,49 @@ void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset
paintMaskImages(paintInfo, rect);
}
+void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
+{
+ recalcSectionsIfNeeded();
+ // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
+ // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
+ // of reading out stale values.
+ const_cast<RenderTable*>(this)->recalcBordersInRowDirection();
+ // FIXME: Restructure the table layout code so that we can make this method const.
+ const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth);
+
+ // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
+}
+
void RenderTable::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
- recalcSectionsIfNeeded();
- recalcBordersInRowDirection();
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
+
+ int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
+ m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
+ m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
- m_tableLayout->computePreferredLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
+ m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
for (unsigned i = 0; i < m_captions.size(); i++)
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
+ RenderStyle* styleToUse = style();
+ // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
+ if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
+ m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
+ }
+
+ // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
+ if (styleToUse->logicalMaxWidth().isFixed()) {
+ m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
+ }
+
+ // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
+ // so a bunch of tests break doing this naively.
setPreferredLogicalWidthsDirty(false);
}
@@ -762,7 +805,6 @@ void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
}
m_columnPos.grow(numEffCols() + 1);
- setNeedsLayoutAndPrefWidthsRecalc();
}
void RenderTable::appendColumn(unsigned span)
@@ -784,7 +826,6 @@ void RenderTable::appendColumn(unsigned span)
}
m_columnPos.grow(numEffCols() + 1);
- setNeedsLayoutAndPrefWidthsRecalc();
}
RenderTableCol* RenderTable::firstColumn() const
@@ -1314,9 +1355,16 @@ int RenderTable::firstLineBoxBaseline() const
return -1;
}
-LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
+LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy, PaintPhase phase)
{
- LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy);
+ LayoutRect rect;
+ // Don't clip out the table's side of the collapsed borders if we're in the paint phase that will ask the sections to paint them.
+ // Likewise, if we're self-painting we avoid clipping them out as the clip rect that will be passed down to child layers from RenderLayer will do that instead.
+ if (phase == PaintPhaseChildBlockBackgrounds || layer()->isSelfPaintingLayer()) {
+ rect = borderBoxRectInRegion(region);
+ rect.setLocation(location + rect.location());
+ } else
+ rect = RenderBox::overflowClipRect(location, region, relevancy);
// If we have a caption, expand the clip to include the caption.
// FIXME: Technically this is wrong, but it's virtually impossible to fix this
@@ -1368,7 +1416,8 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
{
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
- RenderTable* newTable = new (parent->renderArena()) RenderTable(parent->document() /* is anonymous */);
+ RenderTable* newTable = new (parent->renderArena()) RenderTable(0);
+ newTable->setDocumentForAnonymous(parent->document());
newTable->setStyle(newStyle.release());
return newTable;
}
diff --git a/Source/WebCore/rendering/RenderTable.h b/Source/WebCore/rendering/RenderTable.h
index 55a450957..85a807a0f 100644
--- a/Source/WebCore/rendering/RenderTable.h
+++ b/Source/WebCore/rendering/RenderTable.h
@@ -42,7 +42,7 @@ enum SkipEmptySectionsValue { DoNotSkipEmptySections, SkipEmptySections };
class RenderTable : public RenderBlock {
public:
- explicit RenderTable(Node*);
+ explicit RenderTable(Element*);
virtual ~RenderTable();
// Per CSS 3 writing-mode: "The first and second values of the 'border-spacing' property represent spacing between columns
@@ -194,6 +194,10 @@ public:
return 0;
}
+ // Override paddingStart/End to return pixel values to match behavor of RenderTableCell.
+ virtual LayoutUnit paddingEnd() const OVERRIDE { return static_cast<int>(RenderBlock::paddingEnd()); }
+ virtual LayoutUnit paddingStart() const OVERRIDE { return static_cast<int>(RenderBlock::paddingStart()); }
+
LayoutUnit bordersPaddingAndSpacingInRowDirection() const
{
// 'border-spacing' only applies to separate borders (see 17.6.1 The separated borders model).
@@ -260,6 +264,7 @@ public:
protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ virtual void simplifiedNormalFlowLayout();
private:
virtual const char* renderName() const { return "RenderTable"; }
@@ -273,7 +278,8 @@ private:
virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
virtual void paintMask(PaintInfo&, const LayoutPoint&);
virtual void layout();
- virtual void computePreferredLogicalWidths();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE;
@@ -293,7 +299,8 @@ private:
LayoutUnit convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth);
LayoutUnit convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight);
- virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize);
+ virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, PaintPhase = PaintPhaseBlockBackground);
+ virtual LayoutRect overflowClipRectForChildLayers(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) { return RenderBox::overflowClipRect(location, region, relevancy); }
virtual void addOverflowFromChildren();
@@ -344,13 +351,13 @@ inline RenderTableSection* RenderTable::topSection() const
inline RenderTable* toRenderTable(RenderObject* object)
{
- ASSERT(!object || object->isTable());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTable());
return static_cast<RenderTable*>(object);
}
inline const RenderTable* toRenderTable(const RenderObject* object)
{
- ASSERT(!object || object->isTable());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTable());
return static_cast<const RenderTable*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTableCaption.cpp b/Source/WebCore/rendering/RenderTableCaption.cpp
index df5194c97..76486f975 100644
--- a/Source/WebCore/rendering/RenderTableCaption.cpp
+++ b/Source/WebCore/rendering/RenderTableCaption.cpp
@@ -24,8 +24,8 @@
namespace WebCore {
-RenderTableCaption::RenderTableCaption(Node* node)
- : RenderBlock(node)
+RenderTableCaption::RenderTableCaption(Element* element)
+ : RenderBlock(element)
{
}
diff --git a/Source/WebCore/rendering/RenderTableCaption.h b/Source/WebCore/rendering/RenderTableCaption.h
index 91edb9f6e..3fb51db33 100644
--- a/Source/WebCore/rendering/RenderTableCaption.h
+++ b/Source/WebCore/rendering/RenderTableCaption.h
@@ -28,7 +28,7 @@ class RenderTable;
class RenderTableCaption : public RenderBlock {
public:
- explicit RenderTableCaption(Node*);
+ explicit RenderTableCaption(Element*);
virtual ~RenderTableCaption();
virtual LayoutUnit containingBlockLogicalWidthForContent() const OVERRIDE;
@@ -43,13 +43,13 @@ private:
inline RenderTableCaption* toRenderTableCaption(RenderObject* object)
{
- ASSERT(!object || object->isTableCaption());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableCaption());
return static_cast<RenderTableCaption*>(object);
}
inline const RenderTableCaption* toRenderTableCaption(const RenderObject* object)
{
- ASSERT(!object || object->isTableCaption());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableCaption());
return static_cast<const RenderTableCaption*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp
index aa3ad197f..9b0d57cd3 100644
--- a/Source/WebCore/rendering/RenderTableCell.cpp
+++ b/Source/WebCore/rendering/RenderTableCell.cpp
@@ -33,8 +33,9 @@
#include "PaintInfo.h"
#include "RenderTableCol.h"
#include "RenderView.h"
-#include "StyleInheritedData.h"
+#include "StylePropertySet.h"
#include "TransformState.h"
+#include <wtf/StackStats.h>
#if ENABLE(MATHML)
#include "MathMLElement.h"
@@ -55,8 +56,8 @@ struct SameSizeAsRenderTableCell : public RenderBlock {
COMPILE_ASSERT(sizeof(RenderTableCell) == sizeof(SameSizeAsRenderTableCell), RenderTableCell_should_stay_small);
COMPILE_ASSERT(sizeof(CollapsedBorderValue) == 8, CollapsedBorderValue_should_stay_small);
-RenderTableCell::RenderTableCell(Node* node)
- : RenderBlock(node)
+RenderTableCell::RenderTableCell(Element* element)
+ : RenderBlock(element)
, m_column(unsetColumnIndex)
, m_cellWidthChanged(false)
, m_intrinsicPaddingBefore(0)
@@ -79,10 +80,10 @@ unsigned RenderTableCell::parseColSpanFromDOM() const
{
ASSERT(node());
if (node()->hasTagName(tdTag) || node()->hasTagName(thTag))
- return toHTMLTableCellElement(node())->colSpan();
+ return min<unsigned>(toHTMLTableCellElement(node())->colSpan(), maxColumnIndex);
#if ENABLE(MATHML)
if (node()->hasTagName(MathMLNames::mtdTag))
- return toMathMLElement(node())->colSpan();
+ return min<unsigned>(toMathMLElement(node())->colSpan(), maxColumnIndex);
#endif
return 1;
}
@@ -91,10 +92,10 @@ unsigned RenderTableCell::parseRowSpanFromDOM() const
{
ASSERT(node());
if (node()->hasTagName(tdTag) || node()->hasTagName(thTag))
- return toHTMLTableCellElement(node())->rowSpan();
+ return min<unsigned>(toHTMLTableCellElement(node())->rowSpan(), maxRowIndex);
#if ENABLE(MATHML)
if (node()->hasTagName(MathMLNames::mtdTag))
- return toMathMLElement(node())->rowSpan();
+ return min<unsigned>(toMathMLElement(node())->rowSpan(), maxRowIndex);
#endif
return 1;
}
@@ -168,7 +169,7 @@ void RenderTableCell::computePreferredLogicalWidths()
if (node() && style()->autoWrap()) {
// See if nowrap was set.
Length w = styleOrColLogicalWidth();
- String nowrap = static_cast<Element*>(node())->getAttribute(nowrapAttr);
+ String nowrap = toElement(node())->getAttribute(nowrapAttr);
if (!nowrap.isNull() && w.isFixed())
// Nowrap is set, but we didn't actually use it because of the
// fixed width set on the cell. Even so, it is a WinIE/Moz trait
@@ -194,7 +195,7 @@ void RenderTableCell::computeIntrinsicPadding(int rowHeight)
case LENGTH:
case BASELINE: {
LayoutUnit baseline = cellBaselinePosition();
- if (baseline > borderBefore() + paddingBefore())
+ if (baseline > borderAndPaddingBefore())
intrinsicPaddingBefore = section()->rowBaseline(rowIndex()) - (baseline - oldIntrinsicPaddingBefore);
break;
}
@@ -243,7 +244,21 @@ void RenderTableCell::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
updateFirstLetter();
+
+ int oldCellBaseline = cellBaselinePosition();
layoutBlock(cellWidthChanged());
+
+ // If we have replaced content, the intrinsic height of our content may have changed since the last time we laid out. If that's the case the intrinsic padding we used
+ // for layout (the padding required to push the contents of the cell down to the row's baseline) is included in our new height and baseline and makes both
+ // of them wrong. So if our content's intrinsic height has changed push the new content up into the intrinsic padding and relayout so that the rest of
+ // table and row layout can use the correct baseline and height for this cell.
+ if (isBaselineAligned() && section()->rowBaseline(rowIndex()) && cellBaselinePosition() > section()->rowBaseline(rowIndex())) {
+ int newIntrinsicPaddingBefore = max<LayoutUnit>(0, intrinsicPaddingBefore() - max<LayoutUnit>(0, cellBaselinePosition() - oldCellBaseline));
+ setIntrinsicPaddingBefore(newIntrinsicPaddingBefore);
+ setNeedsLayout(true, MarkOnlyThis);
+ layoutBlock(cellWidthChanged());
+ }
+
setCellWidthChanged(false);
}
@@ -376,7 +391,7 @@ LayoutUnit RenderTableCell::cellBaselinePosition() const
LayoutUnit firstLineBaseline = firstLineBoxBaseline();
if (firstLineBaseline != -1)
return firstLineBaseline;
- return paddingBefore() + borderBefore() + contentLogicalHeight();
+ return borderAndPaddingBefore() + contentLogicalHeight();
}
void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -390,6 +405,11 @@ void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* ol
if (parent() && section() && oldStyle && style()->height() != oldStyle->height())
section()->rowLogicalHeightChanged(rowIndex());
+ // Our intrinsic padding pushes us down to align with the baseline of other cells on the row. If our vertical-align
+ // has changed then so will the padding needed to align with other cells - clear it so we can recalculate it from scratch.
+ if (oldStyle && style()->verticalAlign() != oldStyle->verticalAlign())
+ clearIntrinsicPadding();
+
// If border was changed, notify table.
if (parent()) {
RenderTable* table = this->table();
@@ -1081,6 +1101,31 @@ void RenderTableCell::sortBorderValues(RenderTable::CollapsedBorderValues& borde
compareBorderValuesForQSort);
}
+bool RenderTableCell::alignLeftRightBorderPaintRect(int& leftXOffset, int& rightXOffset)
+{
+ const RenderStyle* styleForTopCell = styleForCellFlow();
+ int left = cachedCollapsedLeftBorder(styleForTopCell).width();
+ int right = cachedCollapsedRightBorder(styleForTopCell).width();
+ leftXOffset = max<int>(leftXOffset, left);
+ rightXOffset = max<int>(rightXOffset, right);
+ if (colSpan() > 1)
+ return false;
+ return true;
+}
+
+bool RenderTableCell::alignTopBottomBorderPaintRect(int& topYOffset, int& bottomYOffset)
+{
+ const RenderStyle* styleForBottomCell = styleForCellFlow();
+ int top = cachedCollapsedTopBorder(styleForBottomCell).width();
+ int bottom = cachedCollapsedBottomBorder(styleForBottomCell).width();
+ topYOffset = max<int>(topYOffset, top);
+ bottomYOffset = max<int>(bottomYOffset, bottom);
+ if (rowSpan() > 1)
+ return false;
+ return true;
+}
+
+
void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
ASSERT(paintInfo.phase == PaintPhaseCollapsedTableBorders);
@@ -1091,7 +1136,7 @@ void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPo
LayoutRect localRepaintRect = paintInfo.rect;
localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase));
- LayoutRect paintRect = LayoutRect(paintOffset + location(), size());
+ LayoutRect paintRect = LayoutRect(paintOffset + location(), pixelSnappedSize());
if (paintRect.y() - table()->outerBorderTop() >= localRepaintRect.maxY())
return;
@@ -1114,35 +1159,80 @@ void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPo
int leftWidth = leftVal.width();
int rightWidth = rightVal.width();
+ int leftXOffsetTop = leftWidth;
+ int leftXOffsetBottom = leftWidth;
+ int rightXOffsetTop = rightWidth;
+ int rightXOffsetBottom = rightWidth;
+ int topYOffsetLeft = topWidth;
+ int topYOffsetRight = topWidth;
+ int bottomYOffsetLeft = bottomWidth;
+ int bottomYOffsetRight = bottomWidth;
+
+ bool shouldDrawTopBorder = true;
+ bool shouldDrawLeftBorder = true;
+ bool shouldDrawRightBorder = true;
+
+ if (RenderTableCell* top = table()->cellAbove(this)) {
+ shouldDrawTopBorder = top->alignLeftRightBorderPaintRect(leftXOffsetTop, rightXOffsetTop);
+ if (this->colSpan() > 1)
+ shouldDrawTopBorder = false;
+ }
+
+ if (RenderTableCell* bottom = table()->cellBelow(this))
+ bottom->alignLeftRightBorderPaintRect(leftXOffsetBottom, rightXOffsetBottom);
+
+ if (RenderTableCell* left = table()->cellBefore(this))
+ shouldDrawLeftBorder = left->alignTopBottomBorderPaintRect(topYOffsetLeft, bottomYOffsetLeft);
+
+ if (RenderTableCell* right = table()->cellAfter(this))
+ shouldDrawRightBorder = right->alignTopBottomBorderPaintRect(topYOffsetRight, bottomYOffsetRight);
+
+ IntRect cellRect = pixelSnappedIntRect(paintRect.x(), paintRect.y(), paintRect.width(), paintRect.height());
+
IntRect borderRect = pixelSnappedIntRect(paintRect.x() - leftWidth / 2,
- paintRect.y() - topWidth / 2,
- paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2,
- paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2);
+ paintRect.y() - topWidth / 2,
+ paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2,
+ paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2);
EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
- bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
+ bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent() && shouldDrawTopBorder;
bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
- bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
- bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
+ bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent() && shouldDrawLeftBorder;
+ bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent() && shouldDrawRightBorder;
// We never paint diagonals at the joins. We simply let the border with the highest
// precedence paint on top of borders with lower precedence.
CollapsedBorders borders;
- borders.addBorder(topVal, BSTop, renderTop, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, topStyle);
- borders.addBorder(bottomVal, BSBottom, renderBottom, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), bottomStyle);
- borders.addBorder(leftVal, BSLeft, renderLeft, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), leftStyle);
- borders.addBorder(rightVal, BSRight, renderRight, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), rightStyle);
+ if (topVal.style() == DOTTED)
+ borders.addBorder(topVal, BSTop, renderTop, cellRect.x() - leftXOffsetTop / 2, cellRect.y() - topWidth / 2, cellRect.maxX() + rightXOffsetTop / 2, cellRect.y() + topWidth / 2 + topWidth % 2, topStyle);
+ else
+ borders.addBorder(topVal, BSTop, renderTop, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, topStyle);
+
+ if (bottomVal.style() == DOTTED)
+ borders.addBorder(bottomVal, BSBottom, renderBottom, cellRect.x() - leftXOffsetBottom / 2, cellRect.maxY() - bottomWidth / 2, cellRect.maxX() + rightXOffsetBottom / 2, cellRect.maxY() + bottomWidth / 2 + bottomWidth % 2, bottomStyle);
+ else
+ borders.addBorder(bottomVal, BSBottom, renderBottom, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), bottomStyle);
+
+ if (leftVal.style() == DOTTED)
+ borders.addBorder(leftVal, BSLeft, renderLeft, cellRect.x() - leftWidth / 2, cellRect.y() - topYOffsetLeft / 2, cellRect.x() + leftWidth / 2 + leftWidth % 2, cellRect.maxY() + bottomYOffsetLeft / 2 + bottomYOffsetLeft % 2, leftStyle);
+ else
+ borders.addBorder(leftVal, BSLeft, renderLeft, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), leftStyle);
+
+ if (rightVal.style() == DOTTED)
+ borders.addBorder(rightVal, BSRight, renderRight, cellRect.maxX() - rightWidth / 2, cellRect.y() - topYOffsetRight / 2, cellRect.maxX() + rightWidth / 2 + rightWidth % 2, cellRect.maxY() + bottomYOffsetRight / 2 + bottomYOffsetRight % 2, rightStyle);
+ else
+ borders.addBorder(rightVal, BSRight, renderRight, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), rightStyle);
bool antialias = shouldAntialiasLines(graphicsContext);
for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
if (border->borderValue.isSameIgnoringColor(*table()->currentBorderValue()))
drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side,
- border->borderValue.color(), border->style, 0, 0, antialias);
+ border->borderValue.color(), border->style, 0, 0, antialias);
}
}
@@ -1178,7 +1268,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, const Lay
width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
paintInfo.context->clip(clipRect);
}
- paintFillLayers(paintInfo, c, bgLayer, LayoutRect(adjustedPaintOffset, size()), BackgroundBleedNone, CompositeSourceOver, backgroundObject);
+ paintFillLayers(paintInfo, c, bgLayer, LayoutRect(adjustedPaintOffset, pixelSnappedSize()), BackgroundBleedNone, CompositeSourceOver, backgroundObject);
}
}
@@ -1191,7 +1281,7 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoin
if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
return;
- LayoutRect paintRect = LayoutRect(paintOffset, size());
+ LayoutRect paintRect = LayoutRect(paintOffset, pixelSnappedSize());
paintBoxShadow(paintInfo, paintRect, style(), Normal);
// Paint our cell background.
@@ -1214,7 +1304,7 @@ void RenderTableCell::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOf
if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
return;
- paintMaskImages(paintInfo, LayoutRect(paintOffset, size()));
+ paintMaskImages(paintInfo, LayoutRect(paintOffset, pixelSnappedSize()));
}
bool RenderTableCell::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const
@@ -1246,10 +1336,17 @@ void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool ve
setIntrinsicPaddingAfter(intrinsicPaddingAfter() - scrollbarHeight);
}
+RenderTableCell* RenderTableCell::createAnonymous(Document* document)
+{
+ RenderTableCell* renderer = new (document->renderArena()) RenderTableCell(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
RenderTableCell* RenderTableCell::createAnonymousWithParentRenderer(const RenderObject* parent)
{
+ RenderTableCell* newCell = RenderTableCell::createAnonymous(parent->document());
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_CELL);
- RenderTableCell* newCell = new (parent->renderArena()) RenderTableCell(parent->document() /* is anonymous */);
newCell->setStyle(newStyle.release());
return newCell;
}
diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h
index 2dd26a24d..720aa98c4 100644
--- a/Source/WebCore/rendering/RenderTableCell.h
+++ b/Source/WebCore/rendering/RenderTableCell.h
@@ -37,7 +37,7 @@ enum IncludeBorderColorOrNot { DoNotIncludeBorderColor, IncludeBorderColor };
class RenderTableCell : public RenderBlock {
public:
- explicit RenderTableCell(Node*);
+ explicit RenderTableCell(Element*);
unsigned colSpan() const
{
@@ -90,19 +90,18 @@ public:
return styleWidth;
}
- LayoutUnit logicalHeightForRowSizing() const
+ int logicalHeightForRowSizing() const
{
// FIXME: This function does too much work, and is very hot during table layout!
- LayoutUnit adjustedLogicalHeight = logicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter());
- LayoutUnit styleLogicalHeight = valueForLength(style()->logicalHeight(), 0, view());
+ int adjustedLogicalHeight = pixelSnappedLogicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter());
+ int styleLogicalHeight = valueForLength(style()->logicalHeight(), 0, view());
// In strict mode, box-sizing: content-box do the right thing and actually add in the border and padding.
// Call computedCSSPadding* directly to avoid including implicitPadding.
if (!document()->inQuirksMode() && style()->boxSizing() != BORDER_BOX)
- styleLogicalHeight += computedCSSPaddingBefore() + computedCSSPaddingAfter() + borderBefore() + borderAfter();
+ styleLogicalHeight += (computedCSSPaddingBefore() + computedCSSPaddingAfter()).floor() + borderBefore() + borderAfter();
return max(styleLogicalHeight, adjustedLogicalHeight);
}
- virtual void computePreferredLogicalWidths();
void setCellLogicalWidth(int constrainedLogicalWidth);
@@ -122,10 +121,17 @@ public:
virtual void paint(PaintInfo&, const LayoutPoint&);
+ bool alignLeftRightBorderPaintRect(int& leftXOffset, int& rightXOffset);
+ bool alignTopBottomBorderPaintRect(int& topYOffset, int& bottomYOffset);
void paintCollapsedBorders(PaintInfo&, const LayoutPoint&);
void paintBackgroundsBehindCell(PaintInfo&, const LayoutPoint&, RenderObject* backgroundObject);
LayoutUnit cellBaselinePosition() const;
+ bool isBaselineAligned() const
+ {
+ EVerticalAlign va = style()->verticalAlign();
+ return va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH;
+ }
void computeIntrinsicPadding(int rowHeight);
void clearIntrinsicPadding() { setIntrinsicPadding(0, 0); }
@@ -151,6 +157,7 @@ public:
bool cellWidthChanged() const { return m_cellWidthChanged; }
void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; }
+ static RenderTableCell* createAnonymous(Document*);
static RenderTableCell* createAnonymousWithParentRenderer(const RenderObject*);
virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE
{
@@ -207,9 +214,10 @@ public:
#endif
protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ virtual void computePreferredLogicalWidths();
private:
- virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
+ virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
virtual bool isTableCell() const { return true; }
@@ -276,13 +284,13 @@ private:
inline RenderTableCell* toRenderTableCell(RenderObject* object)
{
- ASSERT(!object || object->isTableCell());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableCell());
return static_cast<RenderTableCell*>(object);
}
inline const RenderTableCell* toRenderTableCell(const RenderObject* object)
{
- ASSERT(!object || object->isTableCell());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableCell());
return static_cast<const RenderTableCell*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTableCol.cpp b/Source/WebCore/rendering/RenderTableCol.cpp
index cc630cb11..23a06b966 100644
--- a/Source/WebCore/rendering/RenderTableCol.cpp
+++ b/Source/WebCore/rendering/RenderTableCol.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "RenderTableCol.h"
-#include "CachedImage.h"
#include "HTMLNames.h"
#include "HTMLTableColElement.h"
#include "RenderTable.h"
@@ -36,8 +35,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderTableCol::RenderTableCol(Node* node)
- : RenderBox(node)
+RenderTableCol::RenderTableCol(Element* element)
+ : RenderBox(element)
, m_span(1)
{
// init RenderObject attributes
@@ -114,7 +113,7 @@ void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*)
repaint();
}
-void RenderTableCol::computePreferredLogicalWidths()
+void RenderTableCol::clearPreferredLogicalWidthsDirtyBits()
{
setPreferredLogicalWidthsDirty(false);
diff --git a/Source/WebCore/rendering/RenderTableCol.h b/Source/WebCore/rendering/RenderTableCol.h
index a091a9399..c93b01922 100644
--- a/Source/WebCore/rendering/RenderTableCol.h
+++ b/Source/WebCore/rendering/RenderTableCol.h
@@ -35,7 +35,7 @@ class RenderTableCell;
class RenderTableCol : public RenderBox {
public:
- explicit RenderTableCol(Node*);
+ explicit RenderTableCol(Element*);
RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); }
RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); }
@@ -43,7 +43,7 @@ public:
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
- virtual void computePreferredLogicalWidths();
+ void clearPreferredLogicalWidthsDirtyBits();
unsigned span() const { return m_span; }
void setSpan(unsigned span) { m_span = span; }
@@ -83,6 +83,7 @@ private:
virtual const char* renderName() const { return "RenderTableCol"; }
virtual bool isRenderTableCol() const OVERRIDE { return true; }
virtual void updateFromElement();
+ virtual void computePreferredLogicalWidths() OVERRIDE { ASSERT_NOT_REACHED(); }
virtual void insertedIntoTree() OVERRIDE;
virtual void willBeRemovedFromTree() OVERRIDE;
@@ -104,13 +105,13 @@ private:
inline RenderTableCol* toRenderTableCol(RenderObject* object)
{
- ASSERT(!object || object->isRenderTableCol());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderTableCol());
return static_cast<RenderTableCol*>(object);
}
inline const RenderTableCol* toRenderTableCol(const RenderObject* object)
{
- ASSERT(!object || object->isRenderTableCol());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderTableCol());
return static_cast<const RenderTableCol*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp
index e00c9a64f..8dec058a2 100644
--- a/Source/WebCore/rendering/RenderTableRow.cpp
+++ b/Source/WebCore/rendering/RenderTableRow.cpp
@@ -25,7 +25,6 @@
#include "config.h"
#include "RenderTableRow.h"
-#include "CachedImage.h"
#include "Document.h"
#include "HTMLNames.h"
#include "HitTestResult.h"
@@ -33,13 +32,14 @@
#include "RenderTableCell.h"
#include "RenderView.h"
#include "StyleInheritedData.h"
+#include <wtf/StackStats.h>
namespace WebCore {
using namespace HTMLNames;
-RenderTableRow::RenderTableRow(Node* node)
- : RenderBox(node)
+RenderTableRow::RenderTableRow(Element* element)
+ : RenderBox(element)
, m_rowIndex(unsetRowIndex)
{
// init RenderObject attributes
@@ -53,12 +53,12 @@ void RenderTableRow::willBeRemovedFromTree()
section()->setNeedsCellRecalc();
}
-void RenderTableRow::updateBeforeAndAfterContent()
+static bool borderWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
{
- if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules()) {
- children()->updateBeforeAfterContent(this, BEFORE);
- children()->updateBeforeAfterContent(this, AFTER);
- }
+ return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
+ || oldStyle->borderTopWidth() != newStyle->borderTopWidth()
+ || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
+ || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth();
}
void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -68,9 +68,6 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old
RenderBox::styleDidChange(diff, oldStyle);
propagateStyleToAnonymousChildren();
- if (parent())
- updateBeforeAndAfterContent();
-
if (section() && oldStyle && style()->logicalHeight() != oldStyle->logicalHeight())
section()->rowLogicalHeightChanged(rowIndex());
@@ -79,6 +76,17 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old
RenderTable* table = this->table();
if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border())
table->invalidateCollapsedBorders();
+
+ if (table && oldStyle && diff == StyleDifferenceLayout && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, style())) {
+ // If the border width changes on a row, we need to make sure the cells in the row know to lay out again.
+ // This only happens when borders are collapsed, since they end up affecting the border sides of the cell
+ // itself.
+ for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
+ if (!childBox->isTableCell())
+ continue;
+ childBox->setChildNeedsLayout(true, MarkOnlyThis);
+ }
+ }
}
}
@@ -98,10 +106,6 @@ const BorderValue& RenderTableRow::borderAdjoiningEndCell(const RenderTableCell*
void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
{
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild)
- beforeChild = afterPseudoElementRenderer();
-
if (!child->isTableCell()) {
RenderObject* last = beforeChild;
if (!last)
@@ -155,7 +159,7 @@ void RenderTableRow::layout()
ASSERT(needsLayout());
// Table rows do not add translation.
- LayoutStateMaintainer statePusher(view(), this, LayoutSize(), style()->isFlippedBlocksWritingMode());
+ LayoutStateMaintainer statePusher(view(), this, LayoutSize(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
bool paginated = view()->layoutState()->isPaginated();
@@ -233,7 +237,7 @@ void RenderTableRow::paintOutlineForRowIfNeeded(PaintInfo& paintInfo, const Layo
LayoutPoint adjustedPaintOffset = paintOffset + location();
PaintPhase paintPhase = paintInfo.phase;
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && style()->visibility() == VISIBLE)
- paintOutline(paintInfo.context, LayoutRect(adjustedPaintOffset, size()));
+ paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
}
void RenderTableRow::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
@@ -260,10 +264,17 @@ void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*)
repaint();
}
+RenderTableRow* RenderTableRow::createAnonymous(Document* document)
+{
+ RenderTableRow* renderer = new (document->renderArena()) RenderTableRow(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
RenderTableRow* RenderTableRow::createAnonymousWithParentRenderer(const RenderObject* parent)
{
+ RenderTableRow* newRow = RenderTableRow::createAnonymous(parent->document());
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW);
- RenderTableRow* newRow = new (parent->renderArena()) RenderTableRow(parent->document() /* is anonymous */);
newRow->setStyle(newStyle.release());
return newRow;
}
diff --git a/Source/WebCore/rendering/RenderTableRow.h b/Source/WebCore/rendering/RenderTableRow.h
index 6f195d304..d2bfbc6f6 100644
--- a/Source/WebCore/rendering/RenderTableRow.h
+++ b/Source/WebCore/rendering/RenderTableRow.h
@@ -34,7 +34,7 @@ static const unsigned maxRowIndex = 0x7FFFFFFE; // 2,147,483,646
class RenderTableRow : public RenderBox {
public:
- explicit RenderTableRow(Node*);
+ explicit RenderTableRow(Element*);
RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); }
RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); }
@@ -45,9 +45,9 @@ public:
RenderTableSection* section() const { return toRenderTableSection(parent()); }
RenderTable* table() const { return toRenderTable(parent()->parent()); }
- void updateBeforeAndAfterContent();
void paintOutlineForRowIfNeeded(PaintInfo&, const LayoutPoint&);
+ static RenderTableRow* createAnonymous(Document*);
static RenderTableRow* createAnonymousWithParentRenderer(const RenderObject*);
virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE
{
@@ -92,7 +92,7 @@ private:
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
- virtual const char* renderName() const { return isAnonymous() ? "RenderTableRow (anonymous)" : "RenderTableRow"; }
+ virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableRow (anonymous)" : "RenderTableRow"; }
virtual bool isTableRow() const { return true; }
@@ -117,13 +117,13 @@ private:
inline RenderTableRow* toRenderTableRow(RenderObject* object)
{
- ASSERT(!object || object->isTableRow());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableRow());
return static_cast<RenderTableRow*>(object);
}
inline const RenderTableRow* toRenderTableRow(const RenderObject* object)
{
- ASSERT(!object || object->isTableRow());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableRow());
return static_cast<const RenderTableRow*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp
index 4bc186874..a415af583 100644
--- a/Source/WebCore/rendering/RenderTableSection.cpp
+++ b/Source/WebCore/rendering/RenderTableSection.cpp
@@ -25,7 +25,6 @@
#include "config.h"
#include "RenderTableSection.h"
-#include "CachedImage.h"
#include "Document.h"
#include "HitTestResult.h"
#include "HTMLNames.h"
@@ -37,7 +36,7 @@
#include "StyleInheritedData.h"
#include <limits>
#include <wtf/HashSet.h>
-#include <wtf/Vector.h>
+#include <wtf/StackStats.h>
using namespace std;
@@ -85,8 +84,8 @@ static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row
}
-RenderTableSection::RenderTableSection(Node* node)
- : RenderBox(node)
+RenderTableSection::RenderTableSection(Element* element)
+ : RenderBox(element)
, m_cCol(0)
, m_cRow(0)
, m_outerBorderStart(0)
@@ -126,10 +125,6 @@ void RenderTableSection::willBeRemovedFromTree()
void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild)
{
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild)
- beforeChild = afterPseudoElementRenderer();
-
if (!child->isTableRow()) {
RenderObject* last = beforeChild;
if (!last)
@@ -186,7 +181,6 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild
ASSERT(!beforeChild || beforeChild->isTableRow());
RenderBox::addChild(child, beforeChild);
- toRenderTableRow(child)->updateBeforeAndAfterContent();
}
void RenderTableSection::ensureRows(unsigned numRows)
@@ -264,7 +258,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
int RenderTableSection::calcRowLogicalHeight()
{
#ifndef NDEBUG
- setNeedsLayoutIsForbidden(true);
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(this);
#endif
ASSERT(!needsLayout());
@@ -279,7 +273,9 @@ int RenderTableSection::calcRowLogicalHeight()
m_rowPos.resize(m_grid.size() + 1);
m_rowPos[0] = spacing;
- for (unsigned r = 0; r < m_grid.size(); r++) {
+ unsigned totalRows = m_grid.size();
+
+ for (unsigned r = 0; r < totalRows; r++) {
m_grid[r].baseline = 0;
LayoutUnit baselineDescent = 0;
@@ -298,8 +294,26 @@ int RenderTableSection::calcRowLogicalHeight()
// FIXME: We are always adding the height of a rowspan to the last rows which doesn't match
// other browsers. See webkit.org/b/52185 for example.
- if ((cell->rowIndex() + cell->rowSpan() - 1) != r)
- continue;
+ if ((cell->rowIndex() + cell->rowSpan() - 1) != r) {
+ // We will apply the height of the rowspan to the current row if next row is not valid.
+ if ((r + 1) < totalRows) {
+ unsigned col = 0;
+ CellStruct nextRowCell = cellAt(r + 1, col);
+
+ // We are trying to find that next row is valid or not.
+ while (nextRowCell.cells.size() && nextRowCell.cells[0]->rowSpan() > 1 && nextRowCell.cells[0]->rowIndex() < (r + 1)) {
+ col++;
+ if (col < totalCols)
+ nextRowCell = cellAt(r + 1, col);
+ else
+ break;
+ }
+
+ // We are adding the height of the rowspan to the current row if next row is not valid.
+ if (col < totalCols && nextRowCell.cells.size())
+ continue;
+ }
+ }
// For row spanning cells, |r| is the last row in the span.
unsigned cellStartRow = cell->rowIndex();
@@ -319,32 +333,30 @@ int RenderTableSection::calcRowLogicalHeight()
int cellLogicalHeight = cell->logicalHeightForRowSizing();
m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[cellStartRow] + cellLogicalHeight);
- // find out the baseline
- EVerticalAlign va = cell->style()->verticalAlign();
- if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH) {
+ // Find out the baseline. The baseline is set on the first row in a rowspan.
+ if (cell->isBaselineAligned()) {
LayoutUnit baselinePosition = cell->cellBaselinePosition();
- if (baselinePosition > cell->borderBefore() + cell->paddingBefore()) {
- m_grid[cellStartRow].baseline = max(m_grid[cellStartRow].baseline, baselinePosition - cell->intrinsicPaddingBefore());
- baselineDescent = max(baselineDescent, m_rowPos[cellStartRow] + cellLogicalHeight - (baselinePosition - cell->intrinsicPaddingBefore()));
+ if (baselinePosition > cell->borderAndPaddingBefore()) {
+ m_grid[cellStartRow].baseline = max(m_grid[cellStartRow].baseline, baselinePosition);
+ // The descent of a cell that spans multiple rows does not affect the height of the first row it spans, so don't let it
+ // become the baseline descent applied to the rest of the row. Also we don't account for the baseline descent of
+ // non-spanning cells when computing a spanning cell's extent.
+ int cellStartRowBaselineDescent = 0;
+ if (cell->rowSpan() == 1) {
+ baselineDescent = max(baselineDescent, cellLogicalHeight - (baselinePosition - cell->intrinsicPaddingBefore()));
+ cellStartRowBaselineDescent = baselineDescent;
+ }
+ m_rowPos[cellStartRow + 1] = max<int>(m_rowPos[cellStartRow + 1], m_rowPos[cellStartRow] + m_grid[cellStartRow].baseline + cellStartRowBaselineDescent);
}
}
}
}
- // do we have baseline aligned elements?
- if (m_grid[r].baseline)
- // increase rowheight if baseline requires
- m_rowPos[r + 1] = max<int>(m_rowPos[r + 1], m_grid[r].baseline + baselineDescent);
-
// Add the border-spacing to our final position.
m_rowPos[r + 1] += m_grid[r].rowRenderer ? spacing : 0;
m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]);
}
-#ifndef NDEBUG
- setNeedsLayoutIsForbidden(false);
-#endif
-
ASSERT(!needsLayout());
statePusher.pop();
@@ -363,7 +375,7 @@ void RenderTableSection::layout()
// can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure.
m_grid.shrinkToFit();
- LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
+ LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
const Vector<int>& columnPos = table()->columnPositions();
@@ -494,7 +506,7 @@ int RenderTableSection::distributeExtraLogicalHeightToRows(int extraLogicalHeigh
void RenderTableSection::layoutRows()
{
#ifndef NDEBUG
- setNeedsLayoutIsForbidden(true);
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(this);
#endif
ASSERT(!needsLayout());
@@ -503,14 +515,12 @@ void RenderTableSection::layoutRows()
// Set the width of our section now. The rows will also be this width.
setLogicalWidth(table()->contentLogicalWidth());
- m_overflow.clear();
- m_overflowingCells.clear();
m_forceSlowPaintPathWithOverflowingCell = false;
int vspacing = table()->vBorderSpacing();
unsigned nEffCols = table()->numEffCols();
- LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
+ LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || style()->isFlippedBlocksWritingMode());
for (unsigned r = 0; r < totalRows; r++) {
// Set the row's x/y position and width/height.
@@ -551,7 +561,7 @@ void RenderTableSection::layoutRows()
|| (!table()->style()->logicalHeight().isAuto() && rHeight != cell->logicalHeight());
for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
- if (!o->isText() && o->style()->logicalHeight().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) {
+ if (!o->isText() && o->style()->logicalHeight().isPercent() && (flexAllChildren || ((o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow())) && !o->isTextControl()))) {
// Tables with no sections do not flex.
if (!o->isTable() || toRenderTable(o)->hasSections()) {
o->setNeedsLayout(true, MarkOnlyThis);
@@ -589,10 +599,9 @@ void RenderTableSection::layoutRows()
cell->layoutIfNeeded();
// If the baseline moved, we may have to update the data for our row. Find out the new baseline.
- EVerticalAlign va = cell->style()->verticalAlign();
- if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH) {
+ if (cell->isBaselineAligned()) {
LayoutUnit baseline = cell->cellBaselinePosition();
- if (baseline > cell->borderBefore() + cell->paddingBefore())
+ if (baseline > cell->borderAndPaddingBefore())
m_grid[r].baseline = max(m_grid[r].baseline, baseline);
}
}
@@ -640,14 +649,26 @@ void RenderTableSection::layoutRows()
}
}
-#ifndef NDEBUG
- setNeedsLayoutIsForbidden(false);
-#endif
-
ASSERT(!needsLayout());
setLogicalHeight(m_rowPos[totalRows]);
+ computeOverflowFromCells(totalRows, nEffCols);
+
+ statePusher.pop();
+}
+
+void RenderTableSection::computeOverflowFromCells()
+{
+ unsigned totalRows = m_grid.size();
+ unsigned nEffCols = table()->numEffCols();
+ computeOverflowFromCells(totalRows, nEffCols);
+}
+
+void RenderTableSection::computeOverflowFromCells(unsigned totalRows, unsigned nEffCols)
+{
+ m_overflow.clear();
+ m_overflowingCells.clear();
unsigned totalCellsCount = nEffCols * totalRows;
int maxAllowedOverflowingCellsCount = totalCellsCount < gMinTableSizeToUseFastPaintPathWithOverflowingCell ? 0 : gMaxAllowedOverflowingCellRatioForFastPaintPath * totalCellsCount;
@@ -680,8 +701,6 @@ void RenderTableSection::layoutRows()
}
ASSERT(hasOverflowingCell == this->hasOverflowingCell());
-
- statePusher.pop();
}
int RenderTableSection::calcOuterBorderBefore() const
@@ -898,7 +917,7 @@ int RenderTableSection::firstLineBoxBaseline() const
const RenderTableCell* cell = cs.primaryCell();
// Only cells with content have a baseline
if (cell && cell->contentLogicalHeight())
- firstLineBaseline = max<int>(firstLineBaseline, cell->logicalTop() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight());
+ firstLineBaseline = max<int>(firstLineBaseline, cell->logicalTop() + cell->borderAndPaddingBefore() + cell->contentLogicalHeight());
}
return firstLineBaseline;
@@ -927,7 +946,7 @@ void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOff
popContentsClip(paintInfo, phase, adjustedPaintOffset);
if ((phase == PaintPhaseOutline || phase == PaintPhaseSelfOutline) && style()->visibility() == VISIBLE)
- paintOutline(paintInfo.context, LayoutRect(adjustedPaintOffset, size()));
+ paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
}
static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2)
@@ -1081,9 +1100,7 @@ CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect) const
return CellSpan(startColumn, endColumn);
}
-#if defined(_MSC_VER) && _MSC_VER == 1700
-#pragma optimize("", off)
-#endif
+
void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
PaintPhase paintPhase = paintInfo.phase;
@@ -1101,8 +1118,10 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa
if (!m_hasMultipleCellLevels && !m_overflowingCells.size()) {
if (paintInfo.phase == PaintPhaseCollapsedTableBorders) {
// Collapsed borders are painted from the bottom right to the top left so that precedence
- // due to cell position is respected.
- for (unsigned r = dirtiedRows.end(); r > dirtiedRows.start(); r--) {
+ // due to cell position is respected. We need to paint one row beyond the topmost dirtied
+ // row to calculate its collapsed border value.
+ unsigned startRow = dirtiedRows.start() ? dirtiedRows.start() - 1 : 0;
+ for (unsigned r = dirtiedRows.end(); r > startRow; r--) {
unsigned row = r - 1;
for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.start(); c--) {
unsigned col = c - 1;
@@ -1156,9 +1175,8 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa
continue;
if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) {
- if (spanningCells.contains(current.cells[i]))
+ if (!spanningCells.add(current.cells[i]).isNewEntry)
continue;
- spanningCells.add(current.cells[i]);
}
cells.append(current.cells[i]);
@@ -1184,9 +1202,6 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa
}
}
}
-#if defined(_MSC_VER) && _MSC_VER == 1700
-#pragma optimize("", on)
-#endif
void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*)
{
@@ -1312,7 +1327,7 @@ void RenderTableSection::splitColumn(unsigned pos, unsigned first)
Row& r = m_grid[row].row;
r.insert(pos + 1, CellStruct());
if (r[pos].hasCells()) {
- r[pos + 1].cells.append(r[pos].cells);
+ r[pos + 1].cells.appendVector(r[pos].cells);
RenderTableCell* cell = r[pos].primaryCell();
ASSERT(cell);
ASSERT(cell->colSpan() >= (r[pos].inColSpan ? 1u : 0));
@@ -1421,7 +1436,8 @@ CollapsedBorderValue& RenderTableSection::cachedCollapsedBorder(const RenderTabl
RenderTableSection* RenderTableSection::createAnonymousWithParentRenderer(const RenderObject* parent)
{
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW_GROUP);
- RenderTableSection* newSection = new (parent->renderArena()) RenderTableSection(parent->document() /* is anonymous */);
+ RenderTableSection* newSection = new (parent->renderArena()) RenderTableSection(0);
+ newSection->setDocumentForAnonymous(parent->document());
newSection->setStyle(newStyle.release());
return newSection;
}
diff --git a/Source/WebCore/rendering/RenderTableSection.h b/Source/WebCore/rendering/RenderTableSection.h
index 79cdd4a1d..1e14b9a26 100644
--- a/Source/WebCore/rendering/RenderTableSection.h
+++ b/Source/WebCore/rendering/RenderTableSection.h
@@ -62,7 +62,7 @@ class RenderTableRow;
class RenderTableSection : public RenderBox {
public:
- RenderTableSection(Node*);
+ RenderTableSection(Element*);
virtual ~RenderTableSection();
RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); }
@@ -79,6 +79,7 @@ public:
int calcRowLogicalHeight();
void layoutRows();
+ void computeOverflowFromCells();
RenderTable* table() const { return toRenderTable(parent()); }
@@ -149,6 +150,8 @@ public:
return c.primaryCell();
}
+ RenderTableRow* rowRendererAt(unsigned row) const { return m_grid[row].rowRenderer; }
+
void appendColumn(unsigned pos);
void splitColumn(unsigned pos, unsigned first);
@@ -202,7 +205,7 @@ private:
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
- virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
+ virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
virtual bool isTableSection() const { return true; }
@@ -224,6 +227,7 @@ private:
void distributeRemainingExtraLogicalHeight(int& extraLogicalHeight);
bool hasOverflowingCell() const { return m_overflowingCells.size() || m_forceSlowPaintPathWithOverflowingCell; }
+ void computeOverflowFromCells(unsigned totalRows, unsigned nEffCols);
CellSpan fullTableRowSpan() const { return CellSpan(0, m_grid.size()); }
CellSpan fullTableColumnSpan() const { return CellSpan(0, table()->columns().size()); }
@@ -272,13 +276,13 @@ private:
inline RenderTableSection* toRenderTableSection(RenderObject* object)
{
- ASSERT(!object || object->isTableSection());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableSection());
return static_cast<RenderTableSection*>(object);
}
inline const RenderTableSection* toRenderTableSection(const RenderObject* object)
{
- ASSERT(!object || object->isTableSection());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTableSection());
return static_cast<const RenderTableSection*>(object);
}
diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp
index a9a25df63..cc7607f74 100644
--- a/Source/WebCore/rendering/RenderText.cpp
+++ b/Source/WebCore/rendering/RenderText.cpp
@@ -44,7 +44,6 @@
#include "TextResourceDecoder.h"
#include "VisiblePosition.h"
#include "break_lines.h"
-#include <wtf/AlwaysInline.h>
#include <wtf/text/StringBuffer.h>
#include <wtf/unicode/CharacterNames.h>
@@ -58,7 +57,7 @@ struct SameSizeAsRenderText : public RenderObject {
uint32_t bitfields : 16;
float widths[4];
String text;
- void* pointers[3];
+ void* pointers[2];
};
COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
@@ -101,7 +100,7 @@ static void makeCapitalized(String* string, UChar previous)
return;
unsigned length = string->length();
- const UChar* characters = string->characters();
+ const StringImpl& stringImpl = *string->impl();
if (length >= numeric_limits<unsigned>::max())
CRASH();
@@ -110,52 +109,52 @@ static void makeCapitalized(String* string, UChar previous)
stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
for (unsigned i = 1; i < length + 1; i++) {
// Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
- if (characters[i - 1] == noBreakSpace)
+ if (stringImpl[i - 1] == noBreakSpace)
stringWithPrevious[i] = ' ';
else
- stringWithPrevious[i] = characters[i - 1];
+ stringWithPrevious[i] = stringImpl[i - 1];
}
TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
if (!boundary)
return;
- StringBuffer<UChar> data(length);
+ StringBuilder result;
+ result.reserveCapacity(length);
int32_t endOfWord;
int32_t startOfWord = textBreakFirst(boundary);
for (endOfWord = textBreakNext(boundary); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = textBreakNext(boundary)) {
if (startOfWord) // Ignore first char of previous string
- data[startOfWord - 1] = characters[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]);
+ result.append(stringImpl[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]));
for (int i = startOfWord + 1; i < endOfWord; i++)
- data[i - 1] = characters[i - 1];
+ result.append(stringImpl[i - 1]);
}
- *string = String::adopt(data);
+ *string = result.toString();
}
RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
- : RenderObject(node)
- , m_hasTab(false)
- , m_linesDirty(false)
- , m_containsReversedText(false)
- , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
- , m_needsTranscoding(false)
- , m_minWidth(-1)
- , m_maxWidth(-1)
- , m_beginMinWidth(0)
- , m_endMinWidth(0)
- , m_text(str)
- , m_firstTextBox(0)
- , m_lastTextBox(0)
+ : RenderObject(!node || node->isDocumentNode() ? 0 : node)
+ , m_hasTab(false)
+ , m_linesDirty(false)
+ , m_containsReversedText(false)
+ , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
+ , m_needsTranscoding(false)
+ , m_minWidth(-1)
+ , m_maxWidth(-1)
+ , m_beginMinWidth(0)
+ , m_endMinWidth(0)
+ , m_text(str)
+ , m_firstTextBox(0)
+ , m_lastTextBox(0)
{
ASSERT(m_text);
+ // FIXME: Some clients of RenderText (and subclasses) pass Document as node to create anonymous renderer.
+ // They should be switched to passing null and using setDocumentForAnonymous.
+ if (node && node->isDocumentNode())
+ setDocumentForAnonymous(toDocument(node));
- m_is8Bit = m_text.is8Bit();
- if (is8Bit())
- m_data.characters8 = m_text.characters8();
- else
- m_data.characters16 = m_text.characters16();
m_isAllASCII = m_text.containsOnlyASCII();
m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
setIsText();
@@ -210,7 +209,7 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
if (!oldStyle) {
updateNeedsTranscoding();
needsResetText = m_needsTranscoding;
- } else if (oldStyle->font().needsTranscoding() != newStyle->font().needsTranscoding() || (newStyle->font().needsTranscoding() && oldStyle->font().family().family() != newStyle->font().family().family())) {
+ } else if (oldStyle->font().needsTranscoding() != newStyle->font().needsTranscoding() || (newStyle->font().needsTranscoding() && oldStyle->font().firstFamily() != newStyle->font().firstFamily())) {
updateNeedsTranscoding();
needsResetText = true;
}
@@ -332,10 +331,10 @@ static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigne
// Change the height and y position (or width and x for vertical text)
// because selectionRect uses selection-specific values.
if (box->isHorizontal()) {
- r.setHeight(box->logicalHeight());
+ r.setHeight(box->height());
r.setY(box->y());
} else {
- r.setWidth(box->logicalWidth());
+ r.setWidth(box->width());
r.setX(box->x());
}
}
@@ -370,12 +369,12 @@ void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u
r.setX(selectionRect.x());
}
}
- rects.append(localToAbsoluteQuad(r, SnapOffsetForTransforms, wasFixed).enclosingBoundingBox());
+ rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
} else {
// FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
if (!rect.isZero())
- rects.append(localToAbsoluteQuad(rect, SnapOffsetForTransforms, wasFixed).enclosingBoundingBox());
+ rects.append(localToAbsoluteQuad(rect, 0, wasFixed).enclosingBoundingBox());
}
}
}
@@ -418,7 +417,7 @@ void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, Clippin
else
boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
}
- quads.append(localToAbsoluteQuad(boundaries, SnapOffsetForTransforms, wasFixed));
+ quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed));
}
}
@@ -453,11 +452,11 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
r.setX(selectionRect.x());
}
}
- quads.append(localToAbsoluteQuad(r, SnapOffsetForTransforms, wasFixed));
+ quads.append(localToAbsoluteQuad(r, 0, wasFixed));
} else {
FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
if (!rect.isZero())
- quads.append(localToAbsoluteQuad(rect, SnapOffsetForTransforms, wasFixed));
+ quads.append(localToAbsoluteQuad(rect, 0, wasFixed));
}
}
}
@@ -895,7 +894,7 @@ static inline float hyphenWidth(RenderText* renderer, const Font& font)
return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphenString().string(), style));
}
-static float maxWordFragmentWidth(RenderText* renderer, RenderStyle* style, const Font& font, const UChar* word, int wordLength, int minimumPrefixLength, int minimumSuffixLength, int& suffixStart)
+static float maxWordFragmentWidth(RenderText* renderer, RenderStyle* style, const Font& font, const UChar* word, int wordLength, int minimumPrefixLength, int minimumSuffixLength, int& suffixStart, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
{
suffixStart = 0;
if (wordLength <= minimumSuffixLength)
@@ -922,7 +921,7 @@ static float maxWordFragmentWidth(RenderText* renderer, RenderStyle* style, cons
TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWithHyphen.characters(), fragmentWithHyphen.length(), style);
run.setCharactersLength(fragmentWithHyphen.length());
run.setCharacterScanForCodePath(!renderer->canUseSimpleFontCodePath());
- float fragmentWidth = font.width(run);
+ float fragmentWidth = font.width(run, &fallbackFonts, &glyphOverflow);
// Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLayout.cpp.
if (fragmentWidth <= minimumFragmentWidthToConsider)
@@ -970,7 +969,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
// Non-zero only when kerning is enabled, in which case we measure words with their trailing
// space, then subtract its width.
- float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(RenderBlock::constructTextRun(this, f, &space, 1, styleToUse)) + wordSpacing : 0;
+ float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(RenderBlock::constructTextRun(this, f, &space, 1, styleToUse), &fallbackFonts) + wordSpacing : 0;
// If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
// fragment) encountered so far, and only try hyphenating words that are wider.
@@ -1071,7 +1070,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
if (w > maxWordWidth) {
int suffixStart;
- float maxFragmentWidth = maxWordFragmentWidth(this, styleToUse, f, characters() + i, wordLen, minimumPrefixLength, minimumSuffixLength, suffixStart);
+ float maxFragmentWidth = maxWordFragmentWidth(this, styleToUse, f, characters() + i, wordLen, minimumPrefixLength, minimumSuffixLength, suffixStart, fallbackFonts, glyphOverflow);
if (suffixStart) {
float suffixWidth;
@@ -1152,7 +1151,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
run.setXPos(leadWidth + currMaxWidth);
- currMaxWidth += f.width(run);
+ currMaxWidth += f.width(run, &fallbackFonts);
glyphOverflow.right = 0;
needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
}
@@ -1182,12 +1181,18 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
setPreferredLogicalWidthsDirty(false);
}
-bool RenderText::isAllCollapsibleWhitespace()
+bool RenderText::isAllCollapsibleWhitespace() const
{
- int length = textLength();
- const UChar* text = characters();
- for (int i = 0; i < length; i++) {
- if (!style()->isCollapsibleWhiteSpace(text[i]))
+ unsigned length = textLength();
+ if (is8Bit()) {
+ for (unsigned i = 0; i < length; ++i) {
+ if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
+ return false;
+ }
+ return true;
+ }
+ for (unsigned i = 0; i < length; ++i) {
+ if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
return false;
}
return true;
@@ -1422,11 +1427,6 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
ASSERT(m_text);
ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
- m_is8Bit = m_text.is8Bit();
- if (is8Bit())
- m_data.characters8 = m_text.characters8();
- else
- m_data.characters16 = m_text.characters16();
m_isAllASCII = m_text.containsOnlyASCII();
m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
}
@@ -1464,9 +1464,8 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
setNeedsLayoutAndPrefWidthsRecalc();
m_knownToHaveNoOverflowAndNoFallbackFonts = false;
- AXObjectCache* axObjectCache = document()->axObjectCache();
- if (axObjectCache->accessibilityEnabled())
- axObjectCache->textChanged(this);
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->textChanged(this);
}
String RenderText::textWithoutTranscoding() const
@@ -1727,8 +1726,11 @@ unsigned RenderText::renderedTextLength() const
int RenderText::previousOffset(int current) const
{
- StringImpl* si = m_text.impl();
- TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
+ if (isAllASCII() || m_text.is8Bit())
+ return current - 1;
+
+ StringImpl* textImpl = m_text.impl();
+ TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
if (!iterator)
return current - 1;
@@ -1740,7 +1742,7 @@ int RenderText::previousOffset(int current) const
return result;
}
-#if PLATFORM(MAC) || PLATFORM(CHROMIUM) && OS(MAC_OS_X)
+#if PLATFORM(MAC)
#define HANGUL_CHOSEONG_START (0x1100)
#define HANGUL_CHOSEONG_END (0x115F)
@@ -1782,7 +1784,7 @@ inline bool isRegionalIndicator(UChar32 c)
int RenderText::previousOffsetForBackwardDeletion(int current) const
{
-#if PLATFORM(MAC) || PLATFORM(CHROMIUM) && OS(MAC_OS_X)
+#if PLATFORM(MAC)
ASSERT(m_text);
StringImpl& text = *m_text.impl();
UChar32 character;
@@ -1880,8 +1882,11 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const
int RenderText::nextOffset(int current) const
{
- StringImpl* si = m_text.impl();
- TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
+ if (isAllASCII() || m_text.is8Bit())
+ return current + 1;
+
+ StringImpl* textImpl = m_text.impl();
+ TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
if (!iterator)
return current + 1;
@@ -1889,7 +1894,6 @@ int RenderText::nextOffset(int current) const
if (result == TextBreakDone)
result = current + 1;
-
return result;
}
diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h
index 7b986917d..6e44e326e 100644
--- a/Source/WebCore/rendering/RenderText.h
+++ b/Source/WebCore/rendering/RenderText.h
@@ -45,12 +45,6 @@ public:
virtual PassRefPtr<StringImpl> originalText() const;
- void updateTextIfNeeded()
- {
- if (preferredLogicalWidthsDirty())
- updateText();
- }
-
void extractTextBox(InlineTextBox*);
void attachTextBox(InlineTextBox*);
void removeTextBox(InlineTextBox*);
@@ -72,11 +66,11 @@ public:
virtual VisiblePosition positionForPoint(const LayoutPoint&);
- bool is8Bit() const { return m_is8Bit; }
- const LChar* characters8() const { ASSERT(m_is8Bit); return m_data.characters8; }
- const UChar* characters16() const { ASSERT(!m_is8Bit); return m_data.characters16; }
+ bool is8Bit() const { return m_text.is8Bit(); }
+ const LChar* characters8() const { return m_text.impl()->characters8(); }
+ const UChar* characters16() const { return m_text.impl()->characters16(); }
const UChar* characters() const { return m_text.characters(); }
- UChar characterAt(unsigned i) const { return m_is8Bit ? characters8()[i] : characters16()[i]; }
+ UChar characterAt(unsigned i) const { return is8Bit() ? characters8()[i] : characters16()[i]; }
UChar operator[](unsigned i) const { return characterAt(i); }
unsigned textLength() const { return m_text.length(); } // non virtual implementation of length()
void positionLineBox(InlineBox*);
@@ -136,8 +130,7 @@ public:
void checkConsistency() const;
- virtual void computePreferredLogicalWidths(float leadWidth);
- bool isAllCollapsibleWhitespace();
+ bool isAllCollapsibleWhitespace() const;
bool canUseSimpleFontCodePath() const { return m_canUseSimpleFontCodePath; }
bool knownToHaveNoOverflowAndNoFallbackFonts() const { return m_knownToHaveNoOverflowAndNoFallbackFonts; }
@@ -145,12 +138,12 @@ public:
void removeAndDestroyTextBoxes();
protected:
+ virtual void computePreferredLogicalWidths(float leadWidth);
virtual void willBeDestroyed();
virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
- virtual void updateText() { }
virtual void setTextInternal(PassRefPtr<StringImpl>);
virtual UChar previousCharacter() const;
@@ -189,7 +182,6 @@ private:
// just dirtying everything when character data is modified (e.g., appended/inserted
// or removed).
bool m_containsReversedText : 1;
- bool m_is8Bit : 1;
bool m_isAllASCII : 1;
bool m_canUseSimpleFontCodePath : 1;
mutable bool m_knownToHaveNoOverflowAndNoFallbackFonts : 1;
@@ -201,10 +193,6 @@ private:
float m_endMinWidth;
String m_text;
- union {
- const LChar* characters8;
- const UChar* characters16;
- } m_data;
InlineTextBox* m_firstTextBox;
InlineTextBox* m_lastTextBox;
@@ -212,13 +200,13 @@ private:
inline RenderText* toRenderText(RenderObject* object)
{
- ASSERT(!object || object->isText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isText());
return static_cast<RenderText*>(object);
}
inline const RenderText* toRenderText(const RenderObject* object)
{
- ASSERT(!object || object->isText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isText());
return static_cast<const RenderText*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp
index 35da70455..3c328ef95 100644
--- a/Source/WebCore/rendering/RenderTextControl.cpp
+++ b/Source/WebCore/rendering/RenderTextControl.cpp
@@ -36,10 +36,10 @@ using namespace std;
namespace WebCore {
-RenderTextControl::RenderTextControl(Node* node)
- : RenderBlock(node)
+RenderTextControl::RenderTextControl(Element* element)
+ : RenderBlock(element)
{
- ASSERT(toTextFormControl(node));
+ ASSERT(isHTMLTextFormControlElement(element));
}
RenderTextControl::~RenderTextControl()
@@ -48,7 +48,7 @@ RenderTextControl::~RenderTextControl()
HTMLTextFormControlElement* RenderTextControl::textFormControlElement() const
{
- return static_cast<HTMLTextFormControlElement*>(node());
+ return toHTMLTextFormControlElement(node());
}
HTMLElement* RenderTextControl::innerTextElement() const
@@ -76,17 +76,17 @@ void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle*
static inline bool updateUserModifyProperty(Node* node, RenderStyle* style)
{
- bool isEnabled = true;
+ bool isDisabled = false;
bool isReadOnlyControl = false;
if (node->isElementNode()) {
- Element* element = static_cast<Element*>(node);
- isEnabled = element->isEnabledFormControl();
- isReadOnlyControl = element->isTextFormControl() && static_cast<HTMLTextFormControlElement*>(element)->readOnly();
+ Element* element = toElement(node);
+ isDisabled = element->isDisabledFormControl();
+ isReadOnlyControl = element->isTextFormControl() && toHTMLTextFormControlElement(element)->isReadOnly();
}
- style->setUserModify((isReadOnlyControl || !isEnabled) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
- return !isEnabled;
+ style->setUserModify((isReadOnlyControl || isDisabled) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
+ return isDisabled;
}
void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const
@@ -101,19 +101,19 @@ void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, Rend
textBlockStyle->setColor(theme()->disabledTextColor(textBlockStyle->visitedDependentColor(CSSPropertyColor), startStyle->visitedDependentColor(CSSPropertyBackgroundColor)));
}
-int RenderTextControl::textBlockHeight() const
+int RenderTextControl::textBlockLogicalHeight() const
{
- return height() - borderAndPaddingHeight();
+ return logicalHeight() - borderAndPaddingLogicalHeight();
}
-int RenderTextControl::textBlockWidth() const
+int RenderTextControl::textBlockLogicalWidth() const
{
Element* innerText = innerTextElement();
ASSERT(innerText);
- LayoutUnit unitWidth = width() - borderAndPaddingWidth();
+ LayoutUnit unitWidth = logicalWidth() - borderAndPaddingLogicalWidth();
if (innerText->renderer())
- unitWidth -= innerText->renderBox()->paddingLeft() + innerText->renderBox()->paddingRight();
+ unitWidth -= innerText->renderBox()->paddingStart() + innerText->renderBox()->paddingEnd();
return unitWidth;
}
@@ -129,10 +129,8 @@ VisiblePosition RenderTextControl::visiblePositionForIndex(int index) const
{
if (index <= 0)
return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTREAM);
- ExceptionCode ec = 0;
RefPtr<Range> range = Range::create(document());
- range->selectNodeContents(innerTextElement(), ec);
- ASSERT(!ec);
+ range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION);
CharacterIterator it(range.get());
it.advance(index - 1);
return VisiblePosition(it.range()->endPosition(), UPSTREAM);
@@ -150,10 +148,11 @@ void RenderTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUni
ASSERT(innerText);
if (RenderBox* innerTextBox = innerText->renderBox()) {
LayoutUnit nonContentHeight = innerTextBox->borderAndPaddingHeight() + innerTextBox->marginHeight();
- logicalHeight = computeControlHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + borderAndPaddingHeight();
+ logicalHeight = computeControlLogicalHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + borderAndPaddingHeight();
// We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
- if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap))
+ if ((isHorizontalWritingMode() && (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap)))
+ || (!isHorizontalWritingMode() && (style()->overflowY() == OSCROLL || (style()->overflowY() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap))))
logicalHeight += scrollbarThickness();
}
@@ -219,11 +218,17 @@ static const char* fontFamiliesWithInvalidCharWidth[] = {
// all platforms.
bool RenderTextControl::hasValidAvgCharWidth(AtomicString family)
{
- static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
-
if (family.isEmpty())
return false;
+ // Internal fonts on OS X also have an invalid entry in the table for avgCharWidth.
+ // They are hidden by having a name that begins with a period, so simply search
+ // for that here rather than try to keep the list up to date.
+ if (family.startsWith('.'))
+ return false;
+
+ static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
+
if (!fontFamiliesWithInvalidCharWidthMap) {
fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>;
@@ -254,6 +259,17 @@ float RenderTextControl::scaleEmToUnits(int x) const
return roundf(style()->font().size() * x / unitsPerEm);
}
+void RenderTextControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ // Use average character width. Matches IE.
+ const AtomicString& family = style()->font().firstFamily();
+ maxLogicalWidth = preferredContentLogicalWidth(const_cast<RenderTextControl*>(this)->getAvgCharWidth(family));
+ if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox())
+ maxLogicalWidth += innerTextRenderBox->paddingStart() + innerTextRenderBox->paddingEnd();
+ if (!style()->logicalWidth().isPercent())
+ minLogicalWidth = maxLogicalWidth;
+}
+
void RenderTextControl::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
@@ -261,30 +277,22 @@ void RenderTextControl::computePreferredLogicalWidths()
m_minPreferredLogicalWidth = 0;
m_maxPreferredLogicalWidth = 0;
- if (style()->width().isFixed() && style()->width().value() >= 0)
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
- else {
- // Use average character width. Matches IE.
- AtomicString family = style()->font().family().family();
- m_maxPreferredLogicalWidth = preferredContentWidth(getAvgCharWidth(family));
- if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox())
- m_maxPreferredLogicalWidth += innerTextRenderBox->paddingLeft() + innerTextRenderBox->paddingRight();
- }
-
- if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
- m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
- m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
- } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
- m_minPreferredLogicalWidth = 0;
+ if (style()->logicalWidth().isFixed() && style()->logicalWidth().value() >= 0)
+ m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->logicalWidth().value());
else
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
+
+ if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) {
+ m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMinWidth().value()));
+ m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMinWidth().value()));
+ }
- if (style()->maxWidth().isFixed()) {
- m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
- m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
+ if (style()->logicalMaxWidth().isFixed()) {
+ m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMaxWidth().value()));
+ m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMaxWidth().value()));
}
- LayoutUnit toAdd = borderAndPaddingWidth();
+ LayoutUnit toAdd = borderAndPaddingLogicalWidth();
m_minPreferredLogicalWidth += toAdd;
m_maxPreferredLogicalWidth += toAdd;
@@ -292,7 +300,7 @@ void RenderTextControl::computePreferredLogicalWidths()
setPreferredLogicalWidthsDirty(false);
}
-void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
+void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
{
if (!size().isEmpty())
rects.append(pixelSnappedIntRect(additionalOffset, size()));
@@ -300,7 +308,7 @@ void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, const LayoutPo
RenderObject* RenderTextControl::layoutSpecialExcludedChild(bool relayoutChildren)
{
- HTMLElement* placeholder = toTextFormControl(node())->placeholderElement();
+ HTMLElement* placeholder = toHTMLTextFormControlElement(node())->placeholderElement();
RenderObject* placeholderRenderer = placeholder ? placeholder->renderer() : 0;
if (!placeholderRenderer)
return 0;
diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h
index 4de76b4dc..1f6630cee 100644
--- a/Source/WebCore/rendering/RenderTextControl.h
+++ b/Source/WebCore/rendering/RenderTextControl.h
@@ -23,6 +23,7 @@
#define RenderTextControl_h
#include "RenderBlock.h"
+#include "RenderFlexibleBox.h"
namespace WebCore {
@@ -38,7 +39,7 @@ public:
VisiblePosition visiblePositionForIndex(int index) const;
protected:
- RenderTextControl(Node*);
+ RenderTextControl(Element*);
// This convenience function should not be made public because innerTextElement may outlive the render tree.
HTMLElement* innerTextElement() const;
@@ -50,15 +51,15 @@ protected:
void hitInnerTextElement(HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset);
- int textBlockWidth() const;
- int textBlockHeight() const;
+ int textBlockLogicalWidth() const;
+ int textBlockLogicalHeight() const;
float scaleEmToUnits(int x) const;
static bool hasValidAvgCharWidth(AtomicString family);
virtual float getAvgCharWidth(AtomicString family);
- virtual LayoutUnit preferredContentWidth(float charWidth) const = 0;
- virtual LayoutUnit computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const = 0;
+ virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const = 0;
+ virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const = 0;
virtual RenderStyle* textBaseStyle() const = 0;
virtual void updateFromElement();
@@ -68,13 +69,14 @@ protected:
private:
virtual const char* renderName() const { return "RenderTextControl"; }
virtual bool isTextControl() const { return true; }
- virtual void computePreferredLogicalWidths();
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+ virtual void computePreferredLogicalWidths() OVERRIDE;
virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
virtual bool avoidsFloats() const { return true; }
virtual bool canHaveGeneratedChildren() const OVERRIDE { return false; }
virtual bool canBeReplacedWithInlineRunIn() const OVERRIDE;
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
virtual bool canBeProgramaticallyScrolled() const { return true; }
@@ -83,19 +85,40 @@ private:
inline RenderTextControl* toRenderTextControl(RenderObject* object)
{
- ASSERT(!object || object->isTextControl());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTextControl());
return static_cast<RenderTextControl*>(object);
}
inline const RenderTextControl* toRenderTextControl(const RenderObject* object)
{
- ASSERT(!object || object->isTextControl());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTextControl());
return static_cast<const RenderTextControl*>(object);
}
// This will catch anyone doing an unnecessary cast.
void toRenderTextControl(const RenderTextControl*);
+// Renderer for our inner container, for <search> and others.
+// We can't use RenderFlexibleBox directly, because flexboxes have a different
+// baseline definition, and then inputs of different types wouldn't line up
+// anymore.
+class RenderTextControlInnerContainer : public RenderFlexibleBox {
+public:
+ explicit RenderTextControlInnerContainer(Element* element)
+ : RenderFlexibleBox(element)
+ { }
+ virtual ~RenderTextControlInnerContainer() { }
+
+ virtual int baselinePosition(FontBaseline baseline, bool firstLine, LineDirectionMode direction, LinePositionMode position) const OVERRIDE
+ {
+ return RenderBlock::baselinePosition(baseline, firstLine, direction, position);
+ }
+ virtual int firstLineBoxBaseline() const OVERRIDE { return RenderBlock::firstLineBoxBaseline(); }
+ virtual int inlineBlockBaseline(LineDirectionMode direction) const OVERRIDE { return RenderBlock::inlineBlockBaseline(direction); }
+
+};
+
+
} // namespace WebCore
#endif // RenderTextControl_h
diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp
index f40994326..9a121c614 100644
--- a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp
+++ b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp
@@ -32,15 +32,15 @@
namespace WebCore {
-RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node)
- : RenderTextControl(node)
+RenderTextControlMultiLine::RenderTextControlMultiLine(Element* element)
+ : RenderTextControl(element)
{
}
RenderTextControlMultiLine::~RenderTextControlMultiLine()
{
if (node() && node()->inDocument())
- static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed();
+ toHTMLTextAreaElement(node())->rendererWillBeDestroyed();
}
bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
@@ -65,15 +65,15 @@ float RenderTextControlMultiLine::getAvgCharWidth(AtomicString family)
return RenderTextControl::getAvgCharWidth(family);
}
-LayoutUnit RenderTextControlMultiLine::preferredContentWidth(float charWidth) const
+LayoutUnit RenderTextControlMultiLine::preferredContentLogicalWidth(float charWidth) const
{
- int factor = static_cast<HTMLTextAreaElement*>(node())->cols();
+ int factor = toHTMLTextAreaElement(node())->cols();
return static_cast<LayoutUnit>(ceilf(charWidth * factor)) + scrollbarThickness();
}
-LayoutUnit RenderTextControlMultiLine::computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
+LayoutUnit RenderTextControlMultiLine::computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
{
- return lineHeight * static_cast<HTMLTextAreaElement*>(node())->rows() + nonContentHeight;
+ return lineHeight * toHTMLTextAreaElement(node())->rows() + nonContentHeight;
}
int RenderTextControlMultiLine::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
@@ -104,7 +104,7 @@ RenderObject* RenderTextControlMultiLine::layoutSpecialExcludedChild(bool relayo
if (!placeholderRenderer->isBox())
return placeholderRenderer;
RenderBox* placeholderBox = toRenderBox(placeholderRenderer);
- placeholderBox->style()->setWidth(Length(contentWidth() - placeholderBox->borderAndPaddingWidth(), Fixed));
+ placeholderBox->style()->setLogicalWidth(Length(contentLogicalWidth() - placeholderBox->borderAndPaddingLogicalWidth(), Fixed));
placeholderBox->layoutIfNeeded();
placeholderBox->setX(borderLeft() + paddingLeft());
placeholderBox->setY(borderTop() + paddingTop());
diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.h b/Source/WebCore/rendering/RenderTextControlMultiLine.h
index 6dad346c5..592a137d9 100644
--- a/Source/WebCore/rendering/RenderTextControlMultiLine.h
+++ b/Source/WebCore/rendering/RenderTextControlMultiLine.h
@@ -28,7 +28,7 @@ namespace WebCore {
class RenderTextControlMultiLine : public RenderTextControl {
public:
- RenderTextControlMultiLine(Node*);
+ RenderTextControlMultiLine(Element*);
virtual ~RenderTextControlMultiLine();
private:
@@ -37,8 +37,8 @@ private:
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
virtual float getAvgCharWidth(AtomicString family);
- virtual LayoutUnit preferredContentWidth(float charWidth) const;
- virtual LayoutUnit computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE;
+ virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const;
+ virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE;
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
virtual RenderStyle* textBaseStyle() const;
@@ -48,7 +48,7 @@ private:
inline RenderTextControlMultiLine* toRenderTextControlMultiLine(RenderObject* object)
{
- ASSERT(!object || object->isTextArea());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTextArea());
return static_cast<RenderTextControlMultiLine*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp
index c7f075a4b..8ba8ea13b 100644
--- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -42,6 +42,7 @@
#include "SimpleFontData.h"
#include "StyleResolver.h"
#include "TextControlInnerElements.h"
+#include <wtf/StackStats.h>
using namespace std;
@@ -49,13 +50,13 @@ namespace WebCore {
using namespace HTMLNames;
-RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node)
- : RenderTextControl(node)
+RenderTextControlSingleLine::RenderTextControlSingleLine(Element* element)
+ : RenderTextControl(element)
, m_shouldDrawCapsLockIndicator(false)
- , m_desiredInnerTextHeight(-1)
+ , m_desiredInnerTextLogicalHeight(-1)
{
- ASSERT(node->isHTMLElement());
- ASSERT(node->toInputElement());
+ ASSERT(element->isHTMLElement());
+ ASSERT(element->toInputElement());
}
RenderTextControlSingleLine::~RenderTextControlSingleLine()
@@ -80,8 +81,11 @@ void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, const LayoutPoint&
if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
LayoutRect contentsRect = contentBoxRect();
- // Center vertically like the text.
- contentsRect.setY((height() - contentsRect.height()) / 2);
+ // Center in the block progression direction.
+ if (isHorizontalWritingMode())
+ contentsRect.setY((height() - contentsRect.height()) / 2);
+ else
+ contentsRect.setX((width() - contentsRect.width()) / 2);
// Convert the rect into the coords used for painting the content
contentsRect.moveBy(paintOffset + location());
@@ -89,9 +93,9 @@ void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, const LayoutPoint&
}
}
-LayoutUnit RenderTextControlSingleLine::computeHeightLimit() const
+LayoutUnit RenderTextControlSingleLine::computeLogicalHeightLimit() const
{
- return containerElement() ? contentHeight() : height();
+ return containerElement() ? contentLogicalHeight() : logicalHeight();
}
void RenderTextControlSingleLine::layout()
@@ -110,13 +114,17 @@ void RenderTextControlSingleLine::layout()
// because of compability.
RenderBox* innerTextRenderer = innerTextElement()->renderBox();
- ASSERT(innerTextRenderer);
RenderBox* innerBlockRenderer = innerBlockElement() ? innerBlockElement()->renderBox() : 0;
// To ensure consistency between layouts, we need to reset any conditionally overriden height.
- innerTextRenderer->style()->setHeight(Length(Auto));
- if (innerBlockRenderer)
- innerBlockRenderer->style()->setHeight(Length(Auto));
+ if (innerTextRenderer && !innerTextRenderer->style()->logicalHeight().isAuto()) {
+ innerTextRenderer->style()->setLogicalHeight(Length(Auto));
+ innerTextRenderer->setNeedsLayout(true, MarkOnlyThis);
+ }
+ if (innerBlockRenderer && !innerBlockRenderer->style()->logicalHeight().isAuto()) {
+ innerBlockRenderer->style()->setLogicalHeight(Length(Auto));
+ innerBlockRenderer->setNeedsLayout(true, MarkOnlyThis);
+ }
RenderBlock::layoutBlock(false);
@@ -124,42 +132,43 @@ void RenderTextControlSingleLine::layout()
RenderBox* containerRenderer = container ? container->renderBox() : 0;
// Set the text block height
- LayoutUnit desiredHeight = textBlockHeight();
- LayoutUnit currentHeight = innerTextRenderer->height();
-
- LayoutUnit heightLimit = computeHeightLimit();
- if (currentHeight > heightLimit) {
- if (desiredHeight != currentHeight)
+ LayoutUnit desiredLogicalHeight = textBlockLogicalHeight();
+ LayoutUnit logicalHeightLimit = computeLogicalHeightLimit();
+ if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) {
+ if (desiredLogicalHeight != innerTextRenderer->logicalHeight())
setNeedsLayout(true, MarkOnlyThis);
- innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed));
- m_desiredInnerTextHeight = desiredHeight;
- if (innerBlockRenderer)
- innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed));
+ m_desiredInnerTextLogicalHeight = desiredLogicalHeight;
+
+ innerTextRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed));
+ innerTextRenderer->setNeedsLayout(true, MarkOnlyThis);
+ if (innerBlockRenderer) {
+ innerBlockRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed));
+ innerBlockRenderer->setNeedsLayout(true, MarkOnlyThis);
+ }
}
// The container might be taller because of decoration elements.
if (containerRenderer) {
containerRenderer->layoutIfNeeded();
- LayoutUnit containerHeight = containerRenderer->height();
- if (containerHeight > heightLimit) {
- containerRenderer->style()->setHeight(Length(heightLimit, Fixed));
+ LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight();
+ if (containerLogicalHeight > logicalHeightLimit) {
+ containerRenderer->style()->setLogicalHeight(Length(logicalHeightLimit, Fixed));
setNeedsLayout(true, MarkOnlyThis);
- } else if (containerRenderer->height() < contentHeight()) {
- containerRenderer->style()->setHeight(Length(contentHeight(), Fixed));
+ } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) {
+ containerRenderer->style()->setLogicalHeight(Length(contentLogicalHeight(), Fixed));
setNeedsLayout(true, MarkOnlyThis);
} else
- containerRenderer->style()->setHeight(Length(containerHeight, Fixed));
+ containerRenderer->style()->setLogicalHeight(Length(containerLogicalHeight, Fixed));
}
// If we need another layout pass, we have changed one of children's height so we need to relayout them.
if (needsLayout())
RenderBlock::layoutBlock(true);
- // Center the child block vertically
- currentHeight = innerTextRenderer->height();
- if (!container && currentHeight != contentHeight()) {
- LayoutUnit heightDiff = currentHeight - contentHeight();
- innerTextRenderer->setY(innerTextRenderer->y() - (heightDiff / 2 + layoutMod(heightDiff, 2)));
+ // Center the child block in the block progression direction (vertical centering for horizontal text fields).
+ if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) {
+ LayoutUnit logicalHeightDiff = innerTextRenderer->logicalHeight() - contentLogicalHeight();
+ innerTextRenderer->setLogicalTop(innerTextRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2)));
} else
centerContainerIfNeeded(containerRenderer);
@@ -167,19 +176,25 @@ void RenderTextControlSingleLine::layout()
if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) {
RenderBox* parentBox = innerSpinBox->parentBox();
if (containerRenderer && !containerRenderer->style()->isLeftToRightDirection())
- innerSpinBox->setLocation(LayoutPoint(-paddingLeft(), -paddingTop()));
+ innerSpinBox->setLogicalLocation(LayoutPoint(-paddingLogicalLeft(), -paddingBefore()));
else
- innerSpinBox->setLocation(LayoutPoint(parentBox->width() - innerSpinBox->width() + paddingRight(), -paddingTop()));
- innerSpinBox->setHeight(height() - borderTop() - borderBottom());
+ innerSpinBox->setLogicalLocation(LayoutPoint(parentBox->logicalWidth() - innerSpinBox->logicalWidth() + paddingLogicalRight(), -paddingBefore()));
+ innerSpinBox->setLogicalHeight(logicalHeight() - borderBefore() - borderAfter());
}
HTMLElement* placeholderElement = inputElement()->placeholderElement();
if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) {
- placeholderBox->style()->setWidth(Length(innerTextRenderer->width() - placeholderBox->borderAndPaddingWidth(), Fixed));
- placeholderBox->style()->setHeight(Length(innerTextRenderer->height() - placeholderBox->borderAndPaddingHeight(), Fixed));
+ LayoutSize innerTextSize;
+ if (innerTextRenderer)
+ innerTextSize = innerTextRenderer->size();
+ placeholderBox->style()->setWidth(Length(innerTextSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed));
+ placeholderBox->style()->setHeight(Length(innerTextSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed));
+ bool neededLayout = placeholderBox->needsLayout();
bool placeholderBoxHadLayout = placeholderBox->everHadLayout();
placeholderBox->layoutIfNeeded();
- LayoutPoint textOffset = innerTextRenderer->location();
+ LayoutPoint textOffset;
+ if (innerTextRenderer)
+ textOffset = innerTextRenderer->location();
if (innerBlockElement() && innerBlockElement()->renderBox())
textOffset += toLayoutSize(innerBlockElement()->renderBox()->location());
if (containerRenderer)
@@ -191,6 +206,10 @@ void RenderTextControlSingleLine::layout()
// logic should be shared with RenderBlock::layoutBlockChild.
placeholderBox->repaint();
}
+ // The placeholder gets layout last, after the parent text control and its other children,
+ // so in order to get the correct overflow from the placeholder we need to recompute it now.
+ if (neededLayout)
+ computeOverflow(clientLogicalBottom());
}
}
@@ -219,7 +238,7 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit
void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
- m_desiredInnerTextHeight = -1;
+ m_desiredInnerTextLogicalHeight = -1;
RenderTextControl::styleDidChange(diff, oldStyle);
// We may have set the width and the height in the old style in layout().
@@ -234,6 +253,9 @@ void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const Ren
containerRenderer->style()->setHeight(Length());
containerRenderer->style()->setWidth(Length());
}
+ RenderObject* innerTextRenderer = innerTextElement()->renderer();
+ if (innerTextRenderer && diff == StyleDifferenceLayout)
+ innerTextRenderer->setNeedsLayout(true, MarkContainingBlockChain);
if (HTMLElement* placeholder = inputElement()->placeholderElement())
placeholder->setInlineStyleProperty(CSSPropertyTextOverflow, textShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip);
setHasOverflowClip(false);
@@ -254,7 +276,7 @@ void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
if (Frame* frame = document()->frame())
shouldDrawCapsLockIndicator = inputElement()->isPasswordField()
&& frame->selection()->isFocusedAndActive()
- && document()->focusedNode() == node()
+ && document()->focusedElement() == node()
&& PlatformKeyboardEvent::currentCapsLockState();
if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
@@ -272,7 +294,9 @@ bool RenderTextControlSingleLine::hasControlClip() const
LayoutRect RenderTextControlSingleLine::controlClipRect(const LayoutPoint& additionalOffset) const
{
ASSERT(hasControlClip());
- LayoutRect clipRect = unionRect(contentBoxRect(), containerElement()->renderBox()->frameRect());
+ LayoutRect clipRect = contentBoxRect();
+ if (containerElement()->renderBox())
+ clipRect = unionRect(clipRect, containerElement()->renderBox()->frameRect());
clipRect.moveBy(additionalOffset);
return clipRect;
}
@@ -289,7 +313,7 @@ float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family)
return RenderTextControl::getAvgCharWidth(family);
}
-LayoutUnit RenderTextControlSingleLine::preferredContentWidth(float charWidth) const
+LayoutUnit RenderTextControlSingleLine::preferredContentLogicalWidth(float charWidth) const
{
int factor;
bool includesDecoration = inputElement()->sizeShouldIncludeDecoration(factor);
@@ -299,7 +323,7 @@ LayoutUnit RenderTextControlSingleLine::preferredContentWidth(float charWidth) c
LayoutUnit result = static_cast<LayoutUnit>(ceiledLayoutUnit(charWidth * factor));
float maxCharWidth = 0.f;
- AtomicString family = style()->font().family().family();
+ const AtomicString& family = style()->font().firstFamily();
// Since Lucida Grande is the default font, we want this to match the width
// of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
// IE for some encodings (in IE, the default font is encoding specific).
@@ -316,18 +340,17 @@ LayoutUnit RenderTextControlSingleLine::preferredContentWidth(float charWidth) c
if (includesDecoration) {
HTMLElement* spinButton = innerSpinButtonElement();
if (RenderBox* spinRenderer = spinButton ? spinButton->renderBox() : 0) {
- result += spinRenderer->borderLeft() + spinRenderer->borderRight() +
- spinRenderer->paddingLeft() + spinRenderer->paddingRight();
- // Since the width of spinRenderer is not calculated yet, spinRenderer->width() returns 0.
- // So computedStyle()->width() is used instead.
- result += spinButton->computedStyle()->width().value();
+ result += spinRenderer->borderAndPaddingLogicalWidth();
+ // Since the width of spinRenderer is not calculated yet, spinRenderer->logicalWidth() returns 0.
+ // So computedStyle()->logicalWidth() is used instead.
+ result += spinButton->computedStyle()->logicalWidth().value();
}
}
return result;
}
-LayoutUnit RenderTextControlSingleLine::computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
+LayoutUnit RenderTextControlSingleLine::computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
{
return lineHeight + nonContentHeight;
}
@@ -349,8 +372,8 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const
textBlockStyle->setOverflowY(OHIDDEN);
textBlockStyle->setTextOverflow(textShouldBeTruncated() ? TextOverflowEllipsis : TextOverflowClip);
- if (m_desiredInnerTextHeight >= 0)
- textBlockStyle->setHeight(Length(m_desiredInnerTextHeight, Fixed));
+ if (m_desiredInnerTextLogicalHeight >= 0)
+ textBlockStyle->setLogicalHeight(Length(m_desiredInnerTextLogicalHeight, Fixed));
// Do not allow line-height to be smaller than our default.
if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
textBlockStyle->setLineHeight(RenderStyle::initialLineHeight());
@@ -365,7 +388,10 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const
RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
innerBlockStyle->inheritFrom(startStyle);
- innerBlockStyle->setBoxFlex(1);
+ innerBlockStyle->setFlexGrow(1);
+ // min-width: 0; is needed for correct shrinking.
+ // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
+ innerBlockStyle->setMinWidth(Length(0, Fixed));
innerBlockStyle->setDisplay(BLOCK);
innerBlockStyle->setDirection(LTR);
@@ -377,15 +403,18 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const
bool RenderTextControlSingleLine::textShouldBeTruncated() const
{
- return document()->focusedNode() != node()
+ return document()->focusedElement() != node()
&& style()->textOverflow() == TextOverflowEllipsis;
}
-void RenderTextControlSingleLine::autoscroll()
+void RenderTextControlSingleLine::autoscroll(const IntPoint& position)
{
- RenderLayer* layer = innerTextElement()->renderBox()->layer();
+ RenderBox* renderer = innerTextElement()->renderBox();
+ if (!renderer)
+ return;
+ RenderLayer* layer = renderer->layer();
if (layer)
- layer->autoscroll();
+ layer->autoscroll(position);
}
int RenderTextControlSingleLine::scrollWidth() const
@@ -430,7 +459,10 @@ void RenderTextControlSingleLine::setScrollTop(int newTop)
bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
{
- RenderLayer* layer = innerTextElement()->renderBox()->layer();
+ RenderBox* renderer = innerTextElement()->renderBox();
+ if (!renderer)
+ return false;
+ RenderLayer* layer = renderer->layer();
if (layer && layer->scroll(direction, granularity, multiplier))
return true;
return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.h b/Source/WebCore/rendering/RenderTextControlSingleLine.h
index af27bf758..148acfe4a 100644
--- a/Source/WebCore/rendering/RenderTextControlSingleLine.h
+++ b/Source/WebCore/rendering/RenderTextControlSingleLine.h
@@ -32,7 +32,7 @@ class HTMLInputElement;
class RenderTextControlSingleLine : public RenderTextControl {
public:
- RenderTextControlSingleLine(Node*);
+ RenderTextControlSingleLine(Element*);
virtual ~RenderTextControlSingleLine();
// FIXME: Move create*Style() to their classes.
virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const;
@@ -42,7 +42,7 @@ public:
protected:
virtual void centerContainerIfNeeded(RenderBox*) const { }
- virtual LayoutUnit computeHeightLimit() const;
+ virtual LayoutUnit computeLogicalHeightLimit() const;
HTMLElement* containerElement() const;
HTMLElement* innerBlockElement() const;
HTMLInputElement* inputElement() const;
@@ -58,7 +58,7 @@ private:
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
- virtual void autoscroll();
+ virtual void autoscroll(const IntPoint&);
// Subclassed to forward to our inner div.
virtual int scrollLeft() const;
@@ -72,8 +72,8 @@ private:
int textBlockWidth() const;
virtual float getAvgCharWidth(AtomicString family);
- virtual LayoutUnit preferredContentWidth(float charWidth) const;
- virtual LayoutUnit computeControlHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE;
+ virtual LayoutUnit preferredContentLogicalWidth(float charWidth) const;
+ virtual LayoutUnit computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const OVERRIDE;
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -84,7 +84,7 @@ private:
HTMLElement* innerSpinButtonElement() const;
bool m_shouldDrawCapsLockIndicator;
- LayoutUnit m_desiredInnerTextHeight;
+ LayoutUnit m_desiredInnerTextLogicalHeight;
};
inline HTMLElement* RenderTextControlSingleLine::containerElement() const
@@ -99,7 +99,7 @@ inline HTMLElement* RenderTextControlSingleLine::innerBlockElement() const
inline RenderTextControlSingleLine* toRenderTextControlSingleLine(RenderObject* object)
{
- ASSERT(!object || object->isTextField());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isTextField());
return static_cast<RenderTextControlSingleLine*>(object);
}
@@ -110,7 +110,7 @@ void toRenderTextControlSingleLine(const RenderTextControlSingleLine*);
class RenderTextControlInnerBlock : public RenderBlock {
public:
- RenderTextControlInnerBlock(Node* node) : RenderBlock(node) { }
+ RenderTextControlInnerBlock(Element* element) : RenderBlock(element) { }
private:
virtual bool hasLineIfEmpty() const { return true; }
diff --git a/Source/WebCore/rendering/RenderTextFragment.h b/Source/WebCore/rendering/RenderTextFragment.h
index b7f3b0e9a..3f86357ff 100644
--- a/Source/WebCore/rendering/RenderTextFragment.h
+++ b/Source/WebCore/rendering/RenderTextFragment.h
@@ -71,13 +71,13 @@ private:
inline RenderTextFragment* toRenderTextFragment(RenderObject* object)
{
- ASSERT(!object || toRenderText(object)->isTextFragment());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || toRenderText(object)->isTextFragment());
return static_cast<RenderTextFragment*>(object);
}
inline const RenderTextFragment* toRenderTextFragment(const RenderObject* object)
{
- ASSERT(!object || toRenderText(object)->isTextFragment());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || toRenderText(object)->isTextFragment());
return static_cast<const RenderTextFragment*>(object);
}
diff --git a/Source/WebCore/rendering/RenderTextTrackCue.cpp b/Source/WebCore/rendering/RenderTextTrackCue.cpp
index 4e9dc1552..fd88b77ad 100644
--- a/Source/WebCore/rendering/RenderTextTrackCue.cpp
+++ b/Source/WebCore/rendering/RenderTextTrackCue.cpp
@@ -30,12 +30,14 @@
#include "RenderTextTrackCue.h"
#include "TextTrackCue.h"
+#include "TextTrackCueGeneric.h"
+#include <wtf/StackStats.h>
namespace WebCore {
-RenderTextTrackCue::RenderTextTrackCue(TextTrackCueBox* node)
- : RenderBlock(static_cast<Node*>(node))
- , m_cue(node->getCue())
+RenderTextTrackCue::RenderTextTrackCue(TextTrackCueBox* element)
+ : RenderBlock(element)
+ , m_cue(element->getCue())
{
}
@@ -45,10 +47,15 @@ void RenderTextTrackCue::layout()
RenderBlock::layout();
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- if (m_cue->snapToLines())
- repositionCueSnapToLinesSet();
- else
- repositionCueSnapToLinesNotSet();
+
+ if (m_cue->cueType()== TextTrackCue::WebVTT) {
+ if (m_cue->snapToLines())
+ repositionCueSnapToLinesSet();
+ else
+ repositionCueSnapToLinesNotSet();
+ } else
+ repositionGenericCue();
+
statePusher.pop();
}
@@ -117,19 +124,35 @@ void RenderTextTrackCue::placeBoxInDefaultPosition(LayoutUnit position, bool& sw
bool RenderTextTrackCue::isOutside() const
{
- return !containingBlock()->absoluteBoundingBoxRect().contains(absoluteBoundingBoxRect());
+ return !rectIsWithinContainer(absoluteContentBox());
+}
+
+bool RenderTextTrackCue::rectIsWithinContainer(const IntRect& rect) const
+{
+ return containingBlock()->absoluteBoundingBoxRect().contains(rect);
}
+
bool RenderTextTrackCue::isOverlapping() const
{
+ return overlappingObject();
+}
+
+RenderObject* RenderTextTrackCue::overlappingObject() const
+{
+ return overlappingObjectForRect(absoluteBoundingBoxRect());
+}
+
+RenderObject* RenderTextTrackCue::overlappingObjectForRect(const IntRect& rect) const
+{
for (RenderObject* box = previousSibling(); box; box = box->previousSibling()) {
IntRect boxRect = box->absoluteBoundingBoxRect();
- if (absoluteBoundingBoxRect().intersects(boxRect))
- return true;
+ if (rect.intersects(boxRect))
+ return box;
}
- return false;
+ return 0;
}
bool RenderTextTrackCue::shouldSwitchDirection(InlineFlowBox* firstLineBox, LayoutUnit step) const
@@ -195,6 +218,76 @@ bool RenderTextTrackCue::switchDirection(bool& switched, LayoutUnit& step)
return true;
}
+void RenderTextTrackCue::moveIfNecessaryToKeepWithinContainer()
+{
+ IntRect containerRect = containingBlock()->absoluteBoundingBoxRect();
+ IntRect cueRect = absoluteBoundingBoxRect();
+
+ int topOverflow = cueRect.y() - containerRect.y();
+ int bottomOverflow = containerRect.maxY() - cueRect.maxY();
+
+ int verticalAdjustment = 0;
+ if (topOverflow < 0)
+ verticalAdjustment = -topOverflow;
+ else if (bottomOverflow < 0)
+ verticalAdjustment = bottomOverflow;
+
+ if (verticalAdjustment)
+ setY(y() + verticalAdjustment);
+
+ int leftOverflow = cueRect.x() - containerRect.x();
+ int rightOverflow = containerRect.maxX() - cueRect.maxX();
+
+ int horizontalAdjustment = 0;
+ if (leftOverflow < 0)
+ horizontalAdjustment = -leftOverflow;
+ else if (rightOverflow < 0)
+ horizontalAdjustment = rightOverflow;
+
+ if (horizontalAdjustment)
+ setX(x() + horizontalAdjustment);
+}
+
+bool RenderTextTrackCue::findNonOverlappingPosition(int& newX, int& newY) const
+{
+ newX = x();
+ newY = y();
+ IntRect srcRect = absoluteBoundingBoxRect();
+ IntRect destRect = srcRect;
+
+ // Move the box up, looking for a non-overlapping position:
+ while (RenderObject* box = overlappingObjectForRect(destRect)) {
+ if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
+ destRect.setY(box->absoluteBoundingBoxRect().y() - destRect.height());
+ else
+ destRect.setX(box->absoluteBoundingBoxRect().x() - destRect.width());
+ }
+
+ if (rectIsWithinContainer(destRect)) {
+ newX += destRect.x() - srcRect.x();
+ newY += destRect.y() - srcRect.y();
+ return true;
+ }
+
+ destRect = srcRect;
+
+ // Move the box down, looking for a non-overlapping position:
+ while (RenderObject* box = overlappingObjectForRect(destRect)) {
+ if (m_cue->getWritingDirection() == TextTrackCue::Horizontal)
+ destRect.setY(box->absoluteBoundingBoxRect().maxY());
+ else
+ destRect.setX(box->absoluteBoundingBoxRect().maxX());
+ }
+
+ if (rectIsWithinContainer(destRect)) {
+ newX += destRect.x() - srcRect.x();
+ newY += destRect.y() - srcRect.y();
+ return true;
+ }
+
+ return false;
+}
+
void RenderTextTrackCue::repositionCueSnapToLinesSet()
{
InlineFlowBox* firstLineBox;
@@ -219,11 +312,48 @@ void RenderTextTrackCue::repositionCueSnapToLinesSet()
// 19. Jump back to the step labeled step loop.
}
+
+ // Acommodate extra top and bottom padding, border or margin.
+ // Note: this is supported only for internal UA styling, not through the cue selector.
+ if (hasInlineDirectionBordersPaddingOrMargin())
+ moveIfNecessaryToKeepWithinContainer();
+}
+
+void RenderTextTrackCue::repositionGenericCue()
+{
+ ASSERT(firstChild());
+ InlineFlowBox* firstLineBox = toRenderInline(firstChild())->firstLineBox();
+ if (static_cast<TextTrackCueGeneric*>(m_cue)->useDefaultPosition() && firstLineBox) {
+ LayoutUnit parentWidth = containingBlock()->logicalWidth();
+ LayoutUnit width = firstLineBox->width();
+ LayoutUnit right = (parentWidth / 2) - (width / 2);
+ setX(right);
+ }
+ repositionCueSnapToLinesNotSet();
}
void RenderTextTrackCue::repositionCueSnapToLinesNotSet()
{
- // FIXME: Implement overlapping detection when snap-to-lines is not set. http://wkb.ug/84296
+ // 3. If none of the boxes in boxes would overlap any of the boxes in output, and all the boxes in
+ // output are within the video's rendering area, then jump to the step labeled done positioning below.
+ if (!isOutside() && !isOverlapping())
+ return;
+
+ // 4. If there is a position to which the boxes in boxes can be moved while maintaining the relative
+ // positions of the boxes in boxes to each other such that none of the boxes in boxes would overlap
+ // any of the boxes in output, and all the boxes in output would be within the video's rendering area,
+ // then move the boxes in boxes to the closest such position to their current position, and then jump
+ // to the step labeled done positioning below. If there are multiple such positions that are equidistant
+ // from their current position, use the highest one amongst them; if there are several at that height,
+ // then use the leftmost one amongst them.
+ moveIfNecessaryToKeepWithinContainer();
+ int x = 0;
+ int y = 0;
+ if (!findNonOverlappingPosition(x, y))
+ return;
+
+ setX(x);
+ setY(y);
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderTextTrackCue.h b/Source/WebCore/rendering/RenderTextTrackCue.h
index 8973ad8a7..8ffcd91a4 100644
--- a/Source/WebCore/rendering/RenderTextTrackCue.h
+++ b/Source/WebCore/rendering/RenderTextTrackCue.h
@@ -35,6 +35,7 @@
namespace WebCore {
+class RenderBox;
class TextTrackCueBox;
class RenderTextTrackCue : public RenderBlock {
@@ -45,17 +46,22 @@ private:
virtual void layout() OVERRIDE;
bool isOutside() const;
+ bool rectIsWithinContainer(const IntRect&) const;
bool isOverlapping() const;
+ RenderObject* overlappingObject() const;
+ RenderObject* overlappingObjectForRect(const IntRect&) const;
bool shouldSwitchDirection(InlineFlowBox*, LayoutUnit) const;
void moveBoxesByStep(LayoutUnit);
bool switchDirection(bool&, LayoutUnit&);
+ void moveIfNecessaryToKeepWithinContainer();
+ bool findNonOverlappingPosition(int& x, int& y) const;
bool initializeLayoutParameters(InlineFlowBox*&, LayoutUnit&, LayoutUnit&);
void placeBoxInDefaultPosition(LayoutUnit, bool&);
void repositionCueSnapToLinesSet();
-
void repositionCueSnapToLinesNotSet();
+ void repositionGenericCue();
TextTrackCue* m_cue;
FloatPoint m_fallbackPosition;
diff --git a/Source/WebCore/rendering/RenderTheme.cpp b/Source/WebCore/rendering/RenderTheme.cpp
index 0432dc32b..c0c584ddc 100644
--- a/Source/WebCore/rendering/RenderTheme.cpp
+++ b/Source/WebCore/rendering/RenderTheme.cpp
@@ -81,15 +81,14 @@ RenderTheme::RenderTheme()
{
}
-void RenderTheme::adjustStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e,
- bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor)
+void RenderTheme::adjustStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e, bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor)
{
// Force inline and table display styles to be inline-block (except for table- which is block)
ControlPart part = style->appearance();
- if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP ||
- style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP ||
- style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN ||
- style->display() == TABLE_CELL || style->display() == TABLE_CAPTION)
+ if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP
+ || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP
+ || style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN
+ || style->display() == TABLE_CELL || style->display() == TABLE_CAPTION)
style->setDisplay(INLINE_BLOCK);
else if (style->display() == COMPACT || style->display() == RUN_IN || style->display() == LIST_ITEM || style->display() == TABLE)
style->setDisplay(BLOCK);
@@ -110,152 +109,152 @@ void RenderTheme::adjustStyle(StyleResolver* styleResolver, RenderStyle* style,
#if USE(NEW_THEME)
switch (part) {
- case CheckboxPart:
- case InnerSpinButtonPart:
- case RadioPart:
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart: {
- // Border
- LengthBox borderBox(style->borderTopWidth(), style->borderRightWidth(), style->borderBottomWidth(), style->borderLeftWidth());
- borderBox = m_theme->controlBorder(part, style->font(), borderBox, style->effectiveZoom());
- if (borderBox.top().value() != static_cast<int>(style->borderTopWidth())) {
- if (borderBox.top().value())
- style->setBorderTopWidth(borderBox.top().value());
- else
- style->resetBorderTop();
- }
- if (borderBox.right().value() != static_cast<int>(style->borderRightWidth())) {
- if (borderBox.right().value())
- style->setBorderRightWidth(borderBox.right().value());
- else
- style->resetBorderRight();
- }
- if (borderBox.bottom().value() != static_cast<int>(style->borderBottomWidth())) {
+ case CheckboxPart:
+ case InnerSpinButtonPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart: {
+ // Border
+ LengthBox borderBox(style->borderTopWidth(), style->borderRightWidth(), style->borderBottomWidth(), style->borderLeftWidth());
+ borderBox = m_theme->controlBorder(part, style->font(), borderBox, style->effectiveZoom());
+ if (borderBox.top().value() != static_cast<int>(style->borderTopWidth())) {
+ if (borderBox.top().value())
+ style->setBorderTopWidth(borderBox.top().value());
+ else
+ style->resetBorderTop();
+ }
+ if (borderBox.right().value() != static_cast<int>(style->borderRightWidth())) {
+ if (borderBox.right().value())
+ style->setBorderRightWidth(borderBox.right().value());
+ else
+ style->resetBorderRight();
+ }
+ if (borderBox.bottom().value() != static_cast<int>(style->borderBottomWidth())) {
+ style->setBorderBottomWidth(borderBox.bottom().value());
+ if (borderBox.bottom().value())
style->setBorderBottomWidth(borderBox.bottom().value());
- if (borderBox.bottom().value())
- style->setBorderBottomWidth(borderBox.bottom().value());
- else
- style->resetBorderBottom();
- }
- if (borderBox.left().value() != static_cast<int>(style->borderLeftWidth())) {
+ else
+ style->resetBorderBottom();
+ }
+ if (borderBox.left().value() != static_cast<int>(style->borderLeftWidth())) {
+ style->setBorderLeftWidth(borderBox.left().value());
+ if (borderBox.left().value())
style->setBorderLeftWidth(borderBox.left().value());
- if (borderBox.left().value())
- style->setBorderLeftWidth(borderBox.left().value());
- else
- style->resetBorderLeft();
- }
-
- // Padding
- LengthBox paddingBox = m_theme->controlPadding(part, style->font(), style->paddingBox(), style->effectiveZoom());
- if (paddingBox != style->paddingBox())
- style->setPaddingBox(paddingBox);
-
- // Whitespace
- if (m_theme->controlRequiresPreWhiteSpace(part))
- style->setWhiteSpace(PRE);
+ else
+ style->resetBorderLeft();
+ }
+
+ // Padding
+ LengthBox paddingBox = m_theme->controlPadding(part, style->font(), style->paddingBox(), style->effectiveZoom());
+ if (paddingBox != style->paddingBox())
+ style->setPaddingBox(paddingBox);
+
+ // Whitespace
+ if (m_theme->controlRequiresPreWhiteSpace(part))
+ style->setWhiteSpace(PRE);
- // Width / Height
- // The width and height here are affected by the zoom.
- // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
- LengthSize controlSize = m_theme->controlSize(part, style->font(), LengthSize(style->width(), style->height()), style->effectiveZoom());
- if (controlSize.width() != style->width())
- style->setWidth(controlSize.width());
- if (controlSize.height() != style->height())
- style->setHeight(controlSize.height());
-
- // Min-Width / Min-Height
- LengthSize minControlSize = m_theme->minimumControlSize(part, style->font(), style->effectiveZoom());
- if (minControlSize.width() != style->minWidth())
- style->setMinWidth(minControlSize.width());
- if (minControlSize.height() != style->minHeight())
- style->setMinHeight(minControlSize.height());
+ // Width / Height
+ // The width and height here are affected by the zoom.
+ // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
+ LengthSize controlSize = m_theme->controlSize(part, style->font(), LengthSize(style->width(), style->height()), style->effectiveZoom());
+ if (controlSize.width() != style->width())
+ style->setWidth(controlSize.width());
+ if (controlSize.height() != style->height())
+ style->setHeight(controlSize.height());
- // Font
- FontDescription controlFont = m_theme->controlFont(part, style->font(), style->effectiveZoom());
- if (controlFont != style->font().fontDescription()) {
- // Reset our line-height
- style->setLineHeight(RenderStyle::initialLineHeight());
+ // Min-Width / Min-Height
+ LengthSize minControlSize = m_theme->minimumControlSize(part, style->font(), style->effectiveZoom());
+ if (minControlSize.width() != style->minWidth())
+ style->setMinWidth(minControlSize.width());
+ if (minControlSize.height() != style->minHeight())
+ style->setMinHeight(minControlSize.height());
- // Now update our font.
- if (style->setFontDescription(controlFont))
- style->font().update(0);
- }
+ // Font
+ FontDescription controlFont = m_theme->controlFont(part, style->font(), style->effectiveZoom());
+ if (controlFont != style->font().fontDescription()) {
+ // Reset our line-height
+ style->setLineHeight(RenderStyle::initialLineHeight());
+
+ // Now update our font.
+ if (style->setFontDescription(controlFont))
+ style->font().update(0);
}
- default:
- break;
+ }
+ default:
+ break;
}
#endif
// Call the appropriate style adjustment method based off the appearance value.
switch (style->appearance()) {
#if !USE(NEW_THEME)
- case CheckboxPart:
- return adjustCheckboxStyle(styleResolver, style, e);
- case RadioPart:
- return adjustRadioStyle(styleResolver, style, e);
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- return adjustButtonStyle(styleResolver, style, e);
- case InnerSpinButtonPart:
- return adjustInnerSpinButtonStyle(styleResolver, style, e);
+ case CheckboxPart:
+ return adjustCheckboxStyle(styleResolver, style, e);
+ case RadioPart:
+ return adjustRadioStyle(styleResolver, style, e);
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ return adjustButtonStyle(styleResolver, style, e);
+ case InnerSpinButtonPart:
+ return adjustInnerSpinButtonStyle(styleResolver, style, e);
#endif
- case TextFieldPart:
- return adjustTextFieldStyle(styleResolver, style, e);
- case TextAreaPart:
- return adjustTextAreaStyle(styleResolver, style, e);
- case MenulistPart:
- return adjustMenuListStyle(styleResolver, style, e);
- case MenulistButtonPart:
- return adjustMenuListButtonStyle(styleResolver, style, e);
- case MediaPlayButtonPart:
- case MediaCurrentTimePart:
- case MediaTimeRemainingPart:
- case MediaEnterFullscreenButtonPart:
- case MediaExitFullscreenButtonPart:
- case MediaMuteButtonPart:
- case MediaVolumeSliderContainerPart:
- return adjustMediaControlStyle(styleResolver, style, e);
- case MediaSliderPart:
- case MediaVolumeSliderPart:
- case MediaFullScreenVolumeSliderPart:
- case SliderHorizontalPart:
- case SliderVerticalPart:
- return adjustSliderTrackStyle(styleResolver, style, e);
- case SliderThumbHorizontalPart:
- case SliderThumbVerticalPart:
- return adjustSliderThumbStyle(styleResolver, style, e);
- case SearchFieldPart:
- return adjustSearchFieldStyle(styleResolver, style, e);
- case SearchFieldCancelButtonPart:
- return adjustSearchFieldCancelButtonStyle(styleResolver, style, e);
- case SearchFieldDecorationPart:
- return adjustSearchFieldDecorationStyle(styleResolver, style, e);
- case SearchFieldResultsDecorationPart:
- return adjustSearchFieldResultsDecorationStyle(styleResolver, style, e);
- case SearchFieldResultsButtonPart:
- return adjustSearchFieldResultsButtonStyle(styleResolver, style, e);
+ case TextFieldPart:
+ return adjustTextFieldStyle(styleResolver, style, e);
+ case TextAreaPart:
+ return adjustTextAreaStyle(styleResolver, style, e);
+ case MenulistPart:
+ return adjustMenuListStyle(styleResolver, style, e);
+ case MenulistButtonPart:
+ return adjustMenuListButtonStyle(styleResolver, style, e);
+ case MediaPlayButtonPart:
+ case MediaCurrentTimePart:
+ case MediaTimeRemainingPart:
+ case MediaEnterFullscreenButtonPart:
+ case MediaExitFullscreenButtonPart:
+ case MediaMuteButtonPart:
+ case MediaVolumeSliderContainerPart:
+ return adjustMediaControlStyle(styleResolver, style, e);
+ case MediaSliderPart:
+ case MediaVolumeSliderPart:
+ case MediaFullScreenVolumeSliderPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ return adjustSliderTrackStyle(styleResolver, style, e);
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ return adjustSliderThumbStyle(styleResolver, style, e);
+ case SearchFieldPart:
+ return adjustSearchFieldStyle(styleResolver, style, e);
+ case SearchFieldCancelButtonPart:
+ return adjustSearchFieldCancelButtonStyle(styleResolver, style, e);
+ case SearchFieldDecorationPart:
+ return adjustSearchFieldDecorationStyle(styleResolver, style, e);
+ case SearchFieldResultsDecorationPart:
+ return adjustSearchFieldResultsDecorationStyle(styleResolver, style, e);
+ case SearchFieldResultsButtonPart:
+ return adjustSearchFieldResultsButtonStyle(styleResolver, style, e);
#if ENABLE(PROGRESS_ELEMENT)
- case ProgressBarPart:
- return adjustProgressBarStyle(styleResolver, style, e);
+ case ProgressBarPart:
+ return adjustProgressBarStyle(styleResolver, style, e);
#endif
#if ENABLE(METER_ELEMENT)
- case MeterPart:
- case RelevancyLevelIndicatorPart:
- case ContinuousCapacityLevelIndicatorPart:
- case DiscreteCapacityLevelIndicatorPart:
- case RatingLevelIndicatorPart:
- return adjustMeterStyle(styleResolver, style, e);
+ case MeterPart:
+ case RelevancyLevelIndicatorPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ case DiscreteCapacityLevelIndicatorPart:
+ case RatingLevelIndicatorPart:
+ return adjustMeterStyle(styleResolver, style, e);
#endif
#if ENABLE(INPUT_SPEECH)
- case InputSpeechButtonPart:
- return adjustInputFieldSpeechButtonStyle(styleResolver, style, e);
+ case InputSpeechButtonPart:
+ return adjustInputFieldSpeechButtonStyle(styleResolver, style, e);
#endif
- default:
- break;
+ default:
+ break;
}
}
@@ -276,117 +275,119 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRe
#if USE(NEW_THEME)
switch (part) {
- case CheckboxPart:
- case RadioPart:
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- case InnerSpinButtonPart:
- m_theme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView());
- return false;
- default:
- break;
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case InnerSpinButtonPart:
+ m_theme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView());
+ return false;
+ default:
+ break;
}
#endif
// Call the appropriate paint method based off the appearance value.
switch (part) {
#if !USE(NEW_THEME)
- case CheckboxPart:
- return paintCheckbox(o, paintInfo, r);
- case RadioPart:
- return paintRadio(o, paintInfo, r);
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- return paintButton(o, paintInfo, r);
- case InnerSpinButtonPart:
- return paintInnerSpinButton(o, paintInfo, r);
+ case CheckboxPart:
+ return paintCheckbox(o, paintInfo, r);
+ case RadioPart:
+ return paintRadio(o, paintInfo, r);
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ return paintButton(o, paintInfo, r);
+ case InnerSpinButtonPart:
+ return paintInnerSpinButton(o, paintInfo, r);
#endif
- case MenulistPart:
- return paintMenuList(o, paintInfo, r);
+ case MenulistPart:
+ return paintMenuList(o, paintInfo, r);
#if ENABLE(METER_ELEMENT)
- case MeterPart:
- case RelevancyLevelIndicatorPart:
- case ContinuousCapacityLevelIndicatorPart:
- case DiscreteCapacityLevelIndicatorPart:
- case RatingLevelIndicatorPart:
- return paintMeter(o, paintInfo, r);
+ case MeterPart:
+ case RelevancyLevelIndicatorPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ case DiscreteCapacityLevelIndicatorPart:
+ case RatingLevelIndicatorPart:
+ return paintMeter(o, paintInfo, r);
#endif
#if ENABLE(PROGRESS_ELEMENT)
- case ProgressBarPart:
- return paintProgressBar(o, paintInfo, r);
+ case ProgressBarPart:
+ return paintProgressBar(o, paintInfo, r);
#endif
- case SliderHorizontalPart:
- case SliderVerticalPart:
- return paintSliderTrack(o, paintInfo, r);
- case SliderThumbHorizontalPart:
- case SliderThumbVerticalPart:
- return paintSliderThumb(o, paintInfo, r);
- case MediaEnterFullscreenButtonPart:
- case MediaExitFullscreenButtonPart:
- return paintMediaFullscreenButton(o, paintInfo, r);
- case MediaPlayButtonPart:
- return paintMediaPlayButton(o, paintInfo, r);
- case MediaOverlayPlayButtonPart:
- return paintMediaOverlayPlayButton(o, paintInfo, r);
- case MediaMuteButtonPart:
- return paintMediaMuteButton(o, paintInfo, r);
- case MediaSeekBackButtonPart:
- return paintMediaSeekBackButton(o, paintInfo, r);
- case MediaSeekForwardButtonPart:
- return paintMediaSeekForwardButton(o, paintInfo, r);
- case MediaRewindButtonPart:
- return paintMediaRewindButton(o, paintInfo, r);
- case MediaReturnToRealtimeButtonPart:
- return paintMediaReturnToRealtimeButton(o, paintInfo, r);
- case MediaToggleClosedCaptionsButtonPart:
- return paintMediaToggleClosedCaptionsButton(o, paintInfo, r);
- case MediaSliderPart:
- return paintMediaSliderTrack(o, paintInfo, r);
- case MediaSliderThumbPart:
- return paintMediaSliderThumb(o, paintInfo, r);
- case MediaVolumeSliderMuteButtonPart:
- return paintMediaMuteButton(o, paintInfo, r);
- case MediaVolumeSliderContainerPart:
- return paintMediaVolumeSliderContainer(o, paintInfo, r);
- case MediaVolumeSliderPart:
- return paintMediaVolumeSliderTrack(o, paintInfo, r);
- case MediaVolumeSliderThumbPart:
- return paintMediaVolumeSliderThumb(o, paintInfo, r);
- case MediaFullScreenVolumeSliderPart:
- return paintMediaFullScreenVolumeSliderTrack(o, paintInfo, r);
- case MediaFullScreenVolumeSliderThumbPart:
- return paintMediaFullScreenVolumeSliderThumb(o, paintInfo, r);
- case MediaTimeRemainingPart:
- return paintMediaTimeRemaining(o, paintInfo, r);
- case MediaCurrentTimePart:
- return paintMediaCurrentTime(o, paintInfo, r);
- case MediaControlsBackgroundPart:
- return paintMediaControlsBackground(o, paintInfo, r);
- case MenulistButtonPart:
- case TextFieldPart:
- case TextAreaPart:
- case ListboxPart:
- return true;
- case SearchFieldPart:
- return paintSearchField(o, paintInfo, r);
- case SearchFieldCancelButtonPart:
- return paintSearchFieldCancelButton(o, paintInfo, r);
- case SearchFieldDecorationPart:
- return paintSearchFieldDecoration(o, paintInfo, r);
- case SearchFieldResultsDecorationPart:
- return paintSearchFieldResultsDecoration(o, paintInfo, r);
- case SearchFieldResultsButtonPart:
- return paintSearchFieldResultsButton(o, paintInfo, r);
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ return paintSliderTrack(o, paintInfo, r);
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ return paintSliderThumb(o, paintInfo, r);
+ case MediaEnterFullscreenButtonPart:
+ case MediaExitFullscreenButtonPart:
+ return paintMediaFullscreenButton(o, paintInfo, r);
+ case MediaPlayButtonPart:
+ return paintMediaPlayButton(o, paintInfo, r);
+ case MediaOverlayPlayButtonPart:
+ return paintMediaOverlayPlayButton(o, paintInfo, r);
+ case MediaMuteButtonPart:
+ return paintMediaMuteButton(o, paintInfo, r);
+ case MediaSeekBackButtonPart:
+ return paintMediaSeekBackButton(o, paintInfo, r);
+ case MediaSeekForwardButtonPart:
+ return paintMediaSeekForwardButton(o, paintInfo, r);
+ case MediaRewindButtonPart:
+ return paintMediaRewindButton(o, paintInfo, r);
+ case MediaReturnToRealtimeButtonPart:
+ return paintMediaReturnToRealtimeButton(o, paintInfo, r);
+ case MediaToggleClosedCaptionsButtonPart:
+ return paintMediaToggleClosedCaptionsButton(o, paintInfo, r);
+ case MediaSliderPart:
+ return paintMediaSliderTrack(o, paintInfo, r);
+ case MediaSliderThumbPart:
+ return paintMediaSliderThumb(o, paintInfo, r);
+ case MediaVolumeSliderMuteButtonPart:
+ return paintMediaMuteButton(o, paintInfo, r);
+ case MediaVolumeSliderContainerPart:
+ return paintMediaVolumeSliderContainer(o, paintInfo, r);
+ case MediaVolumeSliderPart:
+ return paintMediaVolumeSliderTrack(o, paintInfo, r);
+ case MediaVolumeSliderThumbPart:
+ return paintMediaVolumeSliderThumb(o, paintInfo, r);
+ case MediaFullScreenVolumeSliderPart:
+ return paintMediaFullScreenVolumeSliderTrack(o, paintInfo, r);
+ case MediaFullScreenVolumeSliderThumbPart:
+ return paintMediaFullScreenVolumeSliderThumb(o, paintInfo, r);
+ case MediaTimeRemainingPart:
+ return paintMediaTimeRemaining(o, paintInfo, r);
+ case MediaCurrentTimePart:
+ return paintMediaCurrentTime(o, paintInfo, r);
+ case MediaControlsBackgroundPart:
+ return paintMediaControlsBackground(o, paintInfo, r);
+ case MenulistButtonPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ case ListboxPart:
+ return true;
+ case SearchFieldPart:
+ return paintSearchField(o, paintInfo, r);
+ case SearchFieldCancelButtonPart:
+ return paintSearchFieldCancelButton(o, paintInfo, r);
+ case SearchFieldDecorationPart:
+ return paintSearchFieldDecoration(o, paintInfo, r);
+ case SearchFieldResultsDecorationPart:
+ return paintSearchFieldResultsDecoration(o, paintInfo, r);
+ case SearchFieldResultsButtonPart:
+ return paintSearchFieldResultsButton(o, paintInfo, r);
+ case SnapshottedPluginOverlayPart:
+ return paintSnapshottedPluginOverlay(o, paintInfo, r);
#if ENABLE(INPUT_SPEECH)
- case InputSpeechButtonPart:
- return paintInputFieldSpeechButton(o, paintInfo, r);
+ case InputSpeechButtonPart:
+ return paintInputFieldSpeechButton(o, paintInfo, r);
#endif
- default:
- break;
+ default:
+ break;
}
return true; // We don't support the appearance, so let the normal background/border paint.
@@ -399,44 +400,44 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, c
// Call the appropriate paint method based off the appearance value.
switch (o->style()->appearance()) {
- case TextFieldPart:
- return paintTextField(o, paintInfo, r);
- case ListboxPart:
- case TextAreaPart:
- return paintTextArea(o, paintInfo, r);
- case MenulistButtonPart:
- case SearchFieldPart:
- return true;
- case CheckboxPart:
- case RadioPart:
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- case MenulistPart:
+ case TextFieldPart:
+ return paintTextField(o, paintInfo, r);
+ case ListboxPart:
+ case TextAreaPart:
+ return paintTextArea(o, paintInfo, r);
+ case MenulistButtonPart:
+ case SearchFieldPart:
+ return true;
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case MenulistPart:
#if ENABLE(METER_ELEMENT)
- case MeterPart:
- case RelevancyLevelIndicatorPart:
- case ContinuousCapacityLevelIndicatorPart:
- case DiscreteCapacityLevelIndicatorPart:
- case RatingLevelIndicatorPart:
+ case MeterPart:
+ case RelevancyLevelIndicatorPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ case DiscreteCapacityLevelIndicatorPart:
+ case RatingLevelIndicatorPart:
#endif
#if ENABLE(PROGRESS_ELEMENT)
- case ProgressBarPart:
+ case ProgressBarPart:
#endif
- case SliderHorizontalPart:
- case SliderVerticalPart:
- case SliderThumbHorizontalPart:
- case SliderThumbVerticalPart:
- case SearchFieldCancelButtonPart:
- case SearchFieldDecorationPart:
- case SearchFieldResultsDecorationPart:
- case SearchFieldResultsButtonPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ case SearchFieldCancelButtonPart:
+ case SearchFieldDecorationPart:
+ case SearchFieldResultsDecorationPart:
+ case SearchFieldResultsButtonPart:
#if ENABLE(INPUT_SPEECH)
- case InputSpeechButtonPart:
+ case InputSpeechButtonPart:
#endif
- default:
- break;
+ default:
+ break;
}
return false;
@@ -449,42 +450,42 @@ bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo,
// Call the appropriate paint method based off the appearance value.
switch (o->style()->appearance()) {
- case MenulistButtonPart:
- return paintMenuListButton(o, paintInfo, r);
- case TextFieldPart:
- case TextAreaPart:
- case ListboxPart:
- case CheckboxPart:
- case RadioPart:
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- case MenulistPart:
+ case MenulistButtonPart:
+ return paintMenuListButton(o, paintInfo, r);
+ case TextFieldPart:
+ case TextAreaPart:
+ case ListboxPart:
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case MenulistPart:
#if ENABLE(METER_ELEMENT)
- case MeterPart:
- case RelevancyLevelIndicatorPart:
- case ContinuousCapacityLevelIndicatorPart:
- case DiscreteCapacityLevelIndicatorPart:
- case RatingLevelIndicatorPart:
+ case MeterPart:
+ case RelevancyLevelIndicatorPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ case DiscreteCapacityLevelIndicatorPart:
+ case RatingLevelIndicatorPart:
#endif
#if ENABLE(PROGRESS_ELEMENT)
- case ProgressBarPart:
+ case ProgressBarPart:
#endif
- case SliderHorizontalPart:
- case SliderVerticalPart:
- case SliderThumbHorizontalPart:
- case SliderThumbVerticalPart:
- case SearchFieldPart:
- case SearchFieldCancelButtonPart:
- case SearchFieldDecorationPart:
- case SearchFieldResultsDecorationPart:
- case SearchFieldResultsButtonPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ case SearchFieldPart:
+ case SearchFieldCancelButtonPart:
+ case SearchFieldDecorationPart:
+ case SearchFieldResultsDecorationPart:
+ case SearchFieldResultsButtonPart:
#if ENABLE(INPUT_SPEECH)
- case InputSpeechButtonPart:
+ case InputSpeechButtonPart:
#endif
- default:
- break;
+ default:
+ break;
}
return false;
@@ -494,7 +495,7 @@ bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo,
String RenderTheme::formatMediaControlsTime(float time) const
{
- if (!isfinite(time))
+ if (!std::isfinite(time))
time = 0;
int seconds = (int)fabsf(time);
int hours = seconds / (60 * 60);
@@ -523,7 +524,7 @@ String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float du
IntPoint RenderTheme::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const
{
int y = -size.height();
- FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), IsFixed | UseTransforms | SnapOffsetForTransforms);
+ FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), IsFixed | UseTransforms);
if (absPoint.y() < 0)
y = muteButtonBox->height();
return IntPoint(0, y);
@@ -632,13 +633,6 @@ Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const
return platformInactiveSelectionForegroundColor();
}
-#if ENABLE(CALENDAR_PICKER)
-CString RenderTheme::extraCalendarPickerStyleSheet()
-{
- return CString();
-}
-#endif
-
int RenderTheme::baselinePosition(const RenderObject* o) const
{
if (!o->isBox())
@@ -660,32 +654,31 @@ bool RenderTheme::isControlContainer(ControlPart appearance) const
return appearance != CheckboxPart && appearance != RadioPart;
}
-bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background,
- const Color& backgroundColor) const
+bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const
{
switch (style->appearance()) {
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- case ListboxPart:
- case MenulistPart:
- case ProgressBarPart:
- case MeterPart:
- case RelevancyLevelIndicatorPart:
- case ContinuousCapacityLevelIndicatorPart:
- case DiscreteCapacityLevelIndicatorPart:
- case RatingLevelIndicatorPart:
- // FIXME: Uncomment this when making search fields style-able.
- // case SearchFieldPart:
- case TextFieldPart:
- case TextAreaPart:
- // Test the style to see if the UA border and background match.
- return (style->border() != border ||
- *style->backgroundLayers() != background ||
- style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
- default:
- return false;
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case ListboxPart:
+ case MenulistPart:
+ case ProgressBarPart:
+ case MeterPart:
+ case RelevancyLevelIndicatorPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ case DiscreteCapacityLevelIndicatorPart:
+ case RatingLevelIndicatorPart:
+ // FIXME: Uncomment this when making search fields style-able.
+ // case SearchFieldPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ // Test the style to see if the UA border and background match.
+ return (style->border() != border
+ || *style->backgroundLayers() != background
+ || style->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor);
+ default:
+ return false;
}
}
@@ -787,7 +780,7 @@ bool RenderTheme::isIndeterminate(const RenderObject* o) const
if (!inputElement)
return false;
- return inputElement->isIndeterminate();
+ return inputElement->shouldAppearIndeterminate();
}
bool RenderTheme::isEnabled(const RenderObject* o) const
@@ -795,36 +788,37 @@ bool RenderTheme::isEnabled(const RenderObject* o) const
Node* node = o->node();
if (!node || !node->isElementNode())
return true;
- return static_cast<Element*>(node)->isEnabledFormControl();
+ return !toElement(node)->isDisabledFormControl();
}
bool RenderTheme::isFocused(const RenderObject* o) const
{
Node* node = o->node();
- if (!node)
+ if (!node || !node->isElementNode())
return false;
- node = node->focusDelegate();
- Document* document = node->document();
+ Element* focusDelegate = toElement(node)->focusDelegate();
+ Document* document = focusDelegate->document();
Frame* frame = document->frame();
- return node == document->focusedNode() && frame && frame->selection()->isFocusedAndActive();
+ return focusDelegate == document->focusedElement() && frame && frame->selection()->isFocusedAndActive();
}
bool RenderTheme::isPressed(const RenderObject* o) const
{
- if (!o->node())
+ if (!o->node() || !o->node()->isElementNode())
return false;
- return o->node()->active();
+ return toElement(o->node())->active();
}
bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const
{
Node* node = o->node();
- if (!node || !node->active() || !node->isElementNode()
- || !static_cast<Element*>(node)->isSpinButtonElement())
+ if (!node || !node->isElementNode())
return false;
- SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
- return element->upDownState() == SpinButtonElement::Up;
+ Element* element = toElement(node);
+ if (!element->active() || !element->isSpinButtonElement())
+ return false;
+ return static_cast<SpinButtonElement*>(element)->upDownState() == SpinButtonElement::Up;
}
bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
@@ -832,16 +826,16 @@ bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
Node* node = o->node();
if (!node || !node->isElementNode())
return false;
- return static_cast<Element*>(node)->shouldMatchReadOnlySelector();
+ return toElement(node)->matchesReadOnlyPseudoClass();
}
bool RenderTheme::isHovered(const RenderObject* o) const
{
Node* node = o->node();
- if (!node)
+ if (!node || !node->isElementNode())
return false;
- if (!node->isElementNode() || !static_cast<Element*>(node)->isSpinButtonElement())
- return node->hovered();
+ if (!toElement(node)->isSpinButtonElement())
+ return toElement(node)->hovered();
SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate;
}
@@ -849,7 +843,7 @@ bool RenderTheme::isHovered(const RenderObject* o) const
bool RenderTheme::isSpinUpButtonPartHovered(const RenderObject* o) const
{
Node* node = o->node();
- if (!node || !node->isElementNode() || !static_cast<Element*>(node)->isSpinButtonElement())
+ if (!node || !node->isElementNode() || !toElement(node)->isSpinButtonElement())
return false;
SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
return element->upDownState() == SpinButtonElement::Up;
@@ -865,7 +859,7 @@ bool RenderTheme::isDefault(const RenderObject* o) const
return false;
Settings* settings = o->document()->settings();
- if (!settings || !settings->inApplicationChromeMode())
+ if (!settings || !settings->applicationChromeMode())
return false;
return o->style()->appearance() == DefaultButtonPart;
@@ -909,8 +903,9 @@ void RenderTheme::adjustRadioStyle(StyleResolver*, RenderStyle* style, Element*)
void RenderTheme::adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
{
- // Most platforms will completely honor all CSS, and so we have no need to adjust the style
- // at all by default. We will still allow the theme a crack at setting up a desired vertical size.
+ // Most platforms will completely honor all CSS, and so we have no need to
+ // adjust the style at all by default. We will still allow the theme a crack
+ // at setting up a desired vertical size.
setButtonSize(style);
}
@@ -1037,8 +1032,8 @@ void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo,
GraphicsContextStateSaver stateSaver(*paintInfo.context);
paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
for (unsigned i = 0; Node* node = options->item(i); i++) {
- ASSERT(node->hasTagName(optionTag));
- HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(node);
+ ASSERT(isHTMLOptionElement(node));
+ HTMLOptionElement* optionElement = toHTMLOptionElement(node);
String value = optionElement->value();
if (!input->isValidValue(value))
continue;
@@ -1129,70 +1124,72 @@ void RenderTheme::platformColorsDidChange()
m_activeListBoxSelectionBackgroundColor = Color();
m_inactiveListBoxSelectionForegroundColor = Color();
- Page::scheduleForcedStyleRecalcForAllPages();
+ Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
}
-Color RenderTheme::systemColor(int cssValueId) const
+Color RenderTheme::systemColor(CSSValueID cssValueId) const
{
switch (cssValueId) {
- case CSSValueActiveborder:
- return 0xFFFFFFFF;
- case CSSValueActivecaption:
- return 0xFFCCCCCC;
- case CSSValueAppworkspace:
- return 0xFFFFFFFF;
- case CSSValueBackground:
- return 0xFF6363CE;
- case CSSValueButtonface:
- return 0xFFC0C0C0;
- case CSSValueButtonhighlight:
- return 0xFFDDDDDD;
- case CSSValueButtonshadow:
- return 0xFF888888;
- case CSSValueButtontext:
- return 0xFF000000;
- case CSSValueCaptiontext:
- return 0xFF000000;
- case CSSValueGraytext:
- return 0xFF808080;
- case CSSValueHighlight:
- return 0xFFB5D5FF;
- case CSSValueHighlighttext:
- return 0xFF000000;
- case CSSValueInactiveborder:
- return 0xFFFFFFFF;
- case CSSValueInactivecaption:
- return 0xFFFFFFFF;
- case CSSValueInactivecaptiontext:
- return 0xFF7F7F7F;
- case CSSValueInfobackground:
- return 0xFFFBFCC5;
- case CSSValueInfotext:
- return 0xFF000000;
- case CSSValueMenu:
- return 0xFFC0C0C0;
- case CSSValueMenutext:
- return 0xFF000000;
- case CSSValueScrollbar:
- return 0xFFFFFFFF;
- case CSSValueText:
- return 0xFF000000;
- case CSSValueThreeddarkshadow:
- return 0xFF666666;
- case CSSValueThreedface:
- return 0xFFC0C0C0;
- case CSSValueThreedhighlight:
- return 0xFFDDDDDD;
- case CSSValueThreedlightshadow:
- return 0xFFC0C0C0;
- case CSSValueThreedshadow:
- return 0xFF888888;
- case CSSValueWindow:
- return 0xFFFFFFFF;
- case CSSValueWindowframe:
- return 0xFFCCCCCC;
- case CSSValueWindowtext:
- return 0xFF000000;
+ case CSSValueActiveborder:
+ return 0xFFFFFFFF;
+ case CSSValueActivecaption:
+ return 0xFFCCCCCC;
+ case CSSValueAppworkspace:
+ return 0xFFFFFFFF;
+ case CSSValueBackground:
+ return 0xFF6363CE;
+ case CSSValueButtonface:
+ return 0xFFC0C0C0;
+ case CSSValueButtonhighlight:
+ return 0xFFDDDDDD;
+ case CSSValueButtonshadow:
+ return 0xFF888888;
+ case CSSValueButtontext:
+ return 0xFF000000;
+ case CSSValueCaptiontext:
+ return 0xFF000000;
+ case CSSValueGraytext:
+ return 0xFF808080;
+ case CSSValueHighlight:
+ return 0xFFB5D5FF;
+ case CSSValueHighlighttext:
+ return 0xFF000000;
+ case CSSValueInactiveborder:
+ return 0xFFFFFFFF;
+ case CSSValueInactivecaption:
+ return 0xFFFFFFFF;
+ case CSSValueInactivecaptiontext:
+ return 0xFF7F7F7F;
+ case CSSValueInfobackground:
+ return 0xFFFBFCC5;
+ case CSSValueInfotext:
+ return 0xFF000000;
+ case CSSValueMenu:
+ return 0xFFC0C0C0;
+ case CSSValueMenutext:
+ return 0xFF000000;
+ case CSSValueScrollbar:
+ return 0xFFFFFFFF;
+ case CSSValueText:
+ return 0xFF000000;
+ case CSSValueThreeddarkshadow:
+ return 0xFF666666;
+ case CSSValueThreedface:
+ return 0xFFC0C0C0;
+ case CSSValueThreedhighlight:
+ return 0xFFDDDDDD;
+ case CSSValueThreedlightshadow:
+ return 0xFFC0C0C0;
+ case CSSValueThreedshadow:
+ return 0xFF888888;
+ case CSSValueWindow:
+ return 0xFFFFFFFF;
+ case CSSValueWindowframe:
+ return 0xFFCCCCCC;
+ case CSSValueWindowtext:
+ return 0xFF000000;
+ default:
+ break;
}
return Color();
}
diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h
index bbb86e192..d3b92b2b1 100644
--- a/Source/WebCore/rendering/RenderTheme.h
+++ b/Source/WebCore/rendering/RenderTheme.h
@@ -86,17 +86,15 @@ public:
// RenderThemeMac.cpp for Mac OS X.
// These methods return the theme's extra style sheets rules, to let each platform
- // adjust the default CSS rules in html.css, quirks.css, or mediaControls.css
+ // adjust the default CSS rules in html.css, quirks.css, mediaControls.css, or plugIns.css
virtual String extraDefaultStyleSheet() { return String(); }
virtual String extraQuirksStyleSheet() { return String(); }
+ virtual String extraPlugInsStyleSheet() { return String(); }
#if ENABLE(VIDEO)
- virtual String extraMediaControlsStyleSheet() { return String(); };
+ virtual String extraMediaControlsStyleSheet() { return String(); }
#endif
#if ENABLE(FULLSCREEN_API)
- virtual String extraFullScreenStyleSheet() { return String(); };
-#endif
-#if ENABLE(CALENDAR_PICKER)
- virtual CString extraCalendarPickerStyleSheet();
+ virtual String extraFullScreenStyleSheet() { return String(); }
#endif
// A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline
@@ -138,11 +136,6 @@ public:
// A method asking if the platform is able to show datalist suggestions for a given input type.
virtual bool supportsDataListUI(const AtomicString&) const { return false; }
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
- // A method asking if the platform is able to show a calendar picker for a given input type.
- virtual bool supportsCalendarPicker(const AtomicString&) const { return false; }
-#endif
-
// Text selection colors.
Color activeSelectionBackgroundColor() const;
Color inactiveSelectionBackgroundColor() const;
@@ -173,8 +166,8 @@ public:
virtual double caretBlinkInterval() const { return 0.5; }
// System fonts and colors for CSS.
- virtual void systemFont(int cssValueId, FontDescription&) const = 0;
- virtual Color systemColor(int cssValueId) const;
+ virtual void systemFont(CSSValueID, FontDescription&) const = 0;
+ virtual Color systemColor(CSSValueID) const;
virtual int minimumMenuListSize(RenderStyle*) const { return 0; }
@@ -207,7 +200,6 @@ public:
virtual bool usesVerticalVolumeSlider() const { return true; }
virtual double mediaControlsFadeInDuration() { return 0.1; }
virtual double mediaControlsFadeOutDuration() { return 0.3; }
- virtual double timeWithoutMouseMovementBeforeHidingControls() { return 3.0; }
virtual String formatMediaControlsTime(float time) const;
virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const;
virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const;
@@ -347,6 +339,8 @@ protected:
virtual bool paintMediaFullScreenVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaFullScreenVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintSnapshottedPluginOverlay(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
+
public:
// Methods for state querying
ControlStates controlStatesForRenderer(const RenderObject* o) const;
diff --git a/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp b/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp
deleted file mode 100644
index d25a80444..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RenderThemeChromiumAndroid.h"
-
-#include "CSSValueKeywords.h"
-#include "Color.h"
-#include "LayoutTestSupport.h"
-#include "PaintInfo.h"
-#include "RenderMediaControlsChromium.h"
-#include "RenderObject.h"
-#include "RenderProgress.h"
-#include "RenderSlider.h"
-#include "ScrollbarTheme.h"
-#include "UserAgentStyleSheets.h"
-
-#include <public/Platform.h>
-#include <public/android/WebThemeEngine.h>
-
-namespace WebCore {
-
-PassRefPtr<RenderTheme> RenderThemeChromiumAndroid::create()
-{
- return adoptRef(new RenderThemeChromiumAndroid());
-}
-
-PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
-{
- static RenderTheme* renderTheme = RenderThemeChromiumAndroid::create().leakRef();
- return renderTheme;
-}
-
-RenderThemeChromiumAndroid::~RenderThemeChromiumAndroid()
-{
-}
-
-Color RenderThemeChromiumAndroid::systemColor(int cssValueId) const
-{
- if (isRunningLayoutTest() && cssValueId == CSSValueButtonface) {
- // Match Chromium Linux' button color in layout tests.
- static const Color linuxButtonGrayColor(0xffdddddd);
- return linuxButtonGrayColor;
- }
- return RenderTheme::systemColor(cssValueId);
-}
-
-String RenderThemeChromiumAndroid::extraMediaControlsStyleSheet()
-{
- return String(mediaControlsChromiumAndroidUserAgentStyleSheet, sizeof(mediaControlsChromiumAndroidUserAgentStyleSheet));
-}
-
-String RenderThemeChromiumAndroid::extraDefaultStyleSheet()
-{
- return RenderThemeChromiumLinux::extraDefaultStyleSheet() +
- String(themeChromiumAndroidUserAgentStyleSheet, sizeof(themeChromiumAndroidUserAgentStyleSheet));
-}
-
-void RenderThemeChromiumAndroid::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- if (isRunningLayoutTest()) {
- // Match Chromium Linux spin button style in layout tests.
- // FIXME: Consider removing the conditional if a future Android theme matches this.
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartInnerSpinButton);
-
- style->setWidth(Length(size.width(), Fixed));
- style->setMinWidth(Length(size.width(), Fixed));
- }
-}
-
-bool RenderThemeChromiumAndroid::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-int RenderThemeChromiumAndroid::menuListArrowPadding() const
-{
- // We cannot use the scrollbar thickness here, as it's width is 0 on Android.
- // Instead, use the width of the scrollbar down arrow.
- IntSize scrollbarSize = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartScrollbarDownArrow);
- return scrollbarSize.width();
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumAndroid.h b/Source/WebCore/rendering/RenderThemeChromiumAndroid.h
deleted file mode 100644
index 027628e81..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumAndroid.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RenderThemeChromiumAndroid_h
-#define RenderThemeChromiumAndroid_h
-
-#include "RenderThemeChromiumLinux.h"
-
-namespace WebCore {
-
-class RenderThemeChromiumAndroid : public RenderThemeChromiumLinux {
-public:
- static PassRefPtr<RenderTheme> create();
- virtual String extraDefaultStyleSheet() OVERRIDE;
-
- virtual Color systemColor(int cssValidId) const OVERRIDE;
-
- virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const OVERRIDE;
-
- virtual bool delegatesMenuListRendering() const OVERRIDE { return true; }
-
- virtual bool paintMediaOverlayPlayButton(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE;
-
-#if ENABLE(VIDEO)
- virtual String extraMediaControlsStyleSheet() OVERRIDE;
-#endif
-
-#if ENABLE(TOUCH_EVENTS)
- virtual Color platformTapHighlightColor() const OVERRIDE
- {
- return RenderThemeChromiumAndroid::defaultTapHighlightColor;
- }
-#endif
-
- virtual Color platformActiveSelectionBackgroundColor() const OVERRIDE
- {
- return RenderThemeChromiumAndroid::defaultActiveSelectionBackgroundColor;
- }
-
-protected:
- virtual int menuListArrowPadding() const OVERRIDE;
-
-private:
- virtual ~RenderThemeChromiumAndroid();
-
- static const RGBA32 defaultTapHighlightColor = 0x6633b5e5;
- static const RGBA32 defaultActiveSelectionBackgroundColor = 0x6633b5e5;
-};
-
-} // namespace WebCore
-
-#endif // RenderThemeChromiumAndroid_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp b/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp
deleted file mode 100644
index 51f87c5e3..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RenderThemeChromiumCommon.h"
-
-#include "InputTypeNames.h"
-#include "LayoutUnit.h"
-
-namespace WebCore {
-
-bool RenderThemeChromiumCommon::supportsDataListUI(const AtomicString& type)
-{
- return type == InputTypeNames::text() || type == InputTypeNames::search() || type == InputTypeNames::url()
- || type == InputTypeNames::telephone() || type == InputTypeNames::email() || type == InputTypeNames::number()
-#if ENABLE(INPUT_TYPE_COLOR)
- || type == InputTypeNames::color()
-#endif
-#if ENABLE(CALENDAR_PICKER)
- || type == InputTypeNames::date()
-#endif
- || type == InputTypeNames::datetime()
- || type == InputTypeNames::datetimelocal()
- || type == InputTypeNames::month()
- || type == InputTypeNames::week()
- || type == InputTypeNames::time()
- || type == InputTypeNames::range();
-}
-
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
-bool RenderThemeChromiumCommon::supportsCalendarPicker(const AtomicString& type)
-{
- return type == InputTypeNames::date()
- || type == InputTypeNames::datetime()
- || type == InputTypeNames::datetimelocal()
- || type == InputTypeNames::month()
- || type == InputTypeNames::week();
-}
-#endif
-
-LayoutUnit RenderThemeChromiumCommon::sliderTickSnappingThreshold()
-{
- return 5;
-}
-
-}
diff --git a/Source/WebCore/rendering/RenderThemeChromiumCommon.h b/Source/WebCore/rendering/RenderThemeChromiumCommon.h
deleted file mode 100644
index 5f6d71a6e..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumCommon.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-#ifndef RenderThemeChromiumCommon_h
-#define RenderThemeChromiumCommon_h
-
-#include "LayoutUnit.h"
-#include <wtf/text/AtomicString.h>
-
-namespace WebCore {
-
-class RenderThemeChromiumCommon {
-public:
- static bool supportsDataListUI(const AtomicString& type);
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
- static bool supportsCalendarPicker(const AtomicString& type);
-#endif
- static LayoutUnit sliderTickSnappingThreshold();
-};
-
-}
-
-#endif // RenderThemeChromiumCommon_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumDefault.cpp b/Source/WebCore/rendering/RenderThemeChromiumDefault.cpp
deleted file mode 100644
index d643729ad..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumDefault.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc.
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008 Collabora Ltd.
- * Copyright (C) 2008, 2009 Google Inc.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderThemeChromiumDefault.h"
-
-#include "CSSValueKeywords.h"
-#include "Color.h"
-#include "PaintInfo.h"
-#include "PlatformContextSkia.h"
-#include "RenderObject.h"
-#include "RenderProgress.h"
-#include "RenderSlider.h"
-#include "ScrollbarTheme.h"
-#include "UserAgentStyleSheets.h"
-#include <public/Platform.h>
-#include <public/WebRect.h>
-#include <public/default/WebThemeEngine.h>
-
-namespace WebCore {
-
-unsigned RenderThemeChromiumDefault::m_activeSelectionBackgroundColor =
- 0xff1e90ff;
-unsigned RenderThemeChromiumDefault::m_activeSelectionForegroundColor =
- Color::black;
-unsigned RenderThemeChromiumDefault::m_inactiveSelectionBackgroundColor =
- 0xffc8c8c8;
-unsigned RenderThemeChromiumDefault::m_inactiveSelectionForegroundColor =
- 0xff323232;
-
-double RenderThemeChromiumDefault::m_caretBlinkInterval;
-
-static const unsigned defaultButtonBackgroundColor = 0xffdddddd;
-
-static WebKit::WebThemeEngine::State getWebThemeState(const RenderTheme* theme, const RenderObject* o)
-{
- if (!theme->isEnabled(o))
- return WebKit::WebThemeEngine::StateDisabled;
- if (theme->isPressed(o))
- return WebKit::WebThemeEngine::StatePressed;
- if (theme->isHovered(o))
- return WebKit::WebThemeEngine::StateHover;
-
- return WebKit::WebThemeEngine::StateNormal;
-}
-
-PassRefPtr<RenderTheme> RenderThemeChromiumDefault::create()
-{
- return adoptRef(new RenderThemeChromiumDefault());
-}
-
-// RenderTheme::themeForPage for Android is defined in RenderThemeChromiumAndroid.cpp.
-#if !OS(ANDROID)
-PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
-{
- static RenderTheme* rt = RenderThemeChromiumDefault::create().leakRef();
- return rt;
-}
-#endif
-
-RenderThemeChromiumDefault::RenderThemeChromiumDefault()
-{
- m_caretBlinkInterval = RenderTheme::caretBlinkInterval();
-}
-
-RenderThemeChromiumDefault::~RenderThemeChromiumDefault()
-{
-}
-
-Color RenderThemeChromiumDefault::systemColor(int cssValueId) const
-{
- static const Color defaultButtonGrayColor(0xffdddddd);
-
- if (cssValueId == CSSValueButtonface)
- return defaultButtonGrayColor;
- return RenderTheme::systemColor(cssValueId);
-}
-
-String RenderThemeChromiumDefault::extraDefaultStyleSheet()
-{
-#if !OS(WINDOWS)
- return RenderThemeChromiumSkia::extraDefaultStyleSheet() +
- String(themeChromiumLinuxUserAgentStyleSheet, sizeof(themeChromiumLinuxUserAgentStyleSheet));
-#else
- return RenderThemeChromiumSkia::extraDefaultStyleSheet();
-#endif
-}
-
-bool RenderThemeChromiumDefault::controlSupportsTints(const RenderObject* o) const
-{
- return isEnabled(o);
-}
-
-Color RenderThemeChromiumDefault::activeListBoxSelectionBackgroundColor() const
-{
- return Color(0x28, 0x28, 0x28);
-}
-
-Color RenderThemeChromiumDefault::activeListBoxSelectionForegroundColor() const
-{
- return Color::black;
-}
-
-Color RenderThemeChromiumDefault::inactiveListBoxSelectionBackgroundColor() const
-{
- return Color(0xc8, 0xc8, 0xc8);
-}
-
-Color RenderThemeChromiumDefault::inactiveListBoxSelectionForegroundColor() const
-{
- return Color(0x32, 0x32, 0x32);
-}
-
-Color RenderThemeChromiumDefault::platformActiveSelectionBackgroundColor() const
-{
- return m_activeSelectionBackgroundColor;
-}
-
-Color RenderThemeChromiumDefault::platformInactiveSelectionBackgroundColor() const
-{
- return m_inactiveSelectionBackgroundColor;
-}
-
-Color RenderThemeChromiumDefault::platformActiveSelectionForegroundColor() const
-{
- return m_activeSelectionForegroundColor;
-}
-
-Color RenderThemeChromiumDefault::platformInactiveSelectionForegroundColor() const
-{
- return m_inactiveSelectionForegroundColor;
-}
-
-#if ENABLE(DATALIST_ELEMENT)
-IntSize RenderThemeChromiumDefault::sliderTickSize() const
-{
- return IntSize(1, 6);
-}
-
-int RenderThemeChromiumDefault::sliderTickOffsetFromTrackCenter() const
-{
- return -16;
-}
-#endif
-
-void RenderThemeChromiumDefault::adjustSliderThumbSize(RenderStyle* style, Element* element) const
-{
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartSliderThumb);
-
- if (style->appearance() == SliderThumbHorizontalPart) {
- style->setWidth(Length(size.width(), Fixed));
- style->setHeight(Length(size.height(), Fixed));
- } else if (style->appearance() == SliderThumbVerticalPart) {
- style->setWidth(Length(size.height(), Fixed));
- style->setHeight(Length(size.width(), Fixed));
- } else
- RenderThemeChromiumSkia::adjustSliderThumbSize(style, element);
-}
-
-bool RenderThemeChromiumDefault::supportsControlTints() const
-{
- return true;
-}
-
-void RenderThemeChromiumDefault::setCaretBlinkInterval(double interval)
-{
- m_caretBlinkInterval = interval;
-}
-
-double RenderThemeChromiumDefault::caretBlinkIntervalInternal() const
-{
- return m_caretBlinkInterval;
-}
-
-void RenderThemeChromiumDefault::setSelectionColors(
- unsigned activeBackgroundColor,
- unsigned activeForegroundColor,
- unsigned inactiveBackgroundColor,
- unsigned inactiveForegroundColor)
-{
- m_activeSelectionBackgroundColor = activeBackgroundColor;
- m_activeSelectionForegroundColor = activeForegroundColor;
- m_inactiveSelectionBackgroundColor = inactiveBackgroundColor;
- m_inactiveSelectionForegroundColor = inactiveForegroundColor;
-}
-
-bool RenderThemeChromiumDefault::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.button.checked = isChecked(o);
- extraParams.button.indeterminate = isIndeterminate(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartCheckbox, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-void RenderThemeChromiumDefault::setCheckboxSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartCheckbox);
- setSizeIfAuto(style, size);
-}
-
-bool RenderThemeChromiumDefault::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.button.checked = isChecked(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartRadio, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-void RenderThemeChromiumDefault::setRadioSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartRadio);
- setSizeIfAuto(style, size);
-}
-
-bool RenderThemeChromiumDefault::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.button.isDefault = isDefault(o);
- extraParams.button.hasBorder = true;
- extraParams.button.backgroundColor = defaultButtonBackgroundColor;
- if (o->hasBackground())
- extraParams.button.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb();
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartButton, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-bool RenderThemeChromiumDefault::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- // WebThemeEngine does not handle border rounded corner and background image
- // so return true to draw CSS border and background.
- if (o->style()->hasBorderRadius() || o->style()->hasBackgroundImage())
- return true;
-
- ControlPart part = o->style()->appearance();
-
- WebKit::WebThemeEngine::ExtraParams extraParams;
- extraParams.textField.isTextArea = part == TextAreaPart;
- extraParams.textField.isListbox = part == ListboxPart;
-
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
-
- // Fallback to white if the specified color object is invalid.
- Color backgroundColor(Color::white);
- if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
- backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
- extraParams.textField.backgroundColor = backgroundColor.rgb();
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartTextField, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-bool RenderThemeChromiumDefault::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- if (!o->isBox())
- return false;
-
- const int right = rect.x() + rect.width();
- const int middle = rect.y() + rect.height() / 2;
-
- WebKit::WebThemeEngine::ExtraParams extraParams;
- extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13;
- extraParams.menuList.arrowY = middle;
- const RenderBox* box = toRenderBox(o);
- // Match Chromium Win behaviour of showing all borders if any are shown.
- extraParams.menuList.hasBorder = box->borderRight() || box->borderLeft() || box->borderTop() || box->borderBottom();
- extraParams.menuList.hasBorderRadius = o->style()->hasBorderRadius();
- // Fallback to transparent if the specified color object is invalid.
- extraParams.menuList.backgroundColor = Color::transparent;
- if (o->hasBackground())
- extraParams.menuList.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb();
-
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartMenuList, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-bool RenderThemeChromiumDefault::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.slider.vertical = o->style()->appearance() == SliderVerticalPart;
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartSliderTrack, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
-
-#if ENABLE(DATALIST_ELEMENT)
- paintSliderTicks(o, i, rect);
-#endif
-
- return false;
-}
-
-bool RenderThemeChromiumDefault::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.slider.vertical = o->style()->appearance() == SliderThumbVerticalPart;
- extraParams.slider.inDrag = isPressed(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartSliderThumb, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-void RenderThemeChromiumDefault::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartInnerSpinButton);
-
- style->setWidth(Length(size.width(), Fixed));
- style->setMinWidth(Length(size.width(), Fixed));
-}
-
-bool RenderThemeChromiumDefault::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.innerSpin.spinUp = (controlStatesForRenderer(o) & SpinUpState);
- extraParams.innerSpin.readOnly = isReadOnlyControl(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartInnerSpinButton, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-#if ENABLE(PROGRESS_ELEMENT)
-
-bool RenderThemeChromiumDefault::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- if (!o->isProgress())
- return true;
-
- RenderProgress* renderProgress = toRenderProgress(o);
- IntRect valueRect = progressValueRectFor(renderProgress, rect);
-
- WebKit::WebThemeEngine::ExtraParams extraParams;
- extraParams.progressBar.determinate = renderProgress->isDeterminate();
- extraParams.progressBar.valueRectX = valueRect.x();
- extraParams.progressBar.valueRectY = valueRect.y();
- extraParams.progressBar.valueRectWidth = valueRect.width();
- extraParams.progressBar.valueRectHeight = valueRect.height();
-
- DirectionFlippingScope scope(o, i, rect);
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartProgressBar, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-#endif
-
-bool RenderThemeChromiumDefault::shouldOpenPickerWithF4Key() const
-{
- return true;
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumDefault.h b/Source/WebCore/rendering/RenderThemeChromiumDefault.h
deleted file mode 100644
index 129b482cb..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumDefault.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * This file is part of the WebKit project.
- *
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008, 2009 Google, Inc.
- * All rights reserved.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderThemeChromiumDefault_h
-#define RenderThemeChromiumDefault_h
-
-#include "RenderThemeChromiumSkia.h"
-
-namespace WebCore {
-
-class RenderThemeChromiumDefault : public RenderThemeChromiumSkia {
-public:
- static PassRefPtr<RenderTheme> create();
- virtual String extraDefaultStyleSheet();
-
- virtual Color systemColor(int cssValidId) const;
-
- // A method asking if the control changes its tint when the window has focus or not.
- virtual bool controlSupportsTints(const RenderObject*) const;
-
- // List Box selection color
- virtual Color activeListBoxSelectionBackgroundColor() const;
- virtual Color activeListBoxSelectionForegroundColor() const;
- virtual Color inactiveListBoxSelectionBackgroundColor() const;
- virtual Color inactiveListBoxSelectionForegroundColor() const;
-
- virtual Color platformActiveSelectionBackgroundColor() const;
- virtual Color platformInactiveSelectionBackgroundColor() const;
- virtual Color platformActiveSelectionForegroundColor() const;
- virtual Color platformInactiveSelectionForegroundColor() const;
-
-#if ENABLE(DATALIST_ELEMENT)
- virtual IntSize sliderTickSize() const OVERRIDE;
- virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE;
-#endif
- virtual void adjustSliderThumbSize(RenderStyle*, Element*) const;
-
- static void setCaretBlinkInterval(double);
- virtual double caretBlinkIntervalInternal() const;
-
- virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void setCheckboxSize(RenderStyle*) const;
-
- virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void setRadioSize(RenderStyle*) const;
-
- virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual bool popsMenuBySpaceOrReturn() const OVERRIDE { return true; }
-
-#if ENABLE(PROGRESS_ELEMENT)
- virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
-#endif
-
- virtual bool shouldOpenPickerWithF4Key() const OVERRIDE;
-
- static void setSelectionColors(unsigned activeBackgroundColor, unsigned activeForegroundColor, unsigned inactiveBackgroundColor, unsigned inactiveForegroundColor);
-
-protected:
- RenderThemeChromiumDefault();
- virtual ~RenderThemeChromiumDefault();
-
-private:
- // A general method asking if any control tinting is supported at all.
- virtual bool supportsControlTints() const;
-
- static double m_caretBlinkInterval;
-
- static unsigned m_activeSelectionBackgroundColor;
- static unsigned m_activeSelectionForegroundColor;
- static unsigned m_inactiveSelectionBackgroundColor;
- static unsigned m_inactiveSelectionForegroundColor;
-};
-
-} // namespace WebCore
-
-#endif // RenderThemeChromiumDefault_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp b/Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp
deleted file mode 100644
index 78068e537..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumFontProvider.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RenderThemeChromiumFontProvider.h"
-
-#include <wtf/StdLibExtras.h>
-#include <wtf/text/WTFString.h>
-
-namespace WebCore {
-
-// The default variable-width font size. We use this as the default font
-// size for the "system font", and as a base size (which we then shrink) for
-// form control fonts.
-// static
-float RenderThemeChromiumFontProvider::s_defaultFontSize = 16.0;
-
-// We aim to match IE here.
-// -IE uses a font based on the encoding as the default font for form controls.
-// -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT),
-// which returns MS Shell Dlg)
-// -Safari uses Lucida Grande.
-//
-// FIXME: The only case where we know we don't match IE is for ANSI encodings.
-// IE uses MS Shell Dlg there, which we render incorrectly at certain pixel
-// sizes (e.g. 15px). So, for now we just use Arial.
-const String& RenderThemeChromiumFontProvider::defaultGUIFont()
-{
- DEFINE_STATIC_LOCAL(String, fontFace, (ASCIILiteral("Arial")));
- return fontFace;
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProvider.h b/Source/WebCore/rendering/RenderThemeChromiumFontProvider.h
deleted file mode 100644
index 0f7eeac27..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumFontProvider.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RenderThemeChromiumFontProvider_h
-#define RenderThemeChromiumFontProvider_h
-
-namespace WTF {
-class String;
-}
-
-namespace WebCore {
-
-class FontDescription;
-
-class RenderThemeChromiumFontProvider {
-public:
- static void systemFont(int propId, FontDescription&);
- static void setDefaultFontSize(int);
-
-protected:
- static const WTF::String& defaultGUIFont();
-
- static float s_defaultFontSize;
-};
-
-} // namespace WebCore
-
-#endif // RenderThemeChromiumFontProvider_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp b/Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp
deleted file mode 100644
index 009c72417..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumFontProviderLinux.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RenderThemeChromiumFontProvider.h"
-
-#include "CSSValueKeywords.h"
-#include "FontDescription.h"
-
-#include <wtf/StdLibExtras.h>
-#include <wtf/text/WTFString.h>
-
-namespace WebCore {
-
-// static
-void RenderThemeChromiumFontProvider::setDefaultFontSize(int fontSize)
-{
- s_defaultFontSize = static_cast<float>(fontSize);
-}
-
-// static
-void RenderThemeChromiumFontProvider::systemFont(int propId, FontDescription& fontDescription)
-{
- float fontSize = s_defaultFontSize;
-
- switch (propId) {
- case CSSValueWebkitMiniControl:
- case CSSValueWebkitSmallControl:
- case CSSValueWebkitControl:
- // Why 2 points smaller? Because that's what Gecko does. Note that we
- // are assuming a 96dpi screen, which is the default that we use on
- // Windows.
- static const float pointsPerInch = 72.0f;
- static const float pixelsPerInch = 96.0f;
- fontSize -= (2.0f / pointsPerInch) * pixelsPerInch;
- break;
- }
-
- fontDescription.firstFamily().setFamily(defaultGUIFont());
- fontDescription.setSpecifiedSize(fontSize);
- fontDescription.setIsAbsoluteSize(true);
- fontDescription.setGenericFamily(FontDescription::NoFamily);
- fontDescription.setWeight(FontWeightNormal);
- fontDescription.setItalic(false);
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp
deleted file mode 100644
index faf3c942b..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumFontProviderWin.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RenderThemeChromiumFontProvider.h"
-
-#include "CSSValueKeywords.h"
-#include "FontDescription.h"
-#include "HWndDC.h"
-#include "SystemInfo.h"
-
-#include <windows.h>
-#include <wtf/text/WTFString.h>
-
-#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
- offsetof(structName, member) + \
- (sizeof static_cast<structName*>(0)->member)
-#define NONCLIENTMETRICS_SIZE_PRE_VISTA \
- SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
-
-namespace WebCore {
-
-static FontDescription& smallSystemFont()
-{
- DEFINE_STATIC_LOCAL(FontDescription, font, ());
- return font;
-}
-
-static FontDescription& menuFont()
-{
- DEFINE_STATIC_LOCAL(FontDescription, font, ());
- return font;
-}
-
-static FontDescription& labelFont()
-{
- DEFINE_STATIC_LOCAL(FontDescription, font, ());
- return font;
-}
-
-// Converts |points| to pixels. One point is 1/72 of an inch.
-static float pointsToPixels(float points)
-{
- static float pixelsPerInch = 0.0f;
- if (!pixelsPerInch) {
- HWndDC hdc(0); // What about printing? Is this the right DC?
- if (hdc) // Can this ever actually be 0?
- pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
- else
- pixelsPerInch = 96.0f;
- }
-
- static const float pointsPerInch = 72.0f;
- return points / pointsPerInch * pixelsPerInch;
-}
-
-static void getNonClientMetrics(NONCLIENTMETRICS* metrics)
-{
- static UINT size = (windowsVersion() >= WindowsVista) ?
- sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
- metrics->cbSize = size;
- bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0);
- ASSERT(success);
-}
-
-// Return the height of system font |font| in pixels. We use this size by
-// default for some non-form-control elements.
-static float systemFontSize(const LOGFONT& font)
-{
- float size = -font.lfHeight;
- if (size < 0) {
- HFONT hFont = CreateFontIndirect(&font);
- if (hFont) {
- HWndDC hdc(0); // What about printing? Is this the right DC?
- if (hdc) {
- HGDIOBJ hObject = SelectObject(hdc, hFont);
- TEXTMETRIC tm;
- GetTextMetrics(hdc, &tm);
- SelectObject(hdc, hObject);
- size = tm.tmAscent;
- }
- DeleteObject(hFont);
- }
- }
-
- // The "codepage 936" bit here is from Gecko; apparently this helps make
- // fonts more legible in Simplified Chinese where the default font size is
- // too small.
- //
- // FIXME: http://b/1119883 Since this is only used for "small caption",
- // "menu", and "status bar" objects, I'm not sure how much this even
- // matters. Plus the Gecko patch went in back in 2002, and maybe this
- // isn't even relevant anymore. We should investigate whether this should
- // be removed, or perhaps broadened to be "any CJK locale".
- //
- return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size;
-}
-
-// static
-void RenderThemeChromiumFontProvider::systemFont(int propId, FontDescription& fontDescription)
-{
- // This logic owes much to RenderThemeSafari.cpp.
- FontDescription* cachedDesc = 0;
- AtomicString faceName;
- float fontSize = 0;
- switch (propId) {
- case CSSValueSmallCaption:
- cachedDesc = &smallSystemFont();
- if (!smallSystemFont().isAbsoluteSize()) {
- NONCLIENTMETRICS metrics;
- getNonClientMetrics(&metrics);
- faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName));
- fontSize = systemFontSize(metrics.lfSmCaptionFont);
- }
- break;
- case CSSValueMenu:
- cachedDesc = &menuFont();
- if (!menuFont().isAbsoluteSize()) {
- NONCLIENTMETRICS metrics;
- getNonClientMetrics(&metrics);
- faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName));
- fontSize = systemFontSize(metrics.lfMenuFont);
- }
- break;
- case CSSValueStatusBar:
- cachedDesc = &labelFont();
- if (!labelFont().isAbsoluteSize()) {
- NONCLIENTMETRICS metrics;
- getNonClientMetrics(&metrics);
- faceName = metrics.lfStatusFont.lfFaceName;
- fontSize = systemFontSize(metrics.lfStatusFont);
- }
- break;
- case CSSValueWebkitMiniControl:
- case CSSValueWebkitSmallControl:
- case CSSValueWebkitControl:
- faceName = defaultGUIFont();
- // Why 2 points smaller? Because that's what Gecko does.
- fontSize = s_defaultFontSize - pointsToPixels(2);
- break;
- default:
- faceName = defaultGUIFont();
- fontSize = s_defaultFontSize;
- break;
- }
-
- if (!cachedDesc)
- cachedDesc = &fontDescription;
-
- if (fontSize) {
- cachedDesc->firstFamily().setFamily(faceName);
- cachedDesc->setIsAbsoluteSize(true);
- cachedDesc->setGenericFamily(FontDescription::NoFamily);
- cachedDesc->setSpecifiedSize(fontSize);
- cachedDesc->setWeight(FontWeightNormal);
- cachedDesc->setItalic(false);
- }
- fontDescription = *cachedDesc;
-}
-
-// static
-void RenderThemeChromiumFontProvider::setDefaultFontSize(int fontSize)
-{
- s_defaultFontSize = static_cast<float>(fontSize);
-
- // Reset cached fonts.
- smallSystemFont() = menuFont() = labelFont() = FontDescription();
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp
deleted file mode 100644
index 8af4fc782..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc.
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008 Collabora Ltd.
- * Copyright (C) 2008, 2009 Google Inc.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderThemeChromiumLinux.h"
-
-#include "CSSValueKeywords.h"
-#include "Color.h"
-#include "PaintInfo.h"
-#include "PlatformContextSkia.h"
-#include "RenderObject.h"
-#include "RenderProgress.h"
-#include "RenderSlider.h"
-#include "ScrollbarTheme.h"
-#include "UserAgentStyleSheets.h"
-#include <public/Platform.h>
-#include <public/WebRect.h>
-#include <public/linux/WebThemeEngine.h>
-
-namespace WebCore {
-
-unsigned RenderThemeChromiumLinux::m_activeSelectionBackgroundColor =
- 0xff1e90ff;
-unsigned RenderThemeChromiumLinux::m_activeSelectionForegroundColor =
- Color::black;
-unsigned RenderThemeChromiumLinux::m_inactiveSelectionBackgroundColor =
- 0xffc8c8c8;
-unsigned RenderThemeChromiumLinux::m_inactiveSelectionForegroundColor =
- 0xff323232;
-
-double RenderThemeChromiumLinux::m_caretBlinkInterval;
-
-static const unsigned defaultButtonBackgroundColor = 0xffdddddd;
-
-static WebKit::WebThemeEngine::State getWebThemeState(const RenderTheme* theme, const RenderObject* o)
-{
- if (!theme->isEnabled(o))
- return WebKit::WebThemeEngine::StateDisabled;
- if (theme->isPressed(o))
- return WebKit::WebThemeEngine::StatePressed;
- if (theme->isHovered(o))
- return WebKit::WebThemeEngine::StateHover;
-
- return WebKit::WebThemeEngine::StateNormal;
-}
-
-PassRefPtr<RenderTheme> RenderThemeChromiumLinux::create()
-{
- return adoptRef(new RenderThemeChromiumLinux());
-}
-
-// RenderTheme::themeForPage for Android is defined in RenderThemeChromiumAndroid.cpp.
-#if !OS(ANDROID)
-PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
-{
- static RenderTheme* rt = RenderThemeChromiumLinux::create().leakRef();
- return rt;
-}
-#endif
-
-RenderThemeChromiumLinux::RenderThemeChromiumLinux()
-{
- m_caretBlinkInterval = RenderTheme::caretBlinkInterval();
-}
-
-RenderThemeChromiumLinux::~RenderThemeChromiumLinux()
-{
-}
-
-Color RenderThemeChromiumLinux::systemColor(int cssValueId) const
-{
- static const Color linuxButtonGrayColor(0xffdddddd);
-
- if (cssValueId == CSSValueButtonface)
- return linuxButtonGrayColor;
- return RenderTheme::systemColor(cssValueId);
-}
-
-String RenderThemeChromiumLinux::extraDefaultStyleSheet()
-{
- return RenderThemeChromiumSkia::extraDefaultStyleSheet() +
- String(themeChromiumLinuxUserAgentStyleSheet, sizeof(themeChromiumLinuxUserAgentStyleSheet));
-}
-
-bool RenderThemeChromiumLinux::controlSupportsTints(const RenderObject* o) const
-{
- return isEnabled(o);
-}
-
-Color RenderThemeChromiumLinux::activeListBoxSelectionBackgroundColor() const
-{
- return Color(0x28, 0x28, 0x28);
-}
-
-Color RenderThemeChromiumLinux::activeListBoxSelectionForegroundColor() const
-{
- return Color::black;
-}
-
-Color RenderThemeChromiumLinux::inactiveListBoxSelectionBackgroundColor() const
-{
- return Color(0xc8, 0xc8, 0xc8);
-}
-
-Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const
-{
- return Color(0x32, 0x32, 0x32);
-}
-
-Color RenderThemeChromiumLinux::platformActiveSelectionBackgroundColor() const
-{
- return m_activeSelectionBackgroundColor;
-}
-
-Color RenderThemeChromiumLinux::platformInactiveSelectionBackgroundColor() const
-{
- return m_inactiveSelectionBackgroundColor;
-}
-
-Color RenderThemeChromiumLinux::platformActiveSelectionForegroundColor() const
-{
- return m_activeSelectionForegroundColor;
-}
-
-Color RenderThemeChromiumLinux::platformInactiveSelectionForegroundColor() const
-{
- return m_inactiveSelectionForegroundColor;
-}
-
-#if ENABLE(DATALIST_ELEMENT)
-IntSize RenderThemeChromiumLinux::sliderTickSize() const
-{
- return IntSize(1, 6);
-}
-
-int RenderThemeChromiumLinux::sliderTickOffsetFromTrackCenter() const
-{
- return -16;
-}
-#endif
-
-void RenderThemeChromiumLinux::adjustSliderThumbSize(RenderStyle* style, Element* element) const
-{
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartSliderThumb);
-
- if (style->appearance() == SliderThumbHorizontalPart) {
- style->setWidth(Length(size.width(), Fixed));
- style->setHeight(Length(size.height(), Fixed));
- } else if (style->appearance() == SliderThumbVerticalPart) {
- style->setWidth(Length(size.height(), Fixed));
- style->setHeight(Length(size.width(), Fixed));
- } else
- RenderThemeChromiumSkia::adjustSliderThumbSize(style, element);
-}
-
-bool RenderThemeChromiumLinux::supportsControlTints() const
-{
- return true;
-}
-
-void RenderThemeChromiumLinux::setCaretBlinkInterval(double interval)
-{
- m_caretBlinkInterval = interval;
-}
-
-double RenderThemeChromiumLinux::caretBlinkIntervalInternal() const
-{
- return m_caretBlinkInterval;
-}
-
-void RenderThemeChromiumLinux::setSelectionColors(
- unsigned activeBackgroundColor,
- unsigned activeForegroundColor,
- unsigned inactiveBackgroundColor,
- unsigned inactiveForegroundColor)
-{
- m_activeSelectionBackgroundColor = activeBackgroundColor;
- m_activeSelectionForegroundColor = activeForegroundColor;
- m_inactiveSelectionBackgroundColor = inactiveBackgroundColor;
- m_inactiveSelectionForegroundColor = inactiveForegroundColor;
-}
-
-bool RenderThemeChromiumLinux::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.button.checked = isChecked(o);
- extraParams.button.indeterminate = isIndeterminate(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartCheckbox, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-void RenderThemeChromiumLinux::setCheckboxSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartCheckbox);
- setSizeIfAuto(style, size);
-}
-
-bool RenderThemeChromiumLinux::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.button.checked = isChecked(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartRadio, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-void RenderThemeChromiumLinux::setRadioSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartRadio);
- setSizeIfAuto(style, size);
-}
-
-bool RenderThemeChromiumLinux::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.button.isDefault = isDefault(o);
- extraParams.button.hasBorder = true;
- extraParams.button.backgroundColor = defaultButtonBackgroundColor;
- if (o->hasBackground())
- extraParams.button.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb();
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartButton, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-bool RenderThemeChromiumLinux::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- // WebThemeEngine does not handle border rounded corner and background image
- // so return true to draw CSS border and background.
- if (o->style()->hasBorderRadius() || o->style()->hasBackgroundImage())
- return true;
-
- ControlPart part = o->style()->appearance();
-
- WebKit::WebThemeEngine::ExtraParams extraParams;
- extraParams.textField.isTextArea = part == TextAreaPart;
- extraParams.textField.isListbox = part == ListboxPart;
-
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
-
- // Fallback to white if the specified color object is invalid.
- Color backgroundColor(Color::white);
- if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
- backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
- extraParams.textField.backgroundColor = backgroundColor.rgb();
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartTextField, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-bool RenderThemeChromiumLinux::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- if (!o->isBox())
- return false;
-
- const int right = rect.x() + rect.width();
- const int middle = rect.y() + rect.height() / 2;
-
- WebKit::WebThemeEngine::ExtraParams extraParams;
- extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13;
- extraParams.menuList.arrowY = middle;
- const RenderBox* box = toRenderBox(o);
- // Match Chromium Win behaviour of showing all borders if any are shown.
- extraParams.menuList.hasBorder = box->borderRight() || box->borderLeft() || box->borderTop() || box->borderBottom();
- extraParams.menuList.hasBorderRadius = o->style()->hasBorderRadius();
- // Fallback to transparent if the specified color object is invalid.
- extraParams.menuList.backgroundColor = Color::transparent;
- if (o->hasBackground())
- extraParams.menuList.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb();
-
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartMenuList, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-bool RenderThemeChromiumLinux::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.slider.vertical = o->style()->appearance() == SliderVerticalPart;
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartSliderTrack, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
-
-#if ENABLE(DATALIST_ELEMENT)
- paintSliderTicks(o, i, rect);
-#endif
-
- return false;
-}
-
-bool RenderThemeChromiumLinux::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.slider.vertical = o->style()->appearance() == SliderThumbVerticalPart;
- extraParams.slider.inDrag = isPressed(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartSliderThumb, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-void RenderThemeChromiumLinux::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize size = WebKit::Platform::current()->themeEngine()->getSize(WebKit::WebThemeEngine::PartInnerSpinButton);
-
- style->setWidth(Length(size.width(), Fixed));
- style->setMinWidth(Length(size.width(), Fixed));
-}
-
-bool RenderThemeChromiumLinux::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- WebKit::WebThemeEngine::ExtraParams extraParams;
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- extraParams.innerSpin.spinUp = (controlStatesForRenderer(o) & SpinUpState);
- extraParams.innerSpin.readOnly = isReadOnlyControl(o);
-
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartInnerSpinButton, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-#if ENABLE(PROGRESS_ELEMENT)
-
-bool RenderThemeChromiumLinux::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- if (!o->isProgress())
- return true;
-
- RenderProgress* renderProgress = toRenderProgress(o);
- IntRect valueRect = progressValueRectFor(renderProgress, rect);
-
- WebKit::WebThemeEngine::ExtraParams extraParams;
- extraParams.progressBar.determinate = renderProgress->isDeterminate();
- extraParams.progressBar.valueRectX = valueRect.x();
- extraParams.progressBar.valueRectY = valueRect.y();
- extraParams.progressBar.valueRectWidth = valueRect.width();
- extraParams.progressBar.valueRectHeight = valueRect.height();
-
- DirectionFlippingScope scope(o, i, rect);
- WebKit::WebCanvas* canvas = i.context->platformContext()->canvas();
- WebKit::Platform::current()->themeEngine()->paint(canvas, WebKit::WebThemeEngine::PartProgressBar, getWebThemeState(this, o), WebKit::WebRect(rect), &extraParams);
- return false;
-}
-
-#endif
-
-bool RenderThemeChromiumLinux::shouldOpenPickerWithF4Key() const
-{
- return true;
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumLinux.h b/Source/WebCore/rendering/RenderThemeChromiumLinux.h
deleted file mode 100644
index 5fc4b35db..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumLinux.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * This file is part of the WebKit project.
- *
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008, 2009 Google, Inc.
- * All rights reserved.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderThemeChromiumLinux_h
-#define RenderThemeChromiumLinux_h
-
-#include "RenderThemeChromiumSkia.h"
-
-namespace WebCore {
-
- class RenderThemeChromiumLinux : public RenderThemeChromiumSkia {
- public:
- static PassRefPtr<RenderTheme> create();
- virtual String extraDefaultStyleSheet();
-
- virtual Color systemColor(int cssValidId) const;
-
- // A method asking if the control changes its tint when the window has focus or not.
- virtual bool controlSupportsTints(const RenderObject*) const;
-
- // List Box selection color
- virtual Color activeListBoxSelectionBackgroundColor() const;
- virtual Color activeListBoxSelectionForegroundColor() const;
- virtual Color inactiveListBoxSelectionBackgroundColor() const;
- virtual Color inactiveListBoxSelectionForegroundColor() const;
-
- virtual Color platformActiveSelectionBackgroundColor() const;
- virtual Color platformInactiveSelectionBackgroundColor() const;
- virtual Color platformActiveSelectionForegroundColor() const;
- virtual Color platformInactiveSelectionForegroundColor() const;
-
-#if ENABLE(DATALIST_ELEMENT)
- virtual IntSize sliderTickSize() const OVERRIDE;
- virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE;
-#endif
- virtual void adjustSliderThumbSize(RenderStyle*, Element*) const;
-
- static void setCaretBlinkInterval(double interval);
- virtual double caretBlinkIntervalInternal() const;
-
- virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void setCheckboxSize(RenderStyle*) const;
-
- virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void setRadioSize(RenderStyle*) const;
-
- virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual bool popsMenuBySpaceOrReturn() const OVERRIDE { return true; }
-
-#if ENABLE(PROGRESS_ELEMENT)
- virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
-#endif
-
- virtual bool shouldOpenPickerWithF4Key() const OVERRIDE;
-
- static void setSelectionColors(unsigned activeBackgroundColor,
- unsigned activeForegroundColor,
- unsigned inactiveBackgroundColor,
- unsigned inactiveForegroundColor);
-
- protected:
- RenderThemeChromiumLinux();
- virtual ~RenderThemeChromiumLinux();
-
- private:
- // A general method asking if any control tinting is supported at all.
- virtual bool supportsControlTints() const;
-
- static double m_caretBlinkInterval;
-
- static unsigned m_activeSelectionBackgroundColor;
- static unsigned m_activeSelectionForegroundColor;
- static unsigned m_inactiveSelectionBackgroundColor;
- static unsigned m_inactiveSelectionForegroundColor;
- };
-
-} // namespace WebCore
-
-#endif // RenderThemeChromiumLinux_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h
deleted file mode 100644
index 5acd13af5..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumMac.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * This file is part of the theme implementation for form controls in WebCore.
- *
- * Copyright (C) 2005 Apple Computer, Inc.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderThemeChromiumMac_h
-#define RenderThemeChromiumMac_h
-
-#import "RenderThemeChromiumCommon.h"
-#import "RenderThemeMacShared.h"
-
-namespace WebCore {
-
-class RenderThemeChromiumMac : public RenderThemeMacShared {
-public:
- static PassRefPtr<RenderTheme> create();
-
- virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE;
-
-protected:
-#if ENABLE(VIDEO)
- virtual void adjustMediaSliderThumbSize(RenderStyle*) const;
- virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual String extraMediaControlsStyleSheet();
-#if ENABLE(FULLSCREEN_API)
- virtual String extraFullScreenStyleSheet();
-#endif
-
- virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
- virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE;
- virtual bool usesMediaControlStatusDisplay() { return false; }
- virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; }
- virtual bool usesVerticalVolumeSlider() const { return false; }
- virtual String formatMediaControlsTime(float time) const;
- virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const;
- virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const;
- virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&);
-#endif
-
- virtual bool usesTestModeFocusRingColor() const;
- virtual NSView* documentViewFor(RenderObject*) const;
-
- virtual int popupInternalPaddingLeft(RenderStyle*) const;
- virtual int popupInternalPaddingRight(RenderStyle*) const;
-
-private:
- virtual Color disabledTextColor(const Color& textColor, const Color&) const OVERRIDE { return textColor; }
- virtual void updateActiveState(NSCell*, const RenderObject*);
- virtual String extraDefaultStyleSheet();
-#if ENABLE(DATALIST_ELEMENT)
- virtual LayoutUnit sliderTickSnappingThreshold() const OVERRIDE;
-#endif
-#if ENABLE(CALENDAR_PICKER)
- virtual CString extraCalendarPickerStyleSheet() OVERRIDE;
-#endif
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
- virtual bool supportsCalendarPicker(const AtomicString& type) const OVERRIDE;
-#endif
- virtual bool shouldShowPlaceholderWhenFocused() const OVERRIDE;
-};
-
-} // namespace WebCore
-
-#endif // RenderThemeChromiumMac_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.mm b/Source/WebCore/rendering/RenderThemeChromiumMac.mm
deleted file mode 100644
index 91fe6ba66..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumMac.mm
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#import "config.h"
-
-#import "CalendarPickerMac.h"
-#import "LayoutTestSupport.h"
-#import "LocalCurrentGraphicsContext.h"
-#import "RenderThemeChromiumMac.h"
-#import "PaintInfo.h"
-#import "RenderMediaControlsChromium.h"
-#import "WebCoreSystemInterface.h"
-#import "UserAgentStyleSheets.h"
-#import <Carbon/Carbon.h>
-#import <Cocoa/Cocoa.h>
-#import <wtf/RetainPtr.h>
-#import <wtf/StdLibExtras.h>
-#import <math.h>
-
-@interface RTCMFlippedView : NSView
-{}
-
-- (BOOL)isFlipped;
-- (NSText *)currentEditor;
-
-@end
-
-@implementation RTCMFlippedView
-
-- (BOOL)isFlipped {
- return [[NSGraphicsContext currentContext] isFlipped];
-}
-
-- (NSText *)currentEditor {
- return nil;
-}
-
-@end
-
-namespace WebCore {
-
-NSView* FlippedView()
-{
- static NSView* view = [[RTCMFlippedView alloc] init];
- return view;
-}
-
-PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
-{
- static RenderTheme* rt = RenderThemeChromiumMac::create().leakRef();
- return rt;
-}
-
-PassRefPtr<RenderTheme> RenderThemeChromiumMac::create()
-{
- return adoptRef(new RenderThemeChromiumMac);
-}
-
-bool RenderThemeChromiumMac::supportsDataListUI(const AtomicString& type) const
-{
- return RenderThemeChromiumCommon::supportsDataListUI(type);
-}
-
-bool RenderThemeChromiumMac::usesTestModeFocusRingColor() const
-{
- return isRunningLayoutTest();
-}
-
-NSView* RenderThemeChromiumMac::documentViewFor(RenderObject*) const
-{
- return FlippedView();
-}
-
-const int autofillPopupHorizontalPadding = 4;
-
-// These functions are called with MenuListPart or MenulistButtonPart appearance by RenderMenuList, or with TextFieldPart appearance by AutofillPopupMenuClient.
-// We assume only AutofillPopupMenuClient gives TexfieldPart appearance here.
-// We want to change only Autofill padding.
-// In the future, we have to separate Autofill popup window logic from WebKit to Chromium.
-int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const
-{
- if (style->appearance() == TextFieldPart)
- return autofillPopupHorizontalPadding;
-
- return RenderThemeMacShared::popupInternalPaddingLeft(style);
-}
-
-int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const
-{
- if (style->appearance() == TextFieldPart)
- return autofillPopupHorizontalPadding;
-
- return RenderThemeMacShared::popupInternalPaddingRight(style);
-}
-
-// Updates the control tint (a.k.a. active state) of |cell| (from |o|).
-// In the Chromium port, the renderer runs as a background process and controls'
-// NSCell(s) lack a parent NSView. Therefore controls don't have their tint
-// color updated correctly when the application is activated/deactivated.
-// FocusController's setActive() is called when the application is
-// activated/deactivated, which causes a repaint at which time this code is
-// called.
-// This function should be called before drawing any NSCell-derived controls,
-// unless you're sure it isn't needed.
-void RenderThemeChromiumMac::updateActiveState(NSCell* cell, const RenderObject* o)
-{
- NSControlTint oldTint = [cell controlTint];
- NSControlTint tint = isActive(o) ? [NSColor currentControlTint] :
- static_cast<NSControlTint>(NSClearControlTint);
-
- if (tint != oldTint)
- [cell setControlTint:tint];
-}
-
-bool RenderThemeChromiumMac::shouldShowPlaceholderWhenFocused() const
-{
- return true;
-}
-
-#if ENABLE(VIDEO)
-
-void RenderThemeChromiumMac::adjustMediaSliderThumbSize(RenderStyle* style) const
-{
- RenderMediaControlsChromium::adjustMediaSliderThumbSize(style);
-}
-
-bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
-}
-
-bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
-}
-
-bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
-}
-
-String RenderThemeChromiumMac::extraMediaControlsStyleSheet()
-{
- return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet));
-}
-
-#if ENABLE(FULLSCREEN_API)
-String RenderThemeChromiumMac::extraFullScreenStyleSheet()
-{
- // FIXME: Chromium may wish to style its default media controls differently in fullscreen.
- return String();
-}
-#endif
-
-String RenderThemeChromiumMac::extraDefaultStyleSheet()
-{
- return RenderThemeMacShared::extraDefaultStyleSheet() +
- String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet));
-}
-
-#if ENABLE(DATALIST_ELEMENT)
-LayoutUnit RenderThemeChromiumMac::sliderTickSnappingThreshold() const
-{
- return RenderThemeChromiumCommon::sliderTickSnappingThreshold();
-}
-#endif
-
-#if ENABLE(CALENDAR_PICKER)
-CString RenderThemeChromiumMac::extraCalendarPickerStyleSheet()
-{
- return CString(calendarPickerMacCss, WTF_ARRAY_LENGTH(calendarPickerMacCss));
-}
-#endif
-
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) && ENABLE(CALENDAR_PICKER)
-bool RenderThemeChromiumMac::supportsCalendarPicker(const AtomicString& type) const
-{
- return RenderThemeChromiumCommon::supportsCalendarPicker(type);
-}
-#endif
-
-bool RenderThemeChromiumMac::paintMediaVolumeSliderContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return true;
-}
-
-bool RenderThemeChromiumMac::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
-}
-
-bool RenderThemeChromiumMac::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
-}
-
-bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
-}
-
-IntPoint RenderThemeChromiumMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const
-{
- return RenderTheme::volumeSliderOffsetFromMuteButton(muteButtonBox, size);
-}
-
-String RenderThemeChromiumMac::formatMediaControlsTime(float time) const
-{
- return RenderMediaControlsChromium::formatMediaControlsTime(time);
-}
-
-String RenderThemeChromiumMac::formatMediaControlsCurrentTime(float currentTime, float duration) const
-{
- return RenderMediaControlsChromium::formatMediaControlsCurrentTime(currentTime, duration);
-}
-
-String RenderThemeChromiumMac::formatMediaControlsRemainingTime(float currentTime, float duration) const
-{
- return RenderThemeChromiumMac::formatMediaControlsRemainingTime(currentTime, duration);
-}
-
-bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
-}
-
-bool RenderThemeChromiumMac::paintMediaToggleClosedCaptionsButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaShowClosedCaptionsButton, object, paintInfo, rect);
-}
-#endif
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp
deleted file mode 100644
index 968423d81..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc.
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008 Collabora Ltd.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderThemeChromiumSkia.h"
-
-#include "CSSValueKeywords.h"
-#include "Font.h"
-#include "GraphicsContext.h"
-#include "HTMLMediaElement.h"
-#include "HTMLNames.h"
-#include "Image.h"
-#include "LayoutTestSupport.h"
-#include "MediaControlElements.h"
-#include "PaintInfo.h"
-#include "PlatformContextSkia.h"
-#include "RenderBox.h"
-#include "RenderMediaControlsChromium.h"
-#include "RenderObject.h"
-#include "RenderProgress.h"
-#include "RenderSlider.h"
-#include "RenderThemeChromiumFontProvider.h"
-#include "ScrollbarTheme.h"
-#include "TimeRanges.h"
-#include "TransformationMatrix.h"
-#include "UserAgentStyleSheets.h"
-
-#include <wtf/CurrentTime.h>
-
-#include "SkShader.h"
-#include "SkGradientShader.h"
-
-namespace WebCore {
-
-enum PaddingType {
- TopPadding,
- RightPadding,
- BottomPadding,
- LeftPadding
-};
-
-static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 };
-
-// These values all match Safari/Win.
-static const float defaultControlFontPixelSize = 13;
-static const float defaultCancelButtonSize = 9;
-static const float minCancelButtonSize = 5;
-static const float maxCancelButtonSize = 21;
-static const float defaultSearchFieldResultsDecorationSize = 13;
-static const float minSearchFieldResultsDecorationSize = 9;
-static const float maxSearchFieldResultsDecorationSize = 30;
-static const float defaultSearchFieldResultsButtonWidth = 18;
-
-RenderThemeChromiumSkia::RenderThemeChromiumSkia()
-{
-}
-
-RenderThemeChromiumSkia::~RenderThemeChromiumSkia()
-{
-}
-
-// Use the Windows style sheets to match their metrics.
-String RenderThemeChromiumSkia::extraDefaultStyleSheet()
-{
- return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)) +
- String(themeChromiumSkiaUserAgentStyleSheet, sizeof(themeChromiumSkiaUserAgentStyleSheet)) +
- String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet));
-}
-
-String RenderThemeChromiumSkia::extraQuirksStyleSheet()
-{
- return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
-}
-
-#if ENABLE(VIDEO)
-String RenderThemeChromiumSkia::extraMediaControlsStyleSheet()
-{
- return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet));
-}
-#endif
-
-bool RenderThemeChromiumSkia::supportsHover(const RenderStyle* style) const
-{
- return true;
-}
-
-bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const
-{
- // This causes WebKit to draw the focus rings for us.
- return false;
-}
-
-bool RenderThemeChromiumSkia::supportsDataListUI(const AtomicString& type) const
-{
- return RenderThemeChromiumCommon::supportsDataListUI(type);
-}
-
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) && ENABLE(CALENDAR_PICKER)
-bool RenderThemeChromiumSkia::supportsCalendarPicker(const AtomicString& type) const
-{
- return RenderThemeChromiumCommon::supportsCalendarPicker(type);
-}
-#endif
-
-#if ENABLE(VIDEO_TRACK)
-bool RenderThemeChromiumSkia::supportsClosedCaptioning() const
-{
- return true;
-}
-#endif
-
-Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const
-{
- return Color(0x1e, 0x90, 0xff);
-}
-
-Color RenderThemeChromiumSkia::platformInactiveSelectionBackgroundColor() const
-{
- return Color(0xc8, 0xc8, 0xc8);
-}
-
-Color RenderThemeChromiumSkia::platformActiveSelectionForegroundColor() const
-{
- return Color::black;
-}
-
-Color RenderThemeChromiumSkia::platformInactiveSelectionForegroundColor() const
-{
- return Color(0x32, 0x32, 0x32);
-}
-
-Color RenderThemeChromiumSkia::platformFocusRingColor() const
-{
- static Color focusRingColor(229, 151, 0, 255);
- return focusRingColor;
-}
-
-double RenderThemeChromiumSkia::caretBlinkInterval() const
-{
- // Disable the blinking caret in layout test mode, as it introduces
- // a race condition for the pixel tests. http://b/1198440
- if (isRunningLayoutTest())
- return 0;
-
- return caretBlinkIntervalInternal();
-}
-
-void RenderThemeChromiumSkia::systemFont(int propId, FontDescription& fontDescription) const
-{
- RenderThemeChromiumFontProvider::systemFont(propId, fontDescription);
-}
-
-int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const
-{
- return 0;
-}
-
-// These are the default dimensions of radio buttons and checkboxes.
-static const int widgetStandardWidth = 13;
-static const int widgetStandardHeight = 13;
-
-// Return a rectangle that has the same center point as |original|, but with a
-// size capped at |width| by |height|.
-IntRect center(const IntRect& original, int width, int height)
-{
- width = std::min(original.width(), width);
- height = std::min(original.height(), height);
- int x = original.x() + (original.width() - width) / 2;
- int y = original.y() + (original.height() - height) / 2;
-
- return IntRect(x, y, width, height);
-}
-
-void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- // FIXME: A hard-coded size of 13 is used. This is wrong but necessary
- // for now. It matches Firefox. At different DPI settings on Windows,
- // querying the theme gives you a larger size that accounts for the higher
- // DPI. Until our entire engine honors a DPI setting other than 96, we
- // can't rely on the theme's metrics.
- const IntSize size(widgetStandardWidth, widgetStandardHeight);
- setSizeIfAuto(style, size);
-}
-
-void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const
-{
- // Use same sizing for radio box as checkbox.
- setCheckboxSize(style);
-}
-
-void RenderThemeChromiumSkia::adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- if (style->appearance() == PushButtonPart) {
- // Ignore line-height.
- style->setLineHeight(RenderStyle::initialLineHeight());
- }
-}
-
-bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- return paintTextField(o, i, r);
-}
-
-void RenderThemeChromiumSkia::adjustSearchFieldStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- // Ignore line-height.
- style->setLineHeight(RenderStyle::initialLineHeight());
-}
-
-bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- return paintTextField(o, i, r);
-}
-
-void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- // Scale the button size based on the font size
- float fontScale = style->fontSize() / defaultControlFontPixelSize;
- int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
- style->setWidth(Length(cancelButtonSize, Fixed));
- style->setHeight(Length(cancelButtonSize, Fixed));
-}
-
-IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const
-{
- // Compute an offset between the part renderer and the input renderer.
- LayoutSize offsetFromInputRenderer = -partRenderer->offsetFromAncestorContainer(inputRenderer);
- // Move the rect into partRenderer's coords.
- partRect.move(offsetFromInputRenderer);
- // Account for the local drawing offset.
- partRect.move(localOffset.x(), localOffset.y());
-
- return pixelSnappedIntRect(partRect);
-}
-
-bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const PaintInfo& paintInfo, const IntRect& r)
-{
- // Get the renderer of <input> element.
- Node* input = cancelButtonObject->node()->shadowHost();
- RenderObject* baseRenderer = input ? input->renderer() : cancelButtonObject;
- if (!baseRenderer->isBox())
- return false;
- RenderBox* inputRenderBox = toRenderBox(baseRenderer);
- LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
-
- // Make sure the scaled button stays square and will fit in its parent's box.
- LayoutUnit cancelButtonSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
- // Calculate cancel button's coordinates relative to the input element.
- // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will
- // be one pixel closer to the bottom of the field. This tends to look better with the text.
- LayoutRect cancelButtonRect(cancelButtonObject->offsetFromAncestorContainer(inputRenderBox).width(),
- inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
- cancelButtonSize, cancelButtonSize);
- IntRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r);
-
- static Image* cancelImage = Image::loadPlatformResource("searchCancel").leakRef();
- static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").leakRef();
- paintInfo.context->drawImage(isPressed(cancelButtonObject) ? cancelPressedImage : cancelImage,
- cancelButtonObject->style()->colorSpace(), paintingRect);
- return false;
-}
-
-void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize emptySize(1, 11);
- style->setWidth(Length(emptySize.width(), Fixed));
- style->setHeight(Length(emptySize.height(), Fixed));
-}
-
-void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- // Scale the decoration size based on the font size
- float fontScale = style->fontSize() / defaultControlFontPixelSize;
- int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
- maxSearchFieldResultsDecorationSize));
- style->setWidth(Length(magnifierSize, Fixed));
- style->setHeight(Length(magnifierSize, Fixed));
-}
-
-bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
-{
- // Get the renderer of <input> element.
- Node* input = magnifierObject->node()->shadowHost();
- RenderObject* baseRenderer = input ? input->renderer() : magnifierObject;
- if (!baseRenderer->isBox())
- return false;
- RenderBox* inputRenderBox = toRenderBox(baseRenderer);
- LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
-
- // Make sure the scaled decoration stays square and will fit in its parent's box.
- LayoutUnit magnifierSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
- // Calculate decoration's coordinates relative to the input element.
- // Center the decoration vertically. Round up though, so if it has to be one pixel off-center, it will
- // be one pixel closer to the bottom of the field. This tends to look better with the text.
- LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
- inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2,
- magnifierSize, magnifierSize);
- IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);
-
- static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").leakRef();
- paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect);
- return false;
-}
-
-void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- // Scale the button size based on the font size
- float fontScale = style->fontSize() / defaultControlFontPixelSize;
- int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
- maxSearchFieldResultsDecorationSize));
- int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
- style->setWidth(Length(magnifierWidth, Fixed));
- style->setHeight(Length(magnifierHeight, Fixed));
-}
-
-bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
-{
- // Get the renderer of <input> element.
- Node* input = magnifierObject->node()->shadowHost();
- RenderObject* baseRenderer = input ? input->renderer() : magnifierObject;
- if (!baseRenderer->isBox())
- return false;
- RenderBox* inputRenderBox = toRenderBox(baseRenderer);
- LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
-
- // Make sure the scaled decoration will fit in its parent's box.
- LayoutUnit magnifierHeight = std::min<LayoutUnit>(inputContentBox.height(), r.height());
- LayoutUnit magnifierWidth = std::min<LayoutUnit>(inputContentBox.width(), magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
- LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
- inputContentBox.y() + (inputContentBox.height() - magnifierHeight + 1) / 2,
- magnifierWidth, magnifierHeight);
- IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);
-
- static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").leakRef();
- paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect);
- return false;
-}
-
-bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderStyle* style, Element*) const
-{
-#if ENABLE(VIDEO)
- RenderMediaControlsChromium::adjustMediaSliderThumbSize(style);
-#else
- UNUSED_PARAM(style);
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
-#if ENABLE(VIDEO_TRACK)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-String RenderThemeChromiumSkia::formatMediaControlsTime(float time) const
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::formatMediaControlsTime(time);
-#else
- UNUSED_PARAM(time);
- return 0;
-#endif
-}
-
-String RenderThemeChromiumSkia::formatMediaControlsCurrentTime(float currentTime, float duration) const
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::formatMediaControlsCurrentTime(currentTime, duration);
-#else
- UNUSED_PARAM(currentTime);
- UNUSED_PARAM(duration);
- return 0;
-#endif
-}
-
-String RenderThemeChromiumSkia::formatMediaControlsRemainingTime(float currentTime, float duration) const
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::formatMediaControlsRemainingTime(currentTime, duration);
-#else
- UNUSED_PARAM(currentTime);
- UNUSED_PARAM(duration);
- return 0;
-#endif
-}
-
-bool RenderThemeChromiumSkia::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
-{
-#if ENABLE(VIDEO)
- return RenderMediaControlsChromium::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
-#else
- UNUSED_PARAM(object);
- UNUSED_PARAM(paintInfo);
- UNUSED_PARAM(rect);
- return false;
-#endif
-}
-
-void RenderThemeChromiumSkia::adjustMenuListStyle(StyleResolver*, RenderStyle* style, WebCore::Element*) const
-{
- // Height is locked to auto on all browsers.
- style->setLineHeight(RenderStyle::initialLineHeight());
-}
-
-void RenderThemeChromiumSkia::adjustMenuListButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
-{
- adjustMenuListStyle(styleResolver, style, e);
-}
-
-// Used to paint styled menulists (i.e. with a non-default border)
-bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
-{
- return paintMenuList(o, i, rect);
-}
-
-int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const
-{
- return menuListInternalPadding(style, LeftPadding);
-}
-
-int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const
-{
- return menuListInternalPadding(style, RightPadding);
-}
-
-int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const
-{
- return menuListInternalPadding(style, TopPadding);
-}
-
-int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const
-{
- return menuListInternalPadding(style, BottomPadding);
-}
-
-// static
-void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize)
-{
- RenderThemeChromiumFontProvider::setDefaultFontSize(fontSize);
-}
-
-double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const
-{
- return RenderTheme::caretBlinkInterval();
-}
-
-int RenderThemeChromiumSkia::menuListArrowPadding() const
-{
- return ScrollbarTheme::theme()->scrollbarThickness();
-}
-
-// static
-void RenderThemeChromiumSkia::setSizeIfAuto(RenderStyle* style, const IntSize& size)
-{
- if (style->width().isIntrinsicOrAuto())
- style->setWidth(Length(size.width(), Fixed));
- if (style->height().isAuto())
- style->setHeight(Length(size.height(), Fixed));
-}
-
-int RenderThemeChromiumSkia::menuListInternalPadding(RenderStyle* style, int paddingType) const
-{
- // This internal padding is in addition to the user-supplied padding.
- // Matches the FF behavior.
- int padding = styledMenuListInternalPadding[paddingType];
-
- // Reserve the space for right arrow here. The rest of the padding is
- // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from
- // RenderMenuList to lay out the individual items in the popup.
- // If the MenuList actually has appearance "NoAppearance", then that means
- // we don't draw a button, so don't reserve space for it.
- const int barType = style->direction() == LTR ? RightPadding : LeftPadding;
- if (paddingType == barType && style->appearance() != NoControlPart)
- padding += menuListArrowPadding();
-
- return padding;
-}
-
-bool RenderThemeChromiumSkia::shouldShowPlaceholderWhenFocused() const
-{
- return true;
-}
-
-#if ENABLE(DATALIST_ELEMENT)
-LayoutUnit RenderThemeChromiumSkia::sliderTickSnappingThreshold() const
-{
- return RenderThemeChromiumCommon::sliderTickSnappingThreshold();
-}
-#endif
-
-#if ENABLE(PROGRESS_ELEMENT)
-
-//
-// Following values are come from default of GTK+
-//
-static const int progressDeltaPixelsPerSecond = 100;
-static const int progressActivityBlocks = 5;
-static const int progressAnimationFrmaes = 10;
-static const double progressAnimationInterval = 0.125;
-
-IntRect RenderThemeChromiumSkia::determinateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
-{
- int dx = rect.width() * renderProgress->position();
- return IntRect(rect.x(), rect.y(), dx, rect.height());
-}
-
-IntRect RenderThemeChromiumSkia::indeterminateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
-{
-
- int valueWidth = rect.width() / progressActivityBlocks;
- int movableWidth = rect.width() - valueWidth;
- if (movableWidth <= 0)
- return IntRect();
-
- double progress = renderProgress->animationProgress();
- if (progress < 0.5)
- return IntRect(rect.x() + progress * 2 * movableWidth, rect.y(), valueWidth, rect.height());
- return IntRect(rect.x() + (1.0 - progress) * 2 * movableWidth, rect.y(), valueWidth, rect.height());
-}
-
-double RenderThemeChromiumSkia::animationRepeatIntervalForProgressBar(RenderProgress*) const
-{
- return progressAnimationInterval;
-}
-
-double RenderThemeChromiumSkia::animationDurationForProgressBar(RenderProgress* renderProgress) const
-{
- return progressAnimationInterval * progressAnimationFrmaes * 2; // "2" for back and forth
-}
-
-IntRect RenderThemeChromiumSkia::progressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
-{
- return renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, rect) : indeterminateProgressValueRectFor(renderProgress, rect);
-}
-
-RenderThemeChromiumSkia::DirectionFlippingScope::DirectionFlippingScope(RenderObject* renderer, const PaintInfo& paintInfo, const IntRect& rect)
- : m_needsFlipping(!renderer->style()->isLeftToRightDirection())
- , m_paintInfo(paintInfo)
-{
- if (!m_needsFlipping)
- return;
- m_paintInfo.context->save();
- m_paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
- m_paintInfo.context->scale(FloatSize(-1, 1));
-}
-
-RenderThemeChromiumSkia::DirectionFlippingScope::~DirectionFlippingScope()
-{
- if (!m_needsFlipping)
- return;
- m_paintInfo.context->restore();
-}
-
-
-#endif
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.h b/Source/WebCore/rendering/RenderThemeChromiumSkia.h
deleted file mode 100644
index 8dc3a3a36..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumSkia.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * This file is part of the WebKit project.
- *
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008, 2009 Google, Inc.
- * All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderThemeChromiumSkia_h
-#define RenderThemeChromiumSkia_h
-
-#include "RenderTheme.h"
-#include "RenderThemeChromiumCommon.h"
-
-namespace WebCore {
-
-class RenderProgress;
-
-class RenderThemeChromiumSkia : public RenderTheme {
-public:
- RenderThemeChromiumSkia();
- virtual ~RenderThemeChromiumSkia();
-
- virtual String extraDefaultStyleSheet();
- virtual String extraQuirksStyleSheet();
-#if ENABLE(VIDEO)
- virtual String extraMediaControlsStyleSheet();
-#endif
-
-#if ENABLE(TOUCH_EVENTS)
- virtual Color platformTapHighlightColor() const OVERRIDE
- {
- return Color(defaultTapHighlightColor);
- }
-#endif
-
- // A method asking if the theme's controls actually care about redrawing when hovered.
- virtual bool supportsHover(const RenderStyle*) const;
-
- // A method asking if the theme is able to draw the focus ring.
- virtual bool supportsFocusRing(const RenderStyle*) const;
-
- virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE;
-
-#if ENABLE(VIDEO_TRACK)
- virtual bool supportsClosedCaptioning() const OVERRIDE;
-#endif
- // The platform selection color.
- virtual Color platformActiveSelectionBackgroundColor() const;
- virtual Color platformInactiveSelectionBackgroundColor() const;
- virtual Color platformActiveSelectionForegroundColor() const;
- virtual Color platformInactiveSelectionForegroundColor() const;
- virtual Color platformFocusRingColor() const;
-
- // To change the blink interval, override caretBlinkIntervalInternal instead of this one so that we may share layout test code an intercepts.
- virtual double caretBlinkInterval() const;
-
- // System fonts.
- virtual void systemFont(int propId, FontDescription&) const;
-
- virtual int minimumMenuListSize(RenderStyle*) const;
-
- virtual void setCheckboxSize(RenderStyle*) const;
-
- virtual void setRadioSize(RenderStyle*) const;
-
- virtual void adjustButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustSliderThumbSize(RenderStyle*, Element*) const;
- virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual String formatMediaControlsTime(float time) const;
- virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const;
- virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const;
- virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&);
-
- // MenuList refers to an unstyled menulist (meaning a menulist without
- // background-color or border set) and MenuListButton refers to a styled
- // menulist (a menulist with background-color or border set). They have
- // this distinction to support showing aqua style themes whenever they
- // possibly can, which is something we don't want to replicate.
- //
- // In short, we either go down the MenuList code path or the MenuListButton
- // codepath. We never go down both. And in both cases, they render the
- // entire menulist.
- virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&);
-
-#if ENABLE(PROGRESS_ELEMENT)
- virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const;
- virtual double animationDurationForProgressBar(RenderProgress*) const;
-#endif
-
- // These methods define the padding for the MenuList's inner block.
- virtual int popupInternalPaddingLeft(RenderStyle*) const;
- virtual int popupInternalPaddingRight(RenderStyle*) const;
- virtual int popupInternalPaddingTop(RenderStyle*) const;
- virtual int popupInternalPaddingBottom(RenderStyle*) const;
-
-#if ENABLE(VIDEO)
- // Media controls
- virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; }
- virtual bool usesVerticalVolumeSlider() const { return false; }
-#endif
-
- // Provide a way to pass the default font size from the Settings object
- // to the render theme. FIXME: http://b/1129186 A cleaner way would be
- // to remove the default font size from this object and have callers
- // that need the value to get it directly from the appropriate Settings
- // object.
- static void setDefaultFontSize(int);
-
-protected:
- virtual double caretBlinkIntervalInternal() const;
-
- virtual int menuListArrowPadding() const;
-
- static void setSizeIfAuto(RenderStyle*, const IntSize&);
-
-#if ENABLE(PROGRESS_ELEMENT)
- IntRect determinateProgressValueRectFor(RenderProgress*, const IntRect&) const;
- IntRect indeterminateProgressValueRectFor(RenderProgress*, const IntRect&) const;
- IntRect progressValueRectFor(RenderProgress*, const IntRect&) const;
-
- class DirectionFlippingScope {
- public:
- DirectionFlippingScope(RenderObject*, const PaintInfo&, const IntRect&);
- ~DirectionFlippingScope();
-
- private:
- bool m_needsFlipping;
- const PaintInfo& m_paintInfo;
- };
-#endif
-
-private:
- virtual Color disabledTextColor(const Color& textColor, const Color&) const OVERRIDE { return textColor; }
- virtual bool shouldShowPlaceholderWhenFocused() const OVERRIDE;
-
-#if ENABLE(DATALIST_ELEMENT)
- virtual LayoutUnit sliderTickSnappingThreshold() const OVERRIDE;
-#endif
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
- virtual bool supportsCalendarPicker(const AtomicString& type) const OVERRIDE;
-#endif
-
- int menuListInternalPadding(RenderStyle*, int paddingType) const;
- bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*);
- IntRect convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const;
-
- static const RGBA32 defaultTapHighlightColor = 0x2e000000; // 18% black.
-};
-
-} // namespace WebCore
-
-#endif // RenderThemeChromiumSkia_h
diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp
deleted file mode 100644
index 709904c59..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * This file is part of the WebKit project.
- *
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2008, 2009 Google, Inc.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- */
-
-#include "config.h"
-#include "RenderThemeChromiumWin.h"
-
-#include <windows.h>
-#include <uxtheme.h>
-#include <vssym32.h>
-
-#include "CSSValueKeywords.h"
-#include "FontSelector.h"
-#include "FontUtilsChromiumWin.h"
-#include "GraphicsContext.h"
-#include "HTMLMediaElement.h"
-#include "HTMLNames.h"
-#include "LayoutTestSupport.h"
-#include "MediaControlElements.h"
-#include "PaintInfo.h"
-#include "PlatformSupport.h"
-#include "RenderBox.h"
-#include "RenderProgress.h"
-#include "RenderSlider.h"
-#include "RenderThemeChromiumCommon.h"
-#include "ScrollbarTheme.h"
-#include "SystemInfo.h"
-#include "TransparencyWin.h"
-#include <wtf/CurrentTime.h>
-
-
-// FIXME: This dependency should eventually be removed.
-#include <skia/ext/skia_utils_win.h>
-
-namespace WebCore {
-
-// The standard width for the menu list drop-down button when run under
-// layout test mode. Use the value that's currently captured in most baselines.
-static const int kStandardMenuListButtonWidth = 17;
-
-namespace {
-// We must not create multiple ThemePainter instances.
-class ThemePainter {
-public:
- ThemePainter(GraphicsContext* context, const IntRect& r)
- {
-#ifndef NDEBUG
- ASSERT(!s_hasInstance);
- s_hasInstance = true;
-#endif
- TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM());
- m_helper.init(context, getLayerMode(context, transformMode), transformMode, r);
-
- if (!m_helper.context()) {
- // TransparencyWin doesn't have well-defined copy-ctor nor op=()
- // so we re-initialize it instead of assigning a fresh istance.
- // On the reinitialization, we fallback to use NoLayer mode.
- // Note that the original initialization failure can be caused by
- // a failure of an internal buffer allocation and NoLayer mode
- // does not have such buffer allocations.
- m_helper.~TransparencyWin();
- new (&m_helper) TransparencyWin();
- m_helper.init(context, TransparencyWin::NoLayer, transformMode, r);
- }
- }
-
- ~ThemePainter()
- {
- m_helper.composite();
-#ifndef NDEBUG
- s_hasInstance = false;
-#endif
- }
-
- GraphicsContext* context() { return m_helper.context(); }
- const IntRect& drawRect() { return m_helper.drawRect(); }
-
-private:
-
- static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode)
- {
- if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background.
- return TransparencyWin::WhiteLayer;
- if (context->platformContext()->canvas()->isDrawingToLayer()) // Needs antialiasing help.
- return TransparencyWin::OpaqueCompositeLayer;
- // Nothing interesting.
- return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer;
- }
-
- static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix)
- {
- if (matrix.b() || matrix.c()) // Skew.
- return TransparencyWin::Untransform;
- if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale.
- return TransparencyWin::ScaleTransform;
- // Nothing interesting.
- return TransparencyWin::KeepTransform;
- }
-
- TransparencyWin m_helper;
-#ifndef NDEBUG
- static bool s_hasInstance;
-#endif
-};
-
-#ifndef NDEBUG
-bool ThemePainter::s_hasInstance = false;
-#endif
-
-} // namespace
-
-// Internal static helper functions. We don't put them in an anonymous
-// namespace so they have easier access to the WebCore namespace.
-
-static bool supportsFocus(ControlPart appearance)
-{
- switch (appearance) {
- case SquareButtonPart:
- case PushButtonPart:
- case ButtonPart:
- case DefaultButtonPart:
- case SearchFieldPart:
- case TextFieldPart:
- case TextAreaPart:
- return true;
- }
- return false;
-}
-
-static double querySystemBlinkInterval(double defaultInterval)
-{
- UINT blinkTime = GetCaretBlinkTime();
- if (!blinkTime)
- return defaultInterval;
- if (blinkTime == INFINITE)
- return 0;
- return blinkTime / 1000.0;
-}
-
-PassRefPtr<RenderTheme> RenderThemeChromiumWin::create()
-{
- return adoptRef(new RenderThemeChromiumWin);
-}
-
-PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
-{
- static RenderTheme* rt = RenderThemeChromiumWin::create().leakRef();
- return rt;
-}
-
-bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const
-{
- // Let webkit draw one of its halo rings around any focused element,
- // except push buttons. For buttons we use the windows PBS_DEFAULTED
- // styling to give it a blue border.
- return style->appearance() == ButtonPart
- || style->appearance() == PushButtonPart
- || style->appearance() == SquareButtonPart;
-}
-
-Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
-{
- if (isRunningLayoutTest())
- return Color(0x00, 0x00, 0xff); // Royal blue.
- COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
- return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
-}
-
-Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const
-{
- if (isRunningLayoutTest())
- return Color(0x99, 0x99, 0x99); // Medium gray.
- COLORREF color = GetSysColor(COLOR_GRAYTEXT);
- return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
-}
-
-Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const
-{
- if (isRunningLayoutTest())
- return Color(0xff, 0xff, 0xcc); // Pale yellow.
- COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
- return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
-}
-
-Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const
-{
- return Color::white;
-}
-
-Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const
-{
- return Color(0xff, 0x96, 0x32); // Orange.
-}
-
-Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const
-{
- return Color(0xff, 0xff, 0x96); // Yellow.
-}
-
-// Map a CSSValue* system color to an index understood by GetSysColor().
-static int cssValueIdToSysColorIndex(int cssValueId)
-{
- switch (cssValueId) {
- case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
- case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
- case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
- case CSSValueBackground: return COLOR_BACKGROUND;
- case CSSValueButtonface: return COLOR_BTNFACE;
- case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
- case CSSValueButtonshadow: return COLOR_BTNSHADOW;
- case CSSValueButtontext: return COLOR_BTNTEXT;
- case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
- case CSSValueGraytext: return COLOR_GRAYTEXT;
- case CSSValueHighlight: return COLOR_HIGHLIGHT;
- case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
- case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
- case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
- case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
- case CSSValueInfobackground: return COLOR_INFOBK;
- case CSSValueInfotext: return COLOR_INFOTEXT;
- case CSSValueMenu: return COLOR_MENU;
- case CSSValueMenutext: return COLOR_MENUTEXT;
- case CSSValueScrollbar: return COLOR_SCROLLBAR;
- case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
- case CSSValueThreedface: return COLOR_3DFACE;
- case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
- case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
- case CSSValueThreedshadow: return COLOR_3DSHADOW;
- case CSSValueWindow: return COLOR_WINDOW;
- case CSSValueWindowframe: return COLOR_WINDOWFRAME;
- case CSSValueWindowtext: return COLOR_WINDOWTEXT;
- default: return -1; // Unsupported CSSValue
- }
-}
-
-Color RenderThemeChromiumWin::systemColor(int cssValueId) const
-{
- int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
- if (isRunningLayoutTest() || (sysColorIndex == -1))
- return RenderTheme::systemColor(cssValueId);
-
- COLORREF color = GetSysColor(sysColorIndex);
- return Color(GetRValue(color), GetGValue(color), GetBValue(color));
-}
-
-#if ENABLE(DATALIST_ELEMENT)
-IntSize RenderThemeChromiumWin::sliderTickSize() const
-{
- return IntSize(1, 3);
-}
-
-int RenderThemeChromiumWin::sliderTickOffsetFromTrackCenter() const
-{
- return 11;
-}
-#endif
-
-void RenderThemeChromiumWin::adjustSliderThumbSize(RenderStyle* style, Element* element) const
-{
- // These sizes match what WinXP draws for various menus.
- const int sliderThumbAlongAxis = 11;
- const int sliderThumbAcrossAxis = 21;
- if (style->appearance() == SliderThumbHorizontalPart) {
- style->setWidth(Length(sliderThumbAlongAxis, Fixed));
- style->setHeight(Length(sliderThumbAcrossAxis, Fixed));
- } else if (style->appearance() == SliderThumbVerticalPart) {
- style->setWidth(Length(sliderThumbAcrossAxis, Fixed));
- style->setHeight(Length(sliderThumbAlongAxis, Fixed));
- } else
- RenderThemeChromiumSkia::adjustSliderThumbSize(style, element);
-}
-
-bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- return paintButton(o, i, r);
-}
-bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- return paintButton(o, i, r);
-}
-
-bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- const ThemeData& themeData = getThemeData(o);
-
- ThemePainter painter(i.context, r);
- PlatformSupport::paintButton(painter.context(),
- themeData.m_part,
- themeData.m_state,
- themeData.m_classicState,
- painter.drawRect());
- return false;
-}
-
-bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- return paintTextFieldInternal(o, i, r, true);
-}
-
-bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- const ThemeData& themeData = getThemeData(o);
-
- ThemePainter painter(i.context, r);
- PlatformSupport::paintTrackbar(painter.context(),
- themeData.m_part,
- themeData.m_state,
- themeData.m_classicState,
- painter.drawRect());
-
-#if ENABLE(DATALIST_ELEMENT)
- paintSliderTicks(o, i, r);
-#endif
-
- return false;
-}
-
-bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- const ThemeData& themeData = getThemeData(o);
-
- ThemePainter painter(i.context, r);
- PlatformSupport::paintTrackbar(painter.context(),
- themeData.m_part,
- themeData.m_state,
- themeData.m_classicState,
- painter.drawRect());
-
- return false;
-}
-
-static int menuListButtonWidth()
-{
- static int width = isRunningLayoutTest() ? kStandardMenuListButtonWidth : GetSystemMetrics(SM_CXVSCROLL);
- return width;
-}
-
-// Used to paint unstyled menulists (i.e. with the default border)
-bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- if (!o->isBox())
- return false;
-
- const RenderBox* box = toRenderBox(o);
- int borderRight = box->borderRight();
- int borderLeft = box->borderLeft();
- int borderTop = box->borderTop();
- int borderBottom = box->borderBottom();
-
- // If all the borders are 0, then tell skia not to paint the border on the
- // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not
- // draw individual borders and then pass that to skia so we can avoid
- // drawing any borders that are set to 0. For non-zero borders, we draw the
- // border, but webkit just draws over it.
- bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom);
-
- paintTextFieldInternal(o, i, r, drawEdges);
-
- // Take padding and border into account. If the MenuList is smaller than
- // the size of a button, make sure to shrink it appropriately and not put
- // its x position to the left of the menulist.
- const int buttonWidth = menuListButtonWidth();
- int spacingLeft = borderLeft + box->paddingLeft();
- int spacingRight = borderRight + box->paddingRight();
- int spacingTop = borderTop + box->paddingTop();
- int spacingBottom = borderBottom + box->paddingBottom();
-
- int buttonX;
- if (r.maxX() - r.x() < buttonWidth)
- buttonX = r.x();
- else
- buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft;
-
- // Compute the rectangle of the button in the destination image.
- IntRect rect(buttonX,
- r.y() + spacingTop,
- std::min(buttonWidth, r.maxX() - r.x()),
- r.height() - (spacingTop + spacingBottom));
-
- // Get the correct theme data for a textfield and paint the menu.
- ThemePainter painter(i.context, rect);
- PlatformSupport::paintMenuList(painter.context(),
- CP_DROPDOWNBUTTON,
- determineState(o),
- determineClassicState(o),
- painter.drawRect());
- return false;
-}
-
-double RenderThemeChromiumWin::caretBlinkIntervalInternal() const
-{
- // This involves a system call, so we cache the result.
- static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval());
- return blinkInterval;
-}
-
-unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart)
-{
- unsigned result = TS_NORMAL;
- ControlPart appearance = o->style()->appearance();
- if (!isEnabled(o))
- result = TS_DISABLED;
- else if (isReadOnlyControl(o))
- result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED;
- // Active overrides hover and focused.
- else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
- result = TS_PRESSED;
- else if (supportsFocus(appearance) && isFocused(o))
- result = ETS_FOCUSED;
- else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
- result = TS_HOT;
-
- // CBS_UNCHECKED*: 1-4
- // CBS_CHECKED*: 5-8
- // CBS_MIXED*: 9-12
- if (isIndeterminate(o))
- result += 8;
- else if (isChecked(o))
- result += 4;
- return result;
-}
-
-unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o)
-{
- unsigned result = TUS_NORMAL;
- if (!isEnabled(o))
- result = TUS_DISABLED;
- else if (supportsFocus(o->style()->appearance()) && isFocused(o))
- result = TUS_FOCUSED;
- else if (isPressed(o))
- result = TUS_PRESSED;
- else if (isHovered(o))
- result = TUS_HOT;
- return result;
-}
-
-unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart)
-{
- unsigned result = 0;
-
- ControlPart part = o->style()->appearance();
-
- // Sliders are always in the normal state.
- if (part == SliderHorizontalPart || part == SliderVerticalPart)
- return result;
-
- // So are readonly text fields.
- if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart))
- return result;
-
- if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
- if (!isEnabled(o))
- result = DFCS_INACTIVE;
- else if (isPressed(o)) // Active supersedes hover
- result = DFCS_PUSHED;
- else if (isHovered(o))
- result = DFCS_HOT;
- } else {
- if (!isEnabled(o) || isReadOnlyControl(o))
- result = DFCS_INACTIVE;
- // Active supersedes hover
- else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
- result = DFCS_PUSHED;
- else if (supportsFocus(part) && isFocused(o)) // So does focused
- result = 0;
- else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
- result = DFCS_HOT;
- // Classic theme can't represent indeterminate states. Use unchecked appearance.
- if (isChecked(o) && !isIndeterminate(o))
- result |= DFCS_CHECKED;
- }
- return result;
-}
-
-ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart)
-{
- ThemeData result;
- switch (o->style()->appearance()) {
- case CheckboxPart:
- result.m_part = BP_CHECKBOX;
- result.m_state = determineState(o);
- result.m_classicState = DFCS_BUTTONCHECK;
- break;
- case RadioPart:
- result.m_part = BP_RADIOBUTTON;
- result.m_state = determineState(o);
- result.m_classicState = DFCS_BUTTONRADIO;
- break;
- case SquareButtonPart:
- case PushButtonPart:
- case ButtonPart:
- result.m_part = BP_PUSHBUTTON;
- result.m_state = determineState(o);
- result.m_classicState = DFCS_BUTTONPUSH;
- break;
- case SliderHorizontalPart:
- result.m_part = TKP_TRACK;
- result.m_state = TRS_NORMAL;
- break;
- case SliderVerticalPart:
- result.m_part = TKP_TRACKVERT;
- result.m_state = TRVS_NORMAL;
- break;
- case SliderThumbHorizontalPart:
- result.m_part = TKP_THUMBBOTTOM;
- result.m_state = determineSliderThumbState(o);
- break;
- case SliderThumbVerticalPart:
- result.m_part = TKP_THUMBVERT;
- result.m_state = determineSliderThumbState(o);
- break;
- case ListboxPart:
- case MenulistPart:
- case MenulistButtonPart:
- case SearchFieldPart:
- case TextFieldPart:
- case TextAreaPart:
- result.m_part = EP_EDITTEXT;
- result.m_state = determineState(o);
- break;
- case InnerSpinButtonPart:
- result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
- result.m_state = determineState(o, subPart);
- result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
- break;
- }
-
- result.m_classicState |= determineClassicState(o, subPart);
-
- return result;
-}
-
-bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
- const PaintInfo& i,
- const IntRect& r,
- bool drawEdges)
-{
- // Fallback to white if the specified color object is invalid.
- // (Note PlatformSupport::paintTextField duplicates this check).
- Color backgroundColor(Color::white);
- if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
- backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
-
- // If we have background-image, don't fill the content area to expose the
- // parent's background. Also, we shouldn't fill the content area if the
- // alpha of the color is 0. The API of Windows GDI ignores the alpha.
- //
- // Note that we should paint the content area white if we have neither the
- // background color nor background image explicitly specified to keep the
- // appearance of select element consistent with other browsers.
- bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha();
-
- if (o->style()->hasBorderRadius()) {
- // If the style has rounded borders, setup the context to clip the
- // background (themed or filled) appropriately.
- // FIXME: make sure we do the right thing if css background-clip is set.
- i.context->save();
- i.context->addRoundedRectClip(o->style()->getRoundedBorderFor(r));
- }
- {
- const ThemeData& themeData = getThemeData(o);
- ThemePainter painter(i.context, r);
- PlatformSupport::paintTextField(painter.context(),
- themeData.m_part,
- themeData.m_state,
- themeData.m_classicState,
- painter.drawRect(),
- backgroundColor,
- fillContentArea,
- drawEdges);
- // End of block commits the painter before restoring context.
- }
- if (o->style()->hasBorderRadius())
- i.context->restore();
- return false;
-}
-
-void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- int width = ScrollbarTheme::theme()->scrollbarThickness();
- style->setWidth(Length(width, Fixed));
- style->setMinWidth(Length(width, Fixed));
-}
-
-bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
-{
- IntRect half = rect;
-
- // Need explicit blocks to avoid to create multiple ThemePainter instances.
- {
- half.setHeight(rect.height() / 2);
- const ThemeData& upThemeData = getThemeData(object, SpinButtonUp);
- ThemePainter upPainter(info.context, half);
- PlatformSupport::paintSpinButton(upPainter.context(),
- upThemeData.m_part,
- upThemeData.m_state,
- upThemeData.m_classicState,
- upPainter.drawRect());
- }
-
- {
- half.setY(rect.y() + rect.height() / 2);
- const ThemeData& downThemeData = getThemeData(object, SpinButtonDown);
- ThemePainter downPainter(info.context, half);
- PlatformSupport::paintSpinButton(downPainter.context(),
- downThemeData.m_part,
- downThemeData.m_state,
- downThemeData.m_classicState,
- downPainter.drawRect());
- }
- return false;
-}
-
-#if ENABLE(PROGRESS_ELEMENT)
-
-// MSDN says that update intervals for the bar is 30ms.
-// http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx
-static const double progressAnimationFrameRate = 0.033;
-
-double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const
-{
- return progressAnimationFrameRate;
-}
-
-double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const
-{
- // On Chromium Windows port, animationProgress() and associated values aren't used.
- // So here we can return arbitrary positive value.
- return progressAnimationFrameRate;
-}
-
-void RenderThemeChromiumWin::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const
-{
-}
-
-bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r)
-{
- if (!o->isProgress())
- return true;
-
- RenderProgress* renderProgress = toRenderProgress(o);
- // For indeterminate bar, valueRect is ignored and it is computed by the theme engine
- // because the animation is a platform detail and WebKit doesn't need to know how.
- IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0);
- double animatedSeconds = renderProgress->animationStartTime() ? WTF::currentTime() - renderProgress->animationStartTime() : 0;
- ThemePainter painter(i.context, r);
- DirectionFlippingScope scope(o, i, r);
- PlatformSupport::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds);
- return false;
-}
-
-#endif
-
-bool RenderThemeChromiumWin::shouldOpenPickerWithF4Key() const
-{
- return true;
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.h b/Source/WebCore/rendering/RenderThemeChromiumWin.h
deleted file mode 100644
index bf335c7b8..000000000
--- a/Source/WebCore/rendering/RenderThemeChromiumWin.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * This file is part of the WebKit project.
- *
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderThemeChromiumWin_h
-#define RenderThemeChromiumWin_h
-
-#include "RenderThemeChromiumSkia.h"
-
-#if WIN32
-typedef void* HANDLE;
-typedef struct HINSTANCE__* HINSTANCE;
-typedef HINSTANCE HMODULE;
-#endif
-
-namespace WebCore {
-
- struct ThemeData {
- ThemeData() : m_part(0), m_state(0), m_classicState(0) {}
-
- unsigned m_part;
- unsigned m_state;
- unsigned m_classicState;
- };
-
- class RenderThemeChromiumWin : public RenderThemeChromiumSkia {
- public:
- static PassRefPtr<RenderTheme> create();
-
- // A method asking if the theme is able to draw the focus ring.
- virtual bool supportsFocusRing(const RenderStyle*) const;
-
- // The platform selection color.
- virtual Color platformActiveSelectionBackgroundColor() const;
- virtual Color platformInactiveSelectionBackgroundColor() const;
- virtual Color platformActiveSelectionForegroundColor() const;
- virtual Color platformInactiveSelectionForegroundColor() const;
- virtual Color platformActiveTextSearchHighlightColor() const;
- virtual Color platformInactiveTextSearchHighlightColor() const;
-
- virtual Color systemColor(int cssValueId) const;
-
-#if ENABLE(DATALIST_ELEMENT)
- virtual IntSize sliderTickSize() const OVERRIDE;
- virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE;
-#endif
- virtual void adjustSliderThumbSize(RenderStyle*, Element*) const;
-
- // Various paint functions.
- virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
-
- // MenuList refers to an unstyled menulist (meaning a menulist without
- // background-color or border set) and MenuListButton refers to a styled
- // menulist (a menulist with background-color or border set). They have
- // this distinction to support showing aqua style themes whenever they
- // possibly can, which is something we don't want to replicate.
- //
- // In short, we either go down the MenuList code path or the MenuListButton
- // codepath. We never go down both. And in both cases, they render the
- // entire menulist.
- virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&);
-
-#if ENABLE(PROGRESS_ELEMENT)
- virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const;
- virtual double animationDurationForProgressBar(RenderProgress*) const;
- virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
-#endif
-
- virtual bool shouldOpenPickerWithF4Key() const OVERRIDE;
-
- protected:
- virtual double caretBlinkIntervalInternal() const;
-
- private:
- enum ControlSubPart {
- None,
- SpinButtonDown,
- SpinButtonUp,
- };
-
- RenderThemeChromiumWin() { }
- virtual ~RenderThemeChromiumWin() { }
-
- unsigned determineState(RenderObject*, ControlSubPart = None);
- unsigned determineSliderThumbState(RenderObject*);
- unsigned determineClassicState(RenderObject*, ControlSubPart = None);
-
- ThemeData getThemeData(RenderObject*, ControlSubPart = None);
-
- bool paintTextFieldInternal(RenderObject*, const PaintInfo&, const IntRect&, bool);
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h
index 03d809ed6..a3cefee7e 100644
--- a/Source/WebCore/rendering/RenderThemeMac.h
+++ b/Source/WebCore/rendering/RenderThemeMac.h
@@ -23,19 +23,83 @@
#ifndef RenderThemeMac_h
#define RenderThemeMac_h
-#import "RenderThemeMacShared.h"
+#import "RenderTheme.h"
#import <wtf/RetainPtr.h>
+#import <wtf/HashMap.h>
+
+OBJC_CLASS WebCoreRenderThemeNotificationObserver;
namespace WebCore {
class RenderProgress;
class RenderStyle;
-class RenderThemeMac : public RenderThemeMacShared {
+class RenderThemeMac : public RenderTheme {
public:
static PassRefPtr<RenderTheme> create();
- virtual NSView* documentViewFor(RenderObject*) const;
+ // A method asking if the control changes its tint when the window has focus or not.
+ virtual bool controlSupportsTints(const RenderObject*) const;
+
+ // A general method asking if any control tinting is supported at all.
+ virtual bool supportsControlTints() const { return true; }
+
+ virtual void adjustRepaintRect(const RenderObject*, IntRect&) OVERRIDE;
+
+ virtual bool isControlStyled(const RenderStyle*, const BorderData&, const FillLayer&, const Color& backgroundColor) const;
+
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveListBoxSelectionBackgroundColor() const;
+ virtual Color platformActiveListBoxSelectionForegroundColor() const;
+ virtual Color platformInactiveListBoxSelectionBackgroundColor() const;
+ virtual Color platformInactiveListBoxSelectionForegroundColor() const;
+ virtual Color platformFocusRingColor() const;
+
+ virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; }
+
+ virtual void platformColorsDidChange();
+
+ // System fonts.
+ virtual void systemFont(CSSValueID, FontDescription&) const;
+
+ virtual int minimumMenuListSize(RenderStyle*) const;
+
+ virtual void adjustSliderThumbSize(RenderStyle*, Element*) const;
+
+#if ENABLE(DATALIST_ELEMENT)
+ virtual IntSize sliderTickSize() const OVERRIDE;
+ virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE;
+#endif
+
+ virtual int popupInternalPaddingLeft(RenderStyle*) const;
+ virtual int popupInternalPaddingRight(RenderStyle*) const;
+ virtual int popupInternalPaddingTop(RenderStyle*) const;
+ virtual int popupInternalPaddingBottom(RenderStyle*) const;
+
+ virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE;
+
+ virtual bool popsMenuByArrowKeys() const OVERRIDE { return true; }
+
+#if ENABLE(METER_ELEMENT)
+ virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE;
+ virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool supportsMeter(ControlPart) const;
+#endif
+
+#if ENABLE(PROGRESS_ELEMENT)
+ // Returns the repeat interval of the animation for the progress bar.
+ virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const;
+ // Returns the duration of the animation for the progress bar.
+ virtual double animationDurationForProgressBar(RenderProgress*) const;
+#endif
+
+ virtual Color systemColor(CSSValueID) const;
+ // Controls color values returned from platformFocusRingColor(). systemColor() will be used when false.
+ virtual bool usesTestModeFocusRingColor() const;
+ // A view associated to the contained document. Subclasses may not have such a view and return a fake.
+ NSView* documentViewFor(RenderObject*) const;
+
protected:
RenderThemeMac();
@@ -51,7 +115,6 @@ protected:
virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaRewindButton(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaControlsBackground(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaCurrentTime(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaTimeRemaining(RenderObject*, const PaintInfo&, const IntRect&);
@@ -73,6 +136,125 @@ protected:
virtual void adjustMediaSliderThumbSize(RenderStyle*) const;
virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE;
#endif
+ virtual bool supportsSelectionForegroundColors() const { return false; }
+
+ virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+ virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+ virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+ virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+#if ENABLE(PROGRESS_ELEMENT)
+ virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const;
+ virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
+#endif
+
+ virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+ virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+ virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const;
+
+ virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&);
+
+#if ENABLE(VIDEO)
+ virtual bool supportsClosedCaptioning() const { return true; }
+#endif
+
+ virtual bool shouldShowPlaceholderWhenFocused() const;
+
+ virtual bool paintSnapshottedPluginOverlay(RenderObject*, const PaintInfo&, const IntRect&);
+
+private:
+ virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const OVERRIDE;
+
+ IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const;
+
+ FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect&) const;
+
+ // Get the control size based off the font. Used by some of the controls (like buttons).
+ NSControlSize controlSizeForFont(RenderStyle*) const;
+ NSControlSize controlSizeForSystemFont(RenderStyle*) const;
+ void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f);
+ void setSizeFromFont(RenderStyle*, const IntSize* sizes) const;
+ IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const;
+ IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const;
+ void setFontFromControlSize(StyleResolver*, RenderStyle*, NSControlSize) const;
+
+ void updateCheckedState(NSCell*, const RenderObject*);
+ void updateEnabledState(NSCell*, const RenderObject*);
+ void updateFocusedState(NSCell*, const RenderObject*);
+ void updatePressedState(NSCell*, const RenderObject*);
+ // An optional hook for subclasses to update the control tint of NSCell.
+ virtual void updateActiveState(NSCell*, const RenderObject*) { }
+
+ // Helpers for adjusting appearance and for painting
+
+ void setPopupButtonCellState(const RenderObject*, const IntRect&);
+ const IntSize* popupButtonSizes() const;
+ const int* popupButtonMargins() const;
+ const int* popupButtonPadding(NSControlSize) const;
+ void paintMenuListButtonGradients(RenderObject*, const PaintInfo&, const IntRect&);
+ const IntSize* menuListSizes() const;
+
+ const IntSize* searchFieldSizes() const;
+ const IntSize* cancelButtonSizes() const;
+ const IntSize* resultsButtonSizes() const;
+ void setSearchCellState(RenderObject*, const IntRect&);
+ void setSearchFieldSize(RenderStyle*) const;
+
+ NSPopUpButtonCell* popupButton() const;
+ NSSearchFieldCell* search() const;
+ NSMenu* searchMenuTemplate() const;
+ NSSliderCell* sliderThumbHorizontal() const;
+ NSSliderCell* sliderThumbVertical() const;
+ NSTextFieldCell* textField() const;
+
+#if ENABLE(METER_ELEMENT)
+ NSLevelIndicatorStyle levelIndicatorStyleFor(ControlPart) const;
+ NSLevelIndicatorCell* levelIndicatorFor(const RenderMeter*) const;
+#endif
+
+#if ENABLE(PROGRESS_ELEMENT)
+ int minimumProgressBarHeight(RenderStyle*) const;
+ const IntSize* progressBarSizes() const;
+ const int* progressBarMargins(NSControlSize) const;
+#endif
+
+private:
+ mutable RetainPtr<NSPopUpButtonCell> m_popupButton;
+ mutable RetainPtr<NSSearchFieldCell> m_search;
+ mutable RetainPtr<NSMenu> m_searchMenuTemplate;
+ mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal;
+ mutable RetainPtr<NSSliderCell> m_sliderThumbVertical;
+ mutable RetainPtr<NSLevelIndicatorCell> m_levelIndicator;
+ mutable RetainPtr<NSTextFieldCell> m_textField;
+
+ bool m_isSliderThumbHorizontalPressed;
+ bool m_isSliderThumbVerticalPressed;
+
+ mutable HashMap<int, RGBA32> m_systemColorCache;
+
+ RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm
index fadd09011..3a8c2868f 100644
--- a/Source/WebCore/rendering/RenderThemeMac.mm
+++ b/Source/WebCore/rendering/RenderThemeMac.mm
@@ -20,27 +20,134 @@
#import "config.h"
#import "RenderThemeMac.h"
+#import "BitmapImage.h"
+#import "CSSValueKeywords.h"
+#import "CSSValueList.h"
+#import "ColorMac.h"
+#import "Document.h"
#import "Element.h"
+#import "ExceptionCodePlaceholder.h"
+#import "FileList.h"
+#import "FrameView.h"
#import "GraphicsContextCG.h"
+#import "HTMLAudioElement.h"
+#import "HTMLInputElement.h"
#import "HTMLMediaElement.h"
+#import "HTMLNames.h"
+#import "HTMLPlugInImageElement.h"
+#import "Image.h"
+#import "ImageBuffer.h"
#import "LocalCurrentGraphicsContext.h"
+#import "LocalizedStrings.h"
#import "MediaControlElements.h"
#import "PaintInfo.h"
+#import "RenderLayer.h"
#import "RenderMedia.h"
+#import "RenderMediaControlElements.h"
#import "RenderMediaControls.h"
+#import "RenderProgress.h"
+#import "RenderSlider.h"
+#import "RenderSnapshottedPlugIn.h"
#import "RenderView.h"
-#import "TimeRanges.h"
+#import "SharedBuffer.h"
+#import "StringTruncator.h"
+#import "StyleResolver.h"
#import "ThemeMac.h"
-#import "WebCoreSystemInterface.h"
+#import "TimeRanges.h"
#import "UserAgentStyleSheets.h"
+#import "WebCoreNSCellExtras.h"
+#import "WebCoreSystemInterface.h"
+#import <wtf/RetainPtr.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/StdLibExtras.h>
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
-#import <wtf/RetainPtr.h>
+#import <math.h>
+
+#if ENABLE(METER_ELEMENT)
+#include "RenderMeter.h"
+#include "HTMLMeterElement.h"
+#endif
+
+using namespace std;
+
+// The methods in this file are specific to the Mac OS X platform.
+
+// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
+
+// We estimate the animation rate of a Mac OS X progress bar is 33 fps.
+// Hard code the value here because we haven't found API for it.
+const double progressAnimationFrameRate = 0.033;
+
+// Mac OS X progress bar animation seems to have 256 frames.
+const double progressAnimationNumFrames = 256;
+
+@interface WebCoreRenderThemeNotificationObserver : NSObject
+{
+ WebCore::RenderTheme *_theme;
+}
+
+- (id)initWithTheme:(WebCore::RenderTheme *)theme;
+- (void)systemColorsDidChange:(NSNotification *)notification;
+
+@end
+
+@implementation WebCoreRenderThemeNotificationObserver
+
+- (id)initWithTheme:(WebCore::RenderTheme *)theme
+{
+ if (!(self = [super init]))
+ return nil;
+
+ _theme = theme;
+ return self;
+}
+
+- (void)systemColorsDidChange:(NSNotification *)unusedNotification
+{
+ ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
+ _theme->platformColorsDidChange();
+}
+
+@end
+
+@interface NSTextFieldCell (WKDetails)
+- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
+@end
+
+
+@interface WebCoreTextFieldCell : NSTextFieldCell
+- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
+@end
+
+@implementation WebCoreTextFieldCell
+- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
+{
+ // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
+ CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
+ CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
+ return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
+}
+@end
namespace WebCore {
using namespace HTMLNames;
+enum {
+ topMargin,
+ rightMargin,
+ bottomMargin,
+ leftMargin
+};
+
+enum {
+ topPadding,
+ rightPadding,
+ bottomPadding,
+ leftPadding
+};
+
PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
{
static RenderTheme* rt = RenderThemeMac::create().leakRef();
@@ -53,11 +160,19 @@ PassRefPtr<RenderTheme> RenderThemeMac::create()
}
RenderThemeMac::RenderThemeMac()
+ : m_isSliderThumbHorizontalPressed(false)
+ , m_isSliderThumbVerticalPressed(false)
+ , m_notificationObserver(adoptNS([[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]))
{
+ [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
+ selector:@selector(systemColorsDidChange:)
+ name:NSSystemColorsDidChangeNotification
+ object:nil];
}
RenderThemeMac::~RenderThemeMac()
{
+ [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
}
NSView* RenderThemeMac::documentViewFor(RenderObject* o) const
@@ -136,9 +251,9 @@ static unsigned getMediaUIPartStateFlags(Node* node)
{
unsigned flags = 0;
- if (node->disabled())
+ if (isDisabledFormControl(node))
flags |= MediaUIPartDisabledFlag;
- else if (node->active())
+ else if (node->isElementNode() && toElement(node)->active())
flags |= MediaUIPartPressedFlag;
return flags;
}
@@ -175,7 +290,7 @@ bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const PaintInfo& pain
{
Node* node = o->node();
Node* mediaNode = node ? node->shadowHost() : 0;
- if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
+ if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !isHTMLAudioElement(mediaNode)))
return false;
if (node->isMediaControlElement()) {
@@ -189,7 +304,7 @@ bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const PaintInfo& pain
{
Node* node = o->node();
Node* mediaNode = node ? node->shadowHost() : 0;
- if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
+ if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !isHTMLAudioElement(mediaNode)))
return false;
if (node->isMediaControlElement()) {
@@ -228,16 +343,15 @@ bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pai
if (!mediaNode || !mediaNode->isMediaElement())
return false;
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
+ HTMLMediaElement* mediaElement = toHTMLMediaElement(mediaNode);
if (!mediaElement)
return false;
RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
- ExceptionCode ignoredException;
- float timeLoaded = timeRanges->length() ? timeRanges->end(0, ignoredException) : 0;
+ float timeLoaded = timeRanges->length() ? timeRanges->end(0, IGNORE_EXCEPTION) : 0;
float currentTime = mediaElement->currentTime();
float duration = mediaElement->duration();
- if (isnan(duration))
+ if (std::isnan(duration))
duration = 0;
ContextContainer cgContextContainer(paintInfo.context);
@@ -282,19 +396,6 @@ bool RenderThemeMac::paintMediaReturnToRealtimeButton(RenderObject* o, const Pai
return false;
}
-bool RenderThemeMac::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- Node* node = o->node();
- if (!node)
- return false;
- if (!node->isMediaControlElement())
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(mediaControlElementType(node), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node));
- return false;
-}
-
bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
Node* node = o->node();
@@ -430,4 +531,1752 @@ IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonB
#endif // ENABLE(VIDEO)
+Color RenderThemeMac::platformActiveSelectionBackgroundColor() const
+{
+ NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
+}
+
+Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const
+{
+ NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
+}
+
+Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const
+{
+ NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
+}
+
+Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const
+{
+ return Color::white;
+}
+
+Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const
+{
+ return Color::black;
+}
+
+Color RenderThemeMac::platformFocusRingColor() const
+{
+ if (usesTestModeFocusRingColor())
+ return oldAquaFocusRingColor();
+
+ return systemColor(CSSValueWebkitFocusRingColor);
+}
+
+Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const
+{
+ return platformInactiveSelectionBackgroundColor();
+}
+
+static FontWeight toFontWeight(NSInteger appKitFontWeight)
+{
+ ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
+ if (appKitFontWeight > 14)
+ appKitFontWeight = 14;
+ else if (appKitFontWeight < 1)
+ appKitFontWeight = 1;
+
+ static FontWeight fontWeights[] = {
+ FontWeight100,
+ FontWeight100,
+ FontWeight200,
+ FontWeight300,
+ FontWeight400,
+ FontWeight500,
+ FontWeight600,
+ FontWeight600,
+ FontWeight700,
+ FontWeight800,
+ FontWeight800,
+ FontWeight900,
+ FontWeight900,
+ FontWeight900
+ };
+ return fontWeights[appKitFontWeight - 1];
+}
+
+void RenderThemeMac::systemFont(CSSValueID cssValueId, FontDescription& fontDescription) const
+{
+ DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
+
+ FontDescription* cachedDesc;
+ NSFont* font = nil;
+ switch (cssValueId) {
+ case CSSValueSmallCaption:
+ cachedDesc = &smallSystemFont;
+ if (!smallSystemFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ break;
+ case CSSValueMenu:
+ cachedDesc = &menuFont;
+ if (!menuFont.isAbsoluteSize())
+ font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
+ break;
+ case CSSValueStatusBar:
+ cachedDesc = &labelFont;
+ if (!labelFont.isAbsoluteSize())
+ font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
+ break;
+ case CSSValueWebkitMiniControl:
+ cachedDesc = &miniControlFont;
+ if (!miniControlFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
+ break;
+ case CSSValueWebkitSmallControl:
+ cachedDesc = &smallControlFont;
+ if (!smallControlFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
+ break;
+ case CSSValueWebkitControl:
+ cachedDesc = &controlFont;
+ if (!controlFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ break;
+ default:
+ cachedDesc = &systemFont;
+ if (!systemFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
+ }
+
+ if (font) {
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ cachedDesc->setIsAbsoluteSize(true);
+ cachedDesc->setGenericFamily(FontDescription::NoFamily);
+ cachedDesc->setOneFamily([font webCoreFamilyName]);
+ cachedDesc->setSpecifiedSize([font pointSize]);
+ cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font]));
+ cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
+ }
+ fontDescription = *cachedDesc;
+}
+
+static RGBA32 convertNSColorToColor(NSColor *color)
+{
+ NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ if (colorInColorSpace) {
+ static const double scaleFactor = nextafter(256.0, 0.0);
+ return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
+ static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
+ static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
+ }
+
+ // This conversion above can fail if the NSColor in question is an NSPatternColor
+ // (as many system colors are). These colors are actually a repeating pattern
+ // not just a solid color. To work around this we simply draw a 1x1 image of
+ // the color and use that pixel's color. It might be better to use an average of
+ // the colors in the pattern instead.
+ NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
+ pixelsWide:1
+ pixelsHigh:1
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:4
+ bitsPerPixel:32];
+
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
+ NSEraseRect(NSMakeRect(0, 0, 1, 1));
+ [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
+ [NSGraphicsContext restoreGraphicsState];
+
+ NSUInteger pixel[4];
+ [offscreenRep getPixel:pixel atX:0 y:0];
+
+ [offscreenRep release];
+
+ return makeRGB(pixel[0], pixel[1], pixel[2]);
+}
+
+static RGBA32 menuBackgroundColor()
+{
+ NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
+ pixelsWide:1
+ pixelsHigh:1
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:4
+ bitsPerPixel:32];
+
+ CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
+ CGRect rect = CGRectMake(0, 0, 1, 1);
+ HIThemeMenuDrawInfo drawInfo;
+ drawInfo.version = 0;
+ drawInfo.menuType = kThemeMenuTypePopUp;
+ HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
+
+ NSUInteger pixel[4];
+ [offscreenRep getPixel:pixel atX:0 y:0];
+
+ [offscreenRep release];
+
+ return makeRGB(pixel[0], pixel[1], pixel[2]);
+}
+
+void RenderThemeMac::platformColorsDidChange()
+{
+ m_systemColorCache.clear();
+ RenderTheme::platformColorsDidChange();
+}
+
+Color RenderThemeMac::systemColor(CSSValueID cssValueId) const
+{
+ {
+ HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
+ if (it != m_systemColorCache.end())
+ return it->value;
+ }
+
+ Color color;
+ switch (cssValueId) {
+ case CSSValueActiveborder:
+ color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
+ break;
+ case CSSValueActivecaption:
+ color = convertNSColorToColor([NSColor windowFrameTextColor]);
+ break;
+ case CSSValueAppworkspace:
+ color = convertNSColorToColor([NSColor headerColor]);
+ break;
+ case CSSValueBackground:
+ // Use theme independent default
+ break;
+ case CSSValueButtonface:
+ // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
+ // We may want to change this to use the NSColor in future.
+ color = 0xFFC0C0C0;
+ break;
+ case CSSValueButtonhighlight:
+ color = convertNSColorToColor([NSColor controlHighlightColor]);
+ break;
+ case CSSValueButtonshadow:
+ color = convertNSColorToColor([NSColor controlShadowColor]);
+ break;
+ case CSSValueButtontext:
+ color = convertNSColorToColor([NSColor controlTextColor]);
+ break;
+ case CSSValueCaptiontext:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueGraytext:
+ color = convertNSColorToColor([NSColor disabledControlTextColor]);
+ break;
+ case CSSValueHighlight:
+ color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
+ break;
+ case CSSValueHighlighttext:
+ color = convertNSColorToColor([NSColor selectedTextColor]);
+ break;
+ case CSSValueInactiveborder:
+ color = convertNSColorToColor([NSColor controlBackgroundColor]);
+ break;
+ case CSSValueInactivecaption:
+ color = convertNSColorToColor([NSColor controlBackgroundColor]);
+ break;
+ case CSSValueInactivecaptiontext:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueInfobackground:
+ // There is no corresponding NSColor for this so we use a hard coded value.
+ color = 0xFFFBFCC5;
+ break;
+ case CSSValueInfotext:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueMenu:
+ color = menuBackgroundColor();
+ break;
+ case CSSValueMenutext:
+ color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
+ break;
+ case CSSValueScrollbar:
+ color = convertNSColorToColor([NSColor scrollBarColor]);
+ break;
+ case CSSValueText:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueThreeddarkshadow:
+ color = convertNSColorToColor([NSColor controlDarkShadowColor]);
+ break;
+ case CSSValueThreedshadow:
+ color = convertNSColorToColor([NSColor shadowColor]);
+ break;
+ case CSSValueThreedface:
+ // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
+ // We may want to change this to use the NSColor in future.
+ color = 0xFFC0C0C0;
+ break;
+ case CSSValueThreedhighlight:
+ color = convertNSColorToColor([NSColor highlightColor]);
+ break;
+ case CSSValueThreedlightshadow:
+ color = convertNSColorToColor([NSColor controlLightHighlightColor]);
+ break;
+ case CSSValueWebkitFocusRingColor:
+ color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
+ break;
+ case CSSValueWindow:
+ color = convertNSColorToColor([NSColor windowBackgroundColor]);
+ break;
+ case CSSValueWindowframe:
+ color = convertNSColorToColor([NSColor windowFrameColor]);
+ break;
+ case CSSValueWindowtext:
+ color = convertNSColorToColor([NSColor windowFrameTextColor]);
+ break;
+ default:
+ break;
+ }
+
+ if (!color.isValid())
+ color = RenderTheme::systemColor(cssValueId);
+
+ if (color.isValid())
+ m_systemColorCache.set(cssValueId, color.rgb());
+
+ return color;
+}
+
+bool RenderThemeMac::usesTestModeFocusRingColor() const
+{
+ return WebCore::usesTestModeFocusRingColor();
+}
+
+bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border,
+ const FillLayer& background, const Color& backgroundColor) const
+{
+ if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
+ return style->border() != border;
+
+ // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when
+ // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style
+ // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming
+ // is in effect we treat it like the control is styled.
+ if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f)
+ return true;
+
+ return RenderTheme::isControlStyled(style, border, background, backgroundColor);
+}
+
+void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r)
+{
+ ControlPart part = o->style()->appearance();
+
+#if USE(NEW_THEME)
+ switch (part) {
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case InnerSpinButtonPart:
+ return RenderTheme::adjustRepaintRect(o, r);
+ default:
+ break;
+ }
+#endif
+
+ float zoomLevel = o->style()->effectiveZoom();
+
+ if (part == MenulistPart) {
+ setPopupButtonCellState(o, r);
+ IntSize size = popupButtonSizes()[[popupButton() controlSize]];
+ size.setHeight(size.height() * zoomLevel);
+ size.setWidth(r.width());
+ r = inflateRect(r, size, popupButtonMargins(), zoomLevel);
+ }
+}
+
+IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const
+{
+ // Only do the inflation if the available width/height are too small. Otherwise try to
+ // fit the glow/check space into the available box's width/height.
+ int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
+ int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
+ IntRect result(r);
+ if (widthDelta < 0) {
+ result.setX(result.x() - margins[leftMargin] * zoomLevel);
+ result.setWidth(result.width() - widthDelta);
+ }
+ if (heightDelta < 0) {
+ result.setY(result.y() - margins[topMargin] * zoomLevel);
+ result.setHeight(result.height() - heightDelta);
+ }
+ return result;
+}
+
+FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const
+{
+ FloatRect partRect(inputRect);
+
+ // Compute an offset between the part renderer and the input renderer
+ FloatSize offsetFromInputRenderer;
+ const RenderObject* renderer = partRenderer;
+ while (renderer && renderer != inputRenderer) {
+ RenderObject* containingRenderer = renderer->container();
+ offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint()));
+ renderer = containingRenderer;
+ }
+ // If the input renderer was not a container, something went wrong
+ ASSERT(renderer == inputRenderer);
+ // Move the rect into partRenderer's coords
+ partRect.move(offsetFromInputRenderer);
+ // Account for the local drawing offset (tx, ty)
+ partRect.move(r.x(), r.y());
+
+ return partRect;
+}
+
+void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject* o)
+{
+ bool oldIndeterminate = [cell state] == NSMixedState;
+ bool indeterminate = isIndeterminate(o);
+ bool checked = isChecked(o);
+
+ if (oldIndeterminate != indeterminate) {
+ [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
+ return;
+ }
+
+ bool oldChecked = [cell state] == NSOnState;
+ if (checked != oldChecked)
+ [cell setState:checked ? NSOnState : NSOffState];
+}
+
+void RenderThemeMac::updateEnabledState(NSCell* cell, const RenderObject* o)
+{
+ bool oldEnabled = [cell isEnabled];
+ bool enabled = isEnabled(o);
+ if (enabled != oldEnabled)
+ [cell setEnabled:enabled];
+}
+
+void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o)
+{
+ bool oldFocused = [cell showsFirstResponder];
+ bool focused = isFocused(o) && o->style()->outlineStyleIsAuto();
+ if (focused != oldFocused)
+ [cell setShowsFirstResponder:focused];
+}
+
+void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o)
+{
+ bool oldPressed = [cell isHighlighted];
+ bool pressed = o->node() && o->node()->isElementNode() && toElement(o->node())->active();
+ if (pressed != oldPressed)
+ [cell setHighlighted:pressed];
+}
+
+bool RenderThemeMac::controlSupportsTints(const RenderObject* o) const
+{
+ // An alternate way to implement this would be to get the appropriate cell object
+ // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
+ // that would be that we would match AppKit behavior more closely, but a disadvantage
+ // would be that we would rely on an AppKit SPI method.
+
+ if (!isEnabled(o))
+ return false;
+
+ // Checkboxes only have tint when checked.
+ if (o->style()->appearance() == CheckboxPart)
+ return isChecked(o);
+
+ // For now assume other controls have tint if enabled.
+ return true;
+}
+
+NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const
+{
+ int fontSize = style->fontSize();
+ if (fontSize >= 16)
+ return NSRegularControlSize;
+ if (fontSize >= 11)
+ return NSSmallControlSize;
+ return NSMiniControlSize;
+}
+
+void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
+{
+ NSControlSize size;
+ if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) &&
+ minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
+ size = NSRegularControlSize;
+ else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) &&
+ minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
+ size = NSSmallControlSize;
+ else
+ size = NSMiniControlSize;
+ if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
+ [cell setControlSize:size];
+}
+
+IntSize RenderThemeMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const
+{
+ if (style->effectiveZoom() != 1.0f) {
+ IntSize result = sizes[controlSizeForFont(style)];
+ return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
+ }
+ return sizes[controlSizeForFont(style)];
+}
+
+IntSize RenderThemeMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
+{
+ if (style->effectiveZoom() != 1.0f) {
+ IntSize result = sizes[controlSizeForSystemFont(style)];
+ return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
+ }
+ return sizes[controlSizeForSystemFont(style)];
+}
+
+void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
+{
+ // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
+ IntSize size = sizeForFont(style, sizes);
+ if (style->width().isIntrinsicOrAuto() && size.width() > 0)
+ style->setWidth(Length(size.width(), Fixed));
+ if (style->height().isAuto() && size.height() > 0)
+ style->setHeight(Length(size.height(), Fixed));
+}
+
+void RenderThemeMac::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const
+{
+ FontDescription fontDescription;
+ fontDescription.setIsAbsoluteSize(true);
+ fontDescription.setGenericFamily(FontDescription::SerifFamily);
+
+ NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
+ fontDescription.setOneFamily([font webCoreFamilyName]);
+ fontDescription.setComputedSize([font pointSize] * style->effectiveZoom());
+ fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom());
+
+ // Reset line height
+ style->setLineHeight(RenderStyle::initialLineHeight());
+
+ if (style->setFontDescription(fontDescription))
+ style->font().update(0);
+}
+
+NSControlSize RenderThemeMac::controlSizeForSystemFont(RenderStyle* style) const
+{
+ int fontSize = style->fontSize();
+ if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
+ return NSRegularControlSize;
+ if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
+ return NSSmallControlSize;
+ return NSMiniControlSize;
+}
+
+bool RenderThemeMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
+ bool useNSTextFieldCell = o->style()->hasAppearance()
+ && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white
+ && !o->style()->hasBackgroundImage();
+
+ // We do not use NSTextFieldCell to draw styled text fields on Lion and SnowLeopard because
+ // there are a number of bugs on those platforms that require NSTextFieldCell to be in charge
+ // of painting its own background. We need WebCore to paint styled backgrounds, so we'll use
+ // this WebCoreSystemInterface function instead.
+ if (!useNSTextFieldCell) {
+ wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o));
+ return false;
+ }
+#endif
+
+ NSTextFieldCell *textField = this->textField();
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
+ [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
+
+ [textField setControlView:nil];
+
+ return false;
+}
+
+void RenderThemeMac::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const
+{
+}
+
+bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r)
+{
+ if (paintInfo.context->paintingDisabled())
+ return true;
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ wkDrawCapsLockIndicator(localContext.cgContext(), r);
+
+ return false;
+}
+
+bool RenderThemeMac::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
+ return false;
+}
+
+void RenderThemeMac::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
+{
+}
+
+const int* RenderThemeMac::popupButtonMargins() const
+{
+ static const int margins[3][4] =
+ {
+ { 0, 3, 1, 3 },
+ { 0, 3, 2, 3 },
+ { 0, 1, 0, 1 }
+ };
+ return margins[[popupButton() controlSize]];
+}
+
+const IntSize* RenderThemeMac::popupButtonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
+ return sizes;
+}
+
+const int* RenderThemeMac::popupButtonPadding(NSControlSize size) const
+{
+ static const int padding[3][4] =
+ {
+ { 2, 26, 3, 8 },
+ { 2, 23, 3, 8 },
+ { 2, 22, 3, 10 }
+ };
+ return padding[size];
+}
+
+bool RenderThemeMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ setPopupButtonCellState(o, r);
+
+ NSPopUpButtonCell* popupButton = this->popupButton();
+
+ float zoomLevel = o->style()->effectiveZoom();
+ IntSize size = popupButtonSizes()[[popupButton controlSize]];
+ size.setHeight(size.height() * zoomLevel);
+ size.setWidth(r.width());
+
+ // Now inflate it to account for the shadow.
+ IntRect inflatedRect = r;
+ if (r.width() >= minimumMenuListSize(o->style()))
+ inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel);
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
+ paintInfo.context->clip(inflatedRect);
+
+ if (zoomLevel != 1.0f) {
+ inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
+ inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
+ paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
+ paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
+ paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
+ }
+
+ NSView *view = documentViewFor(o);
+ [popupButton drawWithFrame:inflatedRect inView:view];
+#if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
+ if (isFocused(o) && o->style()->outlineStyleIsAuto())
+ [popupButton _web_drawFocusRingWithFrame:inflatedRect inView:view];
+#endif
+ [popupButton setControlView:nil];
+
+ return false;
+}
+
+#if ENABLE(METER_ELEMENT)
+
+IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const
+{
+ if (NoControlPart == renderMeter->style()->appearance())
+ return bounds.size();
+
+ NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
+ // Makes enough room for cell's intrinsic size.
+ NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
+ return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
+ bounds.height() < cellSize.height ? cellSize.height : bounds.height());
+}
+
+bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!renderObject->isMeter())
+ return true;
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+
+ NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
+ [cell setControlView:nil];
+ return false;
+}
+
+bool RenderThemeMac::supportsMeter(ControlPart part) const
+{
+ switch (part) {
+ case RelevancyLevelIndicatorPart:
+ case DiscreteCapacityLevelIndicatorPart:
+ case RatingLevelIndicatorPart:
+ case MeterPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ return true;
+ default:
+ return false;
+ }
+}
+
+NSLevelIndicatorStyle RenderThemeMac::levelIndicatorStyleFor(ControlPart part) const
+{
+ switch (part) {
+ case RelevancyLevelIndicatorPart:
+ return NSRelevancyLevelIndicatorStyle;
+ case DiscreteCapacityLevelIndicatorPart:
+ return NSDiscreteCapacityLevelIndicatorStyle;
+ case RatingLevelIndicatorPart:
+ return NSRatingLevelIndicatorStyle;
+ case MeterPart:
+ case ContinuousCapacityLevelIndicatorPart:
+ default:
+ return NSContinuousCapacityLevelIndicatorStyle;
+ }
+
+}
+
+NSLevelIndicatorCell* RenderThemeMac::levelIndicatorFor(const RenderMeter* renderMeter) const
+{
+ RenderStyle* style = renderMeter->style();
+ ASSERT(style->appearance() != NoControlPart);
+
+ if (!m_levelIndicator)
+ m_levelIndicator = adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
+ NSLevelIndicatorCell* cell = m_levelIndicator.get();
+
+ HTMLMeterElement* element = renderMeter->meterElement();
+ double value = element->value();
+
+ // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
+ // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
+ switch (element->gaugeRegion()) {
+ case HTMLMeterElement::GaugeRegionOptimum:
+ // Make meter the green
+ [cell setWarningValue:value + 1];
+ [cell setCriticalValue:value + 2];
+ break;
+ case HTMLMeterElement::GaugeRegionSuboptimal:
+ // Make the meter yellow
+ [cell setWarningValue:value - 1];
+ [cell setCriticalValue:value + 1];
+ break;
+ case HTMLMeterElement::GaugeRegionEvenLessGood:
+ // Make the meter red
+ [cell setWarningValue:value - 2];
+ [cell setCriticalValue:value - 1];
+ break;
+ }
+
+ [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
+ [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
+ [cell setMinValue:element->min()];
+ [cell setMaxValue:element->max()];
+ RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
+ [cell setObjectValue:valueObject.get()];
+
+ return cell;
+}
+
+#endif
+
+#if ENABLE(PROGRESS_ELEMENT)
+const IntSize* RenderThemeMac::progressBarSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
+ return sizes;
+}
+
+const int* RenderThemeMac::progressBarMargins(NSControlSize controlSize) const
+{
+ static const int margins[3][4] =
+ {
+ { 0, 0, 1, 0 },
+ { 0, 0, 1, 0 },
+ { 0, 0, 1, 0 },
+ };
+ return margins[controlSize];
+}
+
+int RenderThemeMac::minimumProgressBarHeight(RenderStyle* style) const
+{
+ return sizeForSystemFont(style, progressBarSizes()).height();
+}
+
+double RenderThemeMac::animationRepeatIntervalForProgressBar(RenderProgress*) const
+{
+ return progressAnimationFrameRate;
+}
+
+double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const
+{
+ return progressAnimationNumFrames * progressAnimationFrameRate;
+}
+
+void RenderThemeMac::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const
+{
+}
+
+bool RenderThemeMac::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!renderObject->isProgress())
+ return true;
+
+ float zoomLevel = renderObject->style()->effectiveZoom();
+ int controlSize = controlSizeForFont(renderObject->style());
+ IntSize size = progressBarSizes()[controlSize];
+ size.setHeight(size.height() * zoomLevel);
+ size.setWidth(rect.width());
+
+ // Now inflate it to account for the shadow.
+ IntRect inflatedRect = rect;
+ if (rect.height() <= minimumProgressBarHeight(renderObject->style()))
+ inflatedRect = inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel);
+
+ RenderProgress* renderProgress = toRenderProgress(renderObject);
+ HIThemeTrackDrawInfo trackInfo;
+ trackInfo.version = 0;
+ if (controlSize == NSRegularControlSize)
+ trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
+ else
+ trackInfo.kind = renderProgress->position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
+
+ trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
+ trackInfo.min = 0;
+ trackInfo.max = numeric_limits<SInt32>::max();
+ trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0));
+ trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0));
+ trackInfo.attributes = kThemeTrackHorizontal;
+ trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
+ trackInfo.reserved = 0;
+ trackInfo.filler1 = 0;
+
+ OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size(), 1);
+ if (!imageBuffer)
+ return true;
+
+ ContextContainer cgContextContainer(imageBuffer->context());
+ CGContextRef cgContext = cgContextContainer.context();
+ HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ if (!renderProgress->style()->isLeftToRightDirection()) {
+ paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
+ paintInfo.context->scale(FloatSize(-1, 1));
+ }
+
+ paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location());
+ return false;
+}
+#endif
+
+const float baseFontSize = 11.0f;
+const float baseArrowHeight = 4.0f;
+const float baseArrowWidth = 5.0f;
+const float baseSpaceBetweenArrows = 2.0f;
+const int arrowPaddingLeft = 6;
+const int arrowPaddingRight = 6;
+const int paddingBeforeSeparator = 4;
+const int baseBorderRadius = 5;
+const int styledPopupPaddingLeft = 8;
+const int styledPopupPaddingTop = 1;
+const int styledPopupPaddingBottom = 2;
+
+static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
+{
+ static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
+ static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
+{
+ static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
+ static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
+{
+ static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
+ static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
+{
+ static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
+ static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ if (r.isEmpty())
+ return;
+
+ ContextContainer cgContextContainer(paintInfo.context);
+ CGContextRef context = cgContextContainer.context();
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ RoundedRect border = o->style()->getRoundedBorderFor(r, o->view());
+ int radius = border.radii().topLeft().width();
+
+ CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
+
+ FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
+ struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
+ RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
+
+ FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
+ struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
+ RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
+
+ struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
+ RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
+
+ RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
+
+ RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
+
+ {
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ CGContextClipToRect(context, r);
+ paintInfo.context->clipRoundedRect(border);
+ context = cgContextContainer.context();
+ CGContextDrawShading(context, mainShading.get());
+ }
+
+ {
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ CGContextClipToRect(context, topGradient);
+ paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
+ context = cgContextContainer.context();
+ CGContextDrawShading(context, topShading.get());
+ }
+
+ if (!bottomGradient.isEmpty()) {
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ CGContextClipToRect(context, bottomGradient);
+ paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
+ context = cgContextContainer.context();
+ CGContextDrawShading(context, bottomShading.get());
+ }
+
+ {
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ CGContextClipToRect(context, r);
+ paintInfo.context->clipRoundedRect(border);
+ context = cgContextContainer.context();
+ CGContextDrawShading(context, leftShading.get());
+ CGContextDrawShading(context, rightShading.get());
+ }
+}
+
+bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
+ r.y() + o->style()->borderTopWidth(),
+ r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
+ r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
+ // Draw the gradients to give the styled popup menu a button appearance
+ paintMenuListButtonGradients(o, paintInfo, bounds);
+
+ // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds
+ float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
+ float centerY = bounds.y() + bounds.height() / 2.0f;
+ float arrowHeight = baseArrowHeight * fontScale;
+ float arrowWidth = baseArrowWidth * fontScale;
+ float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth;
+ float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
+
+ if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
+ return false;
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace());
+ paintInfo.context->setStrokeStyle(NoStroke);
+
+ FloatPoint arrow1[3];
+ arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
+ arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
+ arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
+
+ // Draw the top arrow
+ paintInfo.context->drawConvexPolygon(3, arrow1, true);
+
+ FloatPoint arrow2[3];
+ arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
+ arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
+ arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
+
+ // Draw the bottom arrow
+ paintInfo.context->drawConvexPolygon(3, arrow2, true);
+
+ Color leftSeparatorColor(0, 0, 0, 40);
+ Color rightSeparatorColor(255, 255, 255, 40);
+
+ // FIXME: Should the separator thickness and space be scaled up by fontScale?
+ int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
+ int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round?
+
+ // Draw the separator to the left of the arrows
+ paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
+ paintInfo.context->setStrokeStyle(SolidStroke);
+ paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
+ paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
+ IntPoint(leftEdgeOfSeparator, bounds.maxY()));
+
+ paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
+ paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
+ IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
+ return false;
+}
+
+static const IntSize* menuListButtonSizes()
+{
+ static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
+ return sizes;
+}
+
+void RenderThemeMac::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
+{
+ NSControlSize controlSize = controlSizeForFont(style);
+
+ style->resetBorder();
+ style->resetPadding();
+
+ // Height is locked to auto.
+ style->setHeight(Length(Auto));
+
+ // White-space is locked to pre
+ style->setWhiteSpace(PRE);
+
+ // Set the foreground color to black or gray when we have the aqua look.
+ // Cast to RGB32 is to work around a compiler bug.
+ style->setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
+
+ // Set the button's vertical size.
+ setSizeFromFont(style, menuListButtonSizes());
+
+ // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out
+ // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
+ // system font for the control size instead.
+ setFontFromControlSize(styleResolver, style, controlSize);
+
+ style->setBoxShadow(nullptr);
+}
+
+int RenderThemeMac::popupInternalPaddingLeft(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
+ if (style->appearance() == MenulistButtonPart)
+ return styledPopupPaddingLeft * style->effectiveZoom();
+ return 0;
+}
+
+int RenderThemeMac::popupInternalPaddingRight(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
+ if (style->appearance() == MenulistButtonPart) {
+ float fontScale = style->fontSize() / baseFontSize;
+ float arrowWidth = baseArrowWidth * fontScale;
+ return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
+ }
+ return 0;
+}
+
+int RenderThemeMac::popupInternalPaddingTop(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
+ if (style->appearance() == MenulistButtonPart)
+ return styledPopupPaddingTop * style->effectiveZoom();
+ return 0;
+}
+
+int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
+ if (style->appearance() == MenulistButtonPart)
+ return styledPopupPaddingBottom * style->effectiveZoom();
+ return 0;
+}
+
+void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ float fontScale = style->fontSize() / baseFontSize;
+
+ style->resetPadding();
+ style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
+
+ const int minHeight = 15;
+ style->setMinHeight(Length(minHeight, Fixed));
+
+ style->setLineHeight(RenderStyle::initialLineHeight());
+}
+
+void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
+{
+ NSPopUpButtonCell* popupButton = this->popupButton();
+
+ // Set the control size based off the rectangle we're painting into.
+ setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
+
+ // Update the various states we respond to.
+ updateActiveState(popupButton, o);
+ updateCheckedState(popupButton, o);
+ updateEnabledState(popupButton, o);
+ updatePressedState(popupButton, o);
+#if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
+ updateFocusedState(popupButton, o);
+#endif
+}
+
+const IntSize* RenderThemeMac::menuListSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
+ return sizes;
+}
+
+int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const
+{
+ return sizeForSystemFont(style, menuListSizes()).width();
+}
+
+const int trackWidth = 5;
+const int trackRadius = 2;
+
+void RenderThemeMac::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ IntRect bounds = r;
+ float zoomLevel = o->style()->effectiveZoom();
+ float zoomedTrackWidth = trackWidth * zoomLevel;
+
+ if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) {
+ bounds.setHeight(zoomedTrackWidth);
+ bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
+ } else if (o->style()->appearance() == SliderVerticalPart) {
+ bounds.setWidth(zoomedTrackWidth);
+ bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
+ }
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ CGContextRef context = localContext.cgContext();
+ CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
+
+#if ENABLE(DATALIST_ELEMENT)
+ paintSliderTicks(o, paintInfo, r);
+#endif
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ CGContextClipToRect(context, bounds);
+
+ struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
+ RetainPtr<CGShadingRef> mainShading;
+ if (o->style()->appearance() == SliderVerticalPart)
+ mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
+ else
+ mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
+
+ IntSize radius(trackRadius, trackRadius);
+ paintInfo.context->clipRoundedRect(RoundedRect(bounds, radius, radius, radius, radius));
+ context = localContext.cgContext();
+ CGContextDrawShading(context, mainShading.get());
+
+ return false;
+}
+
+void RenderThemeMac::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
+{
+ RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
+ style->setBoxShadow(nullptr);
+}
+
+const float verticalSliderHeightPadding = 0.1f;
+
+bool RenderThemeMac::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart
+ ? sliderThumbVertical()
+ : sliderThumbHorizontal();
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+
+ // Update the various states we respond to.
+ updateActiveState(sliderThumbCell, o);
+ updateEnabledState(sliderThumbCell, o);
+ Element* focusDelegate = (o->node() && o->node()->isElementNode()) ? toElement(o->node())->focusDelegate() : 0;
+ updateFocusedState(sliderThumbCell, focusDelegate ? focusDelegate->renderer() : 0);
+
+ // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
+ bool oldPressed;
+ if (o->style()->appearance() == SliderThumbVerticalPart)
+ oldPressed = m_isSliderThumbVerticalPressed;
+ else
+ oldPressed = m_isSliderThumbHorizontalPressed;
+
+ bool pressed = isPressed(o);
+
+ if (o->style()->appearance() == SliderThumbVerticalPart)
+ m_isSliderThumbVerticalPressed = pressed;
+ else
+ m_isSliderThumbHorizontalPressed = pressed;
+
+ if (pressed != oldPressed) {
+ if (pressed)
+ [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
+ else
+ [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
+ }
+
+ FloatRect bounds = r;
+ // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
+ if (o->style()->appearance() == SliderThumbVerticalPart)
+ bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom());
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ float zoomLevel = o->style()->effectiveZoom();
+
+ FloatRect unzoomedRect = bounds;
+ if (zoomLevel != 1.0f) {
+ unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
+ unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
+ paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
+ paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
+ paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
+ }
+
+ [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
+ [sliderThumbCell setControlView:nil];
+
+ return false;
+}
+
+bool RenderThemeMac::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ NSSearchFieldCell* search = this->search();
+
+ setSearchCellState(o, r);
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ float zoomLevel = o->style()->effectiveZoom();
+
+ IntRect unzoomedRect = r;
+
+ if (zoomLevel != 1.0f) {
+ unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
+ unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
+ paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
+ paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
+ paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
+ }
+
+ // Set the search button to nil before drawing. Then reset it so we can draw it later.
+ [search setSearchButtonCell:nil];
+
+ [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
+
+ [search setControlView:nil];
+ [search resetSearchButtonCell];
+
+ return false;
+}
+
+void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&)
+{
+ NSSearchFieldCell* search = this->search();
+
+ [search setControlSize:controlSizeForFont(o->style())];
+
+ // Update the various states we respond to.
+ updateActiveState(search, o);
+ updateEnabledState(search, o);
+ updateFocusedState(search, o);
+}
+
+const IntSize* RenderThemeMac::searchFieldSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
+ return sizes;
+}
+
+void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const
+{
+ // If the width and height are both specified, then we have nothing to do.
+ if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
+ return;
+
+ // Use the font size to determine the intrinsic width of the control.
+ setSizeFromFont(style, searchFieldSizes());
+}
+
+void RenderThemeMac::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const
+{
+ // Override border.
+ style->resetBorder();
+ const short borderWidth = 2 * style->effectiveZoom();
+ style->setBorderLeftWidth(borderWidth);
+ style->setBorderLeftStyle(INSET);
+ style->setBorderRightWidth(borderWidth);
+ style->setBorderRightStyle(INSET);
+ style->setBorderBottomWidth(borderWidth);
+ style->setBorderBottomStyle(INSET);
+ style->setBorderTopWidth(borderWidth);
+ style->setBorderTopStyle(INSET);
+
+ // Override height.
+ style->setHeight(Length(Auto));
+ setSearchFieldSize(style);
+
+ // Override padding size to match AppKit text positioning.
+ const int padding = 1 * style->effectiveZoom();
+ style->setPaddingLeft(Length(padding, Fixed));
+ style->setPaddingRight(Length(padding, Fixed));
+ style->setPaddingTop(Length(padding, Fixed));
+ style->setPaddingBottom(Length(padding, Fixed));
+
+ NSControlSize controlSize = controlSizeForFont(style);
+ setFontFromControlSize(styleResolver, style, controlSize);
+
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ Element* input = o->node()->shadowHost();
+ if (!input)
+ input = toElement(o->node());
+
+ if (!input->renderer()->isBox())
+ return false;
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ setSearchCellState(input->renderer(), r);
+
+ NSSearchFieldCell* search = this->search();
+
+ if (!input->isDisabledFormControl() && (input->isTextFormControl() && !toHTMLTextFormControlElement(input)->isReadOnly())) {
+ updateActiveState([search cancelButtonCell], o);
+ updatePressedState([search cancelButtonCell], o);
+ }
+ else if ([[search cancelButtonCell] isHighlighted])
+ [[search cancelButtonCell] setHighlighted:NO];
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+
+ float zoomLevel = o->style()->effectiveZoom();
+
+ FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
+
+#if ENABLE(INPUT_SPEECH)
+ // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g.
+ // when speech input is enabled for the input element.
+ IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect();
+ int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight();
+ int spaceToRightOfCancelButton = absRight - (r.x() + r.width());
+ localBounds.setX(localBounds.x() - spaceToRightOfCancelButton);
+#endif
+
+ localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
+
+ FloatRect unzoomedRect(localBounds);
+ if (zoomLevel != 1.0f) {
+ unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
+ unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
+ paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
+ paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
+ paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
+ }
+
+ [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
+ [[search cancelButtonCell] setControlView:nil];
+ return false;
+}
+
+const IntSize* RenderThemeMac::cancelButtonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
+ return sizes;
+}
+
+void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ IntSize size = sizeForSystemFont(style, cancelButtonSizes());
+ style->setWidth(Length(size.width(), Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+ style->setBoxShadow(nullptr);
+}
+
+const IntSize* RenderThemeMac::resultsButtonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
+ return sizes;
+}
+
+const int emptyResultsOffset = 9;
+void RenderThemeMac::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ IntSize size = sizeForSystemFont(style, resultsButtonSizes());
+ style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
+{
+ return false;
+}
+
+void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ IntSize size = sizeForSystemFont(style, resultsButtonSizes());
+ style->setWidth(Length(size.width(), Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ Node* input = o->node()->shadowHost();
+ if (!input)
+ input = o->node();
+ if (!input->renderer()->isBox())
+ return false;
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ setSearchCellState(input->renderer(), r);
+
+ NSSearchFieldCell* search = this->search();
+
+ if ([search searchMenuTemplate] != nil)
+ [search setSearchMenuTemplate:nil];
+
+ updateActiveState([search searchButtonCell], o);
+
+ FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
+ localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
+
+ [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
+ [[search searchButtonCell] setControlView:nil];
+ return false;
+}
+
+const int resultsArrowWidth = 5;
+void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ IntSize size = sizeForSystemFont(style, resultsButtonSizes());
+ style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ Node* input = o->node()->shadowHost();
+ if (!input)
+ input = o->node();
+ if (!input->renderer()->isBox())
+ return false;
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ setSearchCellState(input->renderer(), r);
+
+ NSSearchFieldCell* search = this->search();
+
+ updateActiveState([search searchButtonCell], o);
+
+ if (![search searchMenuTemplate])
+ [search setSearchMenuTemplate:searchMenuTemplate()];
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context);
+ float zoomLevel = o->style()->effectiveZoom();
+
+ FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
+ localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
+
+ IntRect unzoomedRect(localBounds);
+ if (zoomLevel != 1.0f) {
+ unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
+ unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
+ paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
+ paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
+ paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
+ }
+
+ [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
+ [[search searchButtonCell] setControlView:nil];
+
+ return false;
+}
+
+bool RenderThemeMac::paintSnapshottedPluginOverlay(RenderObject* o, const PaintInfo& paintInfo, const IntRect&)
+{
+ if (paintInfo.phase != PaintPhaseBlockBackground)
+ return true;
+
+ if (!o->isRenderBlock())
+ return true;
+
+ RenderBlock* renderBlock = toRenderBlock(o);
+
+ LayoutUnit contentWidth = renderBlock->contentWidth();
+ LayoutUnit contentHeight = renderBlock->contentHeight();
+ if (!contentWidth || !contentHeight)
+ return true;
+
+ GraphicsContext* context = paintInfo.context;
+
+ LayoutSize contentSize(contentWidth, contentHeight);
+ LayoutPoint contentLocation = renderBlock->location();
+ contentLocation.move(renderBlock->borderLeft() + renderBlock->paddingLeft(), renderBlock->borderTop() + renderBlock->paddingTop());
+
+ LayoutRect rect(contentLocation, contentSize);
+ IntRect alignedRect = pixelSnappedIntRect(rect);
+ if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
+ return true;
+
+ // We need to get the snapshot image from the plugin element, which should be available
+ // from our node. Assuming this node is the plugin overlay element, we should get to the
+ // plugin itself by asking for the shadow root parent, and then its parent.
+
+ if (!renderBlock->node()->isHTMLElement())
+ return true;
+
+ HTMLElement* plugInOverlay = toHTMLElement(renderBlock->node());
+ Element* parent = plugInOverlay->parentOrShadowHostElement();
+ while (parent && !parent->isPluginElement())
+ parent = parent->parentOrShadowHostElement();
+
+ if (!parent)
+ return true;
+
+ HTMLPlugInElement* plugInElement = toHTMLPlugInElement(parent);
+ if (!plugInElement->isPlugInImageElement())
+ return true;
+
+ HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(plugInElement);
+
+ Image* snapshot = plugInImageElement->snapshotImage();
+ if (!snapshot)
+ return true;
+
+ RenderSnapshottedPlugIn* plugInRenderer = toRenderSnapshottedPlugIn(plugInImageElement->renderer());
+ FloatPoint snapshotAbsPos = plugInRenderer->localToAbsolute();
+ snapshotAbsPos.move(plugInRenderer->borderLeft() + plugInRenderer->paddingLeft(), plugInRenderer->borderTop() + plugInRenderer->paddingTop());
+
+ // We could draw the snapshot with that coordinates, but we need to make sure there
+ // isn't a composited layer between us and the plugInRenderer.
+ RenderBox* renderBox = toRenderBox(o);
+ while (renderBox != plugInRenderer) {
+ if (renderBox->hasLayer() && renderBox->layer() && renderBox->layer()->isComposited()) {
+ snapshotAbsPos = -renderBox->location();
+ break;
+ }
+ renderBox = renderBox->parentBox();
+ }
+
+ LayoutSize pluginSize(plugInRenderer->contentWidth(), plugInRenderer->contentHeight());
+ LayoutRect pluginRect(snapshotAbsPos, pluginSize);
+ IntRect alignedPluginRect = pixelSnappedIntRect(pluginRect);
+
+ if (alignedPluginRect.width() <= 0 || alignedPluginRect.height() <= 0)
+ return true;
+
+ context->drawImage(snapshot, plugInRenderer->style()->colorSpace(), alignedPluginRect, CompositeSourceOver);
+ return false;
+}
+
+#if ENABLE(DATALIST_ELEMENT)
+IntSize RenderThemeMac::sliderTickSize() const
+{
+ return IntSize(1, 3);
+}
+
+int RenderThemeMac::sliderTickOffsetFromTrackCenter() const
+{
+ return -9;
+}
+#endif
+
+const int sliderThumbWidth = 15;
+const int sliderThumbHeight = 15;
+
+void RenderThemeMac::adjustSliderThumbSize(RenderStyle* style, Element*) const
+{
+ float zoomLevel = style->effectiveZoom();
+ if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
+ style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
+ style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
+ }
+
+#if ENABLE(VIDEO)
+ adjustMediaSliderThumbSize(style);
+#endif
+}
+
+bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ return true;
+#else
+ return false;
+#endif
+}
+
+NSPopUpButtonCell* RenderThemeMac::popupButton() const
+{
+ if (!m_popupButton) {
+ m_popupButton = adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
+ [m_popupButton.get() setUsesItemFromMenu:NO];
+ [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
+ }
+
+ return m_popupButton.get();
+}
+
+NSSearchFieldCell* RenderThemeMac::search() const
+{
+ if (!m_search) {
+ m_search = adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
+ [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
+ [m_search.get() setBezeled:YES];
+ [m_search.get() setEditable:YES];
+ [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
+ }
+
+ return m_search.get();
+}
+
+NSMenu* RenderThemeMac::searchMenuTemplate() const
+{
+ if (!m_searchMenuTemplate)
+ m_searchMenuTemplate = adoptNS([[NSMenu alloc] initWithTitle:@""]);
+
+ return m_searchMenuTemplate.get();
+}
+
+NSSliderCell* RenderThemeMac::sliderThumbHorizontal() const
+{
+ if (!m_sliderThumbHorizontal) {
+ m_sliderThumbHorizontal = adoptNS([[NSSliderCell alloc] init]);
+ [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
+ [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
+ [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
+ }
+
+ return m_sliderThumbHorizontal.get();
+}
+
+NSSliderCell* RenderThemeMac::sliderThumbVertical() const
+{
+ if (!m_sliderThumbVertical) {
+ m_sliderThumbVertical = adoptNS([[NSSliderCell alloc] init]);
+ [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
+ [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
+ [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
+ }
+
+ return m_sliderThumbVertical.get();
+}
+
+NSTextFieldCell* RenderThemeMac::textField() const
+{
+ if (!m_textField) {
+ m_textField = adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
+ [m_textField.get() setBezeled:YES];
+ [m_textField.get() setEditable:YES];
+ [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
+ [m_textField.get() setDrawsBackground:YES];
+ [m_textField.get() setBackgroundColor:[NSColor whiteColor]];
+#else
+ // Post-Lion, WebCore can be in charge of paintinng the background thanks to
+ // the workaround in place for <rdar://problem/11385461>, which is implemented
+ // above as _coreUIDrawOptionsWithFrame.
+ [m_textField.get() setDrawsBackground:NO];
+#endif
+ }
+
+ return m_textField.get();
+}
+
+String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
+{
+ if (width <= 0)
+ return String();
+
+ String strToTruncate;
+ if (fileList->isEmpty())
+ strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
+ else if (fileList->length() == 1)
+ strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
+ else
+ return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
+
+ return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
+}
+
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeMacShared.h b/Source/WebCore/rendering/RenderThemeMacShared.h
deleted file mode 100644
index 5283cb8db..000000000
--- a/Source/WebCore/rendering/RenderThemeMacShared.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * This file is part of the theme implementation for form controls in WebCore.
- *
- * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Computer, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderThemeMacShared_h
-#define RenderThemeMacShared_h
-
-#import "RenderTheme.h"
-#import <wtf/HashMap.h>
-#import <wtf/RetainPtr.h>
-
-OBJC_CLASS WebCoreRenderThemeNotificationObserver;
-
-namespace WebCore {
-
-class RenderProgress;
-class RenderStyle;
-
-class RenderThemeMacShared : public RenderTheme {
-public:
- // A method asking if the control changes its tint when the window has focus or not.
- virtual bool controlSupportsTints(const RenderObject*) const;
-
- // A general method asking if any control tinting is supported at all.
- virtual bool supportsControlTints() const { return true; }
-
- virtual void adjustRepaintRect(const RenderObject*, IntRect&) OVERRIDE;
-
- virtual bool isControlStyled(const RenderStyle*, const BorderData&, const FillLayer&, const Color& backgroundColor) const;
-
- virtual Color platformActiveSelectionBackgroundColor() const;
- virtual Color platformInactiveSelectionBackgroundColor() const;
- virtual Color platformActiveListBoxSelectionBackgroundColor() const;
- virtual Color platformActiveListBoxSelectionForegroundColor() const;
- virtual Color platformInactiveListBoxSelectionBackgroundColor() const;
- virtual Color platformInactiveListBoxSelectionForegroundColor() const;
- virtual Color platformFocusRingColor() const;
-
- virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; }
-
- virtual void platformColorsDidChange();
-
- // System fonts.
- virtual void systemFont(int cssValueId, FontDescription&) const;
-
- virtual int minimumMenuListSize(RenderStyle*) const;
-
- virtual void adjustSliderThumbSize(RenderStyle*, Element*) const;
-
-#if ENABLE(DATALIST_ELEMENT)
- virtual IntSize sliderTickSize() const OVERRIDE;
- virtual int sliderTickOffsetFromTrackCenter() const OVERRIDE;
-#endif
-
- virtual int popupInternalPaddingLeft(RenderStyle*) const;
- virtual int popupInternalPaddingRight(RenderStyle*) const;
- virtual int popupInternalPaddingTop(RenderStyle*) const;
- virtual int popupInternalPaddingBottom(RenderStyle*) const;
-
- virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE;
-
- virtual bool popsMenuByArrowKeys() const OVERRIDE { return true; }
-
-#if ENABLE(METER_ELEMENT)
- virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE;
- virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool supportsMeter(ControlPart) const;
-#endif
-
-#if ENABLE(PROGRESS_ELEMENT)
- // Returns the repeat interval of the animation for the progress bar.
- virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const;
- // Returns the duration of the animation for the progress bar.
- virtual double animationDurationForProgressBar(RenderProgress*) const;
-#endif
-
- virtual Color systemColor(int cssValueId) const;
- // Controls color values returned from platformFocusRingColor(). systemColor() will be used when false.
- virtual bool usesTestModeFocusRingColor() const;
- // A view associated to the contained document. Subclasses may not have such a view and return a fake.
- virtual NSView* documentViewFor(RenderObject*) const = 0;
-
-protected:
- RenderThemeMacShared();
- virtual ~RenderThemeMacShared();
-
- virtual bool supportsSelectionForegroundColors() const { return false; }
-
- virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
-
-#if ENABLE(PROGRESS_ELEMENT)
- virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
-#endif
-
- virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&);
- virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const;
-
- virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&);
-
-#if ENABLE(VIDEO)
- virtual void adjustMediaSliderThumbSize(RenderStyle*) const = 0;
- virtual bool supportsClosedCaptioning() const { return true; }
-#endif
-
- virtual bool shouldShowPlaceholderWhenFocused() const;
-
-private:
- virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const OVERRIDE;
-
- IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const;
-
- FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect&) const;
-
- // Get the control size based off the font. Used by some of the controls (like buttons).
- NSControlSize controlSizeForFont(RenderStyle*) const;
- NSControlSize controlSizeForSystemFont(RenderStyle*) const;
- void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f);
- void setSizeFromFont(RenderStyle*, const IntSize* sizes) const;
- IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const;
- IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const;
- void setFontFromControlSize(StyleResolver*, RenderStyle*, NSControlSize) const;
-
- void updateCheckedState(NSCell*, const RenderObject*);
- void updateEnabledState(NSCell*, const RenderObject*);
- void updateFocusedState(NSCell*, const RenderObject*);
- void updatePressedState(NSCell*, const RenderObject*);
- // An optional hook for subclasses to update the control tint of NSCell.
- virtual void updateActiveState(NSCell*, const RenderObject*) { }
-
- // Helpers for adjusting appearance and for painting
-
- void setPopupButtonCellState(const RenderObject*, const IntRect&);
- const IntSize* popupButtonSizes() const;
- const int* popupButtonMargins() const;
- const int* popupButtonPadding(NSControlSize) const;
- void paintMenuListButtonGradients(RenderObject*, const PaintInfo&, const IntRect&);
- const IntSize* menuListSizes() const;
-
- const IntSize* searchFieldSizes() const;
- const IntSize* cancelButtonSizes() const;
- const IntSize* resultsButtonSizes() const;
- void setSearchCellState(RenderObject*, const IntRect&);
- void setSearchFieldSize(RenderStyle*) const;
-
- NSPopUpButtonCell* popupButton() const;
- NSSearchFieldCell* search() const;
- NSMenu* searchMenuTemplate() const;
- NSSliderCell* sliderThumbHorizontal() const;
- NSSliderCell* sliderThumbVertical() const;
- NSTextFieldCell* textField() const;
-
-#if ENABLE(METER_ELEMENT)
- NSLevelIndicatorStyle levelIndicatorStyleFor(ControlPart) const;
- NSLevelIndicatorCell* levelIndicatorFor(const RenderMeter*) const;
-#endif
-
-#if ENABLE(PROGRESS_ELEMENT)
- int minimumProgressBarHeight(RenderStyle*) const;
- const IntSize* progressBarSizes() const;
- const int* progressBarMargins(NSControlSize) const;
-#endif
-
-private:
- mutable RetainPtr<NSPopUpButtonCell> m_popupButton;
- mutable RetainPtr<NSSearchFieldCell> m_search;
- mutable RetainPtr<NSMenu> m_searchMenuTemplate;
- mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal;
- mutable RetainPtr<NSSliderCell> m_sliderThumbVertical;
- mutable RetainPtr<NSLevelIndicatorCell> m_levelIndicator;
- mutable RetainPtr<NSTextFieldCell> m_textField;
-
- bool m_isSliderThumbHorizontalPressed;
- bool m_isSliderThumbVerticalPressed;
-
- mutable HashMap<int, RGBA32> m_systemColorCache;
-
- RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver;
-};
-
-} // namespace WebCore
-
-#endif // RenderThemeMacShared_h
diff --git a/Source/WebCore/rendering/RenderThemeMacShared.mm b/Source/WebCore/rendering/RenderThemeMacShared.mm
deleted file mode 100644
index e6074cc26..000000000
--- a/Source/WebCore/rendering/RenderThemeMacShared.mm
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#import "config.h"
-#import "RenderThemeMacShared.h"
-
-#import "BitmapImage.h"
-#import "ColorMac.h"
-#import "CSSValueList.h"
-#import "CSSValueKeywords.h"
-#import "Document.h"
-#import "Element.h"
-#import "FileList.h"
-#import "FrameView.h"
-#import "GraphicsContextCG.h"
-#import "HTMLInputElement.h"
-#import "HTMLMediaElement.h"
-#import "HTMLNames.h"
-#import "Image.h"
-#import "ImageBuffer.h"
-#import "LocalCurrentGraphicsContext.h"
-#import "LocalizedStrings.h"
-#import "MediaControlElements.h"
-#import "PaintInfo.h"
-#import "RenderMedia.h"
-#import "RenderMediaControls.h"
-#import "RenderSlider.h"
-#import "RenderSnapshottedPlugIn.h"
-#import "RenderView.h"
-#import "SharedBuffer.h"
-#import "StringTruncator.h"
-#import "StyleResolver.h"
-#import "TimeRanges.h"
-#import "ThemeMac.h"
-#import "WebCoreNSCellExtras.h"
-#import "WebCoreSystemInterface.h"
-#import "UserAgentStyleSheets.h"
-#import <Carbon/Carbon.h>
-#import <Cocoa/Cocoa.h>
-#import <wtf/RetainPtr.h>
-#import <wtf/StdLibExtras.h>
-#import <math.h>
-
-#import "RenderProgress.h"
-
-#if ENABLE(METER_ELEMENT)
-#include "RenderMeter.h"
-#include "HTMLMeterElement.h"
-#endif
-
-using namespace std;
-
-// The methods in this file are specific to the Mac OS X platform.
-
-// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
-
-// We estimate the animation rate of a Mac OS X progress bar is 33 fps.
-// Hard code the value here because we haven't found API for it.
-const double progressAnimationFrameRate = 0.033;
-
-// Mac OS X progress bar animation seems to have 256 frames.
-const double progressAnimationNumFrames = 256;
-
-@interface WebCoreRenderThemeNotificationObserver : NSObject
-{
- WebCore::RenderTheme *_theme;
-}
-
-- (id)initWithTheme:(WebCore::RenderTheme *)theme;
-- (void)systemColorsDidChange:(NSNotification *)notification;
-
-@end
-
-@implementation WebCoreRenderThemeNotificationObserver
-
-- (id)initWithTheme:(WebCore::RenderTheme *)theme
-{
- if (!(self = [super init]))
- return nil;
-
- _theme = theme;
- return self;
-}
-
-- (void)systemColorsDidChange:(NSNotification *)unusedNotification
-{
- ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
- _theme->platformColorsDidChange();
-}
-
-@end
-
-@interface NSTextFieldCell (WKDetails)
-- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
-@end
-
-
-@interface WebCoreTextFieldCell : NSTextFieldCell
-- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus;
-@end
-
-@implementation WebCoreTextFieldCell
-- (CFDictionaryRef)_coreUIDrawOptionsWithFrame:(NSRect)cellFrame inView:(NSView *)controlView includeFocus:(BOOL)includeFocus
-{
- // FIXME: This is a post-Lion-only workaround for <rdar://problem/11385461>. When that bug is resolved, we should remove this code.
- CFMutableDictionaryRef coreUIDrawOptions = CFDictionaryCreateMutableCopy(NULL, 0, [super _coreUIDrawOptionsWithFrame:cellFrame inView:controlView includeFocus:includeFocus]);
- CFDictionarySetValue(coreUIDrawOptions, @"borders only", kCFBooleanTrue);
- return (CFDictionaryRef)[NSMakeCollectable(coreUIDrawOptions) autorelease];
-}
-@end
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-enum {
- topMargin,
- rightMargin,
- bottomMargin,
- leftMargin
-};
-
-enum {
- topPadding,
- rightPadding,
- bottomPadding,
- leftPadding
-};
-
-RenderThemeMacShared::RenderThemeMacShared()
- : m_isSliderThumbHorizontalPressed(false)
- , m_isSliderThumbVerticalPressed(false)
- , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this])
-{
- [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
- selector:@selector(systemColorsDidChange:)
- name:NSSystemColorsDidChangeNotification
- object:nil];
-}
-
-RenderThemeMacShared::~RenderThemeMacShared()
-{
- [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()];
-}
-
-Color RenderThemeMacShared::platformActiveSelectionBackgroundColor() const
-{
- NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
-}
-
-Color RenderThemeMacShared::platformInactiveSelectionBackgroundColor() const
-{
- NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
-}
-
-Color RenderThemeMacShared::platformActiveListBoxSelectionBackgroundColor() const
-{
- NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
-}
-
-Color RenderThemeMacShared::platformActiveListBoxSelectionForegroundColor() const
-{
- return Color::white;
-}
-
-Color RenderThemeMacShared::platformInactiveListBoxSelectionForegroundColor() const
-{
- return Color::black;
-}
-
-Color RenderThemeMacShared::platformFocusRingColor() const
-{
- if (usesTestModeFocusRingColor())
- return oldAquaFocusRingColor();
-
- return systemColor(CSSValueWebkitFocusRingColor);
-}
-
-Color RenderThemeMacShared::platformInactiveListBoxSelectionBackgroundColor() const
-{
- return platformInactiveSelectionBackgroundColor();
-}
-
-static FontWeight toFontWeight(NSInteger appKitFontWeight)
-{
- ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
- if (appKitFontWeight > 14)
- appKitFontWeight = 14;
- else if (appKitFontWeight < 1)
- appKitFontWeight = 1;
-
- static FontWeight fontWeights[] = {
- FontWeight100,
- FontWeight100,
- FontWeight200,
- FontWeight300,
- FontWeight400,
- FontWeight500,
- FontWeight600,
- FontWeight600,
- FontWeight700,
- FontWeight800,
- FontWeight800,
- FontWeight900,
- FontWeight900,
- FontWeight900
- };
- return fontWeights[appKitFontWeight - 1];
-}
-
-void RenderThemeMacShared::systemFont(int cssValueId, FontDescription& fontDescription) const
-{
- DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
- DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
- DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
- DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
- DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
- DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
- DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
-
- FontDescription* cachedDesc;
- NSFont* font = nil;
- switch (cssValueId) {
- case CSSValueSmallCaption:
- cachedDesc = &smallSystemFont;
- if (!smallSystemFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
- break;
- case CSSValueMenu:
- cachedDesc = &menuFont;
- if (!menuFont.isAbsoluteSize())
- font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
- break;
- case CSSValueStatusBar:
- cachedDesc = &labelFont;
- if (!labelFont.isAbsoluteSize())
- font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
- break;
- case CSSValueWebkitMiniControl:
- cachedDesc = &miniControlFont;
- if (!miniControlFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
- break;
- case CSSValueWebkitSmallControl:
- cachedDesc = &smallControlFont;
- if (!smallControlFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
- break;
- case CSSValueWebkitControl:
- cachedDesc = &controlFont;
- if (!controlFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
- break;
- default:
- cachedDesc = &systemFont;
- if (!systemFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
- }
-
- if (font) {
- NSFontManager *fontManager = [NSFontManager sharedFontManager];
- cachedDesc->setIsAbsoluteSize(true);
- cachedDesc->setGenericFamily(FontDescription::NoFamily);
- cachedDesc->firstFamily().setFamily([font familyName]);
- cachedDesc->setSpecifiedSize([font pointSize]);
- cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font]));
- cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask);
- }
- fontDescription = *cachedDesc;
-}
-
-static RGBA32 convertNSColorToColor(NSColor *color)
-{
- NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- if (colorInColorSpace) {
- static const double scaleFactor = nextafter(256.0, 0.0);
- return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
- static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]),
- static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
- }
-
- // This conversion above can fail if the NSColor in question is an NSPatternColor
- // (as many system colors are). These colors are actually a repeating pattern
- // not just a solid color. To work around this we simply draw a 1x1 image of
- // the color and use that pixel's color. It might be better to use an average of
- // the colors in the pattern instead.
- NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
- pixelsWide:1
- pixelsHigh:1
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:4
- bitsPerPixel:32];
-
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]];
- NSEraseRect(NSMakeRect(0, 0, 1, 1));
- [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)];
- [NSGraphicsContext restoreGraphicsState];
-
- NSUInteger pixel[4];
- [offscreenRep getPixel:pixel atX:0 y:0];
-
- [offscreenRep release];
-
- return makeRGB(pixel[0], pixel[1], pixel[2]);
-}
-
-static RGBA32 menuBackgroundColor()
-{
- NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
- pixelsWide:1
- pixelsHigh:1
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:4
- bitsPerPixel:32];
-
- CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]);
- CGRect rect = CGRectMake(0, 0, 1, 1);
- HIThemeMenuDrawInfo drawInfo;
- drawInfo.version = 0;
- drawInfo.menuType = kThemeMenuTypePopUp;
- HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted);
-
- NSUInteger pixel[4];
- [offscreenRep getPixel:pixel atX:0 y:0];
-
- [offscreenRep release];
-
- return makeRGB(pixel[0], pixel[1], pixel[2]);
-}
-
-void RenderThemeMacShared::platformColorsDidChange()
-{
- m_systemColorCache.clear();
- RenderTheme::platformColorsDidChange();
-}
-
-Color RenderThemeMacShared::systemColor(int cssValueId) const
-{
- {
- HashMap<int, RGBA32>::iterator it = m_systemColorCache.find(cssValueId);
- if (it != m_systemColorCache.end())
- return it->value;
- }
-
- Color color;
- switch (cssValueId) {
- case CSSValueActiveborder:
- color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
- break;
- case CSSValueActivecaption:
- color = convertNSColorToColor([NSColor windowFrameTextColor]);
- break;
- case CSSValueAppworkspace:
- color = convertNSColorToColor([NSColor headerColor]);
- break;
- case CSSValueBackground:
- // Use theme independent default
- break;
- case CSSValueButtonface:
- // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
- // We may want to change this to use the NSColor in future.
- color = 0xFFC0C0C0;
- break;
- case CSSValueButtonhighlight:
- color = convertNSColorToColor([NSColor controlHighlightColor]);
- break;
- case CSSValueButtonshadow:
- color = convertNSColorToColor([NSColor controlShadowColor]);
- break;
- case CSSValueButtontext:
- color = convertNSColorToColor([NSColor controlTextColor]);
- break;
- case CSSValueCaptiontext:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueGraytext:
- color = convertNSColorToColor([NSColor disabledControlTextColor]);
- break;
- case CSSValueHighlight:
- color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
- break;
- case CSSValueHighlighttext:
- color = convertNSColorToColor([NSColor selectedTextColor]);
- break;
- case CSSValueInactiveborder:
- color = convertNSColorToColor([NSColor controlBackgroundColor]);
- break;
- case CSSValueInactivecaption:
- color = convertNSColorToColor([NSColor controlBackgroundColor]);
- break;
- case CSSValueInactivecaptiontext:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueInfobackground:
- // There is no corresponding NSColor for this so we use a hard coded value.
- color = 0xFFFBFCC5;
- break;
- case CSSValueInfotext:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueMenu:
- color = menuBackgroundColor();
- break;
- case CSSValueMenutext:
- color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
- break;
- case CSSValueScrollbar:
- color = convertNSColorToColor([NSColor scrollBarColor]);
- break;
- case CSSValueText:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueThreeddarkshadow:
- color = convertNSColorToColor([NSColor controlDarkShadowColor]);
- break;
- case CSSValueThreedshadow:
- color = convertNSColorToColor([NSColor shadowColor]);
- break;
- case CSSValueThreedface:
- // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
- // We may want to change this to use the NSColor in future.
- color = 0xFFC0C0C0;
- break;
- case CSSValueThreedhighlight:
- color = convertNSColorToColor([NSColor highlightColor]);
- break;
- case CSSValueThreedlightshadow:
- color = convertNSColorToColor([NSColor controlLightHighlightColor]);
- break;
- case CSSValueWebkitFocusRingColor:
- color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
- break;
- case CSSValueWindow:
- color = convertNSColorToColor([NSColor windowBackgroundColor]);
- break;
- case CSSValueWindowframe:
- color = convertNSColorToColor([NSColor windowFrameColor]);
- break;
- case CSSValueWindowtext:
- color = convertNSColorToColor([NSColor windowFrameTextColor]);
- break;
- }
-
- if (!color.isValid())
- color = RenderTheme::systemColor(cssValueId);
-
- if (color.isValid())
- m_systemColorCache.set(cssValueId, color.rgb());
-
- return color;
-}
-
-bool RenderThemeMacShared::usesTestModeFocusRingColor() const
-{
- return WebCore::usesTestModeFocusRingColor();
-}
-
-bool RenderThemeMacShared::isControlStyled(const RenderStyle* style, const BorderData& border,
- const FillLayer& background, const Color& backgroundColor) const
-{
- if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
- return style->border() != border;
-
- // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when
- // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style
- // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming
- // is in effect we treat it like the control is styled.
- if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f)
- return true;
-
- return RenderTheme::isControlStyled(style, border, background, backgroundColor);
-}
-
-void RenderThemeMacShared::adjustRepaintRect(const RenderObject* o, IntRect& r)
-{
- ControlPart part = o->style()->appearance();
-
-#if USE(NEW_THEME)
- switch (part) {
- case CheckboxPart:
- case RadioPart:
- case PushButtonPart:
- case SquareButtonPart:
- case DefaultButtonPart:
- case ButtonPart:
- case InnerSpinButtonPart:
- return RenderTheme::adjustRepaintRect(o, r);
- default:
- break;
- }
-#endif
-
- float zoomLevel = o->style()->effectiveZoom();
-
- if (part == MenulistPart) {
- setPopupButtonCellState(o, r);
- IntSize size = popupButtonSizes()[[popupButton() controlSize]];
- size.setHeight(size.height() * zoomLevel);
- size.setWidth(r.width());
- r = inflateRect(r, size, popupButtonMargins(), zoomLevel);
- }
-}
-
-IntRect RenderThemeMacShared::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const
-{
- // Only do the inflation if the available width/height are too small. Otherwise try to
- // fit the glow/check space into the available box's width/height.
- int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
- int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
- IntRect result(r);
- if (widthDelta < 0) {
- result.setX(result.x() - margins[leftMargin] * zoomLevel);
- result.setWidth(result.width() - widthDelta);
- }
- if (heightDelta < 0) {
- result.setY(result.y() - margins[topMargin] * zoomLevel);
- result.setHeight(result.height() - heightDelta);
- }
- return result;
-}
-
-FloatRect RenderThemeMacShared::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const
-{
- FloatRect partRect(inputRect);
-
- // Compute an offset between the part renderer and the input renderer
- FloatSize offsetFromInputRenderer;
- const RenderObject* renderer = partRenderer;
- while (renderer && renderer != inputRenderer) {
- RenderObject* containingRenderer = renderer->container();
- offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint()));
- renderer = containingRenderer;
- }
- // If the input renderer was not a container, something went wrong
- ASSERT(renderer == inputRenderer);
- // Move the rect into partRenderer's coords
- partRect.move(offsetFromInputRenderer);
- // Account for the local drawing offset (tx, ty)
- partRect.move(r.x(), r.y());
-
- return partRect;
-}
-
-void RenderThemeMacShared::updateCheckedState(NSCell* cell, const RenderObject* o)
-{
- bool oldIndeterminate = [cell state] == NSMixedState;
- bool indeterminate = isIndeterminate(o);
- bool checked = isChecked(o);
-
- if (oldIndeterminate != indeterminate) {
- [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
- return;
- }
-
- bool oldChecked = [cell state] == NSOnState;
- if (checked != oldChecked)
- [cell setState:checked ? NSOnState : NSOffState];
-}
-
-void RenderThemeMacShared::updateEnabledState(NSCell* cell, const RenderObject* o)
-{
- bool oldEnabled = [cell isEnabled];
- bool enabled = isEnabled(o);
- if (enabled != oldEnabled)
- [cell setEnabled:enabled];
-}
-
-void RenderThemeMacShared::updateFocusedState(NSCell* cell, const RenderObject* o)
-{
- bool oldFocused = [cell showsFirstResponder];
- bool focused = isFocused(o) && o->style()->outlineStyleIsAuto();
- if (focused != oldFocused)
- [cell setShowsFirstResponder:focused];
-}
-
-void RenderThemeMacShared::updatePressedState(NSCell* cell, const RenderObject* o)
-{
- bool oldPressed = [cell isHighlighted];
- bool pressed = (o->node() && o->node()->active());
- if (pressed != oldPressed)
- [cell setHighlighted:pressed];
-}
-
-bool RenderThemeMacShared::controlSupportsTints(const RenderObject* o) const
-{
- // An alternate way to implement this would be to get the appropriate cell object
- // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of
- // that would be that we would match AppKit behavior more closely, but a disadvantage
- // would be that we would rely on an AppKit SPI method.
-
- if (!isEnabled(o))
- return false;
-
- // Checkboxes only have tint when checked.
- if (o->style()->appearance() == CheckboxPart)
- return isChecked(o);
-
- // For now assume other controls have tint if enabled.
- return true;
-}
-
-NSControlSize RenderThemeMacShared::controlSizeForFont(RenderStyle* style) const
-{
- int fontSize = style->fontSize();
- if (fontSize >= 16)
- return NSRegularControlSize;
- if (fontSize >= 11)
- return NSSmallControlSize;
- return NSMiniControlSize;
-}
-
-void RenderThemeMacShared::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel)
-{
- NSControlSize size;
- if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) &&
- minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel))
- size = NSRegularControlSize;
- else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) &&
- minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel))
- size = NSSmallControlSize;
- else
- size = NSMiniControlSize;
- if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
- [cell setControlSize:size];
-}
-
-IntSize RenderThemeMacShared::sizeForFont(RenderStyle* style, const IntSize* sizes) const
-{
- if (style->effectiveZoom() != 1.0f) {
- IntSize result = sizes[controlSizeForFont(style)];
- return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
- }
- return sizes[controlSizeForFont(style)];
-}
-
-IntSize RenderThemeMacShared::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
-{
- if (style->effectiveZoom() != 1.0f) {
- IntSize result = sizes[controlSizeForSystemFont(style)];
- return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom());
- }
- return sizes[controlSizeForSystemFont(style)];
-}
-
-void RenderThemeMacShared::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
-{
- // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
- IntSize size = sizeForFont(style, sizes);
- if (style->width().isIntrinsicOrAuto() && size.width() > 0)
- style->setWidth(Length(size.width(), Fixed));
- if (style->height().isAuto() && size.height() > 0)
- style->setHeight(Length(size.height(), Fixed));
-}
-
-void RenderThemeMacShared::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const
-{
- FontDescription fontDescription;
- fontDescription.setIsAbsoluteSize(true);
- fontDescription.setGenericFamily(FontDescription::SerifFamily);
-
- NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
- fontDescription.firstFamily().setFamily([font familyName]);
- fontDescription.setComputedSize([font pointSize] * style->effectiveZoom());
- fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom());
-
- // Reset line height
- style->setLineHeight(RenderStyle::initialLineHeight());
-
- if (style->setFontDescription(fontDescription))
- style->font().update(0);
-}
-
-NSControlSize RenderThemeMacShared::controlSizeForSystemFont(RenderStyle* style) const
-{
- int fontSize = style->fontSize();
- if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize])
- return NSRegularControlSize;
- if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize])
- return NSSmallControlSize;
- return NSMiniControlSize;
-}
-
-bool RenderThemeMacShared::paintTextField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
- bool useNSTextFieldCell = o->style()->hasAppearance()
- && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white
- && !o->style()->hasBackgroundImage();
-
- // We do not use NSTextFieldCell to draw styled text fields on Lion and SnowLeopard because
- // there are a number of bugs on those platforms that require NSTextFieldCell to be in charge
- // of painting its own background. We need WebCore to paint styled backgrounds, so we'll use
- // this WebCoreSystemInterface function instead.
- if (!useNSTextFieldCell) {
- wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o));
- return false;
- }
-#endif
-
- NSTextFieldCell *textField = this->textField();
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- [textField setEnabled:(isEnabled(o) && !isReadOnlyControl(o))];
- [textField drawWithFrame:NSRect(r) inView:documentViewFor(o)];
-
- [textField setControlView:nil];
-
- return false;
-}
-
-void RenderThemeMacShared::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const
-{
-}
-
-bool RenderThemeMacShared::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r)
-{
- if (paintInfo.context->paintingDisabled())
- return true;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawCapsLockIndicator(localContext.cgContext(), r);
-
- return false;
-}
-
-bool RenderThemeMacShared::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
- return false;
-}
-
-void RenderThemeMacShared::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
-{
-}
-
-const int* RenderThemeMacShared::popupButtonMargins() const
-{
- static const int margins[3][4] =
- {
- { 0, 3, 1, 3 },
- { 0, 3, 2, 3 },
- { 0, 1, 0, 1 }
- };
- return margins[[popupButton() controlSize]];
-}
-
-const IntSize* RenderThemeMacShared::popupButtonSizes() const
-{
- static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
- return sizes;
-}
-
-const int* RenderThemeMacShared::popupButtonPadding(NSControlSize size) const
-{
- static const int padding[3][4] =
- {
- { 2, 26, 3, 8 },
- { 2, 23, 3, 8 },
- { 2, 22, 3, 10 }
- };
- return padding[size];
-}
-
-bool RenderThemeMacShared::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- setPopupButtonCellState(o, r);
-
- NSPopUpButtonCell* popupButton = this->popupButton();
-
- float zoomLevel = o->style()->effectiveZoom();
- IntSize size = popupButtonSizes()[[popupButton controlSize]];
- size.setHeight(size.height() * zoomLevel);
- size.setWidth(r.width());
-
- // Now inflate it to account for the shadow.
- IntRect inflatedRect = r;
- if (r.width() >= minimumMenuListSize(o->style()))
- inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel);
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
- paintInfo.context->clip(inflatedRect);
-
- if (zoomLevel != 1.0f) {
- inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
- inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
- paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
- }
-
- NSView *view = documentViewFor(o);
- [popupButton drawWithFrame:inflatedRect inView:view];
-#if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
- if (isFocused(o) && o->style()->outlineStyleIsAuto())
- [popupButton _web_drawFocusRingWithFrame:inflatedRect inView:view];
-#endif
- [popupButton setControlView:nil];
-
- return false;
-}
-
-#if ENABLE(METER_ELEMENT)
-
-IntSize RenderThemeMacShared::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const
-{
- if (NoControlPart == renderMeter->style()->appearance())
- return bounds.size();
-
- NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter);
- // Makes enough room for cell's intrinsic size.
- NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())];
- return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(),
- bounds.height() < cellSize.height ? cellSize.height : bounds.height());
-}
-
-bool RenderThemeMacShared::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
-{
- if (!renderObject->isMeter())
- return true;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
- NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject));
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- [cell drawWithFrame:rect inView:documentViewFor(renderObject)];
- [cell setControlView:nil];
- return false;
-}
-
-bool RenderThemeMacShared::supportsMeter(ControlPart part) const
-{
- switch (part) {
- case RelevancyLevelIndicatorPart:
- case DiscreteCapacityLevelIndicatorPart:
- case RatingLevelIndicatorPart:
- case MeterPart:
- case ContinuousCapacityLevelIndicatorPart:
- return true;
- default:
- return false;
- }
-}
-
-NSLevelIndicatorStyle RenderThemeMacShared::levelIndicatorStyleFor(ControlPart part) const
-{
- switch (part) {
- case RelevancyLevelIndicatorPart:
- return NSRelevancyLevelIndicatorStyle;
- case DiscreteCapacityLevelIndicatorPart:
- return NSDiscreteCapacityLevelIndicatorStyle;
- case RatingLevelIndicatorPart:
- return NSRatingLevelIndicatorStyle;
- case MeterPart:
- case ContinuousCapacityLevelIndicatorPart:
- default:
- return NSContinuousCapacityLevelIndicatorStyle;
- }
-
-}
-
-NSLevelIndicatorCell* RenderThemeMacShared::levelIndicatorFor(const RenderMeter* renderMeter) const
-{
- RenderStyle* style = renderMeter->style();
- ASSERT(style->appearance() != NoControlPart);
-
- if (!m_levelIndicator)
- m_levelIndicator.adoptNS([[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]);
- NSLevelIndicatorCell* cell = m_levelIndicator.get();
-
- HTMLMeterElement* element = renderMeter->meterElement();
- double value = element->value();
-
- // Because NSLevelIndicatorCell does not support optimum-in-the-middle type coloring,
- // we explicitly control the color instead giving low and high value to NSLevelIndicatorCell as is.
- switch (element->gaugeRegion()) {
- case HTMLMeterElement::GaugeRegionOptimum:
- // Make meter the green
- [cell setWarningValue:value + 1];
- [cell setCriticalValue:value + 2];
- break;
- case HTMLMeterElement::GaugeRegionSuboptimal:
- // Make the meter yellow
- [cell setWarningValue:value - 1];
- [cell setCriticalValue:value + 1];
- break;
- case HTMLMeterElement::GaugeRegionEvenLessGood:
- // Make the meter red
- [cell setWarningValue:value - 2];
- [cell setCriticalValue:value - 1];
- break;
- }
-
- [cell setLevelIndicatorStyle:levelIndicatorStyleFor(style->appearance())];
- [cell setBaseWritingDirection:style->isLeftToRightDirection() ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft];
- [cell setMinValue:element->min()];
- [cell setMaxValue:element->max()];
- RetainPtr<NSNumber> valueObject = [NSNumber numberWithDouble:value];
- [cell setObjectValue:valueObject.get()];
-
- return cell;
-}
-
-#endif
-
-#if ENABLE(PROGRESS_ELEMENT)
-const IntSize* RenderThemeMacShared::progressBarSizes() const
-{
- static const IntSize sizes[3] = { IntSize(0, 20), IntSize(0, 12), IntSize(0, 12) };
- return sizes;
-}
-
-const int* RenderThemeMacShared::progressBarMargins(NSControlSize controlSize) const
-{
- static const int margins[3][4] =
- {
- { 0, 0, 1, 0 },
- { 0, 0, 1, 0 },
- { 0, 0, 1, 0 },
- };
- return margins[controlSize];
-}
-
-int RenderThemeMacShared::minimumProgressBarHeight(RenderStyle* style) const
-{
- return sizeForSystemFont(style, progressBarSizes()).height();
-}
-
-double RenderThemeMacShared::animationRepeatIntervalForProgressBar(RenderProgress*) const
-{
- return progressAnimationFrameRate;
-}
-
-double RenderThemeMacShared::animationDurationForProgressBar(RenderProgress*) const
-{
- return progressAnimationNumFrames * progressAnimationFrameRate;
-}
-
-void RenderThemeMacShared::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const
-{
-}
-
-bool RenderThemeMacShared::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
-{
- if (!renderObject->isProgress())
- return true;
-
- float zoomLevel = renderObject->style()->effectiveZoom();
- int controlSize = controlSizeForFont(renderObject->style());
- IntSize size = progressBarSizes()[controlSize];
- size.setHeight(size.height() * zoomLevel);
- size.setWidth(rect.width());
-
- // Now inflate it to account for the shadow.
- IntRect inflatedRect = rect;
- if (rect.height() <= minimumProgressBarHeight(renderObject->style()))
- inflatedRect = inflateRect(inflatedRect, size, progressBarMargins(controlSize), zoomLevel);
-
- RenderProgress* renderProgress = toRenderProgress(renderObject);
- HIThemeTrackDrawInfo trackInfo;
- trackInfo.version = 0;
- if (controlSize == NSRegularControlSize)
- trackInfo.kind = renderProgress->position() < 0 ? kThemeLargeIndeterminateBar : kThemeLargeProgressBar;
- else
- trackInfo.kind = renderProgress->position() < 0 ? kThemeMediumIndeterminateBar : kThemeMediumProgressBar;
-
- trackInfo.bounds = IntRect(IntPoint(), inflatedRect.size());
- trackInfo.min = 0;
- trackInfo.max = numeric_limits<SInt32>::max();
- trackInfo.value = lround(renderProgress->position() * nextafter(trackInfo.max, 0));
- trackInfo.trackInfo.progress.phase = lround(renderProgress->animationProgress() * nextafter(progressAnimationNumFrames, 0));
- trackInfo.attributes = kThemeTrackHorizontal;
- trackInfo.enableState = isActive(renderObject) ? kThemeTrackActive : kThemeTrackInactive;
- trackInfo.reserved = 0;
- trackInfo.filler1 = 0;
-
- OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(inflatedRect.size(), 1);
- if (!imageBuffer)
- return true;
-
- ContextContainer cgContextContainer(imageBuffer->context());
- CGContextRef cgContext = cgContextContainer.context();
- HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- if (!renderProgress->style()->isLeftToRightDirection()) {
- paintInfo.context->translate(2 * inflatedRect.x() + inflatedRect.width(), 0);
- paintInfo.context->scale(FloatSize(-1, 1));
- }
-
- paintInfo.context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, inflatedRect.location());
- return false;
-}
-#endif
-
-const float baseFontSize = 11.0f;
-const float baseArrowHeight = 4.0f;
-const float baseArrowWidth = 5.0f;
-const float baseSpaceBetweenArrows = 2.0f;
-const int arrowPaddingLeft = 6;
-const int arrowPaddingRight = 6;
-const int paddingBeforeSeparator = 4;
-const int baseBorderRadius = 5;
-const int styledPopupPaddingLeft = 8;
-const int styledPopupPaddingTop = 1;
-const int styledPopupPaddingBottom = 2;
-
-static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
-{
- static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
- static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
- float a = inData[0];
- int i = 0;
- for (i = 0; i < 4; i++)
- outData[i] = (1.0f - a) * dark[i] + a * light[i];
-}
-
-static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
-{
- static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
- static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
- float a = inData[0];
- int i = 0;
- for (i = 0; i < 4; i++)
- outData[i] = (1.0f - a) * dark[i] + a * light[i];
-}
-
-static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
-{
- static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
- static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- float a = inData[0];
- int i = 0;
- for (i = 0; i < 4; i++)
- outData[i] = (1.0f - a) * dark[i] + a * light[i];
-}
-
-static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
-{
- static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
- static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
- float a = inData[0];
- int i = 0;
- for (i = 0; i < 4; i++)
- outData[i] = (1.0f - a) * dark[i] + a * light[i];
-}
-
-void RenderThemeMacShared::paintMenuListButtonGradients(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- if (r.isEmpty())
- return;
-
- ContextContainer cgContextContainer(paintInfo.context);
- CGContextRef context = cgContextContainer.context();
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- RoundedRect border = o->style()->getRoundedBorderFor(r, o->view());
- int radius = border.radii().topLeft().width();
-
- CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
-
- FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
- struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
- RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
-
- FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
- struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
- RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
-
- struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
- RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
-
- RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
-
- RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
-
- {
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(border);
- context = cgContextContainer.context();
- CGContextDrawShading(context, mainShading.get());
- }
-
- {
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- CGContextClipToRect(context, topGradient);
- paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(topGradient), border.radii().topLeft(), border.radii().topRight(), IntSize(), IntSize()));
- context = cgContextContainer.context();
- CGContextDrawShading(context, topShading.get());
- }
-
- if (!bottomGradient.isEmpty()) {
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- CGContextClipToRect(context, bottomGradient);
- paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), border.radii().bottomLeft(), border.radii().bottomRight()));
- context = cgContextContainer.context();
- CGContextDrawShading(context, bottomShading.get());
- }
-
- {
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(border);
- context = cgContextContainer.context();
- CGContextDrawShading(context, leftShading.get());
- CGContextDrawShading(context, rightShading.get());
- }
-}
-
-bool RenderThemeMacShared::paintMenuListButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
- r.y() + o->style()->borderTopWidth(),
- r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
- r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
- // Draw the gradients to give the styled popup menu a button appearance
- paintMenuListButtonGradients(o, paintInfo, bounds);
-
- // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds
- float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows));
- float centerY = bounds.y() + bounds.height() / 2.0f;
- float arrowHeight = baseArrowHeight * fontScale;
- float arrowWidth = baseArrowWidth * fontScale;
- float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth;
- float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale;
-
- if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
- return false;
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), o->style()->colorSpace());
- paintInfo.context->setStrokeStyle(NoStroke);
-
- FloatPoint arrow1[3];
- arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f);
- arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f);
- arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight);
-
- // Draw the top arrow
- paintInfo.context->drawConvexPolygon(3, arrow1, true);
-
- FloatPoint arrow2[3];
- arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f);
- arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f);
- arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight);
-
- // Draw the bottom arrow
- paintInfo.context->drawConvexPolygon(3, arrow2, true);
-
- Color leftSeparatorColor(0, 0, 0, 40);
- Color rightSeparatorColor(255, 255, 255, 40);
-
- // FIXME: Should the separator thickness and space be scaled up by fontScale?
- int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin.
- int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round?
-
- // Draw the separator to the left of the arrows
- paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
- paintInfo.context->setStrokeStyle(SolidStroke);
- paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB);
- paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
- IntPoint(leftEdgeOfSeparator, bounds.maxY()));
-
- paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB);
- paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
- IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY()));
- return false;
-}
-
-static const IntSize* menuListButtonSizes()
-{
- static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
- return sizes;
-}
-
-void RenderThemeMacShared::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
-{
- NSControlSize controlSize = controlSizeForFont(style);
-
- style->resetBorder();
- style->resetPadding();
-
- // Height is locked to auto.
- style->setHeight(Length(Auto));
-
- // White-space is locked to pre
- style->setWhiteSpace(PRE);
-
- // Set the foreground color to black or gray when we have the aqua look.
- // Cast to RGB32 is to work around a compiler bug.
- style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
-
- // Set the button's vertical size.
- setSizeFromFont(style, menuListButtonSizes());
-
- // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out
- // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
- // system font for the control size instead.
- setFontFromControlSize(styleResolver, style, controlSize);
-
- style->setBoxShadow(nullptr);
-}
-
-int RenderThemeMacShared::popupInternalPaddingLeft(RenderStyle* style) const
-{
- if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
- if (style->appearance() == MenulistButtonPart)
- return styledPopupPaddingLeft * style->effectiveZoom();
- return 0;
-}
-
-int RenderThemeMacShared::popupInternalPaddingRight(RenderStyle* style) const
-{
- if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
- if (style->appearance() == MenulistButtonPart) {
- float fontScale = style->fontSize() / baseFontSize;
- float arrowWidth = baseArrowWidth * fontScale;
- return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom()));
- }
- return 0;
-}
-
-int RenderThemeMacShared::popupInternalPaddingTop(RenderStyle* style) const
-{
- if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
- if (style->appearance() == MenulistButtonPart)
- return styledPopupPaddingTop * style->effectiveZoom();
- return 0;
-}
-
-int RenderThemeMacShared::popupInternalPaddingBottom(RenderStyle* style) const
-{
- if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
- if (style->appearance() == MenulistButtonPart)
- return styledPopupPaddingBottom * style->effectiveZoom();
- return 0;
-}
-
-void RenderThemeMacShared::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- float fontScale = style->fontSize() / baseFontSize;
-
- style->resetPadding();
- style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
-
- const int minHeight = 15;
- style->setMinHeight(Length(minHeight, Fixed));
-
- style->setLineHeight(RenderStyle::initialLineHeight());
-}
-
-void RenderThemeMacShared::setPopupButtonCellState(const RenderObject* o, const IntRect& r)
-{
- NSPopUpButtonCell* popupButton = this->popupButton();
-
- // Set the control size based off the rectangle we're painting into.
- setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
-
- // Update the various states we respond to.
- updateActiveState(popupButton, o);
- updateCheckedState(popupButton, o);
- updateEnabledState(popupButton, o);
- updatePressedState(popupButton, o);
-#if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
- updateFocusedState(popupButton, o);
-#endif
-}
-
-const IntSize* RenderThemeMacShared::menuListSizes() const
-{
- static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
- return sizes;
-}
-
-int RenderThemeMacShared::minimumMenuListSize(RenderStyle* style) const
-{
- return sizeForSystemFont(style, menuListSizes()).width();
-}
-
-const int trackWidth = 5;
-const int trackRadius = 2;
-
-void RenderThemeMacShared::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- style->setBoxShadow(nullptr);
-}
-
-bool RenderThemeMacShared::paintSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- IntRect bounds = r;
- float zoomLevel = o->style()->effectiveZoom();
- float zoomedTrackWidth = trackWidth * zoomLevel;
-
- if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) {
- bounds.setHeight(zoomedTrackWidth);
- bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2);
- } else if (o->style()->appearance() == SliderVerticalPart) {
- bounds.setWidth(zoomedTrackWidth);
- bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2);
- }
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- CGContextRef context = localContext.cgContext();
- CGColorSpaceRef cspace = deviceRGBColorSpaceRef();
-
-#if ENABLE(DATALIST_ELEMENT)
- paintSliderTicks(o, paintInfo, r);
-#endif
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- CGContextClipToRect(context, bounds);
-
- struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
- RetainPtr<CGShadingRef> mainShading;
- if (o->style()->appearance() == SliderVerticalPart)
- mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false));
- else
- mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false));
-
- IntSize radius(trackRadius, trackRadius);
- paintInfo.context->addRoundedRectClip(RoundedRect(bounds, radius, radius, radius, radius));
- context = localContext.cgContext();
- CGContextDrawShading(context, mainShading.get());
-
- return false;
-}
-
-void RenderThemeMacShared::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
-{
- RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
- style->setBoxShadow(nullptr);
-}
-
-const float verticalSliderHeightPadding = 0.1f;
-
-bool RenderThemeMacShared::paintSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart
- ? sliderThumbVertical()
- : sliderThumbHorizontal();
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
- // Update the various states we respond to.
- updateActiveState(sliderThumbCell, o);
- updateEnabledState(sliderThumbCell, o);
- updateFocusedState(sliderThumbCell, (o->node() && o->node()->focusDelegate()->renderer()) ? o->node()->focusDelegate()->renderer() : o);
-
- // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it.
- bool oldPressed;
- if (o->style()->appearance() == SliderThumbVerticalPart)
- oldPressed = m_isSliderThumbVerticalPressed;
- else
- oldPressed = m_isSliderThumbHorizontalPressed;
-
- bool pressed = isPressed(o);
-
- if (o->style()->appearance() == SliderThumbVerticalPart)
- m_isSliderThumbVerticalPressed = pressed;
- else
- m_isSliderThumbHorizontalPressed = pressed;
-
- if (pressed != oldPressed) {
- if (pressed)
- [sliderThumbCell startTrackingAt:NSPoint() inView:nil];
- else
- [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES];
- }
-
- FloatRect bounds = r;
- // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider.
- if (o->style()->appearance() == SliderThumbVerticalPart)
- bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom());
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- float zoomLevel = o->style()->effectiveZoom();
-
- FloatRect unzoomedRect = bounds;
- if (zoomLevel != 1.0f) {
- unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
- unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
- paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
- }
-
-#if PLATFORM(CHROMIUM)
- paintInfo.context->translate(0, unzoomedRect.y());
- paintInfo.context->scale(FloatSize(1, -1));
- paintInfo.context->translate(0, -(unzoomedRect.y() + unzoomedRect.height()));
-#endif
-
- [sliderThumbCell drawInteriorWithFrame:unzoomedRect inView:documentViewFor(o)];
- [sliderThumbCell setControlView:nil];
-
- return false;
-}
-
-bool RenderThemeMacShared::paintSearchField(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- NSSearchFieldCell* search = this->search();
-
- setSearchCellState(o, r);
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- float zoomLevel = o->style()->effectiveZoom();
-
- IntRect unzoomedRect = r;
-
- if (zoomLevel != 1.0f) {
- unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
- unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
- paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
- }
-
- // Set the search button to nil before drawing. Then reset it so we can draw it later.
- [search setSearchButtonCell:nil];
-
- [search drawWithFrame:NSRect(unzoomedRect) inView:documentViewFor(o)];
-
- [search setControlView:nil];
- [search resetSearchButtonCell];
-
- return false;
-}
-
-void RenderThemeMacShared::setSearchCellState(RenderObject* o, const IntRect&)
-{
- NSSearchFieldCell* search = this->search();
-
- [search setControlSize:controlSizeForFont(o->style())];
-
- // Update the various states we respond to.
- updateActiveState(search, o);
- updateEnabledState(search, o);
- updateFocusedState(search, o);
-}
-
-const IntSize* RenderThemeMacShared::searchFieldSizes() const
-{
- static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) };
- return sizes;
-}
-
-void RenderThemeMacShared::setSearchFieldSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- // Use the font size to determine the intrinsic width of the control.
- setSizeFromFont(style, searchFieldSizes());
-}
-
-void RenderThemeMacShared::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const
-{
- // Override border.
- style->resetBorder();
- const short borderWidth = 2 * style->effectiveZoom();
- style->setBorderLeftWidth(borderWidth);
- style->setBorderLeftStyle(INSET);
- style->setBorderRightWidth(borderWidth);
- style->setBorderRightStyle(INSET);
- style->setBorderBottomWidth(borderWidth);
- style->setBorderBottomStyle(INSET);
- style->setBorderTopWidth(borderWidth);
- style->setBorderTopStyle(INSET);
-
- // Override height.
- style->setHeight(Length(Auto));
- setSearchFieldSize(style);
-
- // Override padding size to match AppKit text positioning.
- const int padding = 1 * style->effectiveZoom();
- style->setPaddingLeft(Length(padding, Fixed));
- style->setPaddingRight(Length(padding, Fixed));
- style->setPaddingTop(Length(padding, Fixed));
- style->setPaddingBottom(Length(padding, Fixed));
-
- NSControlSize controlSize = controlSizeForFont(style);
- setFontFromControlSize(styleResolver, style, controlSize);
-
- style->setBoxShadow(nullptr);
-}
-
-bool RenderThemeMacShared::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- Element* input = o->node()->shadowHost();
- if (!input)
- input = toElement(o->node());
-
- if (!input->renderer()->isBox())
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- setSearchCellState(input->renderer(), r);
-
- NSSearchFieldCell* search = this->search();
-
- if (input->isEnabledFormControl() && (input->isTextFormControl() && !static_cast<HTMLTextFormControlElement*>(input)->readOnly())) {
- updateActiveState([search cancelButtonCell], o);
- updatePressedState([search cancelButtonCell], o);
- }
- else if ([[search cancelButtonCell] isHighlighted])
- [[search cancelButtonCell] setHighlighted:NO];
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
-
- float zoomLevel = o->style()->effectiveZoom();
-
- FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
-
-#if ENABLE(INPUT_SPEECH)
- // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g.
- // when speech input is enabled for the input element.
- IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect();
- int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight();
- int spaceToRightOfCancelButton = absRight - (r.x() + r.width());
- localBounds.setX(localBounds.x() - spaceToRightOfCancelButton);
-#endif
-
- localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
-
- FloatRect unzoomedRect(localBounds);
- if (zoomLevel != 1.0f) {
- unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
- unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
- paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
- }
-
- [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
- [[search cancelButtonCell] setControlView:nil];
- return false;
-}
-
-const IntSize* RenderThemeMacShared::cancelButtonSizes() const
-{
- static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
- return sizes;
-}
-
-void RenderThemeMacShared::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize size = sizeForSystemFont(style, cancelButtonSizes());
- style->setWidth(Length(size.width(), Fixed));
- style->setHeight(Length(size.height(), Fixed));
- style->setBoxShadow(nullptr);
-}
-
-const IntSize* RenderThemeMacShared::resultsButtonSizes() const
-{
- static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
- return sizes;
-}
-
-const int emptyResultsOffset = 9;
-void RenderThemeMacShared::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize size = sizeForSystemFont(style, resultsButtonSizes());
- style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
- style->setHeight(Length(size.height(), Fixed));
- style->setBoxShadow(nullptr);
-}
-
-bool RenderThemeMacShared::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&)
-{
- return false;
-}
-
-void RenderThemeMacShared::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize size = sizeForSystemFont(style, resultsButtonSizes());
- style->setWidth(Length(size.width(), Fixed));
- style->setHeight(Length(size.height(), Fixed));
- style->setBoxShadow(nullptr);
-}
-
-bool RenderThemeMacShared::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- Node* input = o->node()->shadowHost();
- if (!input)
- input = o->node();
- if (!input->renderer()->isBox())
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- setSearchCellState(input->renderer(), r);
-
- NSSearchFieldCell* search = this->search();
-
- if ([search searchMenuTemplate] != nil)
- [search setSearchMenuTemplate:nil];
-
- updateActiveState([search searchButtonCell], o);
-
- FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
- localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
-
- [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)];
- [[search searchButtonCell] setControlView:nil];
- return false;
-}
-
-const int resultsArrowWidth = 5;
-void RenderThemeMacShared::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
-{
- IntSize size = sizeForSystemFont(style, resultsButtonSizes());
- style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
- style->setHeight(Length(size.height(), Fixed));
- style->setBoxShadow(nullptr);
-}
-
-bool RenderThemeMacShared::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
-{
- Node* input = o->node()->shadowHost();
- if (!input)
- input = o->node();
- if (!input->renderer()->isBox())
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- setSearchCellState(input->renderer(), r);
-
- NSSearchFieldCell* search = this->search();
-
- updateActiveState([search searchButtonCell], o);
-
- if (![search searchMenuTemplate])
- [search setSearchMenuTemplate:searchMenuTemplate()];
-
- GraphicsContextStateSaver stateSaver(*paintInfo.context);
- float zoomLevel = o->style()->effectiveZoom();
-
- FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())];
- localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
-
- IntRect unzoomedRect(localBounds);
- if (zoomLevel != 1.0f) {
- unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
- unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
- paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
- }
-
- [[search searchButtonCell] drawWithFrame:unzoomedRect inView:documentViewFor(o)];
- [[search searchButtonCell] setControlView:nil];
-
- return false;
-}
-
-#if ENABLE(DATALIST_ELEMENT)
-IntSize RenderThemeMacShared::sliderTickSize() const
-{
- return IntSize(1, 3);
-}
-
-int RenderThemeMacShared::sliderTickOffsetFromTrackCenter() const
-{
- return -9;
-}
-#endif
-
-const int sliderThumbWidth = 15;
-const int sliderThumbHeight = 15;
-
-void RenderThemeMacShared::adjustSliderThumbSize(RenderStyle* style, Element*) const
-{
- float zoomLevel = style->effectiveZoom();
- if (style->appearance() == SliderThumbHorizontalPart || style->appearance() == SliderThumbVerticalPart) {
- style->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
- style->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
- }
-
-#if ENABLE(VIDEO)
- adjustMediaSliderThumbSize(style);
-#endif
-}
-
-bool RenderThemeMacShared::shouldShowPlaceholderWhenFocused() const
-{
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
- return true;
-#else
- return false;
-#endif
-}
-
-NSPopUpButtonCell* RenderThemeMacShared::popupButton() const
-{
- if (!m_popupButton) {
- m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
- [m_popupButton.get() setUsesItemFromMenu:NO];
- [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
- }
-
- return m_popupButton.get();
-}
-
-NSSearchFieldCell* RenderThemeMacShared::search() const
-{
- if (!m_search) {
- m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]);
- [m_search.get() setBezelStyle:NSTextFieldRoundedBezel];
- [m_search.get() setBezeled:YES];
- [m_search.get() setEditable:YES];
- [m_search.get() setFocusRingType:NSFocusRingTypeExterior];
- }
-
- return m_search.get();
-}
-
-NSMenu* RenderThemeMacShared::searchMenuTemplate() const
-{
- if (!m_searchMenuTemplate)
- m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]);
-
- return m_searchMenuTemplate.get();
-}
-
-NSSliderCell* RenderThemeMacShared::sliderThumbHorizontal() const
-{
- if (!m_sliderThumbHorizontal) {
- m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]);
- [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider];
- [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
- [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
- }
-
- return m_sliderThumbHorizontal.get();
-}
-
-NSSliderCell* RenderThemeMacShared::sliderThumbVertical() const
-{
- if (!m_sliderThumbVertical) {
- m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]);
- [m_sliderThumbVertical.get() setSliderType:NSLinearSlider];
- [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
- [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
- }
-
- return m_sliderThumbVertical.get();
-}
-
-NSTextFieldCell* RenderThemeMacShared::textField() const
-{
- if (!m_textField) {
- m_textField.adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]);
- [m_textField.get() setBezeled:YES];
- [m_textField.get() setEditable:YES];
- [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
-#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
- [m_textField.get() setDrawsBackground:YES];
- [m_textField.get() setBackgroundColor:[NSColor whiteColor]];
-#else
- // Post-Lion, WebCore can be in charge of paintinng the background thanks to
- // the workaround in place for <rdar://problem/11385461>, which is implemented
- // above as _coreUIDrawOptionsWithFrame.
- [m_textField.get() setDrawsBackground:NO];
-#endif
- }
-
- return m_textField.get();
-}
-
-String RenderThemeMacShared::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
-{
- if (width <= 0)
- return String();
-
- String strToTruncate;
- if (fileList->isEmpty())
- strToTruncate = fileListDefaultLabel(multipleFilesAllowed);
- else if (fileList->length() == 1)
- strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())];
- else
- return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);
-
- return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks);
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderThemeSafari.cpp b/Source/WebCore/rendering/RenderThemeSafari.cpp
index 21d978c8b..2ab016d84 100644
--- a/Source/WebCore/rendering/RenderThemeSafari.cpp
+++ b/Source/WebCore/rendering/RenderThemeSafari.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc.
+ * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc.
* Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
@@ -35,9 +35,11 @@
#include "GraphicsContextCG.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
+#include "HTMLMeterElement.h"
#include "HTMLNames.h"
#include "PaintInfo.h"
#include "RenderMediaControls.h"
+#include "RenderMeter.h"
#include "RenderSlider.h"
#include "RenderView.h"
#include "SoftLinking.h"
@@ -170,7 +172,7 @@ Color RenderThemeSafari::platformFocusRingColor() const
if (!focusRingColor.isValid()) {
if (STCopyThemeColorPtr()) {
- RetainPtr<CGColorRef> color(AdoptCF, STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState));
+ RetainPtr<CGColorRef> color = adoptCF(STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState));
focusRingColor = makeRGBAFromCGColor(color.get());
}
if (!focusRingColor.isValid())
@@ -187,7 +189,7 @@ static float systemFontSizeForControlSize(NSControlSize controlSize)
return sizes[controlSize];
}
-void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription) const
+void RenderThemeSafari::systemFont(CSSValueID valueID, FontDescription& fontDescription) const
{
static FontDescription systemFont;
static FontDescription smallSystemFont;
@@ -199,47 +201,47 @@ void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription)
FontDescription* cachedDesc;
float fontSize = 0;
- switch (propId) {
- case CSSValueSmallCaption:
- cachedDesc = &smallSystemFont;
- if (!smallSystemFont.isAbsoluteSize())
- fontSize = systemFontSizeForControlSize(NSSmallControlSize);
- break;
- case CSSValueMenu:
- cachedDesc = &menuFont;
- if (!menuFont.isAbsoluteSize())
- fontSize = systemFontSizeForControlSize(NSRegularControlSize);
- break;
- case CSSValueStatusBar:
- cachedDesc = &labelFont;
- if (!labelFont.isAbsoluteSize())
- fontSize = 10.0f;
- break;
- case CSSValueWebkitMiniControl:
- cachedDesc = &miniControlFont;
- if (!miniControlFont.isAbsoluteSize())
- fontSize = systemFontSizeForControlSize(NSMiniControlSize);
- break;
- case CSSValueWebkitSmallControl:
- cachedDesc = &smallControlFont;
- if (!smallControlFont.isAbsoluteSize())
- fontSize = systemFontSizeForControlSize(NSSmallControlSize);
- break;
- case CSSValueWebkitControl:
- cachedDesc = &controlFont;
- if (!controlFont.isAbsoluteSize())
- fontSize = systemFontSizeForControlSize(NSRegularControlSize);
- break;
- default:
- cachedDesc = &systemFont;
- if (!systemFont.isAbsoluteSize())
- fontSize = 13.0f;
+ switch (valueID) {
+ case CSSValueSmallCaption:
+ cachedDesc = &smallSystemFont;
+ if (!smallSystemFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSSmallControlSize);
+ break;
+ case CSSValueMenu:
+ cachedDesc = &menuFont;
+ if (!menuFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSRegularControlSize);
+ break;
+ case CSSValueStatusBar:
+ cachedDesc = &labelFont;
+ if (!labelFont.isAbsoluteSize())
+ fontSize = 10.0f;
+ break;
+ case CSSValueWebkitMiniControl:
+ cachedDesc = &miniControlFont;
+ if (!miniControlFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSMiniControlSize);
+ break;
+ case CSSValueWebkitSmallControl:
+ cachedDesc = &smallControlFont;
+ if (!smallControlFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSSmallControlSize);
+ break;
+ case CSSValueWebkitControl:
+ cachedDesc = &controlFont;
+ if (!controlFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSRegularControlSize);
+ break;
+ default:
+ cachedDesc = &systemFont;
+ if (!systemFont.isAbsoluteSize())
+ fontSize = 13.0f;
}
if (fontSize) {
cachedDesc->setIsAbsoluteSize(true);
cachedDesc->setGenericFamily(FontDescription::NoFamily);
- cachedDesc->firstFamily().setFamily("Lucida Grande");
+ cachedDesc->setOneFamily("Lucida Grande");
cachedDesc->setSpecifiedSize(fontSize);
cachedDesc->setWeight(FontWeightNormal);
cachedDesc->setItalic(false);
@@ -390,7 +392,7 @@ void RenderThemeSafari::setFontFromControlSize(StyleResolver* styleResolver, Ren
fontDescription.setGenericFamily(FontDescription::SerifFamily);
float fontSize = systemFontSizeForControlSize(controlSize);
- fontDescription.firstFamily().setFamily("Lucida Grande");
+ fontDescription.setOneFamily("Lucida Grande");
fontDescription.setComputedSize(fontSize);
fontDescription.setSpecifiedSize(fontSize);
@@ -760,44 +762,44 @@ void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const Pain
FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
- RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
+ RetainPtr<CGFunctionRef> topFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
+ RetainPtr<CGShadingRef> topShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false));
FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
- RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
+ RetainPtr<CGFunctionRef> bottomFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
+ RetainPtr<CGShadingRef> bottomShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false));
struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
- RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
+ RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
+ RetainPtr<CGShadingRef> mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false));
- RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
+ RetainPtr<CGShadingRef> leftShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
- RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
+ RetainPtr<CGShadingRef> rightShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false));
paintInfo.context->save();
CGContextClipToRect(context, bound.rect());
- paintInfo.context->addRoundedRectClip(bound);
+ paintInfo.context->clipRoundedRect(bound);
CGContextDrawShading(context, mainShading.get());
paintInfo.context->restore();
paintInfo.context->save();
CGContextClipToRect(context, topGradient);
- paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(topGradient), bound.radii().topLeft(), bound.radii().topRight(), IntSize(), IntSize()));
+ paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(topGradient), bound.radii().topLeft(), bound.radii().topRight(), IntSize(), IntSize()));
CGContextDrawShading(context, topShading.get());
paintInfo.context->restore();
if (!bottomGradient.isEmpty()) {
paintInfo.context->save();
CGContextClipToRect(context, bottomGradient);
- paintInfo.context->addRoundedRectClip(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bound.radii().bottomLeft(), bound.radii().bottomRight()));
+ paintInfo.context->clipRoundedRect(RoundedRect(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bound.radii().bottomLeft(), bound.radii().bottomRight()));
CGContextDrawShading(context, bottomShading.get());
paintInfo.context->restore();
}
paintInfo.context->save();
CGContextClipToRect(context, bound.rect());
- paintInfo.context->addRoundedRectClip(bound);
+ paintInfo.context->clipRoundedRect(bound);
CGContextDrawShading(context, leftShading.get());
CGContextDrawShading(context, rightShading.get());
paintInfo.context->restore();
@@ -874,7 +876,7 @@ void RenderThemeSafari::adjustMenuListStyle(StyleResolver* styleResolver, Render
// Set the foreground color to black or gray when we have the aqua look.
// Cast to RGB32 is to work around a compiler bug.
- style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
+ style->setColor(e && !e->isDisabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
// Set the button's vertical size.
setButtonSize(style);
@@ -974,14 +976,14 @@ bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const PaintInfo& paint
CGContextClipToRect(context, bounds.rect());
struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
- RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
+ RetainPtr<CGFunctionRef> mainFunction = adoptCF(CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
RetainPtr<CGShadingRef> mainShading;
if (o->style()->appearance() == SliderVerticalPart)
- mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().maxY()), CGPointMake(bounds.rect().maxX(), bounds.rect().maxY()), mainFunction.get(), false, false));
+ mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().maxY()), CGPointMake(bounds.rect().maxX(), bounds.rect().maxY()), mainFunction.get(), false, false));
else
- mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().y()), CGPointMake(bounds.rect().x(), bounds.rect().maxY()), mainFunction.get(), false, false));
+ mainShading = adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().y()), CGPointMake(bounds.rect().x(), bounds.rect().maxY()), mainFunction.get(), false, false));
- paintInfo.context->addRoundedRectClip(bounds);
+ paintInfo.context->clipRoundedRect(bounds);
CGContextDrawShading(context, mainShading.get());
paintInfo.context->restore();
@@ -1202,6 +1204,52 @@ bool RenderThemeSafari::paintMediaSliderThumb(RenderObject* o, const PaintInfo&
}
#endif
+#if ENABLE(METER_ELEMENT)
+void RenderThemeSafari::adjustMeterStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeSafari::supportsMeter(ControlPart part) const
+{
+ switch (part) {
+ case MeterPart:
+ return true;
+ default:
+ return false;
+ }
+}
+
+IntSize RenderThemeSafari::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const
+{
+ return bounds.size();
+}
+
+bool RenderThemeSafari::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ // NOTE: This routine is for testing only. It should be fleshed out with a real CG-based implementation.
+ // Right now it uses a slider, with the thumb positioned at the meter point.
+ if (!renderObject->isMeter())
+ return true;
+
+ HTMLMeterElement* element = toRenderMeter(renderObject)->meterElement();
+
+ int remaining = static_cast<int>((1.0 - element->valueRatio()) * static_cast<double>(rect.size().width()));
+
+ // Draw the background
+ paintSliderTrack(renderObject, paintInfo, rect);
+
+ // Draw the progress portion
+ IntRect completedRect(rect);
+ completedRect.contract(remaining, 0);
+
+ paintSliderThumb(renderObject, paintInfo, completedRect);
+
+ return true;
+}
+
+#endif
+
} // namespace WebCore
#endif // #if USE(SAFARI_THEME)
diff --git a/Source/WebCore/rendering/RenderThemeSafari.h b/Source/WebCore/rendering/RenderThemeSafari.h
index fe26f326b..457e0d365 100644
--- a/Source/WebCore/rendering/RenderThemeSafari.h
+++ b/Source/WebCore/rendering/RenderThemeSafari.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc.
+ * Copyright (C) 2007, 2008, 2013 Apple Inc.
* Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
@@ -72,7 +72,7 @@ public:
virtual Color platformFocusRingColor() const;
// System fonts.
- virtual void systemFont(int propId, FontDescription&) const;
+ virtual void systemFont(CSSValueID, FontDescription&) const;
virtual int minimumMenuListSize(RenderStyle*) const;
@@ -138,6 +138,13 @@ protected:
virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
#endif
+#if ENABLE(METER_ELEMENT)
+ virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE;
+ virtual bool supportsMeter(ControlPart) const OVERRIDE;
+ virtual void adjustMeterStyle(StyleResolver*, RenderStyle*, Element*) const OVERRIDE;
+ virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE;
+#endif
+
virtual bool shouldShowPlaceholderWhenFocused() const { return true; }
private:
diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp
index 49ab18606..ed91f5b14 100644
--- a/Source/WebCore/rendering/RenderThemeWin.cpp
+++ b/Source/WebCore/rendering/RenderThemeWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2006, 2007, 2013 Apple Inc.
* Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
@@ -26,6 +26,7 @@
#include "Element.h"
#include "FontMetrics.h"
#include "Frame.h"
+#include "FrameSelection.h"
#include "GraphicsContext.h"
#include "LocalWindowsContext.h"
#include "PaintInfo.h"
@@ -108,6 +109,36 @@
#define UPS_PRESSED 3
#define UPS_DISABLED 4
+// Progress bar parts
+#define PP_BAR 1
+#define PP_BARVERT 2
+#define PP_CHUNK 3
+#define PP_CHUNKVERT 4
+#define PP_FILL 5
+#define PP_FILLVERT 6
+#define PP_PULSEOVERLAY 7
+#define PP_MOVEOVERLAY 8
+#define PP_PULSEOVERLAYVERT 9
+#define PP_MOVEOVERLAYVERT 10
+#define PP_TRANSPARENTBAR 11
+#define PP_TRANSPARENTBARVERT 12
+
+// Progress bar states
+#define PBBS_NORMAL 1
+#define PBBS_PARTIAL 2
+#define PBBVS_NORMAL 1 // Vertical
+#define PBBVS_PARTIAL 2
+
+// Progress bar fill states
+#define PBFS_NORMAL 1
+#define PBFS_ERROR 2
+#define PBFS_PAUSED 3
+#define PBFS_PARTIAL 4
+#define PBFVS_NORMAL 1 // Vertical
+#define PBFVS_ERROR 2
+#define PBFVS_PAUSED 3
+#define PBFVS_PARTIAL 4
+
SOFT_LINK_LIBRARY(uxtheme)
SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
@@ -145,7 +176,7 @@ static bool gWebKitIsBeingUnloaded;
static bool documentIsInApplicationChromeMode(const Document* document)
{
Settings* settings = document->settings();
- return settings && settings->inApplicationChromeMode();
+ return settings && settings->applicationChromeMode();
}
void RenderThemeWin::setWebKitIsBeingUnloaded()
@@ -172,6 +203,7 @@ RenderThemeWin::RenderThemeWin()
, m_menuListTheme(0)
, m_sliderTheme(0)
, m_spinButtonTheme(0)
+ , m_progressBarTheme(0)
{
haveTheme = uxthemeLibrary() && IsThemeActive();
}
@@ -219,6 +251,13 @@ HANDLE RenderThemeWin::spinButtonTheme() const
return m_spinButtonTheme;
}
+HANDLE RenderThemeWin::progressBarTheme() const
+{
+ if (haveTheme && !m_progressBarTheme)
+ m_progressBarTheme = OpenThemeData(0, L"Progress");
+ return m_progressBarTheme;
+}
+
void RenderThemeWin::close()
{
// This method will need to be called when the OS theme changes to flush our cached themes.
@@ -232,7 +271,9 @@ void RenderThemeWin::close()
CloseThemeData(m_sliderTheme);
if (m_spinButtonTheme)
CloseThemeData(m_spinButtonTheme);
- m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = m_spinButtonTheme = 0;
+ if (m_progressBarTheme)
+ CloseThemeData(m_progressBarTheme);
+ m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = m_spinButtonTheme = m_progressBarTheme = 0;
haveTheme = uxthemeLibrary() && IsThemeActive();
}
@@ -285,7 +326,7 @@ static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFo
{
fontDescription.setIsAbsoluteSize(true);
fontDescription.setGenericFamily(FontDescription::NoFamily);
- fontDescription.firstFamily().setFamily(String(logFont.lfFaceName));
+ fontDescription.setOneFamily(String(logFont.lfFaceName));
fontDescription.setSpecifiedSize(fontSize);
fontDescription.setWeight(logFont.lfWeight >= 700 ? FontWeightBold : FontWeightNormal); // FIXME: Use real weight.
fontDescription.setItalic(logFont.lfItalic);
@@ -296,7 +337,7 @@ static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFo
fillFontDescription(fontDescription, logFont, abs(logFont.lfHeight));
}
-void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) const
+void RenderThemeWin::systemFont(CSSValueID valueID, FontDescription& fontDescription) const
{
static FontDescription captionFont;
static FontDescription controlFont;
@@ -316,65 +357,65 @@ void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) co
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
}
- switch (propId) {
- case CSSValueIcon: {
- if (!iconFont.isAbsoluteSize()) {
+ switch (valueID) {
+ case CSSValueIcon: {
+ if (!iconFont.isAbsoluteSize()) {
+ LOGFONT logFont;
+ ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
+ fillFontDescription(iconFont, logFont);
+ }
+ fontDescription = iconFont;
+ break;
+ }
+ case CSSValueMenu:
+ if (!menuFont.isAbsoluteSize())
+ fillFontDescription(menuFont, ncm.lfMenuFont);
+ fontDescription = menuFont;
+ break;
+ case CSSValueMessageBox:
+ if (!messageBoxFont.isAbsoluteSize())
+ fillFontDescription(messageBoxFont, ncm.lfMessageFont);
+ fontDescription = messageBoxFont;
+ break;
+ case CSSValueStatusBar:
+ if (!statusBarFont.isAbsoluteSize())
+ fillFontDescription(statusBarFont, ncm.lfStatusFont);
+ fontDescription = statusBarFont;
+ break;
+ case CSSValueCaption:
+ if (!captionFont.isAbsoluteSize())
+ fillFontDescription(captionFont, ncm.lfCaptionFont);
+ fontDescription = captionFont;
+ break;
+ case CSSValueSmallCaption:
+ if (!smallCaptionFont.isAbsoluteSize())
+ fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont);
+ fontDescription = smallCaptionFont;
+ break;
+ case CSSValueWebkitSmallControl:
+ case CSSValueWebkitMiniControl: // Just map to small.
+ case CSSValueWebkitControl: // Just map to small.
+ if (!controlFont.isAbsoluteSize()) {
+ HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
+ if (hGDI) {
LOGFONT logFont;
- ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
- fillFontDescription(iconFont, logFont);
+ if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
+ fillFontDescription(controlFont, logFont, defaultControlFontPixelSize);
}
- fontDescription = iconFont;
- break;
}
- case CSSValueMenu:
- if (!menuFont.isAbsoluteSize())
- fillFontDescription(menuFont, ncm.lfMenuFont);
- fontDescription = menuFont;
- break;
- case CSSValueMessageBox:
- if (!messageBoxFont.isAbsoluteSize())
- fillFontDescription(messageBoxFont, ncm.lfMessageFont);
- fontDescription = messageBoxFont;
- break;
- case CSSValueStatusBar:
- if (!statusBarFont.isAbsoluteSize())
- fillFontDescription(statusBarFont, ncm.lfStatusFont);
- fontDescription = statusBarFont;
- break;
- case CSSValueCaption:
- if (!captionFont.isAbsoluteSize())
- fillFontDescription(captionFont, ncm.lfCaptionFont);
- fontDescription = captionFont;
- break;
- case CSSValueSmallCaption:
- if (!smallCaptionFont.isAbsoluteSize())
- fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont);
- fontDescription = smallCaptionFont;
- break;
- case CSSValueWebkitSmallControl:
- case CSSValueWebkitMiniControl: // Just map to small.
- case CSSValueWebkitControl: // Just map to small.
- if (!controlFont.isAbsoluteSize()) {
- HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
- if (hGDI) {
- LOGFONT logFont;
- if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
- fillFontDescription(controlFont, logFont, defaultControlFontPixelSize);
- }
- }
- fontDescription = controlFont;
- break;
- default: { // Everything else uses the stock GUI font.
- if (!systemFont.isAbsoluteSize()) {
- HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
- if (hGDI) {
- LOGFONT logFont;
- if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
- fillFontDescription(systemFont, logFont);
- }
+ fontDescription = controlFont;
+ break;
+ default: { // Everything else uses the stock GUI font.
+ if (!systemFont.isAbsoluteSize()) {
+ HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
+ if (hGDI) {
+ LOGFONT logFont;
+ if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
+ fillFontDescription(systemFont, logFont);
}
- fontDescription = systemFont;
}
+ fontDescription = systemFont;
+ }
}
}
@@ -522,6 +563,10 @@ ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o, ControlSubPart su
result.m_part = DFC_SCROLL;
result.m_state = determineClassicState(o);
break;
+ case MeterPart:
+ result.m_part = PP_BAR;
+ result.m_state = determineState(o);
+ break;
case SearchFieldPart:
case TextFieldPart:
case TextAreaPart:
@@ -583,6 +628,10 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o, ControlSubPart subPart)
result.m_state = determineState(o);
break;
}
+ case MeterPart:
+ result.m_part = PP_BAR;
+ result.m_state = determineState(o);
+ break;
case RadioPart:
result.m_part = BP_RADIO;
result.m_state = determineState(o);
@@ -675,11 +724,8 @@ static void drawControl(GraphicsContext* context, RenderObject* o, HANDLE theme,
}
}
-
-#if !OS(WINCE)
if (!alphaBlend && !context->isInTransparencyLayer())
DIBPixelData::setRGBABitmapAlpha(windowsContext.hdc(), r, 255);
-#endif
}
bool RenderThemeWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
@@ -988,42 +1034,42 @@ bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const PaintI
}
// Map a CSSValue* system color to an index understood by GetSysColor
-static int cssValueIdToSysColorIndex(int cssValueId)
+static int cssValueIdToSysColorIndex(CSSValueID cssValueId)
{
switch (cssValueId) {
- case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
- case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
- case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
- case CSSValueBackground: return COLOR_BACKGROUND;
- case CSSValueButtonface: return COLOR_BTNFACE;
- case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
- case CSSValueButtonshadow: return COLOR_BTNSHADOW;
- case CSSValueButtontext: return COLOR_BTNTEXT;
- case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
- case CSSValueGraytext: return COLOR_GRAYTEXT;
- case CSSValueHighlight: return COLOR_HIGHLIGHT;
- case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
- case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
- case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
- case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
- case CSSValueInfobackground: return COLOR_INFOBK;
- case CSSValueInfotext: return COLOR_INFOTEXT;
- case CSSValueMenu: return COLOR_MENU;
- case CSSValueMenutext: return COLOR_MENUTEXT;
- case CSSValueScrollbar: return COLOR_SCROLLBAR;
- case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
- case CSSValueThreedface: return COLOR_3DFACE;
- case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
- case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
- case CSSValueThreedshadow: return COLOR_3DSHADOW;
- case CSSValueWindow: return COLOR_WINDOW;
- case CSSValueWindowframe: return COLOR_WINDOWFRAME;
- case CSSValueWindowtext: return COLOR_WINDOWTEXT;
- default: return -1; // Unsupported CSSValue
+ case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
+ case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
+ case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
+ case CSSValueBackground: return COLOR_BACKGROUND;
+ case CSSValueButtonface: return COLOR_BTNFACE;
+ case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
+ case CSSValueButtonshadow: return COLOR_BTNSHADOW;
+ case CSSValueButtontext: return COLOR_BTNTEXT;
+ case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
+ case CSSValueGraytext: return COLOR_GRAYTEXT;
+ case CSSValueHighlight: return COLOR_HIGHLIGHT;
+ case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
+ case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
+ case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
+ case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
+ case CSSValueInfobackground: return COLOR_INFOBK;
+ case CSSValueInfotext: return COLOR_INFOTEXT;
+ case CSSValueMenu: return COLOR_MENU;
+ case CSSValueMenutext: return COLOR_MENUTEXT;
+ case CSSValueScrollbar: return COLOR_SCROLLBAR;
+ case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
+ case CSSValueThreedface: return COLOR_3DFACE;
+ case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
+ case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
+ case CSSValueThreedshadow: return COLOR_3DSHADOW;
+ case CSSValueWindow: return COLOR_WINDOW;
+ case CSSValueWindowframe: return COLOR_WINDOWFRAME;
+ case CSSValueWindowtext: return COLOR_WINDOWTEXT;
+ default: return -1; // Unsupported CSSValue
}
}
-Color RenderThemeWin::systemColor(int cssValueId) const
+Color RenderThemeWin::systemColor(CSSValueID cssValueId) const
{
int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
if (sysColorIndex == -1)
@@ -1049,12 +1095,7 @@ String RenderThemeWin::extraFullScreenStyleSheet()
bool RenderThemeWin::supportsClosedCaptioning() const
{
- // We rely on QuickTime to render captions so only enable the button for a video element.
-#if SAFARI_THEME_VERSION >= 4
return true;
-#else
- return false;
-#endif
}
bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
@@ -1127,7 +1168,54 @@ IntPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonB
return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size);
}
+#endif
+
+#if ENABLE(METER_ELEMENT)
+void RenderThemeWin::adjustMeterStyle(StyleResolver*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(nullptr);
+}
+
+bool RenderThemeWin::supportsMeter(ControlPart part) const
+{
+ switch (part) {
+ case MeterPart:
+ return true;
+ default:
+ return false;
+ }
+}
+
+IntSize RenderThemeWin::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const
+{
+ return bounds.size();
+}
+
+bool RenderThemeWin::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!renderObject->isMeter())
+ return true;
+
+ HTMLMeterElement* element = toRenderMeter(renderObject)->meterElement();
+
+ ThemeData theme = getThemeData(renderObject);
+
+ int remaining = static_cast<int>((1.0 - element->valueRatio()) * static_cast<double>(rect.size().width()));
+
+ // Draw the background
+ drawControl(paintInfo.context, renderObject, progressBarTheme(), theme, rect);
+
+ // Draw the progress portion
+ IntRect completedRect(rect);
+ completedRect.contract(remaining, 0);
+
+ theme.m_part = PP_FILL;
+ drawControl(paintInfo.context, renderObject, progressBarTheme(), theme, completedRect);
+
+ return true;
+}
#endif
+
}
diff --git a/Source/WebCore/rendering/RenderThemeWin.h b/Source/WebCore/rendering/RenderThemeWin.h
index b97f30004..9514554fc 100644
--- a/Source/WebCore/rendering/RenderThemeWin.h
+++ b/Source/WebCore/rendering/RenderThemeWin.h
@@ -1,7 +1,7 @@
/*
* This file is part of the WebKit project.
*
- * Copyright (C) 2006, 2008 Apple Computer, Inc.
+ * Copyright (C) 2006, 2008, 2013 Apple Computer, Inc.
* Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
@@ -63,8 +63,8 @@ public:
virtual Color platformInactiveSelectionForegroundColor() const;
// System fonts.
- virtual void systemFont(int propId, FontDescription&) const;
- virtual Color systemColor(int cssValueId) const;
+ virtual void systemFont(CSSValueID, FontDescription&) const;
+ virtual Color systemColor(CSSValueID) const;
virtual bool paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
{ return paintButton(o, i, r); }
@@ -144,6 +144,13 @@ public:
virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE;
#endif
+#if ENABLE(METER_ELEMENT)
+ virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE;
+ virtual bool supportsMeter(ControlPart) const OVERRIDE;
+ virtual void adjustMeterStyle(StyleResolver*, RenderStyle*, Element*) const OVERRIDE;
+ virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE;
+#endif
+
virtual bool shouldShowPlaceholderWhenFocused() const { return true; }
private:
@@ -154,7 +161,7 @@ private:
};
RenderThemeWin();
- ~RenderThemeWin();
+ virtual ~RenderThemeWin();
void addIntrinsicMargins(RenderStyle*) const;
void close();
@@ -175,12 +182,14 @@ private:
HANDLE menuListTheme() const;
HANDLE sliderTheme() const;
HANDLE spinButtonTheme() const;
+ HANDLE progressBarTheme() const;
mutable HANDLE m_buttonTheme;
mutable HANDLE m_textFieldTheme;
mutable HANDLE m_menuListTheme;
mutable HANDLE m_sliderTheme;
mutable HANDLE m_spinButtonTheme;
+ mutable HANDLE m_progressBarTheme;
};
};
diff --git a/Source/WebCore/rendering/RenderThemeWinCE.cpp b/Source/WebCore/rendering/RenderThemeWinCE.cpp
index c5750f4bc..f32760df1 100644
--- a/Source/WebCore/rendering/RenderThemeWinCE.cpp
+++ b/Source/WebCore/rendering/RenderThemeWinCE.cpp
@@ -257,7 +257,7 @@ bool RenderThemeWinCE::paintMenuListButton(RenderObject* o, const PaintInfo& i,
return true;
}
-void RenderThemeWinCE::systemFont(int propId, FontDescription& fontDescription) const
+void RenderThemeWinCE::systemFont(CSSValueID, FontDescription& fontDescription) const
{
notImplemented();
}
@@ -284,7 +284,7 @@ bool RenderThemeWinCE::supportsHover(const RenderStyle*) const
}
// Map a CSSValue* system color to an index understood by GetSysColor
-static int cssValueIdToSysColorIndex(int cssValueId)
+static int cssValueIdToSysColorIndex(CSSValueID cssValueId)
{
switch (cssValueId) {
case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
@@ -319,7 +319,7 @@ static int cssValueIdToSysColorIndex(int cssValueId)
}
}
-Color RenderThemeWinCE::systemColor(int cssValueId) const
+Color RenderThemeWinCE::systemColor(CSSValueID cssValueId) const
{
int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
if (sysColorIndex == -1)
@@ -371,7 +371,7 @@ bool RenderThemeWinCE::paintSearchField(RenderObject* o, const PaintInfo& i, con
bool RenderThemeWinCE::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
- Color buttonColor = (o->node() && o->node()->active()) ? Color(138, 138, 138) : Color(186, 186, 186);
+ Color buttonColor = (o->node() && o->node()->isElementNode() && toElement(o->node())->active()) ? Color(138, 138, 138) : Color(186, 186, 186);
IntSize cancelSize(10, 10);
IntSize cancelRadius(cancelSize.width() / 2, cancelSize.height() / 2);
@@ -379,7 +379,7 @@ bool RenderThemeWinCE::paintSearchFieldCancelButton(RenderObject* o, const Paint
int y = r.y() + (r.height() - cancelSize.height()) / 2 + 1;
IntRect cancelBounds(IntPoint(x, y), cancelSize);
paintInfo.context->save();
- paintInfo.context->addRoundedRectClip(RoundedRect(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius));
+ paintInfo.context->clipRoundedRect(RoundedRect(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius));
paintInfo.context->fillRect(cancelBounds, buttonColor, ColorSpaceDeviceRGB);
// Draw the 'x'
@@ -482,10 +482,10 @@ static HTMLMediaElement* mediaElementParent(Node* node)
Node* mediaNode = node->shadowHost();
if (!mediaNode)
mediaNode = node;
- if (!mediaNode || !mediaNode->isElementNode() || !static_cast<Element*>(mediaNode)->isMediaElement())
+ if (!mediaNode || !mediaNode->isElementNode() || !toElement(mediaNode)->isMediaElement())
return 0;
- return static_cast<HTMLMediaElement*>(mediaNode);
+ return toHTMLMediaElement(mediaNode);
}
#endif
diff --git a/Source/WebCore/rendering/RenderThemeWinCE.h b/Source/WebCore/rendering/RenderThemeWinCE.h
index bde872c6c..c1ab7be82 100644
--- a/Source/WebCore/rendering/RenderThemeWinCE.h
+++ b/Source/WebCore/rendering/RenderThemeWinCE.h
@@ -62,8 +62,8 @@ namespace WebCore {
virtual Color platformInactiveSelectionForegroundColor() const;
// System fonts.
- virtual void systemFont(int propId, FontDescription&) const;
- virtual Color systemColor(int cssValueId) const;
+ virtual void systemFont(CSSValueID, FontDescription&) const;
+ virtual Color systemColor(CSSValueID) const;
virtual bool paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
{ return paintButton(o, i, r); }
diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp
index 5b4eb7358..dc6fcd47e 100644
--- a/Source/WebCore/rendering/RenderTreeAsText.cpp
+++ b/Source/WebCore/rendering/RenderTreeAsText.cpp
@@ -50,7 +50,6 @@
#include "RenderWidget.h"
#include "StylePropertySet.h"
#include <wtf/HexNumber.h>
-#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
#include <wtf/unicode/CharacterNames.h>
@@ -89,9 +88,15 @@ TextStream& operator<<(TextStream& ts, const IntPoint& p)
return ts << "(" << p.x() << "," << p.y() << ")";
}
+TextStream& operator<<(TextStream& ts, const LayoutRect& r)
+{
+ // FIXME: These should be printed as floats. Keeping them ints for consistency with previous test expectations.
+ return ts << pixelSnappedIntRect(r);
+}
+
TextStream& operator<<(TextStream& ts, const LayoutPoint& p)
{
- // FIXME: These should be printed as floats. Keeping them ints for consistency with pervious test expectations.
+ // FIXME: These should be printed as floats. Keeping them ints for consistency with previous test expectations.
return ts << "(" << p.x().toInt() << "," << p.y().toInt() << ")";
}
@@ -168,7 +173,7 @@ static bool isEmptyOrUnstyledAppleStyleSpan(const Node* node)
if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag))
return false;
- const HTMLElement* elem = static_cast<const HTMLElement*>(node);
+ const HTMLElement* elem = toHTMLElement(node);
if (elem->getAttribute(classAttr) != "Apple-style-span")
return false;
@@ -221,6 +226,9 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o,
if (o.node()) {
String tagName = getTagName(o.node());
+ // FIXME: Temporary hack to make tests pass by simulating the old generated content output.
+ if (o.isPseudoElement() || (o.parent() && o.parent()->isPseudoElement()))
+ tagName = emptyAtom;
if (!tagName.isEmpty()) {
ts << " {" << tagName << "}";
// flag empty or unstyled AppleStyleSpan because we never
@@ -425,17 +433,16 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o,
}
if (behavior & RenderAsTextShowIDAndClass) {
- if (Node* node = o.node()) {
- if (node->hasID())
- ts << " id=\"" + static_cast<Element*>(node)->getIdAttribute() + "\"";
+ if (Element* element = o.node() && o.node()->isElementNode() ? toElement(o.node()) : 0) {
+ if (element->hasID())
+ ts << " id=\"" + element->getIdAttribute() + "\"";
- if (node->hasClass()) {
+ if (element->hasClass()) {
ts << " class=\"";
- StyledElement* styledElement = static_cast<StyledElement*>(node);
- for (size_t i = 0; i < styledElement->classNames().size(); ++i) {
+ for (size_t i = 0; i < element->classNames().size(); ++i) {
if (i > 0)
ts << " ";
- ts << styledElement->classNames()[i];
+ ts << element->classNames()[i];
}
ts << "\"";
}
@@ -579,7 +586,7 @@ void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavi
if (o.isWidget()) {
Widget* widget = toRenderWidget(&o)->widget();
if (widget && widget->isFrameView()) {
- FrameView* view = static_cast<FrameView*>(widget);
+ FrameView* view = toFrameView(widget);
RenderView* root = view->frame()->contentRenderer();
if (root) {
view->layout();
@@ -665,8 +672,8 @@ static void writeRenderRegionList(const RenderRegionList& flowThreadRegionList,
String tagName = getTagName(renderRegion->generatingNode());
if (!tagName.isEmpty())
ts << " {" << tagName << "}";
- if (renderRegion->generatingNode()->isElementNode() && renderRegion->generatingNode()->hasID()) {
- Element* element = static_cast<Element*>(renderRegion->generatingNode());
+ if (renderRegion->generatingNode()->isElementNode() && toElement(renderRegion->generatingNode())->hasID()) {
+ Element* element = toElement(renderRegion->generatingNode());
ts << " #" << element->idForStyleResolution();
}
if (renderRegion->hasCustomRegionStyle())
@@ -712,6 +719,12 @@ static void writeRenderNamedFlowThreads(TextStream& ts, RenderView* renderView,
}
}
+static LayoutSize maxLayoutOverflow(const RenderBox* box)
+{
+ LayoutRect overflowRect = box->layoutOverflowRect();
+ return LayoutSize(overflowRect.maxX(), overflowRect.maxY());
+}
+
static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* l,
const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior)
{
@@ -720,7 +733,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye
if (rootLayer == l) {
paintDirtyRect.setWidth(max<LayoutUnit>(paintDirtyRect.width(), rootLayer->renderBox()->layoutOverflowRect().maxX()));
paintDirtyRect.setHeight(max<LayoutUnit>(paintDirtyRect.height(), rootLayer->renderBox()->layoutOverflowRect().maxY()));
- l->setSize(l->size().expandedTo(pixelSnappedIntSize(l->renderBox()->maxLayoutOverflow(), LayoutPoint(0, 0))));
+ l->setSize(l->size().expandedTo(pixelSnappedIntSize(maxLayoutOverflow(l->renderBox()), LayoutPoint(0, 0))));
}
// Calculate the clip rects we should use.
@@ -763,14 +776,22 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye
}
if (Vector<RenderLayer*>* posList = l->posZOrderList()) {
- int currIndent = indent;
- if (behavior & RenderAsTextShowLayerNesting) {
- writeIndent(ts, indent);
- ts << " positive z-order list(" << posList->size() << ")\n";
- ++currIndent;
- }
+ size_t layerCount = 0;
for (unsigned i = 0; i != posList->size(); ++i)
- writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, currIndent, behavior);
+ if (!posList->at(i)->isOutOfFlowRenderFlowThread())
+ ++layerCount;
+ if (layerCount) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " positive z-order list(" << layerCount << ")\n";
+ ++currIndent;
+ }
+ for (unsigned i = 0; i != posList->size(); ++i) {
+ if (!posList->at(i)->isOutOfFlowRenderFlowThread())
+ writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, currIndent, behavior);
+ }
+ }
}
// Altough the RenderFlowThread requires a layer, it is not collected by its parent,
@@ -788,7 +809,7 @@ static String nodePosition(Node* node)
Element* body = node->document()->body();
Node* parent;
for (Node* n = node; n; n = parent) {
- parent = n->parentOrHostNode();
+ parent = n->parentOrShadowHostNode();
if (n != node)
result.appendLiteral(" of ");
if (parent) {
@@ -821,7 +842,7 @@ static void writeSelection(TextStream& ts, const RenderObject* o)
if (!n || !n->isDocumentNode())
return;
- Document* doc = static_cast<Document*>(n);
+ Document* doc = toDocument(n);
Frame* frame = doc->frame();
if (!frame)
return;
@@ -898,12 +919,10 @@ String counterValueForElement(Element* element)
TextStream stream;
bool isFirstCounter = true;
// The counter renderers should be children of :before or :after pseudo-elements.
- if (RenderObject* renderer = element->renderer()) {
- if (RenderObject* pseudoElement = renderer->beforePseudoElementRenderer())
- writeCounterValuesFromChildren(stream, pseudoElement, isFirstCounter);
- if (RenderObject* pseudoElement = renderer->afterPseudoElementRenderer())
- writeCounterValuesFromChildren(stream, pseudoElement, isFirstCounter);
- }
+ if (RenderObject* before = element->pseudoElementRenderer(BEFORE))
+ writeCounterValuesFromChildren(stream, before, isFirstCounter);
+ if (RenderObject* after = element->pseudoElementRenderer(AFTER))
+ writeCounterValuesFromChildren(stream, after, isFirstCounter);
return stream.release();
}
diff --git a/Source/WebCore/rendering/RenderTreeAsText.h b/Source/WebCore/rendering/RenderTreeAsText.h
index 3a83849d5..39061a0ff 100644
--- a/Source/WebCore/rendering/RenderTreeAsText.h
+++ b/Source/WebCore/rendering/RenderTreeAsText.h
@@ -38,6 +38,7 @@ class Frame;
class IntPoint;
class IntRect;
class LayoutPoint;
+class LayoutRect;
class RenderObject;
class TextStream;
@@ -71,6 +72,7 @@ static void writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTex
TextStream& operator<<(TextStream&, const IntPoint&);
TextStream& operator<<(TextStream&, const IntRect&);
TextStream& operator<<(TextStream&, const LayoutPoint&);
+TextStream& operator<<(TextStream&, const LayoutRect&);
TextStream& operator<<(TextStream&, const FloatPoint&);
TextStream& operator<<(TextStream&, const FloatSize&);
diff --git a/Source/WebCore/rendering/RenderVideo.cpp b/Source/WebCore/rendering/RenderVideo.cpp
index 11269e252..61ec6f244 100644
--- a/Source/WebCore/rendering/RenderVideo.cpp
+++ b/Source/WebCore/rendering/RenderVideo.cpp
@@ -38,6 +38,7 @@
#include "Page.h"
#include "PaintInfo.h"
#include "RenderView.h"
+#include <wtf/StackStats.h>
#if ENABLE(FULLSCREEN_API)
#include "RenderFullScreen.h"
@@ -229,8 +230,7 @@ void RenderVideo::layout()
HTMLVideoElement* RenderVideo::videoElement() const
{
- ASSERT(node()->hasTagName(videoTag));
- return static_cast<HTMLVideoElement*>(node());
+ return toHTMLVideoElement(node());
}
void RenderVideo::updateFromElement()
@@ -262,9 +262,9 @@ void RenderVideo::updatePlayer()
mediaPlayer->setVisible(true);
}
-LayoutUnit RenderVideo::computeReplacedLogicalWidth(bool includeMaxWidth) const
+LayoutUnit RenderVideo::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
{
- return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
+ return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
}
LayoutUnit RenderVideo::computeReplacedLogicalHeight() const
@@ -338,6 +338,14 @@ LayoutUnit RenderVideo::offsetHeight() const
}
#endif
+bool RenderVideo::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
+{
+ if (videoElement()->shouldDisplayPosterImage())
+ return RenderImage::foregroundIsKnownToBeOpaqueInRect(localRect, maxDepthToTest);
+
+ return videoBox().contains(enclosingIntRect(localRect));
+}
+
} // namespace WebCore
#endif
diff --git a/Source/WebCore/rendering/RenderVideo.h b/Source/WebCore/rendering/RenderVideo.h
index 78f855068..4a256d188 100644
--- a/Source/WebCore/rendering/RenderVideo.h
+++ b/Source/WebCore/rendering/RenderVideo.h
@@ -70,7 +70,7 @@ private:
virtual void layout();
- virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE;
virtual LayoutUnit computeReplacedLogicalHeight() const;
virtual LayoutUnit minimumReplacedHeight() const OVERRIDE;
@@ -83,12 +83,14 @@ private:
void updatePlayer();
+ virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const OVERRIDE;
+
LayoutSize m_cachedImageSize;
};
inline RenderVideo* toRenderVideo(RenderObject* object)
{
- ASSERT(!object || object->isVideo());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isVideo());
return static_cast<RenderVideo*>(object);
}
diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp
index bdb9c8069..251659fc1 100644
--- a/Source/WebCore/rendering/RenderView.cpp
+++ b/Source/WebCore/rendering/RenderView.cpp
@@ -27,19 +27,23 @@
#include "FloatQuad.h"
#include "FlowThreadController.h"
#include "Frame.h"
+#include "FrameSelection.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "HTMLFrameOwnerElement.h"
+#include "HTMLIFrameElement.h"
#include "HitTestResult.h"
#include "Page.h"
#include "RenderGeometryMap.h"
#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
#include "RenderNamedFlowThread.h"
#include "RenderSelectionInfo.h"
#include "RenderWidget.h"
#include "RenderWidgetProtector.h"
#include "StyleInheritedData.h"
#include "TransformState.h"
+#include <wtf/StackStats.h>
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerCompositor.h"
@@ -51,9 +55,9 @@
namespace WebCore {
-RenderView::RenderView(Node* node, FrameView* view)
- : RenderBlock(node)
- , m_frameView(view)
+RenderView::RenderView(Document* document)
+ : RenderBlock(document)
+ , m_frameView(document->view())
, m_selectionStart(0)
, m_selectionEnd(0)
, m_selectionStartPos(-1)
@@ -65,12 +69,8 @@ RenderView::RenderView(Node* node, FrameView* view)
, m_layoutStateDisableCount(0)
, m_renderQuoteHead(0)
, m_renderCounterCount(0)
- , m_layoutPhase(RenderViewNormalLayout)
+ , m_selectionWasCaret(false)
{
- // Clear our anonymous bit, set because RenderObject assumes
- // any renderer with document as the node is anonymous.
- setIsAnonymous(false);
-
// init RenderObject attributes
setInline(false);
@@ -79,7 +79,7 @@ RenderView::RenderView(Node* node, FrameView* view)
setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
- setPositioned(true); // to 0,0 :)
+ setPositionState(AbsolutePosition); // to 0,0 :)
}
RenderView::~RenderView()
@@ -93,12 +93,21 @@ bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result)
bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result)
{
- bool inside = layer()->hitTest(request, location, result);
+ if (layer()->hitTest(request, location, result))
+ return true;
- // Next set up the correct :hover/:active state along the new chain.
- document()->updateHoverActiveState(request, result);
+ // FIXME: Consider if this test should be done unconditionally.
+ if (request.allowsFrameScrollbars() && m_frameView) {
+ // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls,
+ // so we need to test ScrollView scrollbars separately here.
+ Scrollbar* frameScrollbar = m_frameView->scrollbarAtPoint(location.roundedPoint());
+ if (frameScrollbar) {
+ result.setScrollbar(frameScrollbar);
+ return true;
+ }
+ }
- return inside;
+ return false;
}
void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const
@@ -112,19 +121,12 @@ void RenderView::updateLogicalWidth()
setLogicalWidth(viewLogicalWidth());
}
-void RenderView::computePreferredLogicalWidths()
-{
- ASSERT(preferredLogicalWidthsDirty());
-
- RenderBlock::computePreferredLogicalWidths();
-}
-
-LayoutUnit RenderView::availableLogicalHeight() const
+LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType heightType) const
{
// If we have columns, then the available logical height is reduced to the column height.
if (hasColumns())
return columnInfo()->columnHeight();
- return RenderBlock::availableLogicalHeight();
+ return RenderBlock::availableLogicalHeight(heightType);
}
bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const
@@ -154,6 +156,110 @@ void RenderView::checkLayoutState(const LayoutState& state)
}
#endif
+static RenderBox* enclosingSeamlessRenderer(Document* doc)
+{
+ if (!doc)
+ return 0;
+ Element* ownerElement = doc->seamlessParentIFrame();
+ if (!ownerElement)
+ return 0;
+ return ownerElement->renderBox();
+}
+
+void RenderView::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ // Seamless iframes are considered part of an enclosing render flow thread from the parent document. This is necessary for them to look
+ // up regions in the parent document during layout.
+ if (newChild && !newChild->isRenderFlowThread()) {
+ RenderBox* seamlessBox = enclosingSeamlessRenderer(document());
+ if (seamlessBox && seamlessBox->flowThreadContainingBlock())
+ newChild->setFlowThreadState(seamlessBox->flowThreadState());
+ }
+ RenderBlock::addChild(newChild, beforeChild);
+}
+
+bool RenderView::initializeLayoutState(LayoutState& state)
+{
+ bool isSeamlessAncestorInFlowThread = false;
+
+ // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
+ state.m_clipped = false;
+
+ // Check the writing mode of the seamless ancestor. It has to match our document's writing mode, or we won't inherit any
+ // pagination information.
+ RenderBox* seamlessAncestor = enclosingSeamlessRenderer(document());
+ LayoutState* seamlessLayoutState = seamlessAncestor ? seamlessAncestor->view()->layoutState() : 0;
+ bool shouldInheritPagination = seamlessLayoutState && !m_pageLogicalHeight && seamlessAncestor->style()->writingMode() == style()->writingMode();
+
+ state.m_pageLogicalHeight = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeight : m_pageLogicalHeight;
+ state.m_pageLogicalHeightChanged = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeightChanged : m_pageLogicalHeightChanged;
+ state.m_isPaginated = state.m_pageLogicalHeight;
+ if (state.m_isPaginated && shouldInheritPagination) {
+ // Set up the correct pagination offset. We can use a negative offset in order to push the top of the RenderView into its correct place
+ // on a page. We can take the iframe's offset from the logical top of the first page and make the negative into the pagination offset within the child
+ // view.
+ bool isFlipped = seamlessAncestor->style()->isFlippedBlocksWritingMode();
+ LayoutSize layoutOffset = seamlessLayoutState->layoutOffset();
+ LayoutSize iFrameOffset(layoutOffset.width() + seamlessAncestor->x() + (!isFlipped ? seamlessAncestor->borderLeft() + seamlessAncestor->paddingLeft() :
+ seamlessAncestor->borderRight() + seamlessAncestor->paddingRight()),
+ layoutOffset.height() + seamlessAncestor->y() + (!isFlipped ? seamlessAncestor->borderTop() + seamlessAncestor->paddingTop() :
+ seamlessAncestor->borderBottom() + seamlessAncestor->paddingBottom()));
+
+ LayoutSize offsetDelta = seamlessLayoutState->m_pageOffset - iFrameOffset;
+ state.m_pageOffset = offsetDelta;
+
+ // Set the current render flow thread to point to our ancestor. This will allow the seamless document to locate the correct
+ // regions when doing a layout.
+ if (seamlessAncestor->flowThreadContainingBlock()) {
+ flowThreadController()->setCurrentRenderFlowThread(seamlessAncestor->view()->flowThreadController()->currentRenderFlowThread());
+ isSeamlessAncestorInFlowThread = true;
+ }
+ }
+
+ // FIXME: We need to make line grids and exclusions work with seamless iframes as well here. Basically all layout state information needs
+ // to propagate here and not just pagination information.
+ return isSeamlessAncestorInFlowThread;
+}
+
+// The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken
+// to ensure the results are the same as those obtained from a full layout (i.e. the auto-height regions from all the flows are marked as needing
+// layout).
+// 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer non-auto-height regions size so the
+// inner flows have the necessary information to correctly fragment the content.
+// 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it goes into the constrained layout phase
+// and marks the auto-height regions they need layout. This means the outer flows will relayout if they depend on regions with auto-height regions
+// belonging to inner flows. This step will correctly set the computedAutoHeight for the auto-height regions. It's possible for non-auto-height
+// regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout.
+// 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions
+// as detected in the previous step.
+void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state)
+{
+ // We need to invalidate all the flows with auto-height regions if one such flow needs layout.
+ // If none is found we do a layout a check back again afterwards.
+ if (!flowThreadController()->updateFlowThreadsNeedingLayout()) {
+ // Do a first layout of the content. In some cases more layouts are not needed (e.g. only flows with non-auto-height regions have changed).
+ layoutContent(state);
+
+ // If we find no named flow needing a two step layout after the first layout, exit early.
+ // Otherwise, initiate the two step layout algorithm and recompute all the flows.
+ if (!flowThreadController()->updateFlowThreadsNeedingTwoStepLayout())
+ return;
+ }
+
+ // Layout to recompute all the named flows with auto-height regions.
+ layoutContent(state);
+
+ // Propagate the computed auto-height values upwards.
+ // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok.
+ flowThreadController()->updateFlowThreadsIntoConstrainedPhase();
+
+ // Do one last layout that should update the auto-height regions found in the main flow
+ // and solve pathological dependencies between regions (e.g. a non-auto-height region depending
+ // on an auto-height one).
+ if (needsLayout())
+ layoutContent(state);
+}
+
void RenderView::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
@@ -168,10 +274,17 @@ void RenderView::layout()
if (relayoutChildren) {
setChildNeedsLayout(true, MarkOnlyThis);
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight())
+ if ((child->isBox() && (toRenderBox(child)->hasRelativeLogicalHeight() || toRenderBox(child)->hasViewportPercentageLogicalHeight()))
|| child->style()->logicalHeight().isPercent()
|| child->style()->logicalMinHeight().isPercent()
- || child->style()->logicalMaxHeight().isPercent())
+ || child->style()->logicalMaxHeight().isPercent()
+ || child->style()->logicalHeight().isViewportPercentage()
+ || child->style()->logicalMinHeight().isViewportPercentage()
+ || child->style()->logicalMaxHeight().isViewportPercentage()
+#if ENABLE(SVG)
+ || child->isSVGRoot()
+#endif
+ )
child->setChildNeedsLayout(true, MarkOnlyThis);
}
}
@@ -181,33 +294,37 @@ void RenderView::layout()
return;
LayoutState state;
- // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
- state.m_clipped = false;
- state.m_pageLogicalHeight = m_pageLogicalHeight;
- state.m_pageLogicalHeightChanged = m_pageLogicalHeightChanged;
- state.m_isPaginated = state.m_pageLogicalHeight;
+ bool isSeamlessAncestorInFlowThread = initializeLayoutState(state);
+
m_pageLogicalHeightChanged = false;
m_layoutState = &state;
- m_layoutPhase = RenderViewNormalLayout;
- bool needsTwoPassLayoutForAutoLogicalHeightRegions = hasRenderNamedFlowThreads() && flowThreadController()->hasAutoLogicalHeightRegions();
-
- if (needsTwoPassLayoutForAutoLogicalHeightRegions)
- flowThreadController()->resetRegionsOverrideLogicalContentHeight();
-
- layoutContent(state);
-
- if (needsTwoPassLayoutForAutoLogicalHeightRegions) {
- m_layoutPhase = ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions;
- flowThreadController()->markAutoLogicalHeightRegionsForLayout();
+ if (checkTwoPassLayoutForAutoHeightRegions())
+ layoutContentInAutoLogicalHeightRegions(state);
+ else
layoutContent(state);
- }
#ifndef NDEBUG
checkLayoutState(state);
#endif
m_layoutState = 0;
setNeedsLayout(false);
+
+ if (isSeamlessAncestorInFlowThread)
+ flowThreadController()->setCurrentRenderFlowThread(0);
+}
+
+LayoutUnit RenderView::pageOrViewLogicalHeight() const
+{
+ if (document()->printing())
+ return pageLogicalHeight();
+
+ if (hasColumns() && !style()->hasInlineColumnAxis()) {
+ if (int pageLength = frameView()->pagination().pageLength)
+ return pageLength;
+ }
+
+ return viewLogicalHeight();
}
void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
@@ -294,7 +411,7 @@ void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset);
// This avoids painting garbage between columns if there is a column gap.
- if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated)
+ if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated && paintInfo.shouldPaintWithinRoot(this))
paintInfo.context->fillRect(paintInfo.rect, m_frameView->baseBackgroundColor(), ColorSpaceDeviceRGB);
paintObject(paintInfo, paintOffset);
@@ -328,6 +445,9 @@ static inline bool rendererObscuresBackground(RenderObject* rootObject)
void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&)
{
+ if (!paintInfo.shouldPaintWithinRoot(this))
+ return;
+
// Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit
// when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers,
// layers with reflections, or transformed layers.
@@ -354,6 +474,9 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&)
if (document()->ownerElement() || !view())
return;
+ if (paintInfo.skipRootBackground())
+ return;
+
bool rootFillsViewport = false;
bool rootObscuresBackground = false;
Node* documentElement = document()->documentElement();
@@ -452,6 +575,14 @@ void RenderView::repaintViewAndCompositedLayers()
#endif
}
+LayoutRect RenderView::visualOverflowRect() const
+{
+ if (m_frameView->paintsEntireContents())
+ return layoutOverflowRect();
+
+ return RenderBlock::visualOverflowRect();
+}
+
void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
{
// If a container was specified, and was not 0 or the RenderView,
@@ -533,7 +664,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const
// RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates.
LayoutRect currRect = info->rect();
if (RenderLayerModelObject* repaintContainer = info->repaintContainer()) {
- FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect), SnapOffsetForTransforms);
+ FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect));
currRect = absQuad.enclosingBoundingBox();
}
selRect.unite(currRect);
@@ -541,6 +672,30 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const
return pixelSnappedIntRect(selRect);
}
+void RenderView::repaintSelection() const
+{
+ document()->updateStyleIfNeeded();
+
+ HashSet<RenderBlock*> processedBlocks;
+
+ RenderObject* end = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
+ for (RenderObject* o = m_selectionStart; o && o != end; o = o->nextInPreOrder()) {
+ if (!o->canBeSelectionLeaf() && o != m_selectionStart && o != m_selectionEnd)
+ continue;
+ if (o->selectionState() == SelectionNone)
+ continue;
+
+ RenderSelectionInfo(o, true).repaint();
+
+ // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
+ for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) {
+ if (!processedBlocks.add(block).isNewEntry)
+ break;
+ RenderSelectionInfo(block, true).repaint();
+ }
+ }
+}
+
#if USE(ACCELERATED_COMPOSITING)
// Compositing layer dimensions take outline size into account, so we have to recompute layer
// bounds when it changes.
@@ -563,9 +718,14 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
if ((start && !end) || (end && !start))
return;
+ bool caretChanged = m_selectionWasCaret != view()->frame()->selection()->isCaret();
+ m_selectionWasCaret = view()->frame()->selection()->isCaret();
// Just return if the selection hasn't changed.
if (m_selectionStart == start && m_selectionStartPos == startPos &&
- m_selectionEnd == end && m_selectionEndPos == endPos)
+ m_selectionEnd == end && m_selectionEndPos == endPos && !caretChanged)
+ return;
+
+ if ((start && end) && (start->flowThreadContainingBlock() != end->flowThreadContainingBlock()))
return;
// Record the old selected objects. These will be used later
@@ -819,6 +979,16 @@ IntRect RenderView::unscaledDocumentRect() const
return pixelSnappedIntRect(overflowRect);
}
+bool RenderView::rootBackgroundIsEntirelyFixed() const
+{
+ RenderObject* rootObject = document()->documentElement() ? document()->documentElement()->renderer() : 0;
+ if (!rootObject)
+ return false;
+
+ RenderObject* rootRenderer = rootObject->rendererForRootBackground();
+ return rootRenderer->hasEntirelyFixedBackground();
+}
+
LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const
{
if (!hasColumns())
@@ -864,12 +1034,6 @@ int RenderView::viewWidth() const
int RenderView::viewLogicalHeight() const
{
int height = style()->isHorizontalWritingMode() ? viewHeight() : viewWidth();
-
- if (hasColumns() && !style()->hasInlineColumnAxis()) {
- if (int pageLength = m_frameView->pagination().pageLength)
- height = pageLength;
- }
-
return height;
}
@@ -884,6 +1048,7 @@ void RenderView::pushLayoutState(RenderObject* root)
ASSERT(m_layoutStateDisableCount == 0);
ASSERT(m_layoutState == 0);
+ pushLayoutStateForCurrentFlowThread(root);
m_layoutState = new (renderArena()) LayoutState(root);
}
@@ -956,19 +1121,11 @@ RenderLayerCompositor* RenderView::compositor()
}
#endif
-void RenderView::didMoveOnscreen()
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (m_compositor)
- m_compositor->didMoveOnscreen();
-#endif
-}
-
-void RenderView::willMoveOffscreen()
+void RenderView::setIsInWindow(bool isInWindow)
{
#if USE(ACCELERATED_COMPOSITING)
if (m_compositor)
- m_compositor->willMoveOffscreen();
+ m_compositor->setIsInWindow(isInWindow);
#endif
}
@@ -993,6 +1150,11 @@ bool RenderView::hasRenderNamedFlowThreads() const
return m_flowThreadController && m_flowThreadController->hasRenderNamedFlowThreads();
}
+bool RenderView::checkTwoPassLayoutForAutoHeightRegions() const
+{
+ return hasRenderNamedFlowThreads() && m_flowThreadController->hasFlowThreadsWithAutoLogicalHeightRegions();
+}
+
FlowThreadController* RenderView::flowThreadController()
{
if (!m_flowThreadController)
@@ -1001,6 +1163,30 @@ FlowThreadController* RenderView::flowThreadController()
return m_flowThreadController.get();
}
+void RenderView::pushLayoutStateForCurrentFlowThread(const RenderObject* object)
+{
+ if (!m_flowThreadController)
+ return;
+
+ RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread();
+ if (!currentFlowThread)
+ return;
+
+ currentFlowThread->pushFlowThreadLayoutState(object);
+}
+
+void RenderView::popLayoutStateForCurrentFlowThread()
+{
+ if (!m_flowThreadController)
+ return;
+
+ RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread();
+ if (!currentFlowThread)
+ return;
+
+ currentFlowThread->popFlowThreadLayoutState();
+}
+
RenderBlock::IntervalArena* RenderView::intervalArena()
{
if (!m_intervalArena)
@@ -1008,4 +1194,42 @@ RenderBlock::IntervalArena* RenderView::intervalArena()
return m_intervalArena.get();
}
+FragmentationDisabler::FragmentationDisabler(RenderObject* root)
+{
+ RenderView* renderView = root->view();
+ ASSERT(renderView);
+
+ LayoutState* layoutState = renderView->layoutState();
+
+ m_root = root;
+ m_fragmenting = layoutState && layoutState->isPaginated();
+ m_flowThreadState = m_root->flowThreadState();
+#ifndef NDEBUG
+ m_layoutState = layoutState;
+#endif
+
+ if (layoutState)
+ layoutState->m_isPaginated = false;
+
+ if (m_flowThreadState != RenderObject::NotInsideFlowThread)
+ m_root->setFlowThreadStateIncludingDescendants(RenderObject::NotInsideFlowThread);
+}
+
+FragmentationDisabler::~FragmentationDisabler()
+{
+ RenderView* renderView = m_root->view();
+ ASSERT(renderView);
+
+ LayoutState* layoutState = renderView->layoutState();
+#ifndef NDEBUG
+ ASSERT(m_layoutState == layoutState);
+#endif
+
+ if (layoutState)
+ layoutState->m_isPaginated = m_fragmenting;
+
+ if (m_flowThreadState != RenderObject::NotInsideFlowThread)
+ m_root->setFlowThreadStateIncludingDescendants(m_flowThreadState);
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderView.h b/Source/WebCore/rendering/RenderView.h
index 99ab1c1a3..09466dec7 100644
--- a/Source/WebCore/rendering/RenderView.h
+++ b/Source/WebCore/rendering/RenderView.h
@@ -31,8 +31,8 @@
namespace WebCore {
class FlowThreadController;
-class RenderWidget;
class RenderQuote;
+class RenderWidget;
#if USE(ACCELERATED_COMPOSITING)
class RenderLayerCompositor;
@@ -44,7 +44,7 @@ class CustomFilterGlobalContext;
class RenderView : public RenderBlock {
public:
- RenderView(Node*, FrameView*);
+ explicit RenderView(Document*);
virtual ~RenderView();
bool hitTest(const HitTestRequest&, HitTestResult&);
@@ -61,11 +61,8 @@ public:
virtual void layout() OVERRIDE;
virtual void updateLogicalWidth() OVERRIDE;
virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE;
- // FIXME: This override is not needed and should be removed
- // it only exists to make computePreferredLogicalWidths public.
- virtual void computePreferredLogicalWidths() OVERRIDE;
- virtual LayoutUnit availableLogicalHeight() const OVERRIDE;
+ virtual LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const OVERRIDE;
// The same as the FrameView's layoutHeight/layoutWidth but with null check guards.
int viewHeight() const;
@@ -77,6 +74,7 @@ public:
FrameView* frameView() const { return m_frameView; }
+ virtual LayoutRect visualOverflowRect() const OVERRIDE;
virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE;
void repaintViewRectangle(const LayoutRect&, bool immediate = false) const;
// Repaint the view, and all composited layers that intersect the given absolute rectangle.
@@ -95,6 +93,7 @@ public:
RenderObject* selectionEnd() const { return m_selectionEnd; }
IntRect selectionBounds(bool clipToVisibleContent = true) const;
void selectionStartEnd(int& startPos, int& endPos) const;
+ void repaintSelection() const;
bool printing() const;
@@ -161,14 +160,15 @@ public:
virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&);
- unsigned pageLogicalHeight() const { return m_pageLogicalHeight; }
- void setPageLogicalHeight(unsigned height)
+ LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; }
+ void setPageLogicalHeight(LayoutUnit height)
{
if (m_pageLogicalHeight != height) {
m_pageLogicalHeight = height;
m_pageLogicalHeightChanged = true;
}
}
+ LayoutUnit pageOrViewLogicalHeight() const;
// FIXME: These functions are deprecated. No code should be added that uses these.
int bestTruncatedAt() const { return m_legacyPrinting.m_bestTruncatedAt; }
@@ -185,10 +185,8 @@ public:
void setPrintRect(const IntRect& r) { m_legacyPrinting.m_printRect = r; }
// End deprecated functions.
- // Notifications that this view became visible in a window, or will be
- // removed from the window.
- void didMoveOnscreen();
- void willMoveOffscreen();
+ // Notification that this view moved into or out of a native window.
+ void setIsInWindow(bool);
#if USE(ACCELERATED_COMPOSITING)
RenderLayerCompositor* compositor();
@@ -204,13 +202,13 @@ public:
IntRect documentRect() const;
+ // Renderer that paints the root background has background-images which all have background-attachment: fixed.
+ bool rootBackgroundIsEntirelyFixed() const;
+
bool hasRenderNamedFlowThreads() const;
+ bool checkTwoPassLayoutForAutoHeightRegions() const;
FlowThreadController* flowThreadController();
- enum RenderViewLayoutPhase { RenderViewNormalLayout, ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions };
- bool normalLayoutPhase() const { return m_layoutPhase == RenderViewNormalLayout; }
- bool constrainedFlowThreadsLayoutPhase() const { return m_layoutPhase == ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions; }
-
void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
IntervalArena* intervalArena();
@@ -227,30 +225,37 @@ public:
void addRenderCounter() { m_renderCounterCount++; }
void removeRenderCounter() { ASSERT(m_renderCounterCount > 0); m_renderCounterCount--; }
bool hasRenderCounters() { return m_renderCounterCount; }
+
+ virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE;
+
+ IntRect pixelSnappedLayoutOverflowRect() const { return pixelSnappedIntRect(layoutOverflowRect()); }
protected:
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const;
virtual bool requiresColumns(int desiredColumnCount) const OVERRIDE;
-
+
private:
+ bool initializeLayoutState(LayoutState&);
+
virtual void calcColumnWidth() OVERRIDE;
virtual ColumnInfo::PaginationUnit paginationUnit() const OVERRIDE;
bool shouldRepaint(const LayoutRect&) const;
// These functions may only be accessed by LayoutStateMaintainer.
- void pushLayoutState(RenderFlowThread*, bool regionsChanged);
bool pushLayoutState(RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
{
// We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
- if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->inRenderFlowThread()
+ if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->flowThreadContainingBlock()
|| m_layoutState->lineGrid() || (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow())
-#if ENABLE(CSS_EXCLUSIONS)
- || (renderer->isRenderBlock() && toRenderBlock(renderer)->exclusionShapeInsideInfo())
+#if ENABLE(CSS_SHAPES)
+ || (renderer->isRenderBlock() && toRenderBlock(renderer)->shapeInsideInfo())
+ || (m_layoutState->shapeInsideInfo() && renderer->isRenderBlock() && !toRenderBlock(renderer)->allowsShapeInsideInfoSharing())
#endif
) {
+ pushLayoutStateForCurrentFlowThread(renderer);
m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo);
return true;
}
@@ -262,6 +267,7 @@ private:
LayoutState* state = m_layoutState;
m_layoutState = state->m_next;
state->destroy(renderArena());
+ popLayoutStateForCurrentFlowThread();
}
// Suspends the LayoutState optimization. Used under transforms that cannot be represented by
@@ -273,12 +279,16 @@ private:
void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; }
void layoutContent(const LayoutState&);
+ void layoutContentInAutoLogicalHeightRegions(const LayoutState&);
#ifndef NDEBUG
void checkLayoutState(const LayoutState&);
#endif
size_t getRetainedWidgets(Vector<RenderWidget*>&);
void releaseWidgets(Vector<RenderWidget*>&);
+
+ void pushLayoutStateForCurrentFlowThread(const RenderObject*);
+ void popLayoutStateForCurrentFlowThread();
friend class LayoutStateMaintainer;
friend class LayoutStateDisabler;
@@ -317,7 +327,7 @@ protected:
private:
bool shouldUsePrintingLayout() const;
- unsigned m_pageLogicalHeight;
+ LayoutUnit m_pageLogicalHeight;
bool m_pageLogicalHeightChanged;
LayoutState* m_layoutState;
unsigned m_layoutStateDisableCount;
@@ -332,18 +342,19 @@ private:
RenderQuote* m_renderQuoteHead;
unsigned m_renderCounterCount;
- RenderViewLayoutPhase m_layoutPhase;
+
+ bool m_selectionWasCaret;
};
inline RenderView* toRenderView(RenderObject* object)
{
- ASSERT(!object || object->isRenderView());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderView());
return static_cast<RenderView*>(object);
}
inline const RenderView* toRenderView(const RenderObject* object)
{
- ASSERT(!object || object->isRenderView());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderView());
return static_cast<const RenderView*>(object);
}
@@ -438,6 +449,20 @@ private:
RenderView* m_view;
};
+class FragmentationDisabler {
+ WTF_MAKE_NONCOPYABLE(FragmentationDisabler);
+public:
+ FragmentationDisabler(RenderObject* root);
+ ~FragmentationDisabler();
+private:
+ RenderObject* m_root;
+ RenderObject::FlowThreadState m_flowThreadState;
+ bool m_fragmenting;
+#ifndef NDEBUG
+ LayoutState* m_layoutState;
+#endif
+};
+
} // namespace WebCore
#endif // RenderView_h
diff --git a/Source/WebCore/rendering/RenderWidget.cpp b/Source/WebCore/rendering/RenderWidget.cpp
index 977751a73..271b8cfe3 100644
--- a/Source/WebCore/rendering/RenderWidget.cpp
+++ b/Source/WebCore/rendering/RenderWidget.cpp
@@ -32,6 +32,7 @@
#include "RenderLayer.h"
#include "RenderView.h"
#include "RenderWidgetProtector.h"
+#include <wtf/StackStats.h>
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerBacking.h"
@@ -57,8 +58,8 @@ WidgetHierarchyUpdatesSuspensionScope::WidgetToParentMap& WidgetHierarchyUpdates
void WidgetHierarchyUpdatesSuspensionScope::moveWidgets()
{
- WidgetToParentMap map = widgetNewParentMap();
- widgetNewParentMap().clear();
+ WidgetToParentMap map;
+ widgetNewParentMap().swap(map);
WidgetToParentMap::iterator end = map.end();
for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) {
Widget* child = it->key.get();
@@ -85,10 +86,10 @@ static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
WidgetHierarchyUpdatesSuspensionScope::scheduleWidgetToMove(child, parent);
}
-RenderWidget::RenderWidget(Node* node)
- : RenderReplaced(node)
+RenderWidget::RenderWidget(Element* element)
+ : RenderReplaced(element)
, m_widget(0)
- , m_frameView(node->document()->view())
+ , m_frameView(element->document()->view())
// Reference counting is used to prevent the widget from being
// destroyed while inside the Widget code, which might not be
// able to handle that.
@@ -102,9 +103,9 @@ void RenderWidget::willBeDestroyed()
if (RenderView* v = view())
v->removeWidget(this);
- if (AXObjectCache::accessibilityEnabled()) {
- document()->axObjectCache()->childrenChanged(this->parent());
- document()->axObjectCache()->remove(this);
+ if (AXObjectCache* cache = document()->existingAXObjectCache()) {
+ cache->childrenChanged(this->parent());
+ cache->remove(this);
}
setWidget(0);
@@ -119,7 +120,7 @@ void RenderWidget::destroy()
// Grab the arena from node()->document()->renderArena() before clearing the node pointer.
// Clear the node before deref-ing, as this may be deleted when deref is called.
RenderArena* arena = renderArena();
- setNode(0);
+ clearNode();
deref(arena);
}
@@ -143,8 +144,9 @@ bool RenderWidget::setWidgetGeometry(const LayoutRect& frame)
return false;
IntRect clipRect = roundedIntRect(enclosingLayer()->childrenClipRect());
+ IntRect newFrame = roundedIntRect(frame);
bool clipChanged = m_clipRect != clipRect;
- bool boundsChanged = m_widget->frameRect() != frame;
+ bool boundsChanged = m_widget->frameRect() != newFrame;
if (!boundsChanged && !clipChanged)
return false;
@@ -153,7 +155,10 @@ bool RenderWidget::setWidgetGeometry(const LayoutRect& frame)
RenderWidgetProtector protector(this);
RefPtr<Node> protectedNode(node());
- m_widget->setFrameRect(roundedIntRect(frame));
+ m_widget->setFrameRect(newFrame);
+
+ if (clipChanged && !boundsChanged)
+ m_widget->clipRectChanged();
#if USE(ACCELERATED_COMPOSITING)
if (hasLayer() && layer()->isComposited())
@@ -169,7 +174,7 @@ bool RenderWidget::updateWidgetGeometry()
if (!m_widget->transformsAffectFrameRect())
return setWidgetGeometry(absoluteContentBox());
- LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox), SnapOffsetForTransforms).boundingBox());
+ LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
if (m_widget->isFrameView()) {
contentBox.setLocation(absoluteContentBox.location());
return setWidgetGeometry(contentBox);
@@ -234,6 +239,39 @@ void RenderWidget::notifyWidget(WidgetNotification notification)
m_widget->notifyWidget(notification);
}
+void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ LayoutPoint adjustedPaintOffset = paintOffset + location();
+
+ // Tell the widget to paint now. This is the only time the widget is allowed
+ // to paint itself. That way it will composite properly with z-indexed layers.
+ IntPoint widgetLocation = m_widget->frameRect().location();
+ IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()),
+ roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop()));
+ IntRect paintRect = paintInfo.rect;
+
+ IntSize widgetPaintOffset = paintLocation - widgetLocation;
+ // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
+ // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
+ if (!widgetPaintOffset.isZero()) {
+ paintInfo.context->translate(widgetPaintOffset);
+ paintRect.move(-widgetPaintOffset);
+ }
+ m_widget->paint(paintInfo.context, paintRect);
+
+ if (!widgetPaintOffset.isZero())
+ paintInfo.context->translate(-widgetPaintOffset);
+
+ if (m_widget->isFrameView()) {
+ FrameView* frameView = toFrameView(m_widget.get());
+ bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContentIncludingDescendants();
+ if (paintInfo.overlapTestRequests && runOverlapTests) {
+ ASSERT(!paintInfo.overlapTestRequests->contains(this));
+ paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
+ }
+ }
+}
+
void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (!shouldPaint(paintInfo, paintOffset))
@@ -250,7 +288,7 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
}
if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && hasOutline())
- paintOutline(paintInfo.context, LayoutRect(adjustedPaintOffset, size()));
+ paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
if (!m_frameView || paintInfo.phase != PaintPhaseForeground)
return;
@@ -273,35 +311,8 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect);
}
- if (m_widget) {
- // Tell the widget to paint now. This is the only time the widget is allowed
- // to paint itself. That way it will composite properly with z-indexed layers.
- IntPoint widgetLocation = m_widget->frameRect().location();
- IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()),
- roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop()));
- IntRect paintRect = paintInfo.rect;
-
- IntSize widgetPaintOffset = paintLocation - widgetLocation;
- // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
- // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
- if (!widgetPaintOffset.isZero()) {
- paintInfo.context->translate(widgetPaintOffset);
- paintRect.move(-widgetPaintOffset);
- }
- m_widget->paint(paintInfo.context, paintRect);
-
- if (!widgetPaintOffset.isZero())
- paintInfo.context->translate(-widgetPaintOffset);
-
- if (m_widget->isFrameView()) {
- FrameView* frameView = static_cast<FrameView*>(m_widget.get());
- bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContentIncludingDescendants();
- if (paintInfo.overlapTestRequests && runOverlapTests) {
- ASSERT(!paintInfo.overlapTestRequests->contains(this));
- paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
- }
- }
- }
+ if (m_widget)
+ paintContents(paintInfo, paintOffset);
if (style()->hasBorderRadius())
paintInfo.context->restore();
@@ -311,13 +322,16 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
// FIXME: selectionRect() is in absolute, not painting coordinates.
paintInfo.context->fillRect(pixelSnappedIntRect(selectionRect()), selectionBackgroundColor(), style()->colorSpace());
}
+
+ if (hasLayer() && layer()->canResize())
+ layer()->paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
}
void RenderWidget::setOverlapTestResult(bool isOverlapped)
{
ASSERT(m_widget);
ASSERT(m_widget->isFrameView());
- static_cast<FrameView*>(m_widget.get())->setIsOverlapped(isOverlapped);
+ toFrameView(m_widget.get())->setIsOverlapped(isOverlapped);
}
void RenderWidget::deref(RenderArena *arena)
@@ -336,7 +350,7 @@ void RenderWidget::updateWidgetPosition()
// if the frame bounds got changed, or if view needs layout (possibly indicating
// content size is wrong) we have to do a layout to set the right widget size
if (m_widget && m_widget->isFrameView()) {
- FrameView* frameView = static_cast<FrameView*>(m_widget.get());
+ FrameView* frameView = toFrameView(m_widget.get());
// Check the frame's page to make sure that the frame isn't in the process of being destroyed.
if ((boundsChanged || frameView->needsLayout()) && frameView->frame()->page())
frameView->layout();
diff --git a/Source/WebCore/rendering/RenderWidget.h b/Source/WebCore/rendering/RenderWidget.h
index d20123a68..ef8f3b741 100644
--- a/Source/WebCore/rendering/RenderWidget.h
+++ b/Source/WebCore/rendering/RenderWidget.h
@@ -73,7 +73,7 @@ public:
void deref(RenderArena*);
protected:
- RenderWidget(Node*);
+ RenderWidget(Element*);
FrameView* frameView() const { return m_frameView; }
@@ -85,6 +85,8 @@ protected:
virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const;
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
+ virtual void paintContents(PaintInfo&, const LayoutPoint&);
+
private:
virtual bool isWidget() const { return true; }
@@ -104,13 +106,13 @@ private:
inline RenderWidget* toRenderWidget(RenderObject* object)
{
- ASSERT(!object || object->isWidget());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isWidget());
return static_cast<RenderWidget*>(object);
}
inline const RenderWidget* toRenderWidget(const RenderObject* object)
{
- ASSERT(!object || object->isWidget());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isWidget());
return static_cast<const RenderWidget*>(object);
}
diff --git a/Source/WebCore/rendering/RenderWidgetProtector.h b/Source/WebCore/rendering/RenderWidgetProtector.h
index 8bf6ac9bb..35c75199d 100644
--- a/Source/WebCore/rendering/RenderWidgetProtector.h
+++ b/Source/WebCore/rendering/RenderWidgetProtector.h
@@ -33,7 +33,7 @@ namespace WebCore {
class RenderWidgetProtector {
WTF_MAKE_NONCOPYABLE(RenderWidgetProtector);
public:
- RenderWidgetProtector(RenderWidget* object)
+ explicit RenderWidgetProtector(RenderWidget* object)
: m_object(object)
, m_arena(object->ref())
{
diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp
index 3e155dba3..29555bf14 100644
--- a/Source/WebCore/rendering/RenderingAllInOne.cpp
+++ b/Source/WebCore/rendering/RenderingAllInOne.cpp
@@ -34,6 +34,7 @@
#include "FixedTableLayout.cpp"
#include "HitTestingTransformState.cpp"
#include "HitTestResult.cpp"
+#include "HitTestLocation.cpp"
#include "InlineBox.cpp"
#include "InlineFlowBox.cpp"
#include "InlineTextBox.cpp"
@@ -74,6 +75,7 @@
#include "RenderListMarker.cpp"
#include "RenderMarquee.cpp"
#include "RenderMedia.cpp"
+#include "RenderMediaControlElements.cpp"
#include "RenderMediaControls.cpp"
#include "RenderMenuList.cpp"
#include "RenderMeter.cpp"
@@ -108,6 +110,7 @@
#include "RenderTextControlMultiLine.cpp"
#include "RenderTextControlSingleLine.cpp"
#include "RenderTextFragment.cpp"
+#include "RenderTextTrackCue.cpp"
#include "RenderTheme.cpp"
#if PLATFORM(WIN)
#include "RenderThemeWin.cpp"
@@ -120,3 +123,4 @@
#include "RootInlineBox.cpp"
#include "ScrollBehavior.cpp"
#include "break_lines.cpp"
+
diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp
index fb1ab2aa6..fc8ef94c1 100644
--- a/Source/WebCore/rendering/RootInlineBox.cpp
+++ b/Source/WebCore/rendering/RootInlineBox.cpp
@@ -29,6 +29,7 @@
#include "GraphicsContext.h"
#include "HitTestResult.h"
#include "InlineTextBox.h"
+#include "LogicalSelectionOffsetCaches.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderArena.h"
@@ -42,6 +43,13 @@ using namespace std;
namespace WebCore {
+struct SameSizeAsRootInlineBox : public InlineFlowBox {
+ unsigned variables[5];
+ void* pointers[4];
+};
+
+COMPILE_ASSERT(sizeof(RootInlineBox) == sizeof(SameSizeAsRootInlineBox), RootInlineBox_should_stay_small);
+
typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap;
static EllipsisBoxMap* gEllipsisBoxMap = 0;
@@ -180,7 +188,7 @@ void RootInlineBox::addHighlightOverflow()
// Highlight acts as a selection inflation.
FloatRect rootRect(0, selectionTop(), logicalWidth(), selectionHeight());
- IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect));
+ IntRect inflatedRect = enclosingIntRect(page->chrome().client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect));
setOverflowFromLogicalRects(inflatedRect, inflatedRect, lineTop(), lineBottom());
}
@@ -198,9 +206,9 @@ void RootInlineBox::paintCustomHighlight(PaintInfo& paintInfo, const LayoutPoint
// Get the inflated rect so that we can properly hit test.
FloatRect rootRect(paintOffset.x() + x(), paintOffset.y() + selectionTop(), logicalWidth(), selectionHeight());
- FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(renderer()->node(), highlightType, rootRect);
+ FloatRect inflatedRect = page->chrome().client()->customHighlightRect(renderer()->node(), highlightType, rootRect);
if (inflatedRect.intersects(paintInfo.rect))
- page->chrome()->client()->paintCustomHighlight(renderer()->node(), highlightType, rootRect, rootRect, false, true);
+ page->chrome().client()->paintCustomHighlight(renderer()->node(), highlightType, rootRect, rootRect, false, true);
}
#endif
@@ -250,28 +258,27 @@ void RootInlineBox::childRemoved(InlineBox* box)
}
}
+RenderRegion* RootInlineBox::containingRegion() const
+{
+ RenderRegion* region = m_fragmentationData ? m_fragmentationData->m_containingRegion : 0;
+
+#ifndef NDEBUG
+ if (region) {
+ RenderFlowThread* flowThread = block()->flowThreadContainingBlock();
+ const RenderRegionList& regionList = flowThread->renderRegionList();
+ ASSERT(regionList.contains(region));
+ }
+#endif
+
+ return region;
+}
+
void RootInlineBox::setContainingRegion(RenderRegion* region)
{
ASSERT(!isDirty());
- ASSERT(block()->inRenderFlowThread());
+ ASSERT(block()->flowThreadContainingBlock());
LineFragmentationData* fragmentationData = ensureLineFragmentationData();
fragmentationData->m_containingRegion = region;
- fragmentationData->m_hasContainingRegion = !!region;
-}
-
-RootInlineBox::LineFragmentationData* RootInlineBox::LineFragmentationData::sanitize(const RenderBlock* block)
-{
- ASSERT(block->inRenderFlowThread());
- if (!m_containingRegion)
- return this;
-
- RenderFlowThread* flowThread = block->enclosingRenderFlowThread();
- const RenderRegionList& regionList = flowThread->renderRegionList();
- // For pointer types the hash function is |safeToCompareToEmptyOrDeleted|. There shouldn't be any problems if m_containingRegion was deleted.
- if (!regionList.contains(m_containingRegion))
- m_containingRegion = 0;
-
- return this;
}
LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
@@ -335,6 +342,15 @@ LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, G
return heightOfBlock + maxHeight;
}
+#if ENABLE(CSS3_TEXT)
+float RootInlineBox::maxLogicalTop() const
+{
+ float maxLogicalTop = 0;
+ computeMaxLogicalTop(maxLogicalTop);
+ return maxLogicalTop;
+}
+#endif // CSS3_TEXT
+
LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const
{
LayoutUnit result = 0;
@@ -414,7 +430,7 @@ LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const
if (layoutState->isPaginated() && layoutState->pageLogicalHeight()) {
pageLogicalTop = block()->pageLogicalTopForOffset(lineTopWithLeading() + delta);
if (pageLogicalTop > firstLineTopWithLeading)
- firstTextTop = pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderBefore() - lineGrid->paddingBefore() + lineGridPaginationOrigin;
+ firstTextTop = pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderAndPaddingBefore() + lineGridPaginationOrigin;
}
if (block()->style()->lineSnap() == LineSnapContain) {
@@ -457,8 +473,8 @@ LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const
return lineSnapAdjustment(newPageLogicalTop - (blockOffset + lineTopWithLeading()));
}
-GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo* paintInfo)
+GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
+ LayoutUnit selTop, LayoutUnit selHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
RenderObject::SelectionState lineState = selectionState();
@@ -469,12 +485,14 @@ GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoi
InlineBox* firstBox = firstSelectedBox();
InlineBox* lastBox = lastSelectedBox();
- if (leftGap)
- result.uniteLeft(block()->logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
- firstBox->parent()->renderer(), firstBox->logicalLeft(), selTop, selHeight, paintInfo));
- if (rightGap)
- result.uniteRight(block()->logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
- lastBox->parent()->renderer(), lastBox->logicalRight(), selTop, selHeight, paintInfo));
+ if (leftGap) {
+ result.uniteLeft(block()->logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, firstBox->parent()->renderer(), firstBox->logicalLeft(),
+ selTop, selHeight, cache, paintInfo));
+ }
+ if (rightGap) {
+ result.uniteRight(block()->logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastBox->parent()->renderer(), lastBox->logicalRight(),
+ selTop, selHeight, cache, paintInfo));
+ }
// When dealing with bidi text, a non-contiguous selection region is possible.
// e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
@@ -563,7 +581,7 @@ LayoutUnit RootInlineBox::selectionTop() const
if (renderer()->style()->isFlippedLinesWritingMode())
return selectionTop;
- LayoutUnit prevBottom = prevRootBox() ? prevRootBox()->selectionBottom() : block()->borderBefore() + block()->paddingBefore();
+ LayoutUnit prevBottom = prevRootBox() ? prevRootBox()->selectionBottom() : block()->borderAndPaddingBefore();
if (prevBottom < selectionTop && block()->containsFloats()) {
// This line has actually been moved further down, probably from a large line-height, but possibly because the
// line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous
@@ -831,8 +849,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb
}
if (includeFontForBox(box) && !setUsedFont) {
- int fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
- int fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent();
+ int fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(baselineType());
+ int fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(baselineType());
setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet);
affectsAscent = fontAscent - box->logicalTop() > 0;
affectsDescent = fontDescent + box->logicalTop() > 0;
@@ -842,16 +860,16 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb
setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet);
affectsAscent = glyphOverflow->top - box->logicalTop() > 0;
affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0;
- glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent()));
- glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(isFirstLineStyle())->fontMetrics().descent()));
+ glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(baselineType())));
+ glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(baselineType())));
}
if (includeMarginForBox(box)) {
- LayoutUnit ascentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
- LayoutUnit descentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent();
+ LayoutUnit ascentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(baselineType());
+ LayoutUnit descentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(baselineType());
if (box->parent() && !box->renderer()->isText()) {
- ascentWithMargin += box->boxModelObject()->borderBefore() + box->boxModelObject()->paddingBefore() + box->boxModelObject()->marginBefore();
- descentWithMargin += box->boxModelObject()->borderAfter() + box->boxModelObject()->paddingAfter() + box->boxModelObject()->marginAfter();
+ ascentWithMargin += box->boxModelObject()->borderAndPaddingBefore() + box->boxModelObject()->marginBefore();
+ descentWithMargin += box->boxModelObject()->borderAndPaddingAfter() + box->boxModelObject()->marginAfter();
}
setAscentAndDescent(ascent, descent, ascentWithMargin, descentWithMargin, ascentDescentSet);
diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h
index e7c3e54b6..05b173f56 100644
--- a/Source/WebCore/rendering/RootInlineBox.h
+++ b/Source/WebCore/rendering/RootInlineBox.h
@@ -28,6 +28,7 @@ namespace WebCore {
class EllipsisBox;
class HitTestResult;
+class LogicalSelectionOffsetCaches;
class RenderRegion;
struct BidiStatus;
@@ -35,18 +36,18 @@ struct GapRects;
class RootInlineBox : public InlineFlowBox {
public:
- RootInlineBox(RenderBlock* block);
+ explicit RootInlineBox(RenderBlock*);
- virtual void destroy(RenderArena*);
+ virtual void destroy(RenderArena*) FINAL;
- virtual bool isRootInlineBox() const { return true; }
+ virtual bool isRootInlineBox() const FINAL { return true; }
void detachEllipsisBox(RenderArena*);
RootInlineBox* nextRootBox() const { return static_cast<RootInlineBox*>(m_nextLineBox); }
RootInlineBox* prevRootBox() const { return static_cast<RootInlineBox*>(m_prevLineBox); }
- virtual void adjustPosition(float dx, float dy);
+ virtual void adjustPosition(float dx, float dy) FINAL;
LayoutUnit lineTop() const { return m_lineTop; }
LayoutUnit lineBottom() const { return m_lineBottom; }
@@ -63,8 +64,7 @@ public:
LayoutUnit paginatedLineWidth() const { return m_fragmentationData ? m_fragmentationData->m_paginatedLineWidth : LayoutUnit(0); }
void setPaginatedLineWidth(LayoutUnit width) { ensureLineFragmentationData()->m_paginatedLineWidth = width; }
- RenderRegion* containingRegion() const { return m_fragmentationData ? m_fragmentationData->sanitize(block())->m_containingRegion : 0; }
- bool hasContainingRegion() const { return m_fragmentationData ? m_fragmentationData->m_hasContainingRegion : false; }
+ RenderRegion* containingRegion() const;
void setContainingRegion(RenderRegion*);
LayoutUnit selectionTop() const;
@@ -85,7 +85,7 @@ public:
m_lineBottomWithLeading = bottomWithLeading;
}
- virtual RenderLineBoxList* rendererLineBoxes() const;
+ virtual RenderLineBoxList* rendererLineBoxes() const FINAL;
RenderObject* lineBreakObj() const { return m_lineBreakObj; }
BidiStatus lineBreakBidiStatus() const;
@@ -103,19 +103,19 @@ public:
// Return the truncatedWidth, the width of the truncated text + ellipsis.
float placeEllipsis(const AtomicString& ellipsisStr, bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, InlineBox* markupBox = 0);
// Return the position of the EllipsisBox or -1.
- virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox) OVERRIDE;
+ virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox) OVERRIDE FINAL;
using InlineBox::hasEllipsisBox;
EllipsisBox* ellipsisBox() const;
void paintEllipsisBox(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) const;
- virtual void clearTruncation() OVERRIDE;
+ virtual void clearTruncation() OVERRIDE FINAL;
bool isHyphenated() const;
- virtual int baselinePosition(FontBaseline baselineType) const;
- virtual LayoutUnit lineHeight() const;
+ virtual int baselinePosition(FontBaseline baselineType) const FINAL;
+ virtual LayoutUnit lineHeight() const FINAL;
#if PLATFORM(MAC)
void addHighlightOverflow();
@@ -123,16 +123,17 @@ public:
#endif
virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom);
- virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE;
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE FINAL;
using InlineBox::hasSelectedChildren;
using InlineBox::setHasSelectedChildren;
- virtual RenderObject::SelectionState selectionState();
+ virtual RenderObject::SelectionState selectionState() FINAL;
InlineBox* firstSelectedBox();
InlineBox* lastSelectedBox();
- GapRects lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo*);
+ GapRects lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
+ LayoutUnit selTop, LayoutUnit selHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
RenderBlock* block() const;
@@ -150,9 +151,9 @@ public:
Vector<RenderBox*>* floatsPtr() { ASSERT(!isDirty()); return m_floats.get(); }
- virtual void extractLineBoxFromRenderObject();
- virtual void attachLineBoxToRenderObject();
- virtual void removeLineBoxFromRenderObject();
+ virtual void extractLineBoxFromRenderObject() FINAL;
+ virtual void attachLineBoxToRenderObject() FINAL;
+ virtual void removeLineBoxFromRenderObject() FINAL;
FontBaseline baselineType() const { return static_cast<FontBaseline>(m_baselineType); }
@@ -187,6 +188,11 @@ public:
return InlineFlowBox::logicalBottomLayoutOverflow(lineBottom());
}
+#if ENABLE(CSS3_TEXT)
+ // Used to calculate the underline offset for TextUnderlinePositionUnder.
+ float maxLogicalTop() const;
+#endif // CSS3_TEXT
+
Node* getLogicalStartBoxWithNode(InlineBox*&) const;
Node* getLogicalEndBoxWithNode(InlineBox*&) const;
@@ -229,21 +235,16 @@ private:
, m_paginationStrut(0)
, m_paginatedLineWidth(0)
, m_isFirstAfterPageBreak(false)
- , m_hasContainingRegion(false)
{
}
- LineFragmentationData* sanitize(const RenderBlock*);
-
// It should not be assumed the |containingRegion| is always valid.
- // It can also be 0 if the flow has no region chain or an invalid pointer if the region is no longer in the chain.
- // Use |sanitize| to filter an invalid region.
+ // It can also be 0 if the flow has no region chain.
RenderRegion* m_containingRegion;
LayoutUnit m_paginationStrut;
LayoutUnit m_paginatedLineWidth;
- unsigned m_isFirstAfterPageBreak : 1;
- unsigned m_hasContainingRegion : 1; // We need to keep this to differentiate between the case of a void region and an invalid region.
+ bool m_isFirstAfterPageBreak;
};
OwnPtr<LineFragmentationData> m_fragmentationData;
diff --git a/Source/WebCore/rendering/TableLayout.h b/Source/WebCore/rendering/TableLayout.h
index 750768347..67472b97c 100644
--- a/Source/WebCore/rendering/TableLayout.h
+++ b/Source/WebCore/rendering/TableLayout.h
@@ -31,18 +31,21 @@ class RenderTable;
class TableLayout {
WTF_MAKE_NONCOPYABLE(TableLayout); WTF_MAKE_FAST_ALLOCATED;
public:
- TableLayout(RenderTable* table)
+ explicit TableLayout(RenderTable* table)
: m_table(table)
{
}
virtual ~TableLayout() { }
- virtual void computePreferredLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) = 0;
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) = 0;
+ virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const = 0;
virtual void layout() = 0;
protected:
- const static int tableMaxWidth = 15000;
+ // FIXME: Once we enable SATURATED_LAYOUT_ARITHMETHIC, this should just be LayoutUnit::nearlyMax().
+ // Until then though, using nearlyMax causes overflow in some tests, so we just pick a large number.
+ const static int tableMaxWidth = 1000000;
RenderTable* m_table;
};
diff --git a/Source/WebCore/rendering/TextAutosizer.cpp b/Source/WebCore/rendering/TextAutosizer.cpp
index 358840dc4..903398c97 100644
--- a/Source/WebCore/rendering/TextAutosizer.cpp
+++ b/Source/WebCore/rendering/TextAutosizer.cpp
@@ -25,7 +25,9 @@
#include "TextAutosizer.h"
#include "Document.h"
+#include "HTMLElement.h"
#include "InspectorInstrumentation.h"
+#include "IntSize.h"
#include "RenderObject.h"
#include "RenderStyle.h"
#include "RenderText.h"
@@ -34,14 +36,52 @@
#include "StyleInheritedData.h"
#include <algorithm>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
namespace WebCore {
+using namespace HTMLNames;
+
struct TextAutosizingWindowInfo {
IntSize windowSize;
IntSize minLayoutSize;
};
+// Represents cluster related data. Instances should not persist between calls to processSubtree.
+struct TextAutosizingClusterInfo {
+ explicit TextAutosizingClusterInfo(RenderBlock* root)
+ : root(root)
+ , blockContainingAllText(0)
+ , maxAllowedDifferenceFromTextWidth(150)
+ {
+ }
+
+ RenderBlock* root;
+ const RenderBlock* blockContainingAllText;
+
+ // Upper limit on the difference between the width of the cluster's block containing all
+ // text and that of a narrow child before the child becomes a separate cluster.
+ float maxAllowedDifferenceFromTextWidth;
+
+ // Descendants of the cluster that are narrower than the block containing all text and must be
+ // processed together.
+ Vector<TextAutosizingClusterInfo> narrowDescendants;
+};
+
+
+static const Vector<QualifiedName>& formInputTags()
+{
+ // Returns the tags for the form input elements.
+ DEFINE_STATIC_LOCAL(Vector<QualifiedName>, formInputTags, ());
+ if (formInputTags.isEmpty()) {
+ formInputTags.append(inputTag);
+ formInputTags.append(buttonTag);
+ formInputTags.append(selectTag);
+ }
+ return formInputTags;
+}
+
TextAutosizer::TextAutosizer(Document* document)
: m_document(document)
{
@@ -51,6 +91,16 @@ TextAutosizer::~TextAutosizer()
{
}
+void TextAutosizer::recalculateMultipliers()
+{
+ RenderObject* renderer = m_document->renderer();
+ while (renderer) {
+ if (renderer->style() && renderer->style()->textAutosizingMultiplier() != 1)
+ setMultiplier(renderer, 1);
+ renderer = renderer->nextInPreOrder();
+ }
+}
+
bool TextAutosizer::processSubtree(RenderObject* layoutRoot)
{
// FIXME: Text Autosizing should only be enabled when m_document->page()->mainFrame()->view()->useFixedLayout()
@@ -66,9 +116,7 @@ bool TextAutosizer::processSubtree(RenderObject* layoutRoot)
windowInfo.windowSize = m_document->settings()->textAutosizingWindowSizeOverride();
if (windowInfo.windowSize.isEmpty()) {
bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(mainFrame);
- windowInfo.windowSize = mainFrame->view()->visibleContentRect(includeScrollbars).size();
- if (!m_document->settings()->applyPageScaleFactorInCompositor())
- windowInfo.windowSize.scale(1 / m_document->page()->deviceScaleFactor());
+ windowInfo.windowSize = mainFrame->view()->unscaledVisibleContentSize(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars);
}
// Largest area of block that can be visible at once (assuming the main
@@ -85,80 +133,96 @@ bool TextAutosizer::processSubtree(RenderObject* layoutRoot)
container = container->containingBlock();
RenderBlock* cluster = container;
- while (cluster && (!isAutosizingContainer(cluster) || !isAutosizingCluster(cluster)))
+ while (cluster && (!isAutosizingContainer(cluster) || !isIndependentDescendant(cluster)))
cluster = cluster->containingBlock();
- processCluster(cluster, container, layoutRoot, windowInfo);
+ TextAutosizingClusterInfo clusterInfo(cluster);
+ processCluster(clusterInfo, container, layoutRoot, windowInfo);
return true;
}
-void TextAutosizer::processCluster(RenderBlock* cluster, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo)
+float TextAutosizer::clusterMultiplier(WritingMode writingMode, const TextAutosizingWindowInfo& windowInfo, float textWidth) const
{
- ASSERT(isAutosizingCluster(cluster));
-
- // Many pages set a max-width on their content. So especially for the
- // RenderView, instead of just taking the width of |cluster| we find
- // the lowest common ancestor of the first and last descendant text node of
- // the cluster (i.e. the deepest wrapper block that contains all the text),
- // and use its width instead.
- const RenderBlock* lowestCommonAncestor = findDeepestBlockContainingAllText(cluster);
- float commonAncestorWidth = lowestCommonAncestor->contentLogicalWidth();
-
- float multiplier = 1;
- if (clusterShouldBeAutosized(lowestCommonAncestor, commonAncestorWidth)) {
- int logicalWindowWidth = cluster->isHorizontalWritingMode() ? windowInfo.windowSize.width() : windowInfo.windowSize.height();
- int logicalLayoutWidth = cluster->isHorizontalWritingMode() ? windowInfo.minLayoutSize.width() : windowInfo.minLayoutSize.height();
- // Ignore box width in excess of the layout width, to avoid extreme multipliers.
- float logicalClusterWidth = std::min<float>(commonAncestorWidth, logicalLayoutWidth);
-
- multiplier = logicalClusterWidth / logicalWindowWidth;
- multiplier *= m_document->settings()->textAutosizingFontScaleFactor();
- multiplier = std::max(1.0f, multiplier);
- }
+ int logicalWindowWidth = isHorizontalWritingMode(writingMode) ? windowInfo.windowSize.width() : windowInfo.windowSize.height();
+ int logicalLayoutWidth = isHorizontalWritingMode(writingMode) ? windowInfo.minLayoutSize.width() : windowInfo.minLayoutSize.height();
+ // Ignore box width in excess of the layout width, to avoid extreme multipliers.
+ float logicalClusterWidth = std::min<float>(textWidth, logicalLayoutWidth);
+
+ float multiplier = logicalClusterWidth / logicalWindowWidth;
+ multiplier *= m_document->settings()->textAutosizingFontScaleFactor();
+ return std::max(1.0f, multiplier);
+}
+
+void TextAutosizer::processClusterInternal(TextAutosizingClusterInfo& clusterInfo, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo, float multiplier)
+{
+ processContainer(multiplier, container, clusterInfo, subtreeRoot, windowInfo);
- processContainer(multiplier, container, subtreeRoot, windowInfo);
+ Vector<Vector<TextAutosizingClusterInfo> > narrowDescendantsGroups;
+ getNarrowDescendantsGroupedByWidth(clusterInfo, narrowDescendantsGroups);
+ for (size_t i = 0; i < narrowDescendantsGroups.size(); ++i)
+ processCompositeCluster(narrowDescendantsGroups[i], windowInfo);
}
-static bool contentHeightIsConstrained(const RenderBlock* container)
+void TextAutosizer::processCluster(TextAutosizingClusterInfo& clusterInfo, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo)
{
- // FIXME: Propagate constrainedness down the tree, to avoid inefficiently walking back up from each box.
- // FIXME: This code needs to take into account vertical writing modes.
- // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in.
- for (; container; container = container->containingBlock()) {
- RenderStyle* style = container->style();
- if (style->overflowY() >= OSCROLL)
- return false;
- if (style->height().isSpecified() || style->maxHeight().isSpecified()) {
- // Some sites (e.g. wikipedia) set their html and/or body elements to height:100%,
- // without intending to constrain the height of the content within them.
- return !container->isRoot() && !container->isBody();
- }
- if (container->isFloatingOrOutOfFlowPositioned())
- return false;
+ // Many pages set a max-width on their content. So especially for the RenderView, instead of
+ // just taking the width of |cluster| we find the lowest common ancestor of the first and last
+ // descendant text node of the cluster (i.e. the deepest wrapper block that contains all the
+ // text), and use its width instead.
+ clusterInfo.blockContainingAllText = findDeepestBlockContainingAllText(clusterInfo.root);
+ float textWidth = clusterInfo.blockContainingAllText->contentLogicalWidth();
+ float multiplier = 1.0;
+ if (clusterShouldBeAutosized(clusterInfo, textWidth))
+ multiplier = clusterMultiplier(clusterInfo.root->style()->writingMode(), windowInfo, textWidth);
+ processClusterInternal(clusterInfo, container, subtreeRoot, windowInfo, multiplier);
+}
+
+void TextAutosizer::processCompositeCluster(Vector<TextAutosizingClusterInfo>& clusterInfos, const TextAutosizingWindowInfo& windowInfo)
+{
+ if (clusterInfos.isEmpty())
+ return;
+
+ float maxTextWidth = 0;
+ for (size_t i = 0; i < clusterInfos.size(); ++i) {
+ TextAutosizingClusterInfo& clusterInfo = clusterInfos[i];
+ clusterInfo.blockContainingAllText = findDeepestBlockContainingAllText(clusterInfo.root);
+ maxTextWidth = max<float>(maxTextWidth, clusterInfo.blockContainingAllText->contentLogicalWidth());
+ }
+
+ float multiplier = 1.0;
+ if (compositeClusterShouldBeAutosized(clusterInfos, maxTextWidth))
+ multiplier = clusterMultiplier(clusterInfos[0].root->style()->writingMode(), windowInfo, maxTextWidth);
+ for (size_t i = 0; i < clusterInfos.size(); ++i) {
+ ASSERT(clusterInfos[i].root->style()->writingMode() == clusterInfos[0].root->style()->writingMode());
+ processClusterInternal(clusterInfos[i], clusterInfos[i].root, clusterInfos[i].root, windowInfo, multiplier);
}
- return false;
}
-void TextAutosizer::processContainer(float multiplier, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo)
+void TextAutosizer::processContainer(float multiplier, RenderBlock* container, TextAutosizingClusterInfo& clusterInfo, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo)
{
ASSERT(isAutosizingContainer(container));
- float localMultiplier = contentHeightIsConstrained(container) ? 1 : multiplier;
+ float localMultiplier = containerShouldBeAutosized(container) ? multiplier: 1;
RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(subtreeRoot, subtreeRoot);
while (descendant) {
if (descendant->isText()) {
- if (localMultiplier != descendant->style()->textAutosizingMultiplier()) {
+ if (localMultiplier != 1 && descendant->style()->textAutosizingMultiplier() == 1) {
setMultiplier(descendant, localMultiplier);
setMultiplier(descendant->parent(), localMultiplier); // Parent does line spacing.
}
// FIXME: Increase list marker size proportionately.
} else if (isAutosizingContainer(descendant)) {
RenderBlock* descendantBlock = toRenderBlock(descendant);
- if (isAutosizingCluster(descendantBlock))
- processCluster(descendantBlock, descendantBlock, descendantBlock, windowInfo);
- else
- processContainer(multiplier, descendantBlock, descendantBlock, windowInfo);
+ TextAutosizingClusterInfo descendantClusterInfo(descendantBlock);
+ if (isWiderDescendant(descendantBlock, clusterInfo) || isIndependentDescendant(descendantBlock))
+ processCluster(descendantClusterInfo, descendantBlock, descendantBlock, windowInfo);
+ else if (isNarrowDescendant(descendantBlock, clusterInfo)) {
+ // Narrow descendants are processed together later to be able to apply the same multiplier
+ // to each of them if necessary.
+ clusterInfo.narrowDescendants.append(descendantClusterInfo);
+ } else
+ processContainer(multiplier, descendantBlock, clusterInfo, descendantBlock, windowInfo);
}
descendant = nextInPreOrderSkippingDescendantsOfContainers(descendant, subtreeRoot);
}
@@ -204,21 +268,71 @@ bool TextAutosizer::isAutosizingContainer(const RenderObject* renderer)
// "Autosizing containers" are the smallest unit for which we can
// enable/disable Text Autosizing.
// - Must not be inline, as different multipliers on one line looks terrible.
+ // Exceptions are inline-block and alike elements (inline-table, -webkit-inline-*),
+ // as they often contain entire multi-line columns of text.
// - Must not be list items, as items in the same list should look consistent (*).
- // * except for those list items positioned out of the list's flow.
- return renderer->isRenderBlock()
- && !renderer->isInline()
- && (!renderer->isListItem() || renderer->isOutOfFlowPositioned());
+ // - Must not be normal list items, as items in the same list should look
+ // consistent, unless they are floating or position:absolute/fixed.
+ if (!renderer->isRenderBlock() || (renderer->isInline() && !renderer->style()->isDisplayReplacedType()))
+ return false;
+ if (renderer->isListItem())
+ return renderer->isFloating() || renderer->isOutOfFlowPositioned();
+ // Avoid creating containers for text within text controls, buttons, or <select> buttons.
+ Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode() : 0;
+ if (parentNode && parentNode->isElementNode() && formInputTags().contains(toElement(parentNode)->tagQName()))
+ return false;
+
+ return true;
+}
+
+bool TextAutosizer::isNarrowDescendant(const RenderBlock* renderer, TextAutosizingClusterInfo& parentClusterInfo)
+{
+ ASSERT(isAutosizingContainer(renderer));
+
+ // Autosizing containers that are significantly narrower than the |blockContainingAllText| of
+ // their enclosing cluster may be acting as separate columns, hence must be autosized
+ // separately. For example the 2nd div in:
+ // <body>
+ // <div style="float: right; width: 50%"></div>
+ // <div style="width: 50%"></div>
+ // <body>
+ // is the left column, and should be autosized differently from the body.
+ // If however the container is only narrower by 150px or less, it's considered part of
+ // the enclosing cluster. This 150px limit is adjusted whenever a descendant container is
+ // less than 50px narrower than the current limit.
+ const float differenceFromMaxWidthDifference = 50;
+ float contentWidth = renderer->contentLogicalWidth();
+ float clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth();
+ float widthDifference = clusterTextWidth - contentWidth;
+
+ if (widthDifference - parentClusterInfo.maxAllowedDifferenceFromTextWidth > differenceFromMaxWidthDifference)
+ return true;
+
+ parentClusterInfo.maxAllowedDifferenceFromTextWidth = std::max(widthDifference, parentClusterInfo.maxAllowedDifferenceFromTextWidth);
+ return false;
+}
+
+bool TextAutosizer::isWiderDescendant(const RenderBlock* renderer, const TextAutosizingClusterInfo& parentClusterInfo)
+{
+ ASSERT(isAutosizingContainer(renderer));
+
+ // Autosizing containers that are wider than the |blockContainingAllText| of their enclosing
+ // cluster are treated the same way as autosizing clusters to be autosized separately.
+ float contentWidth = renderer->contentLogicalWidth();
+ float clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth();
+ return contentWidth > clusterTextWidth;
}
-bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer)
+bool TextAutosizer::isIndependentDescendant(const RenderBlock* renderer)
{
+ ASSERT(isAutosizingContainer(renderer));
+
// "Autosizing clusters" are special autosizing containers within which we
// want to enforce a uniform text size multiplier, in the hopes of making
// the major sections of the page look internally consistent.
- // All their descendents (including other autosizing containers) must share
+ // All their descendants (including other autosizing containers) must share
// the same multiplier, except for subtrees which are themselves clusters,
- // and some of their descendent containers might not be autosized at all
+ // and some of their descendant containers might not be autosized at all
// (for example if their height is constrained).
// Additionally, clusterShouldBeAutosized requires each cluster to contain a
// minimum amount of text, without which it won't be autosized.
@@ -227,13 +341,11 @@ bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer)
// block formatting contexts (http://w3.org/TR/css3-box/#flow-root), since
// flow roots correspond to box containers that behave somewhat
// independently from their parent (for example they don't overlap floats).
- // The definition of a flow flow root also conveniently includes most of the
+ // The definition of a flow root also conveniently includes most of the
// ways that a box and its children can have significantly different width
// from the box's parent (we want to avoid having significantly different
// width blocks within a cluster, since the narrower blocks would end up
// larger than would otherwise be necessary).
- ASSERT(isAutosizingContainer(renderer));
-
return renderer->isRenderView()
|| renderer->isFloating()
|| renderer->isOutOfFlowPositioned()
@@ -241,13 +353,120 @@ bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer)
|| renderer->isTableCaption()
|| renderer->isFlexibleBoxIncludingDeprecated()
|| renderer->hasColumns()
- || renderer->containingBlock()->isHorizontalWritingMode() != renderer->isHorizontalWritingMode();
+ || renderer->containingBlock()->isHorizontalWritingMode() != renderer->isHorizontalWritingMode()
+ || renderer->style()->isDisplayReplacedType();
// FIXME: Tables need special handling to multiply all their columns by
// the same amount even if they're different widths; so do hasColumns()
- // renderers, and probably flexboxes...
+ // containers, and probably flexboxes...
+}
+
+bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer, TextAutosizingClusterInfo& parentClusterInfo)
+{
+ ASSERT(isAutosizingContainer(renderer));
+
+ return isNarrowDescendant(renderer, parentClusterInfo)
+ || isWiderDescendant(renderer, parentClusterInfo)
+ || isIndependentDescendant(renderer);
+}
+
+bool TextAutosizer::containerShouldBeAutosized(const RenderBlock* container)
+{
+ if (containerContainsOneOfTags(container, formInputTags()))
+ return false;
+
+ if (containerIsRowOfLinks(container))
+ return false;
+
+ // Don't autosize block-level text that can't wrap (as it's likely to
+ // expand sideways and break the page's layout).
+ if (!container->style()->autoWrap())
+ return false;
+
+ return !contentHeightIsConstrained(container);
+}
+
+bool TextAutosizer::containerContainsOneOfTags(const RenderBlock* container, const Vector<QualifiedName>& tags)
+{
+ const RenderObject* renderer = container;
+ while (renderer) {
+ const Node* rendererNode = renderer->node();
+ if (rendererNode && rendererNode->isElementNode()) {
+ if (tags.contains(toElement(rendererNode)->tagQName()))
+ return true;
+ }
+ renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, container);
+ }
+
+ return false;
+}
+
+bool TextAutosizer::containerIsRowOfLinks(const RenderObject* container)
+{
+ // A "row of links" is a container for which holds:
+ // 1. it should not contain non-link text elements longer than 3 characters
+ // 2. it should contain min. 3 inline links and all links should
+ // have the same specified font size
+ // 3. it should not contain <br> elements
+ // 4. it should contain only inline elements unless they are containers,
+ // children of link elements or children of sub-containers.
+ int linkCount = 0;
+ RenderObject* renderer = container->nextInPreOrder(container);
+ float matchingFontSize = -1;
+
+ while (renderer) {
+ if (!isAutosizingContainer(renderer)) {
+ if (renderer->isText() && toRenderText(renderer)->text()->stripWhiteSpace()->length() > 3)
+ return false;
+ if (!renderer->isInline())
+ return false;
+ if (renderer->isBR())
+ return false;
+ }
+ if (renderer->style()->isLink()) {
+ if (matchingFontSize < 0)
+ matchingFontSize = renderer->style()->specifiedFontSize();
+ else {
+ if (matchingFontSize != renderer->style()->specifiedFontSize())
+ return false;
+ }
+
+ linkCount++;
+ // Skip traversing descendants of the link.
+ renderer = renderer->nextInPreOrderAfterChildren(container);
+ } else
+ renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, container);
+ }
+
+ return (linkCount >= 3);
+}
+
+bool TextAutosizer::contentHeightIsConstrained(const RenderBlock* container)
+{
+ // FIXME: Propagate constrainedness down the tree, to avoid inefficiently walking back up from each box.
+ // FIXME: This code needs to take into account vertical writing modes.
+ // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in.
+ for (; container; container = container->containingBlock()) {
+ RenderStyle* style = container->style();
+ if (style->overflowY() >= OSCROLL)
+ return false;
+ if (style->height().isSpecified() || style->maxHeight().isSpecified()) {
+ // Some sites (e.g. wikipedia) set their html and/or body elements to height:100%,
+ // without intending to constrain the height of the content within them.
+ return !container->isRoot() && !container->isBody();
+ }
+ if (container->isFloatingOrOutOfFlowPositioned())
+ return false;
+ }
+ return false;
+}
+
+bool TextAutosizer::clusterShouldBeAutosized(TextAutosizingClusterInfo& clusterInfo, float blockWidth)
+{
+ Vector<TextAutosizingClusterInfo> clusterInfos(1, clusterInfo);
+ return compositeClusterShouldBeAutosized(clusterInfos, blockWidth);
}
-bool TextAutosizer::clusterShouldBeAutosized(const RenderBlock* lowestCommonAncestor, float commonAncestorWidth)
+bool TextAutosizer::compositeClusterShouldBeAutosized(Vector<TextAutosizingClusterInfo>& clusterInfos, float blockWidth)
{
// Don't autosize clusters that contain less than 4 lines of text (in
// practice less lines are required, since measureDescendantTextWidth
@@ -259,18 +478,20 @@ bool TextAutosizer::clusterShouldBeAutosized(const RenderBlock* lowestCommonAnce
// if a cluster contains very few lines of text then it's ok to have to zoom
// in and pan from side to side to read each line, since if there are very
// few lines of text you'll only need to pan across once or twice.
+ float totalTextWidth = 0;
const float minLinesOfText = 4;
- float minTextWidth = commonAncestorWidth * minLinesOfText;
- float textWidth = 0;
- measureDescendantTextWidth(lowestCommonAncestor, minTextWidth, textWidth);
- if (textWidth >= minTextWidth)
- return true;
+ float minTextWidth = blockWidth * minLinesOfText;
+ for (size_t i = 0; i < clusterInfos.size(); ++i) {
+ measureDescendantTextWidth(clusterInfos[i].blockContainingAllText, clusterInfos[i], minTextWidth, totalTextWidth);
+ if (totalTextWidth >= minTextWidth)
+ return true;
+ }
return false;
}
-void TextAutosizer::measureDescendantTextWidth(const RenderBlock* container, float minTextWidth, float& textWidth)
+void TextAutosizer::measureDescendantTextWidth(const RenderBlock* container, TextAutosizingClusterInfo& clusterInfo, float minTextWidth, float& textWidth)
{
- bool skipLocalText = contentHeightIsConstrained(container);
+ bool skipLocalText = !containerShouldBeAutosized(container);
RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(container, container);
while (descendant) {
@@ -278,8 +499,8 @@ void TextAutosizer::measureDescendantTextWidth(const RenderBlock* container, flo
textWidth += toRenderText(descendant)->renderedTextLength() * descendant->style()->specifiedFontSize();
} else if (isAutosizingContainer(descendant)) {
RenderBlock* descendantBlock = toRenderBlock(descendant);
- if (!isAutosizingCluster(descendantBlock))
- measureDescendantTextWidth(descendantBlock, minTextWidth, textWidth);
+ if (!isAutosizingCluster(descendantBlock, clusterInfo))
+ measureDescendantTextWidth(descendantBlock, clusterInfo, minTextWidth, textWidth);
}
if (textWidth >= minTextWidth)
return;
@@ -290,23 +511,12 @@ void TextAutosizer::measureDescendantTextWidth(const RenderBlock* container, flo
RenderObject* TextAutosizer::nextInPreOrderSkippingDescendantsOfContainers(const RenderObject* current, const RenderObject* stayWithin)
{
if (current == stayWithin || !isAutosizingContainer(current))
- for (RenderObject* child = current->firstChild(); child; child = child->nextSibling())
- return child;
-
- for (const RenderObject* ancestor = current; ancestor; ancestor = ancestor->parent()) {
- if (ancestor == stayWithin)
- return 0;
- for (RenderObject* sibling = ancestor->nextSibling(); sibling; sibling = sibling->nextSibling())
- return sibling;
- }
-
- return 0;
+ return current->nextInPreOrder(stayWithin);
+ return current->nextInPreOrderAfterChildren(stayWithin);
}
const RenderBlock* TextAutosizer::findDeepestBlockContainingAllText(const RenderBlock* cluster)
{
- ASSERT(isAutosizingCluster(cluster));
-
size_t firstDepth = 0;
const RenderObject* firstTextLeaf = findFirstTextLeafNotInCluster(cluster, firstDepth, FirstToLast);
if (!firstTextLeaf)
@@ -355,7 +565,7 @@ const RenderObject* TextAutosizer::findFirstTextLeafNotInCluster(const RenderObj
++depth;
const RenderObject* child = (direction == FirstToLast) ? parent->firstChild() : parent->lastChild();
while (child) {
- if (!isAutosizingContainer(child) || !isAutosizingCluster(toRenderBlock(child))) {
+ if (!isAutosizingContainer(child) || !isIndependentDescendant(toRenderBlock(child))) {
const RenderObject* leaf = findFirstTextLeafNotInCluster(child, depth, direction);
if (leaf)
return leaf;
@@ -367,6 +577,43 @@ const RenderObject* TextAutosizer::findFirstTextLeafNotInCluster(const RenderObj
return 0;
}
+namespace {
+
+// Compares the width of the specified cluster's roots in descending order.
+bool clusterWiderThanComparisonFn(const TextAutosizingClusterInfo& first, const TextAutosizingClusterInfo& second)
+{
+ return first.root->contentLogicalWidth() > second.root->contentLogicalWidth();
+}
+
+} // namespace
+
+void TextAutosizer::getNarrowDescendantsGroupedByWidth(const TextAutosizingClusterInfo& parentClusterInfo, Vector<Vector<TextAutosizingClusterInfo> >& groups)
+{
+ ASSERT(parentClusterInfo.blockContainingAllText);
+ ASSERT(groups.isEmpty());
+
+ Vector<TextAutosizingClusterInfo> clusterInfos(parentClusterInfo.narrowDescendants);
+ if (clusterInfos.isEmpty())
+ return;
+
+ std::sort(clusterInfos.begin(), clusterInfos.end(), &clusterWiderThanComparisonFn);
+ groups.grow(1);
+
+ // If the width difference between two consecutive elements of |clusterInfos| is greater than
+ // this empirically determined value, the next element should start a new group.
+ const float maxWidthDifferenceWithinGroup = 100;
+ for (size_t i = 0; i < clusterInfos.size(); ++i) {
+ groups.last().append(clusterInfos[i]);
+
+ if (i + 1 < clusterInfos.size()) {
+ float currentWidth = clusterInfos[i].root->contentLogicalWidth();
+ float nextWidth = clusterInfos[i + 1].root->contentLogicalWidth();
+ if (currentWidth - nextWidth > maxWidthDifferenceWithinGroup)
+ groups.grow(groups.size() + 1);
+ }
+ }
+}
+
} // namespace WebCore
#endif // ENABLE(TEXT_AUTOSIZING)
diff --git a/Source/WebCore/rendering/TextAutosizer.h b/Source/WebCore/rendering/TextAutosizer.h
index a709b1168..f1f675385 100644
--- a/Source/WebCore/rendering/TextAutosizer.h
+++ b/Source/WebCore/rendering/TextAutosizer.h
@@ -28,19 +28,19 @@
#if ENABLE(TEXT_AUTOSIZING)
-#include "IntSize.h"
+#include "HTMLNames.h"
+#include "WritingMode.h"
#include <wtf/Noncopyable.h>
#include <wtf/PassOwnPtr.h>
-#include <wtf/PassRefPtr.h>
namespace WebCore {
class Document;
class RenderBlock;
class RenderObject;
-class RenderStyle;
class RenderText;
struct TextAutosizingWindowInfo;
+struct TextAutosizingClusterInfo;
class TextAutosizer {
WTF_MAKE_NONCOPYABLE(TextAutosizer);
@@ -51,6 +51,7 @@ public:
virtual ~TextAutosizer();
bool processSubtree(RenderObject* layoutRoot);
+ void recalculateMultipliers();
static float computeAutosizedFontSize(float specifiedSize, float multiplier);
@@ -62,28 +63,43 @@ private:
explicit TextAutosizer(Document*);
- void processCluster(RenderBlock* cluster, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&);
- void processContainer(float multiplier, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&);
+ float clusterMultiplier(WritingMode, const TextAutosizingWindowInfo&, float textWidth) const;
+
+ void processClusterInternal(TextAutosizingClusterInfo&, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&, float multiplier);
+ void processCluster(TextAutosizingClusterInfo&, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&);
+ void processCompositeCluster(Vector<TextAutosizingClusterInfo>&, const TextAutosizingWindowInfo&);
+ void processContainer(float multiplier, RenderBlock* container, TextAutosizingClusterInfo&, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&);
void setMultiplier(RenderObject*, float);
static bool isAutosizingContainer(const RenderObject*);
- static bool isAutosizingCluster(const RenderBlock*);
-
- static bool clusterShouldBeAutosized(const RenderBlock* lowestCommonAncestor, float commonAncestorWidth);
- static void measureDescendantTextWidth(const RenderBlock* container, float minTextWidth, float& textWidth);
+ static bool isNarrowDescendant(const RenderBlock*, TextAutosizingClusterInfo& parentClusterInfo);
+ static bool isWiderDescendant(const RenderBlock*, const TextAutosizingClusterInfo& parentClusterInfo);
+ static bool isIndependentDescendant(const RenderBlock*);
+ static bool isAutosizingCluster(const RenderBlock*, TextAutosizingClusterInfo& parentClusterInfo);
+
+ static bool containerShouldBeAutosized(const RenderBlock* container);
+ static bool containerContainsOneOfTags(const RenderBlock* cluster, const Vector<QualifiedName>& tags);
+ static bool containerIsRowOfLinks(const RenderObject* container);
+ static bool contentHeightIsConstrained(const RenderBlock* container);
+ static bool clusterShouldBeAutosized(TextAutosizingClusterInfo&, float blockWidth);
+ static bool compositeClusterShouldBeAutosized(Vector<TextAutosizingClusterInfo>&, float blockWidth);
+ static void measureDescendantTextWidth(const RenderBlock* container, TextAutosizingClusterInfo&, float minTextWidth, float& textWidth);
// Use to traverse the tree of descendants, excluding descendants of containers (but returning the containers themselves).
- static RenderObject* nextInPreOrderSkippingDescendantsOfContainers(const RenderObject* current, const RenderObject* stayWithin);
+ static RenderObject* nextInPreOrderSkippingDescendantsOfContainers(const RenderObject*, const RenderObject* stayWithin);
- // Finds the lowest common ancestor of the first and the last descendant
- // text node (excluding those belonging to other autosizing clusters).
static const RenderBlock* findDeepestBlockContainingAllText(const RenderBlock* cluster);
// Depending on the traversal direction specified, finds the first or the last leaf text node child that doesn't
// belong to any cluster.
static const RenderObject* findFirstTextLeafNotInCluster(const RenderObject*, size_t& depth, TraversalDirection);
+ // Returns groups of narrow descendants of a given autosizing cluster. The groups are combined
+ // by the difference between the width of the descendant and the width of the parent cluster's
+ // |blockContainingAllText|.
+ static void getNarrowDescendantsGroupedByWidth(const TextAutosizingClusterInfo& parentClusterInfo, Vector<Vector<TextAutosizingClusterInfo> >&);
+
Document* m_document;
};
diff --git a/Source/WebCore/rendering/TrailingFloatsRootInlineBox.h b/Source/WebCore/rendering/TrailingFloatsRootInlineBox.h
index 960ca8a29..1f9150d1c 100644
--- a/Source/WebCore/rendering/TrailingFloatsRootInlineBox.h
+++ b/Source/WebCore/rendering/TrailingFloatsRootInlineBox.h
@@ -30,7 +30,7 @@
namespace WebCore {
-class TrailingFloatsRootInlineBox : public RootInlineBox {
+class TrailingFloatsRootInlineBox FINAL : public RootInlineBox {
public:
TrailingFloatsRootInlineBox(RenderBlock* block)
: RootInlineBox(block)
diff --git a/Source/WebCore/rendering/break_lines.cpp b/Source/WebCore/rendering/break_lines.cpp
index 10f8b2be2..04b040d34 100644
--- a/Source/WebCore/rendering/break_lines.cpp
+++ b/Source/WebCore/rendering/break_lines.cpp
@@ -153,8 +153,9 @@ static inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator
int len = static_cast<int>(length);
int nextBreak = -1;
- CharacterType lastLastCh = pos > 1 ? str[pos - 2] : 0;
- CharacterType lastCh = pos > 0 ? str[pos - 1] : 0;
+ CharacterType lastLastCh = pos > 1 ? str[pos - 2] : static_cast<CharacterType>(lazyBreakIterator.secondToLastCharacter());
+ CharacterType lastCh = pos > 0 ? str[pos - 1] : static_cast<CharacterType>(lazyBreakIterator.lastCharacter());
+ unsigned priorContextLength = lazyBreakIterator.priorContextLength();
for (int i = pos; i < len; i++) {
CharacterType ch = str[i];
@@ -162,10 +163,16 @@ static inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator
return i;
if (needsLineBreakIterator<treatNoBreakSpaceAsBreak>(ch) || needsLineBreakIterator<treatNoBreakSpaceAsBreak>(lastCh)) {
- if (nextBreak < i && i) {
- TextBreakIterator* breakIterator = lazyBreakIterator.get();
- if (breakIterator)
- nextBreak = textBreakFollowing(breakIterator, i - 1);
+ if (nextBreak < i) {
+ // Don't break if positioned at start of primary context and there is no prior context.
+ if (i || priorContextLength) {
+ TextBreakIterator* breakIterator = lazyBreakIterator.get(priorContextLength);
+ if (breakIterator) {
+ nextBreak = textBreakFollowing(breakIterator, i - 1 + priorContextLength);
+ if (nextBreak >= 0)
+ nextBreak -= priorContextLength;
+ }
+ }
}
if (i == nextBreak && !isBreakableSpace<treatNoBreakSpaceAsBreak>(lastCh))
return i;
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp b/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp
index c23a9de20..025842c39 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp
@@ -33,6 +33,7 @@
#include "GraphicsContext.h"
#include "MathMLNames.h"
#include "RenderView.h"
+#include <wtf/text/StringBuilder.h>
#if ENABLE(DEBUG_MATH_LAYOUT)
#include "PaintInfo.h"
@@ -42,13 +43,9 @@ namespace WebCore {
using namespace MathMLNames;
-RenderMathMLBlock::RenderMathMLBlock(Node* container)
+RenderMathMLBlock::RenderMathMLBlock(Element* container)
: RenderFlexibleBox(container)
, m_ignoreInAccessibilityTree(false)
- , m_intrinsicPaddingBefore(0)
- , m_intrinsicPaddingAfter(0)
- , m_intrinsicPaddingStart(0)
- , m_intrinsicPaddingEnd(0)
, m_preferredLogicalHeight(preferredLogicalHeightUnset)
{
}
@@ -58,90 +55,6 @@ bool RenderMathMLBlock::isChildAllowed(RenderObject* child, RenderStyle*) const
return child->node() && child->node()->nodeType() == Node::ELEMENT_NODE;
}
-LayoutUnit RenderMathMLBlock::paddingTop() const
-{
- LayoutUnit result = computedCSSPaddingTop();
- switch (style()->writingMode()) {
- case TopToBottomWritingMode:
- return result + m_intrinsicPaddingBefore;
- case BottomToTopWritingMode:
- return result + m_intrinsicPaddingAfter;
- case LeftToRightWritingMode:
- case RightToLeftWritingMode:
- return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd);
- }
- ASSERT_NOT_REACHED();
- return result;
-}
-
-LayoutUnit RenderMathMLBlock::paddingBottom() const
-{
- LayoutUnit result = computedCSSPaddingBottom();
- switch (style()->writingMode()) {
- case TopToBottomWritingMode:
- return result + m_intrinsicPaddingAfter;
- case BottomToTopWritingMode:
- return result + m_intrinsicPaddingBefore;
- case LeftToRightWritingMode:
- case RightToLeftWritingMode:
- return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart);
- }
- ASSERT_NOT_REACHED();
- return result;
-}
-
-LayoutUnit RenderMathMLBlock::paddingLeft() const
-{
- LayoutUnit result = computedCSSPaddingLeft();
- switch (style()->writingMode()) {
- case LeftToRightWritingMode:
- return result + m_intrinsicPaddingBefore;
- case RightToLeftWritingMode:
- return result + m_intrinsicPaddingAfter;
- case TopToBottomWritingMode:
- case BottomToTopWritingMode:
- return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd);
- }
- ASSERT_NOT_REACHED();
- return result;
-}
-
-LayoutUnit RenderMathMLBlock::paddingRight() const
-{
- LayoutUnit result = computedCSSPaddingRight();
- switch (style()->writingMode()) {
- case RightToLeftWritingMode:
- return result + m_intrinsicPaddingBefore;
- case LeftToRightWritingMode:
- return result + m_intrinsicPaddingAfter;
- case TopToBottomWritingMode:
- case BottomToTopWritingMode:
- return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart);
- }
- ASSERT_NOT_REACHED();
- return result;
-}
-
-LayoutUnit RenderMathMLBlock::paddingBefore() const
-{
- return computedCSSPaddingBefore() + m_intrinsicPaddingBefore;
-}
-
-LayoutUnit RenderMathMLBlock::paddingAfter() const
-{
- return computedCSSPaddingAfter() + m_intrinsicPaddingAfter;
-}
-
-LayoutUnit RenderMathMLBlock::paddingStart() const
-{
- return computedCSSPaddingStart() + m_intrinsicPaddingStart;
-}
-
-LayoutUnit RenderMathMLBlock::paddingEnd() const
-{
- return computedCSSPaddingEnd() + m_intrinsicPaddingEnd;
-}
-
void RenderMathMLBlock::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
@@ -152,7 +65,8 @@ void RenderMathMLBlock::computePreferredLogicalWidths()
RenderMathMLBlock* RenderMathMLBlock::createAnonymousMathMLBlock(EDisplay display)
{
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), display);
- RenderMathMLBlock* newBlock = new (renderArena()) RenderMathMLBlock(document() /* is anonymous */);
+ RenderMathMLBlock* newBlock = new (renderArena()) RenderMathMLBlock(0);
+ newBlock->setDocumentForAnonymous(document());
newBlock->setStyle(newStyle.release());
return newBlock;
}
@@ -163,10 +77,13 @@ static const int cLargeLogicalWidth = 15000;
void RenderMathMLBlock::computeChildrenPreferredLogicalHeights()
{
ASSERT(needsLayout());
-
+
+ // This is ugly, but disable fragmentation when computing the preferred heights.
+ FragmentationDisabler fragmentationDisabler(this);
+
// Ensure a full repaint will happen after layout finishes.
setNeedsLayout(true, MarkOnlyThis);
-
+
RenderView* renderView = view();
bool hadLayoutState = renderView->layoutState();
if (!hadLayoutState)
@@ -271,6 +188,179 @@ void RenderMathMLBlock::paint(PaintInfo& info, const LayoutPoint& paintOffset)
}
#endif // ENABLE(DEBUG_MATH_LAYOUT)
+//
+// The MathML specification says:
+// (http://www.w3.org/TR/MathML/chapter2.html#fund.units)
+//
+// "Most presentation elements have attributes that accept values representing
+// lengths to be used for size, spacing or similar properties. The syntax of a
+// length is specified as
+//
+// number | number unit | namedspace
+//
+// There should be no space between the number and the unit of a length."
+//
+// "A trailing '%' represents a percent of the default value. The default
+// value, or how it is obtained, is listed in the table of attributes for each
+// element. [...] A number without a unit is intepreted as a multiple of the
+// default value."
+//
+// "The possible units in MathML are:
+//
+// Unit Description
+// em an em (font-relative unit traditionally used for horizontal lengths)
+// ex an ex (font-relative unit traditionally used for vertical lengths)
+// px pixels, or size of a pixel in the current display
+// in inches (1 inch = 2.54 centimeters)
+// cm centimeters
+// mm millimeters
+// pt points (1 point = 1/72 inch)
+// pc picas (1 pica = 12 points)
+// % percentage of default value"
+//
+// The numbers are defined that way:
+// - unsigned-number: "a string of decimal digits with up to one decimal point
+// (U+002E), representing a non-negative terminating decimal number (a type of
+// rational number)"
+// - number: "an optional prefix of '-' (U+002D), followed by an unsigned
+// number, representing a terminating decimal number (a type of rational
+// number)"
+//
+bool parseMathMLLength(const String& string, LayoutUnit& lengthValue, const RenderStyle* style, bool allowNegative)
+{
+ String s = string.simplifyWhiteSpace();
+
+ int stringLength = s.length();
+ if (!stringLength)
+ return false;
+
+ if (parseMathMLNamedSpace(s, lengthValue, style, allowNegative))
+ return true;
+
+ StringBuilder number;
+ String unit;
+
+ // This verifies whether the negative sign is there.
+ int i = 0;
+ UChar c = s[0];
+ if (c == '-') {
+ number.append(c);
+ i++;
+ }
+
+ // This gathers up characters that make up the number.
+ bool gotDot = false;
+ for ( ; i < stringLength; i++) {
+ c = s[i];
+ // The string is invalid if it contains two dots.
+ if (gotDot && c == '.')
+ return false;
+ if (c == '.')
+ gotDot = true;
+ else if (!isASCIIDigit(c)) {
+ unit = s.substring(i, stringLength - i);
+ // Some authors leave blanks before the unit, but that shouldn't
+ // be allowed, so don't simplifyWhitespace on 'unit'.
+ break;
+ }
+ number.append(c);
+ }
+
+ // Convert number to floating point
+ bool ok;
+ float floatValue = number.toString().toFloat(&ok);
+ if (!ok)
+ return false;
+ if (floatValue < 0 && !allowNegative)
+ return false;
+
+ if (unit.isEmpty()) {
+ // no explicit unit, this is a number that will act as a multiplier
+ lengthValue *= floatValue;
+ return true;
+ }
+ if (unit == "%") {
+ lengthValue *= floatValue / 100;
+ return true;
+ }
+ if (unit == "em") {
+ lengthValue = floatValue * style->font().size();
+ return true;
+ }
+ if (unit == "ex") {
+ lengthValue = floatValue * style->fontMetrics().xHeight();
+ return true;
+ }
+ if (unit == "px") {
+ lengthValue = floatValue;
+ return true;
+ }
+ if (unit == "pt") {
+ lengthValue = 4 * (floatValue / 3);
+ return true;
+ }
+ if (unit == "pc") {
+ lengthValue = 16 * floatValue;
+ return true;
+ }
+ if (unit == "in") {
+ lengthValue = 96 * floatValue;
+ return true;
+ }
+ if (unit == "cm") {
+ lengthValue = 96 * (floatValue / 2.54);
+ return true;
+ }
+ if (unit == "mm") {
+ lengthValue = 96 * (floatValue / 25.4);
+ return true;
+ }
+
+ // unexpected unit
+ return false;
+}
+
+bool parseMathMLNamedSpace(const String& string, LayoutUnit& lengthValue, const RenderStyle* style, bool allowNegative)
+{
+ float length = 0;
+ // See if it is one of the namedspaces (ranging -7/18em, -6/18, ... 7/18em)
+ if (string == "veryverythinmathspace")
+ length = 1;
+ else if (string == "verythinmathspace")
+ length = 2;
+ else if (string == "thinmathspace")
+ length = 3;
+ else if (string == "mediummathspace")
+ length = 4;
+ else if (string == "thickmathspace")
+ length = 5;
+ else if (string == "verythickmathspace")
+ length = 6;
+ else if (string == "veryverythickmathspace")
+ length = 7;
+ else if (allowNegative) {
+ if (string == "negativeveryverythinmathspace")
+ length = -1;
+ else if (string == "negativeverythinmathspace")
+ length = -2;
+ else if (string == "negativethinmathspace")
+ length = -3;
+ else if (string == "negativemediummathspace")
+ length = -4;
+ else if (string == "negativethickmathspace")
+ length = -5;
+ else if (string == "negativeverythickmathspace")
+ length = -6;
+ else if (string == "negativeveryverythickmathspace")
+ length = -7;
+ }
+ if (length) {
+ lengthValue = length * style->font().size() / 18;
+ return true;
+ }
+ return false;
+}
+
int RenderMathMLTable::firstLineBoxBaseline() const
{
// In legal MathML, we'll have a MathML parent. That RenderFlexibleBox parent will use our firstLineBoxBaseline() for baseline alignment, per
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLBlock.h b/Source/WebCore/rendering/mathml/RenderMathMLBlock.h
index 51e80ec0a..4c82632d7 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLBlock.h
+++ b/Source/WebCore/rendering/mathml/RenderMathMLBlock.h
@@ -41,7 +41,8 @@ class RenderMathMLOperator;
class RenderMathMLBlock : public RenderFlexibleBox {
public:
- RenderMathMLBlock(Node* container);
+ RenderMathMLBlock(Element* container);
+
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
virtual bool isRenderMathMLBlock() const { return true; }
@@ -51,6 +52,7 @@ public:
virtual bool isRenderMathMLFenced() const { return false; }
virtual bool isRenderMathMLFraction() const { return false; }
virtual bool isRenderMathMLRoot() const { return false; }
+ virtual bool isRenderMathMLSpace() const { return false; }
virtual bool isRenderMathMLSquareRoot() const { return false; }
virtual bool isRenderMathMLSubSup() const { return false; }
virtual bool isRenderMathMLUnderOver() const { return false; }
@@ -63,15 +65,6 @@ public:
// FIXME: We don't yet handle all the cases in the MathML spec. See
// https://bugs.webkit.org/show_bug.cgi?id=78617.
virtual RenderMathMLOperator* unembellishedOperator() { return 0; }
-
- virtual LayoutUnit paddingTop() const OVERRIDE;
- virtual LayoutUnit paddingBottom() const OVERRIDE;
- virtual LayoutUnit paddingLeft() const OVERRIDE;
- virtual LayoutUnit paddingRight() const OVERRIDE;
- virtual LayoutUnit paddingBefore() const OVERRIDE;
- virtual LayoutUnit paddingAfter() const OVERRIDE;
- virtual LayoutUnit paddingStart() const OVERRIDE;
- virtual LayoutUnit paddingEnd() const OVERRIDE;
// A MathML element's preferred logical widths often depend on its children's preferred heights, not just their widths.
// This is due to operator stretching and other layout fine tuning. We define an element's preferred height to be its
@@ -106,24 +99,19 @@ protected:
// This can only be called after children have been sized by computeChildrenPreferredLogicalHeights().
static LayoutUnit preferredLogicalHeightAfterSizing(RenderObject* child);
- int m_intrinsicPaddingBefore;
- int m_intrinsicPaddingAfter;
- int m_intrinsicPaddingStart;
- int m_intrinsicPaddingEnd;
-
// m_preferredLogicalHeight is dirty if it's < 0 or preferredLogicalWidthsDirty().
LayoutUnit m_preferredLogicalHeight;
};
inline RenderMathMLBlock* toRenderMathMLBlock(RenderObject* object)
{
- ASSERT(!object || object->isRenderMathMLBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderMathMLBlock());
return static_cast<RenderMathMLBlock*>(object);
}
inline const RenderMathMLBlock* toRenderMathMLBlock(const RenderObject* object)
{
- ASSERT(!object || object->isRenderMathMLBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderMathMLBlock());
return static_cast<const RenderMathMLBlock*>(object);
}
@@ -132,7 +120,7 @@ void toRenderMathMLBlock(const RenderMathMLBlock*);
class RenderMathMLTable : public RenderTable {
public:
- explicit RenderMathMLTable(Node* node) : RenderTable(node) { }
+ explicit RenderMathMLTable(Element* element) : RenderTable(element) { }
virtual int firstLineBoxBaseline() const OVERRIDE;
@@ -140,6 +128,9 @@ private:
virtual const char* renderName() const OVERRIDE { return "RenderMathMLTable"; }
};
+// Parsing functions for MathML Length values
+bool parseMathMLLength(const String&, LayoutUnit&, const RenderStyle*, bool allowNegative = true);
+bool parseMathMLNamedSpace(const String&, LayoutUnit&, const RenderStyle*, bool allowNegative = true);
}
#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp
index 96f6cbabc..c408aad9b 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp
@@ -55,7 +55,7 @@ RenderMathMLFenced::RenderMathMLFenced(Element* element)
void RenderMathMLFenced::updateFromElement()
{
- Element* fenced = static_cast<Element*>(node());
+ Element* fenced = toElement(node());
// FIXME: Handle open/close values with more than one character (they should be treated like text).
AtomicString openValue = fenced->getAttribute(MathMLNames::openAttr);
@@ -89,7 +89,7 @@ RenderMathMLOperator* RenderMathMLFenced::createMathMLOperator(UChar uChar, Rend
newStyle->setMarginEnd(Length((operatorType == RenderMathMLOperator::Fence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed));
if (operatorType == RenderMathMLOperator::Fence)
newStyle->setMarginStart(Length(gFenceMarginEms * style()->fontSize(), Fixed));
- RenderMathMLOperator* newOperator = new (renderArena()) RenderMathMLOperator(node() /* "almost anonymous" */, uChar);
+ RenderMathMLOperator* newOperator = new (renderArena()) RenderMathMLOperator(toElement(node()), uChar);
newOperator->setOperatorType(operatorType);
newOperator->setStyle(newStyle.release());
return newOperator;
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp
index 5603eb558..e5c92a62d 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp
@@ -63,14 +63,13 @@ void RenderMathMLFraction::updateFromElement()
if (isEmpty())
return;
- Element* fraction = static_cast<Element*>(node());
+ Element* fraction = toElement(node());
RenderObject* numeratorWrapper = firstChild();
RenderObject* denominatorWrapper = numeratorWrapper->nextSibling();
if (!denominatorWrapper)
return;
- // FIXME: parse units
String thickness = fraction->getAttribute(MathMLNames::linethicknessAttr);
m_lineThickness = gLineMedium;
if (equalIgnoringCase(thickness, "thin"))
@@ -79,8 +78,12 @@ void RenderMathMLFraction::updateFromElement()
m_lineThickness = gLineMedium;
else if (equalIgnoringCase(thickness, "thick"))
m_lineThickness = gLineThick;
- else if (equalIgnoringCase(thickness, "0"))
- m_lineThickness = 0;
+ else {
+ // This function parses the thickness attribute using gLineMedium as
+ // the default value. If the parsing fails, m_lineThickness will not be
+ // modified i.e. the default value will be used.
+ parseMathMLLength(thickness, m_lineThickness, style(), false);
+ }
// Update the style for the padding of the denominator for the line thickness
lastChild()->style()->setPaddingTop(Length(static_cast<int>(m_lineThickness), Fixed));
@@ -140,7 +143,7 @@ void RenderMathMLFraction::layout()
void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
RenderMathMLBlock::paint(info, paintOffset);
- if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground)
+ if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground || style()->visibility() != VISIBLE)
return;
RenderBox* denominatorWrapper = lastChildBox();
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFraction.h b/Source/WebCore/rendering/mathml/RenderMathMLFraction.h
index 1ec4a0634..df5308163 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLFraction.h
+++ b/Source/WebCore/rendering/mathml/RenderMathMLFraction.h
@@ -42,6 +42,7 @@ public:
virtual RenderMathMLOperator* unembellishedOperator();
virtual int firstLineBoxBaseline() const OVERRIDE;
+ float lineThickness() const { return m_lineThickness; }
virtual void paint(PaintInfo&, const LayoutPoint&);
protected:
virtual void layout();
@@ -53,8 +54,20 @@ private:
virtual const char* renderName() const { return "RenderMathMLFraction"; }
- float m_lineThickness;
+ LayoutUnit m_lineThickness;
};
+
+inline RenderMathMLFraction* toRenderMathMLFraction(RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || (object->isRenderMathMLBlock() && toRenderMathMLBlock(object)->isRenderMathMLFraction()));
+ return static_cast<RenderMathMLFraction*>(object);
+}
+
+inline const RenderMathMLFraction* toRenderMathMLFraction(const RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || (object->isRenderMathMLBlock() && toRenderMathMLBlock(object)->isRenderMathMLFraction()));
+ return static_cast<const RenderMathMLFraction*>(object);
+}
}
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp b/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp
index bde8baf64..0db64555f 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp
@@ -47,8 +47,8 @@ RenderMathMLOperator::RenderMathMLOperator(Element* element)
{
}
-RenderMathMLOperator::RenderMathMLOperator(Node* node, UChar operatorChar)
- : RenderMathMLBlock(node)
+RenderMathMLOperator::RenderMathMLOperator(Element* element, UChar operatorChar)
+ : RenderMathMLBlock(element)
, m_stretchHeight(0)
, m_operator(convertHyphenMinusToMinusSign(operatorChar))
, m_operatorType(Default)
@@ -83,11 +83,16 @@ void RenderMathMLOperator::styleDidChange(StyleDifference diff, const RenderStyl
void RenderMathMLOperator::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
+
+#ifndef NDEBUG
+ // FIXME: Remove this once mathml stops modifying the render tree here.
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(this, false);
+#endif
// Check for an uninitialized operator.
if (!firstChild())
updateFromElement();
-
+
RenderMathMLBlock::computePreferredLogicalWidths();
}
@@ -146,8 +151,8 @@ void RenderMathMLOperator::updateFromElement()
bool stretchDisabled = false;
// We may need the element later if we can't stretch.
- if (node()->nodeType() == Node::ELEMENT_NODE) {
- if (Element* mo = static_cast<Element*>(node())) {
+ if (node()->isElementNode()) {
+ if (Element* mo = toElement(node())) {
AtomicString stretchyAttr = mo->getAttribute(MathMLNames::stretchyAttr);
stretchDisabled = equalIgnoringCase(stretchyAttr, "false");
@@ -202,7 +207,7 @@ void RenderMathMLOperator::updateFromElement()
// Either stretch is disabled or we don't have a stretchable character over the minimum height
if (stretchDisabled || !shouldStack) {
m_isStacked = false;
- RenderBlock* container = new (renderArena()) RenderMathMLBlock(node());
+ RenderBlock* container = new (renderArena()) RenderMathMLBlock(toElement(node()));
// This container doesn't offer any useful information to accessibility.
toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);
@@ -227,8 +232,8 @@ void RenderMathMLOperator::updateFromElement()
RenderText* text = 0;
if (m_operator)
text = new (renderArena()) RenderText(node(), StringImpl::create(&m_operator, 1));
- else if (node()->nodeType() == Node::ELEMENT_NODE)
- if (Element* mo = static_cast<Element*>(node()))
+ else if (node()->isElementNode())
+ if (Element* mo = toElement(node()))
text = new (renderArena()) RenderText(node(), mo->textContent().replace(hyphenMinus, minusSign).impl());
// If we can't figure out the text, leave it blank.
if (text) {
@@ -296,7 +301,7 @@ PassRefPtr<RenderStyle> RenderMathMLOperator::createStackableStyle(int maxHeight
RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int maxHeightForRenderer, int charRelative)
{
- RenderBlock* container = new (renderArena()) RenderMathMLBlock(node());
+ RenderBlock* container = new (renderArena()) RenderMathMLBlock(toElement(node()));
toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);
container->setStyle(createStackableStyle(maxHeightForRenderer));
addChild(container);
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h
index 75bb941de..747f070d9 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h
+++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h
@@ -36,7 +36,8 @@ namespace WebCore {
class RenderMathMLOperator : public RenderMathMLBlock {
public:
RenderMathMLOperator(Element*);
- RenderMathMLOperator(Node*, UChar operatorChar);
+ RenderMathMLOperator(Element*, UChar operatorChar);
+
virtual bool isRenderMathMLOperator() const { return true; }
virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
@@ -71,13 +72,13 @@ private:
inline RenderMathMLOperator* toRenderMathMLOperator(RenderMathMLBlock* block)
{
- ASSERT(!block || block->isRenderMathMLOperator());
+ ASSERT_WITH_SECURITY_IMPLICATION(!block || block->isRenderMathMLOperator());
return static_cast<RenderMathMLOperator*>(block);
}
inline const RenderMathMLOperator* toRenderMathMLOperator(const RenderMathMLBlock* block)
{
- ASSERT(!block || block->isRenderMathMLOperator());
+ ASSERT_WITH_SECURITY_IMPLICATION(!block || block->isRenderMathMLOperator());
return static_cast<const RenderMathMLOperator*>(block);
}
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp
index cbbf251c0..4918e8696 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp
@@ -68,9 +68,97 @@ const float gRadicalThickLineThicknessEms = 0.1f;
RenderMathMLRoot::RenderMathMLRoot(Element* element)
: RenderMathMLBlock(element)
+ , m_intrinsicPaddingBefore(0)
+ , m_intrinsicPaddingAfter(0)
+ , m_intrinsicPaddingStart(0)
+ , m_intrinsicPaddingEnd(0)
{
}
+LayoutUnit RenderMathMLRoot::paddingTop() const
+{
+ LayoutUnit result = computedCSSPaddingTop();
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return result + m_intrinsicPaddingBefore;
+ case BottomToTopWritingMode:
+ return result + m_intrinsicPaddingAfter;
+ case LeftToRightWritingMode:
+ case RightToLeftWritingMode:
+ return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd);
+ }
+ ASSERT_NOT_REACHED();
+ return result;
+}
+
+LayoutUnit RenderMathMLRoot::paddingBottom() const
+{
+ LayoutUnit result = computedCSSPaddingBottom();
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ return result + m_intrinsicPaddingAfter;
+ case BottomToTopWritingMode:
+ return result + m_intrinsicPaddingBefore;
+ case LeftToRightWritingMode:
+ case RightToLeftWritingMode:
+ return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart);
+ }
+ ASSERT_NOT_REACHED();
+ return result;
+}
+
+LayoutUnit RenderMathMLRoot::paddingLeft() const
+{
+ LayoutUnit result = computedCSSPaddingLeft();
+ switch (style()->writingMode()) {
+ case LeftToRightWritingMode:
+ return result + m_intrinsicPaddingBefore;
+ case RightToLeftWritingMode:
+ return result + m_intrinsicPaddingAfter;
+ case TopToBottomWritingMode:
+ case BottomToTopWritingMode:
+ return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd);
+ }
+ ASSERT_NOT_REACHED();
+ return result;
+}
+
+LayoutUnit RenderMathMLRoot::paddingRight() const
+{
+ LayoutUnit result = computedCSSPaddingRight();
+ switch (style()->writingMode()) {
+ case RightToLeftWritingMode:
+ return result + m_intrinsicPaddingBefore;
+ case LeftToRightWritingMode:
+ return result + m_intrinsicPaddingAfter;
+ case TopToBottomWritingMode:
+ case BottomToTopWritingMode:
+ return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart);
+ }
+ ASSERT_NOT_REACHED();
+ return result;
+}
+
+LayoutUnit RenderMathMLRoot::paddingBefore() const
+{
+ return computedCSSPaddingBefore() + m_intrinsicPaddingBefore;
+}
+
+LayoutUnit RenderMathMLRoot::paddingAfter() const
+{
+ return computedCSSPaddingAfter() + m_intrinsicPaddingAfter;
+}
+
+LayoutUnit RenderMathMLRoot::paddingStart() const
+{
+ return computedCSSPaddingStart() + m_intrinsicPaddingStart;
+}
+
+LayoutUnit RenderMathMLRoot::paddingEnd() const
+{
+ return computedCSSPaddingEnd() + m_intrinsicPaddingEnd;
+}
+
void RenderMathMLRoot::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
// Insert an implicit <mrow> for <mroot> as well as <msqrt>, to ensure firstChild() will have a box
@@ -99,6 +187,11 @@ void RenderMathMLRoot::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty() && needsLayout());
+#ifndef NDEBUG
+ // FIXME: Remove this once mathml stops modifying the render tree here.
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(this, false);
+#endif
+
computeChildrenPreferredLogicalHeights();
int baseHeight = firstChild() ? roundToInt(preferredLogicalHeightAfterSizing(firstChild())) : style()->fontSize();
@@ -131,7 +224,7 @@ void RenderMathMLRoot::computePreferredLogicalWidths()
m_indexTop = - rootExtraTop;
} else
m_intrinsicPaddingStart = frontWidth;
-
+
RenderMathMLBlock::computePreferredLogicalWidths();
// Shrink our logical width to its probable value now without triggering unnecessary relayout of our children.
@@ -158,7 +251,7 @@ void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
RenderMathMLBlock::paint(info, paintOffset);
- if (info.context->paintingDisabled())
+ if (info.context->paintingDisabled() || style()->visibility() != VISIBLE)
return;
IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + contentBoxRect().location());
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h
index 99cd36594..f8ecb9607 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h
+++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h
@@ -36,7 +36,16 @@ namespace WebCore {
class RenderMathMLRoot : public RenderMathMLBlock {
public:
RenderMathMLRoot(Element*);
-
+
+ virtual LayoutUnit paddingTop() const OVERRIDE;
+ virtual LayoutUnit paddingBottom() const OVERRIDE;
+ virtual LayoutUnit paddingLeft() const OVERRIDE;
+ virtual LayoutUnit paddingRight() const OVERRIDE;
+ virtual LayoutUnit paddingBefore() const OVERRIDE;
+ virtual LayoutUnit paddingAfter() const OVERRIDE;
+ virtual LayoutUnit paddingStart() const OVERRIDE;
+ virtual LayoutUnit paddingEnd() const OVERRIDE;
+
virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE;
protected:
@@ -52,7 +61,11 @@ private:
// This may return 0 for a non-MathML index (which won't occur in valid MathML).
RenderBoxModelObject* index() const;
-
+
+ int m_intrinsicPaddingBefore;
+ int m_intrinsicPaddingAfter;
+ int m_intrinsicPaddingStart;
+ int m_intrinsicPaddingEnd;
int m_overbarLeftPointShift;
int m_indexTop;
};
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp
index 52bb6feae..25fb75b7c 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp
@@ -36,8 +36,8 @@ namespace WebCore {
using namespace MathMLNames;
-RenderMathMLRow::RenderMathMLRow(Node* node)
- : RenderMathMLBlock(node)
+RenderMathMLRow::RenderMathMLRow(Element* element)
+ : RenderMathMLBlock(element)
{
}
@@ -45,7 +45,8 @@ RenderMathMLRow::RenderMathMLRow(Node* node)
RenderMathMLRow* RenderMathMLRow::createAnonymousWithParentRenderer(const RenderObject* parent)
{
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), FLEX);
- RenderMathMLRow* newMRow = new (parent->renderArena()) RenderMathMLRow(parent->document() /* is anonymous */);
+ RenderMathMLRow* newMRow = new (parent->renderArena()) RenderMathMLRow(0);
+ newMRow->setDocumentForAnonymous(parent->document());
newMRow->setStyle(newStyle.release());
return newMRow;
}
@@ -53,7 +54,12 @@ RenderMathMLRow* RenderMathMLRow::createAnonymousWithParentRenderer(const Render
void RenderMathMLRow::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty() && needsLayout());
-
+
+#ifndef NDEBUG
+ // FIXME: Remove this once mathml stops modifying the render tree here.
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(this, false);
+#endif
+
computeChildrenPreferredLogicalHeights();
int stretchLogicalHeight = 0;
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
@@ -76,7 +82,7 @@ void RenderMathMLRow::computePreferredLogicalWidths()
renderMo->stretchToHeight(stretchLogicalHeight);
}
}
-
+
RenderMathMLBlock::computePreferredLogicalWidths();
// Shrink our logical width to its probable value now without triggering unnecessary relayout of our children.
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRow.h b/Source/WebCore/rendering/mathml/RenderMathMLRow.h
index 37f64a1db..9c1a1dc35 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLRow.h
+++ b/Source/WebCore/rendering/mathml/RenderMathMLRow.h
@@ -34,7 +34,8 @@ namespace WebCore {
class RenderMathMLRow : public RenderMathMLBlock {
public:
- RenderMathMLRow(Node*);
+ RenderMathMLRow(Element*);
+
static RenderMathMLRow* createAnonymousWithParentRenderer(const RenderObject*);
virtual bool isRenderMathMLRow() const { return true; }
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSpace.cpp b/Source/WebCore/rendering/mathml/RenderMathMLSpace.cpp
new file mode 100644
index 000000000..3de35ffbe
--- /dev/null
+++ b/Source/WebCore/rendering/mathml/RenderMathMLSpace.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 The MathJax Consortium. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderMathMLSpace.h"
+
+#if ENABLE(MATHML)
+
+#include "GraphicsContext.h"
+#include "MathMLNames.h"
+#include "PaintInfo.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+RenderMathMLSpace::RenderMathMLSpace(Element* element)
+ : RenderMathMLBlock(element)
+ , m_width(0)
+ , m_height(0)
+ , m_depth(0)
+{
+}
+
+void RenderMathMLSpace::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ minLogicalWidth = m_width;
+ maxLogicalWidth = m_width;
+}
+
+void RenderMathMLSpace::updateFromElement()
+{
+ Element* space = toElement(node());
+
+ // This parses the mspace attributes, using 0 as the default values.
+ m_width = 0;
+ m_height = 0;
+ m_depth = 0;
+ parseMathMLLength(space->getAttribute(MathMLNames::widthAttr), m_width, style());
+ parseMathMLLength(space->getAttribute(MathMLNames::heightAttr), m_height, style());
+ parseMathMLLength(space->getAttribute(MathMLNames::depthAttr), m_depth, style());
+
+ // FIXME: Negative width values should be accepted.
+ if (m_width < 0)
+ m_width = 0;
+
+ // If the total height is negative, set vertical dimensions to 0.
+ if (m_height + m_depth < 0) {
+ m_height = 0;
+ m_depth = 0;
+ }
+
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderMathMLSpace::updateLogicalWidth()
+{
+ setLogicalWidth(m_width);
+}
+
+void RenderMathMLSpace::updateLogicalHeight()
+{
+ setLogicalHeight(m_height + m_depth);
+}
+
+void RenderMathMLSpace::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderMathMLBlock::styleDidChange(diff, oldStyle);
+ updateFromElement();
+}
+
+int RenderMathMLSpace::firstLineBoxBaseline() const
+{
+ return m_height;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSpace.h b/Source/WebCore/rendering/mathml/RenderMathMLSpace.h
new file mode 100644
index 000000000..46e6a04c2
--- /dev/null
+++ b/Source/WebCore/rendering/mathml/RenderMathMLSpace.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 The MathJax Consortium. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderMathMLSpace_h
+#define RenderMathMLSpace_h
+
+#if ENABLE(MATHML)
+
+#include "RenderMathMLBlock.h"
+
+namespace WebCore {
+
+class RenderMathMLSpace : public RenderMathMLBlock {
+public:
+ explicit RenderMathMLSpace(Element*);
+
+ virtual int firstLineBoxBaseline() const OVERRIDE;
+ virtual void updateLogicalWidth() OVERRIDE;
+ virtual void updateLogicalHeight() OVERRIDE;
+
+private:
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE;
+ virtual const char* renderName() const OVERRIDE { return isAnonymous() ? "RenderMathMLSpace (anonymous)" : "RenderMathMLSpace"; }
+
+ virtual bool isRenderMathMLSpace() const OVERRIDE { return true; }
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE { return false; }
+ virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const OVERRIDE;
+
+ virtual void updateFromElement() OVERRIDE;
+
+ LayoutUnit m_width;
+ LayoutUnit m_height;
+ LayoutUnit m_depth;
+};
+
+inline RenderMathMLSpace* toRenderMathMLSpace(RenderMathMLBlock* block)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!block || block->isRenderMathMLSpace());
+ return static_cast<RenderMathMLSpace*>(block);
+}
+
+inline const RenderMathMLSpace* toRenderMathMLSpace(const RenderMathMLBlock* block)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!block || block->isRenderMathMLSpace());
+ return static_cast<const RenderMathMLSpace*>(block);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderMathMLSpace(const RenderMathMLSpace*);
+}
+
+#endif // ENABLE(MATHML)
+#endif // RenderMathMLSpace_h
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp
index aee1c3934..d07fc8b8d 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp
@@ -113,37 +113,45 @@ RenderMathMLOperator* RenderMathMLSubSup::unembellishedOperator()
void RenderMathMLSubSup::layout()
{
RenderMathMLBlock::layout();
-
+
RenderMathMLBlock* baseWrapper = toRenderMathMLBlock(firstChild());
if (!baseWrapper || !m_scripts)
return;
RenderBox* base = baseWrapper->firstChildBox();
if (!base)
return;
-
+
// Our layout rules include: Don't let the superscript go below the "axis" (half x-height above the
// baseline), or the subscript above the axis. Also, don't let the superscript's top edge be
// below the base's top edge, or the subscript's bottom edge above the base's bottom edge.
//
// FIXME: Check any subscriptshift or superscriptshift attributes, and maybe use more sophisticated
// heuristics from TeX or elsewhere. See https://bugs.webkit.org/show_bug.cgi?id=79274#c5.
-
+
LayoutUnit baseHeight = base->logicalHeight();
LayoutUnit baseBaseline = base->firstLineBoxBaseline();
if (baseBaseline == -1)
baseBaseline = baseHeight;
LayoutUnit axis = style()->fontMetrics().xHeight() / 2;
int fontSize = style()->fontSize();
-
+
+ ASSERT(baseWrapper->style()->hasOneRef());
+ bool needsSecondLayout = false;
+
if (RenderBox* superscript = m_kind == Sub ? 0 : m_scripts->lastChildBox()) {
LayoutUnit superscriptHeight = superscript->logicalHeight();
LayoutUnit superscriptBaseline = superscript->firstLineBoxBaseline();
if (superscriptBaseline == -1)
superscriptBaseline = superscriptHeight;
LayoutUnit minBaseline = max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis);
- baseWrapper->style()->setPaddingTop(Length(max<LayoutUnit>(minBaseline - baseBaseline, 0), Fixed));
+
+ Length newPadding = Length(max<LayoutUnit>(minBaseline - baseBaseline, 0), Fixed);
+ if (newPadding != baseWrapper->style()->paddingTop()) {
+ baseWrapper->style()->setPaddingTop(newPadding);
+ needsSecondLayout = true;
+ }
}
-
+
if (RenderBox* subscript = m_kind == Super ? 0 : m_scripts->firstChildBox()) {
LayoutUnit subscriptHeight = subscript->logicalHeight();
LayoutUnit subscriptBaseline = subscript->firstLineBoxBaseline();
@@ -152,12 +160,20 @@ void RenderMathMLSubSup::layout()
LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline;
LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline;
LayoutUnit minExtendUnderBaseline = max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight - axis);
- baseWrapper->style()->setPaddingBottom(Length(max<LayoutUnit>(minExtendUnderBaseline - baseExtendUnderBaseline, 0), Fixed));
+
+ Length newPadding = Length(max<LayoutUnit>(minExtendUnderBaseline - baseExtendUnderBaseline, 0), Fixed);
+ if (newPadding != baseWrapper->style()->paddingBottom()) {
+ baseWrapper->style()->setPaddingBottom(newPadding);
+ needsSecondLayout = true;
+ }
}
-
- setChildNeedsLayout(true, MarkOnlyThis);
- baseWrapper->setNeedsLayout(true, MarkOnlyThis);
-
+
+ if (!needsSecondLayout)
+ return;
+
+ setNeedsLayout(true, MarkOnlyThis);
+ baseWrapper->setChildNeedsLayout(true, MarkOnlyThis);
+
RenderMathMLBlock::layout();
}
diff --git a/Source/WebCore/rendering/shapes/PolygonShape.cpp b/Source/WebCore/rendering/shapes/PolygonShape.cpp
new file mode 100644
index 000000000..e2124fd56
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/PolygonShape.cpp
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PolygonShape.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+enum EdgeIntersectionType {
+ Normal,
+ VertexMinY,
+ VertexMaxY,
+ VertexYBoth
+};
+
+struct EdgeIntersection {
+ const FloatPolygonEdge* edge;
+ FloatPoint point;
+ EdgeIntersectionType type;
+};
+
+static inline float leftSide(const FloatPoint& vertex1, const FloatPoint& vertex2, const FloatPoint& point)
+{
+ return ((point.x() - vertex1.x()) * (vertex2.y() - vertex1.y())) - ((vertex2.x() - vertex1.x()) * (point.y() - vertex1.y()));
+}
+
+static inline bool isReflexVertex(const FloatPoint& prevVertex, const FloatPoint& vertex, const FloatPoint& nextVertex)
+{
+ return leftSide(prevVertex, nextVertex, vertex) < 0;
+}
+
+static bool computeXIntersection(const FloatPolygonEdge* edgePointer, float y, EdgeIntersection& result)
+{
+ const FloatPolygonEdge& edge = *edgePointer;
+
+ if (edge.minY() > y || edge.maxY() < y)
+ return false;
+
+ const FloatPoint& vertex1 = edge.vertex1();
+ const FloatPoint& vertex2 = edge.vertex2();
+ float dy = vertex2.y() - vertex1.y();
+
+ float intersectionX;
+ EdgeIntersectionType intersectionType;
+
+ if (!dy) {
+ intersectionType = VertexYBoth;
+ intersectionX = edge.minX();
+ } else if (y == edge.minY()) {
+ intersectionType = VertexMinY;
+ intersectionX = (vertex1.y() < vertex2.y()) ? vertex1.x() : vertex2.x();
+ } else if (y == edge.maxY()) {
+ intersectionType = VertexMaxY;
+ intersectionX = (vertex1.y() > vertex2.y()) ? vertex1.x() : vertex2.x();
+ } else {
+ intersectionType = Normal;
+ intersectionX = ((y - vertex1.y()) * (vertex2.x() - vertex1.x()) / dy) + vertex1.x();
+ }
+
+ result.edge = edgePointer;
+ result.type = intersectionType;
+ result.point.set(intersectionX, y);
+
+ return true;
+}
+
+static inline FloatSize inwardEdgeNormal(const FloatPolygonEdge& edge)
+{
+ FloatSize edgeDelta = edge.vertex2() - edge.vertex1();
+ if (!edgeDelta.width())
+ return FloatSize((edgeDelta.height() > 0 ? -1 : 1), 0);
+ if (!edgeDelta.height())
+ return FloatSize(0, (edgeDelta.width() > 0 ? 1 : -1));
+ float edgeLength = edgeDelta.diagonalLength();
+ return FloatSize(-edgeDelta.height() / edgeLength, edgeDelta.width() / edgeLength);
+}
+
+static inline FloatSize outwardEdgeNormal(const FloatPolygonEdge& edge)
+{
+ return -inwardEdgeNormal(edge);
+}
+
+static inline void appendArc(Vector<FloatPoint>& vertices, const FloatPoint& arcCenter, float arcRadius, const FloatPoint& startArcVertex, const FloatPoint& endArcVertex, bool padding)
+{
+ float startAngle = atan2(startArcVertex.y() - arcCenter.y(), startArcVertex.x() - arcCenter.x());
+ float endAngle = atan2(endArcVertex.y() - arcCenter.y(), endArcVertex.x() - arcCenter.x());
+ const float twoPI = piFloat * 2;
+ if (startAngle < 0)
+ startAngle += twoPI;
+ if (endAngle < 0)
+ endAngle += twoPI;
+ float angle = (startAngle > endAngle) ? (startAngle - endAngle) : (startAngle + twoPI - endAngle);
+ const float arcSegmentCount = 6; // An even number so that one arc vertex will be eactly arcRadius from arcCenter.
+ float arcSegmentAngle = ((padding) ? -angle : twoPI - angle) / arcSegmentCount;
+
+ vertices.append(startArcVertex);
+ for (unsigned i = 1; i < arcSegmentCount; ++i) {
+ float angle = startAngle + arcSegmentAngle * i;
+ vertices.append(arcCenter + FloatPoint(cos(angle) * arcRadius, sin(angle) * arcRadius));
+ }
+ vertices.append(endArcVertex);
+}
+
+static inline void snapVerticesToLayoutUnitGrid(Vector<FloatPoint>& vertices)
+{
+ for (unsigned i = 0; i < vertices.size(); ++i)
+ vertices[i].set(LayoutUnit(vertices[i].x()).toFloat(), LayoutUnit(vertices[i].y()).toFloat());
+}
+
+static inline PassOwnPtr<FloatPolygon> computeShapePaddingBounds(const FloatPolygon& polygon, float padding, WindRule fillRule)
+{
+ OwnPtr<Vector<FloatPoint> > paddedVertices = adoptPtr(new Vector<FloatPoint>());
+ FloatPoint intersection;
+
+ for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) {
+ const FloatPolygonEdge& thisEdge = polygon.edgeAt(i);
+ const FloatPolygonEdge& prevEdge = thisEdge.previousEdge();
+ OffsetPolygonEdge thisOffsetEdge(thisEdge, inwardEdgeNormal(thisEdge) * padding);
+ OffsetPolygonEdge prevOffsetEdge(prevEdge, inwardEdgeNormal(prevEdge) * padding);
+
+ if (prevOffsetEdge.intersection(thisOffsetEdge, intersection))
+ paddedVertices->append(intersection);
+ else if (isReflexVertex(prevEdge.vertex1(), thisEdge.vertex1(), thisEdge.vertex2()))
+ appendArc(*paddedVertices, thisEdge.vertex1(), padding, prevOffsetEdge.vertex2(), thisOffsetEdge.vertex1(), true);
+ }
+
+ snapVerticesToLayoutUnitGrid(*paddedVertices);
+ return adoptPtr(new FloatPolygon(paddedVertices.release(), fillRule));
+}
+
+static inline PassOwnPtr<FloatPolygon> computeShapeMarginBounds(const FloatPolygon& polygon, float margin, WindRule fillRule)
+{
+ OwnPtr<Vector<FloatPoint> > marginVertices = adoptPtr(new Vector<FloatPoint>());
+ FloatPoint intersection;
+
+ for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) {
+ const FloatPolygonEdge& thisEdge = polygon.edgeAt(i);
+ const FloatPolygonEdge& prevEdge = thisEdge.previousEdge();
+ OffsetPolygonEdge thisOffsetEdge(thisEdge, outwardEdgeNormal(thisEdge) * margin);
+ OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) * margin);
+
+ if (prevOffsetEdge.intersection(thisOffsetEdge, intersection))
+ marginVertices->append(intersection);
+ else
+ appendArc(*marginVertices, thisEdge.vertex1(), margin, prevOffsetEdge.vertex2(), thisOffsetEdge.vertex1(), false);
+ }
+
+ snapVerticesToLayoutUnitGrid(*marginVertices);
+ return adoptPtr(new FloatPolygon(marginVertices.release(), fillRule));
+}
+
+const FloatPolygon& PolygonShape::shapePaddingBounds() const
+{
+ ASSERT(shapePadding() >= 0);
+ if (!shapePadding())
+ return m_polygon;
+
+ if (!m_paddingBounds)
+ m_paddingBounds = computeShapePaddingBounds(m_polygon, shapePadding(), m_polygon.fillRule());
+
+ return *m_paddingBounds;
+}
+
+const FloatPolygon& PolygonShape::shapeMarginBounds() const
+{
+ ASSERT(shapeMargin() >= 0);
+ if (!shapeMargin())
+ return m_polygon;
+
+ if (!m_marginBounds)
+ m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_polygon.fillRule());
+
+ return *m_marginBounds;
+}
+
+static inline bool getVertexIntersectionVertices(const EdgeIntersection& intersection, FloatPoint& prevVertex, FloatPoint& thisVertex, FloatPoint& nextVertex)
+{
+ if (intersection.type != VertexMinY && intersection.type != VertexMaxY)
+ return false;
+
+ ASSERT(intersection.edge && intersection.edge->polygon());
+ const FloatPolygon& polygon = *(intersection.edge->polygon());
+ const FloatPolygonEdge& thisEdge = *(intersection.edge);
+
+ if ((intersection.type == VertexMinY && (thisEdge.vertex1().y() < thisEdge.vertex2().y()))
+ || (intersection.type == VertexMaxY && (thisEdge.vertex1().y() > thisEdge.vertex2().y()))) {
+ prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex1());
+ thisVertex = polygon.vertexAt(thisEdge.vertexIndex1());
+ nextVertex = polygon.vertexAt(thisEdge.vertexIndex2());
+ } else {
+ prevVertex = polygon.vertexAt(thisEdge.vertexIndex1());
+ thisVertex = polygon.vertexAt(thisEdge.vertexIndex2());
+ nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex2());
+ }
+
+ return true;
+}
+
+static inline bool appendIntervalX(float x, bool inside, Vector<ShapeInterval>& result)
+{
+ if (!inside)
+ result.append(ShapeInterval(x));
+ else
+ result[result.size() - 1].x2 = x;
+
+ return !inside;
+}
+
+static bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, const EdgeIntersection& intersection2)
+{
+ float x1 = intersection1.point.x();
+ float x2 = intersection2.point.x();
+ return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2;
+}
+
+static void computeXIntersections(const FloatPolygon& polygon, float y, bool isMinY, Vector<ShapeInterval>& result)
+{
+ Vector<const FloatPolygonEdge*> edges;
+ if (!polygon.overlappingEdges(y, y, edges))
+ return;
+
+ Vector<EdgeIntersection> intersections;
+ EdgeIntersection intersection;
+ for (unsigned i = 0; i < edges.size(); ++i) {
+ if (computeXIntersection(edges[i], y, intersection) && intersection.type != VertexYBoth)
+ intersections.append(intersection);
+ }
+
+ if (intersections.size() < 2)
+ return;
+
+ std::sort(intersections.begin(), intersections.end(), WebCore::compareEdgeIntersectionX);
+
+ unsigned index = 0;
+ int windCount = 0;
+ bool inside = false;
+
+ while (index < intersections.size()) {
+ const EdgeIntersection& thisIntersection = intersections[index];
+ if (index + 1 < intersections.size()) {
+ const EdgeIntersection& nextIntersection = intersections[index + 1];
+ if ((thisIntersection.point.x() == nextIntersection.point.x()) && (thisIntersection.type == VertexMinY || thisIntersection.type == VertexMaxY)) {
+ if (thisIntersection.type == nextIntersection.type) {
+ // Skip pairs of intersections whose types are VertexMaxY,VertexMaxY and VertexMinY,VertexMinY.
+ index += 2;
+ } else {
+ // Replace pairs of intersections whose types are VertexMinY,VertexMaxY or VertexMaxY,VertexMinY with one intersection.
+ ++index;
+ }
+ continue;
+ }
+ }
+
+ const FloatPolygonEdge& thisEdge = *thisIntersection.edge;
+ bool evenOddCrossing = !windCount;
+
+ if (polygon.fillRule() == RULE_EVENODD) {
+ windCount += (thisEdge.vertex2().y() > thisEdge.vertex1().y()) ? 1 : -1;
+ evenOddCrossing = evenOddCrossing || !windCount;
+ }
+
+ if (evenOddCrossing) {
+ bool edgeCrossing = thisIntersection.type == Normal;
+ if (!edgeCrossing) {
+ FloatPoint prevVertex;
+ FloatPoint thisVertex;
+ FloatPoint nextVertex;
+
+ if (getVertexIntersectionVertices(thisIntersection, prevVertex, thisVertex, nextVertex)) {
+ if (nextVertex.y() == y)
+ edgeCrossing = (isMinY) ? prevVertex.y() > y : prevVertex.y() < y;
+ else if (prevVertex.y() == y)
+ edgeCrossing = (isMinY) ? nextVertex.y() > y : nextVertex.y() < y;
+ else
+ edgeCrossing = true;
+ }
+ }
+ if (edgeCrossing)
+ inside = appendIntervalX(thisIntersection.point.x(), inside, result);
+ }
+
+ ++index;
+ }
+}
+
+static void computeOverlappingEdgeXProjections(const FloatPolygon& polygon, float y1, float y2, Vector<ShapeInterval>& result)
+{
+ Vector<const FloatPolygonEdge*> edges;
+ if (!polygon.overlappingEdges(y1, y2, edges))
+ return;
+
+ EdgeIntersection intersection;
+ for (unsigned i = 0; i < edges.size(); ++i) {
+ const FloatPolygonEdge *edge = edges[i];
+ float x1;
+ float x2;
+
+ if (edge->minY() < y1) {
+ computeXIntersection(edge, y1, intersection);
+ x1 = intersection.point.x();
+ } else
+ x1 = (edge->vertex1().y() < edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x();
+
+ if (edge->maxY() > y2) {
+ computeXIntersection(edge, y2, intersection);
+ x2 = intersection.point.x();
+ } else
+ x2 = (edge->vertex1().y() > edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x();
+
+ if (x1 > x2)
+ std::swap(x1, x2);
+
+ if (x2 > x1)
+ result.append(ShapeInterval(x1, x2));
+ }
+
+ sortShapeIntervals(result);
+}
+
+void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+{
+ const FloatPolygon& polygon = shapeMarginBounds();
+ if (polygon.isEmpty())
+ return;
+
+ float y1 = logicalTop;
+ float y2 = logicalTop + logicalHeight;
+
+ Vector<ShapeInterval> y1XIntervals, y2XIntervals;
+ computeXIntersections(polygon, y1, true, y1XIntervals);
+ computeXIntersections(polygon, y2, false, y2XIntervals);
+
+ Vector<ShapeInterval> mergedIntervals;
+ mergeShapeIntervals(y1XIntervals, y2XIntervals, mergedIntervals);
+
+ Vector<ShapeInterval> edgeIntervals;
+ computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals);
+
+ Vector<ShapeInterval> excludedIntervals;
+ mergeShapeIntervals(mergedIntervals, edgeIntervals, excludedIntervals);
+
+ for (unsigned i = 0; i < excludedIntervals.size(); ++i) {
+ ShapeInterval interval = excludedIntervals[i];
+ result.append(LineSegment(interval.x1, interval.x2));
+ }
+}
+
+void PolygonShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+{
+ const FloatPolygon& polygon = shapePaddingBounds();
+ if (polygon.isEmpty())
+ return;
+
+ float y1 = logicalTop;
+ float y2 = logicalTop + logicalHeight;
+
+ Vector<ShapeInterval> y1XIntervals, y2XIntervals;
+ computeXIntersections(polygon, y1, true, y1XIntervals);
+ computeXIntersections(polygon, y2, false, y2XIntervals);
+
+ Vector<ShapeInterval> commonIntervals;
+ intersectShapeIntervals(y1XIntervals, y2XIntervals, commonIntervals);
+
+ Vector<ShapeInterval> edgeIntervals;
+ computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals);
+
+ Vector<ShapeInterval> includedIntervals;
+ subtractShapeIntervals(commonIntervals, edgeIntervals, includedIntervals);
+
+ for (unsigned i = 0; i < includedIntervals.size(); ++i) {
+ ShapeInterval interval = includedIntervals[i];
+ result.append(LineSegment(interval.x1, interval.x2));
+ }
+}
+
+static inline bool firstFitRectInPolygon(const FloatPolygon& polygon, const FloatRect& rect, unsigned offsetEdgeIndex1, unsigned offsetEdgeIndex2)
+{
+ Vector<const FloatPolygonEdge*> edges;
+ if (!polygon.overlappingEdges(rect.y(), rect.maxY(), edges))
+ return true;
+
+ for (unsigned i = 0; i < edges.size(); ++i) {
+ const FloatPolygonEdge* edge = edges[i];
+ if (edge->edgeIndex() != offsetEdgeIndex1 && edge->edgeIndex() != offsetEdgeIndex2 && edge->overlapsRect(rect))
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool aboveOrToTheLeft(const FloatRect& r1, const FloatRect& r2)
+{
+ if (r1.y() < r2.y())
+ return true;
+ if (r1.y() == r2.y())
+ return r1.x() < r2.x();
+ return false;
+}
+
+bool PolygonShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const
+{
+ float minIntervalTop = minLogicalIntervalTop;
+ float minIntervalHeight = minLogicalIntervalSize.height();
+ float minIntervalWidth = minLogicalIntervalSize.width();
+
+ const FloatPolygon& polygon = shapePaddingBounds();
+ const FloatRect boundingBox = polygon.boundingBox();
+ if (minIntervalWidth > boundingBox.width())
+ return false;
+
+ float minY = std::max(boundingBox.y(), minIntervalTop);
+ float maxY = minY + minIntervalHeight;
+
+ if (maxY > boundingBox.maxY())
+ return false;
+
+ Vector<const FloatPolygonEdge*> edges;
+ polygon.overlappingEdges(minIntervalTop, boundingBox.maxY(), edges);
+
+ float dx = minIntervalWidth / 2;
+ float dy = minIntervalHeight / 2;
+ Vector<OffsetPolygonEdge> offsetEdges;
+
+ for (unsigned i = 0; i < edges.size(); ++i) {
+ const FloatPolygonEdge& edge = *(edges[i]);
+ const FloatPoint& vertex0 = edge.previousEdge().vertex1();
+ const FloatPoint& vertex1 = edge.vertex1();
+ const FloatPoint& vertex2 = edge.vertex2();
+ Vector<OffsetPolygonEdge> offsetEdgeBuffer;
+
+ if (vertex2.y() > vertex1.y() ? vertex2.x() >= vertex1.x() : vertex1.x() >= vertex2.x()) {
+ offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, -dy)));
+ offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, dy)));
+ } else {
+ offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, dy)));
+ offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, -dy)));
+ }
+
+ if (isReflexVertex(vertex0, vertex1, vertex2)) {
+ if (vertex2.x() <= vertex1.x() && vertex0.x() <= vertex1.x())
+ offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(dx, -dy), FloatSize(dx, dy)));
+ else if (vertex2.x() >= vertex1.x() && vertex0.x() >= vertex1.x())
+ offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(-dx, dy)));
+ if (vertex2.y() <= vertex1.y() && vertex0.y() <= vertex1.y())
+ offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, dy), FloatSize(dx, dy)));
+ else if (vertex2.y() >= vertex1.y() && vertex0.y() >= vertex1.y())
+ offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(dx, -dy)));
+ }
+
+ for (unsigned j = 0; j < offsetEdgeBuffer.size(); ++j)
+ if (offsetEdgeBuffer[j].maxY() >= minY)
+ offsetEdges.append(offsetEdgeBuffer[j]);
+ }
+
+ offsetEdges.append(OffsetPolygonEdge(polygon, minIntervalTop, FloatSize(0, dy)));
+
+ FloatPoint offsetEdgesIntersection;
+ FloatRect firstFitRect;
+ bool firstFitFound = false;
+
+ for (unsigned i = 0; i < offsetEdges.size() - 1; ++i) {
+ for (unsigned j = i + 1; j < offsetEdges.size(); ++j) {
+ if (offsetEdges[i].intersection(offsetEdges[j], offsetEdgesIntersection)) {
+ FloatPoint potentialFirstFitLocation(offsetEdgesIntersection.x() - dx, offsetEdgesIntersection.y() - dy);
+ FloatRect potentialFirstFitRect(potentialFirstFitLocation, minLogicalIntervalSize);
+ if ((offsetEdges[i].basis() == OffsetPolygonEdge::LineTop
+ || offsetEdges[j].basis() == OffsetPolygonEdge::LineTop
+ || potentialFirstFitLocation.y() >= minIntervalTop)
+ && (!firstFitFound || aboveOrToTheLeft(potentialFirstFitRect, firstFitRect))
+ && polygon.contains(offsetEdgesIntersection)
+ && firstFitRectInPolygon(polygon, potentialFirstFitRect, offsetEdges[i].edgeIndex(), offsetEdges[j].edgeIndex())) {
+ firstFitFound = true;
+ firstFitRect = potentialFirstFitRect;
+ }
+ }
+ }
+ }
+
+ if (firstFitFound)
+ result = ceiledLayoutUnit(firstFitRect.y());
+ return firstFitFound;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/shapes/PolygonShape.h b/Source/WebCore/rendering/shapes/PolygonShape.h
new file mode 100644
index 000000000..628ac3add
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/PolygonShape.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PolygonShape_h
+#define PolygonShape_h
+
+#include "FloatPolygon.h"
+#include "Shape.h"
+#include "ShapeInterval.h"
+
+namespace WebCore {
+
+class OffsetPolygonEdge : public VertexPair {
+public:
+ enum Basis {
+ Edge,
+ Vertex,
+ LineTop
+ };
+
+ OffsetPolygonEdge(const FloatPolygonEdge& edge, const FloatSize& offset)
+ : m_vertex1(edge.vertex1() + offset)
+ , m_vertex2(edge.vertex2() + offset)
+ , m_edgeIndex(edge.edgeIndex())
+ , m_basis(Edge)
+ {
+ }
+
+ OffsetPolygonEdge(const FloatPoint& reflexVertex, const FloatSize& offset1, const FloatSize& offset2)
+ : m_vertex1(reflexVertex + offset1)
+ , m_vertex2(reflexVertex + offset2)
+ , m_edgeIndex(-1)
+ , m_basis(Vertex)
+ {
+ }
+
+ OffsetPolygonEdge(const FloatPolygon& polygon, float minLogicalIntervalTop, const FloatSize& offset)
+ : m_vertex1(FloatPoint(polygon.boundingBox().x(), minLogicalIntervalTop) + offset)
+ , m_vertex2(FloatPoint(polygon.boundingBox().maxX(), minLogicalIntervalTop) + offset)
+ , m_edgeIndex(-1)
+ , m_basis(LineTop)
+ {
+ }
+
+ virtual const FloatPoint& vertex1() const OVERRIDE { return m_vertex1; }
+ virtual const FloatPoint& vertex2() const OVERRIDE { return m_vertex2; }
+ int edgeIndex() const { return m_edgeIndex; }
+ Basis basis() const { return m_basis; }
+
+private:
+ FloatPoint m_vertex1;
+ FloatPoint m_vertex2;
+ int m_edgeIndex;
+ Basis m_basis;
+};
+
+class PolygonShape : public Shape {
+ WTF_MAKE_NONCOPYABLE(PolygonShape);
+public:
+ PolygonShape(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule)
+ : Shape()
+ , m_polygon(vertices, fillRule)
+ , m_marginBounds(nullptr)
+ , m_paddingBounds(nullptr)
+ {
+ }
+
+ virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapeMarginBounds().boundingBox()); }
+ virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapePaddingBounds().boundingBox()); }
+ virtual bool isEmpty() const OVERRIDE { return m_polygon.isEmpty(); }
+ virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE;
+ virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE;
+ virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE;
+
+private:
+ const FloatPolygon& shapeMarginBounds() const;
+ const FloatPolygon& shapePaddingBounds() const;
+
+ FloatPolygon m_polygon;
+ mutable OwnPtr<FloatPolygon> m_marginBounds;
+ mutable OwnPtr<FloatPolygon> m_paddingBounds;
+};
+
+} // namespace WebCore
+
+#endif // PolygonShape_h
diff --git a/Source/WebCore/rendering/shapes/RectangleShape.cpp b/Source/WebCore/rendering/shapes/RectangleShape.cpp
new file mode 100644
index 000000000..7527fcfa7
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/RectangleShape.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RectangleShape.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+static inline float ellipseXIntercept(float y, float rx, float ry)
+{
+ ASSERT(ry > 0);
+ return rx * sqrt(1 - (y * y) / (ry * ry));
+}
+
+static inline float ellipseYIntercept(float x, float rx, float ry)
+{
+ ASSERT(rx > 0);
+ return ry * sqrt(1 - (x * x) / (rx * rx));
+}
+
+FloatRoundedRect FloatRoundedRect::paddingBounds(float padding) const
+{
+ ASSERT(padding >= 0);
+ if (!padding || isEmpty())
+ return *this;
+
+ float boundsX = x() + std::min(width() / 2, padding);
+ float boundsY = y() + std::min(height() / 2, padding);
+ float boundsWidth = std::max(0.0f, width() - padding * 2);
+ float boundsHeight = std::max(0.0f, height() - padding * 2);
+ float boundsRadiusX = std::max(0.0f, rx() - padding);
+ float boundsRadiusY = std::max(0.0f, ry() - padding);
+ return FloatRoundedRect(FloatRect(boundsX, boundsY, boundsWidth, boundsHeight), FloatSize(boundsRadiusX, boundsRadiusY));
+}
+
+FloatRoundedRect FloatRoundedRect::marginBounds(float margin) const
+{
+ ASSERT(margin >= 0);
+ if (!margin)
+ return *this;
+
+ float boundsX = x() - margin;
+ float boundsY = y() - margin;
+ float boundsWidth = width() + margin * 2;
+ float boundsHeight = height() + margin * 2;
+ float boundsRadiusX = rx() + margin;
+ float boundsRadiusY = ry() + margin;
+ return FloatRoundedRect(FloatRect(boundsX, boundsY, boundsWidth, boundsHeight), FloatSize(boundsRadiusX, boundsRadiusY));
+}
+
+FloatPoint FloatRoundedRect::cornerInterceptForWidth(float widthAtIntercept) const
+{
+ float xi = (width() - widthAtIntercept) / 2;
+ float yi = ry() - ellipseYIntercept(rx() - xi, rx(), ry());
+ return FloatPoint(xi, yi);
+}
+
+FloatRoundedRect RectangleShape::shapePaddingBounds() const
+{
+ if (!m_haveInitializedPaddingBounds) {
+ m_haveInitializedPaddingBounds = true;
+ m_paddingBounds = m_bounds.paddingBounds(shapePadding());
+ }
+ return m_paddingBounds;
+}
+
+FloatRoundedRect RectangleShape::shapeMarginBounds() const
+{
+ if (!m_haveInitializedMarginBounds) {
+ m_haveInitializedMarginBounds = true;
+ m_marginBounds = m_bounds.marginBounds(shapeMargin());
+ }
+ return m_marginBounds;
+}
+
+void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+{
+ const FloatRoundedRect& bounds = shapeMarginBounds();
+ if (bounds.isEmpty())
+ return;
+
+ float y1 = logicalTop;
+ float y2 = logicalTop + logicalHeight;
+
+ if (y2 < bounds.y() || y1 >= bounds.maxY())
+ return;
+
+ float x1 = bounds.x();
+ float x2 = bounds.maxX();
+
+ if (bounds.ry() > 0) {
+ if (y2 < bounds.y() + bounds.ry()) {
+ float yi = y2 - bounds.y() - bounds.ry();
+ float xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
+ x1 = bounds.x() + bounds.rx() - xi;
+ x2 = bounds.maxX() - bounds.rx() + xi;
+ } else if (y1 > bounds.maxY() - bounds.ry()) {
+ float yi = y1 - (bounds.maxY() - bounds.ry());
+ float xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
+ x1 = bounds.x() + bounds.rx() - xi;
+ x2 = bounds.maxX() - bounds.rx() + xi;
+ }
+ }
+
+ result.append(LineSegment(x1, x2));
+}
+
+void RectangleShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+{
+ const FloatRoundedRect& bounds = shapePaddingBounds();
+ if (bounds.isEmpty())
+ return;
+
+ float y1 = logicalTop;
+ float y2 = logicalTop + logicalHeight;
+
+ if (y1 < bounds.y() || y2 > bounds.maxY())
+ return;
+
+ float x1 = bounds.x();
+ float x2 = bounds.maxX();
+
+ if (bounds.ry() > 0) {
+ bool y1InterceptsCorner = y1 < bounds.y() + bounds.ry();
+ bool y2InterceptsCorner = y2 > bounds.maxY() - bounds.ry();
+ float xi = 0;
+
+ if (y1InterceptsCorner && y2InterceptsCorner) {
+ if (y1 < bounds.height() + 2 * bounds.y() - y2) {
+ float yi = y1 - bounds.y() - bounds.ry();
+ xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
+ } else {
+ float yi = y2 - (bounds.maxY() - bounds.ry());
+ xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
+ }
+ } else if (y1InterceptsCorner) {
+ float yi = y1 - bounds.y() - bounds.ry();
+ xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
+ } else if (y2InterceptsCorner) {
+ float yi = y2 - (bounds.maxY() - bounds.ry());
+ xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
+ }
+
+ if (y1InterceptsCorner || y2InterceptsCorner) {
+ x1 = bounds.x() + bounds.rx() - xi;
+ x2 = bounds.maxX() - bounds.rx() + xi;
+ }
+ }
+
+ result.append(LineSegment(x1, x2));
+}
+
+bool RectangleShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const
+{
+ float minIntervalTop = minLogicalIntervalTop;
+ float minIntervalHeight = minLogicalIntervalSize.height();
+ float minIntervalWidth = minLogicalIntervalSize.width();
+
+ const FloatRoundedRect& bounds = shapePaddingBounds();
+ if (bounds.isEmpty() || minIntervalWidth > bounds.width())
+ return false;
+
+ float minY = std::max(bounds.y(), minIntervalTop);
+ float maxY = minY + minIntervalHeight;
+
+ if (maxY > bounds.maxY())
+ return false;
+
+ bool intervalOverlapsMinCorner = minY < bounds.y() + bounds.ry();
+ bool intervalOverlapsMaxCorner = maxY > bounds.maxY() - bounds.ry();
+
+ if (!intervalOverlapsMinCorner && !intervalOverlapsMaxCorner) {
+ result = minY;
+ return true;
+ }
+
+ float centerY = bounds.y() + bounds.height() / 2;
+ bool minCornerDefinesX = fabs(centerY - minY) > fabs(centerY - maxY);
+ bool intervalFitsWithinCorners = minIntervalWidth + 2 * bounds.rx() <= bounds.width();
+ FloatPoint cornerIntercept = bounds.cornerInterceptForWidth(minIntervalWidth);
+
+ if (intervalOverlapsMinCorner && (!intervalOverlapsMaxCorner || minCornerDefinesX)) {
+ if (intervalFitsWithinCorners || bounds.y() + cornerIntercept.y() < minY) {
+ result = minY;
+ return true;
+ }
+ if (minIntervalHeight < bounds.height() - (2 * cornerIntercept.y())) {
+ result = ceiledLayoutUnit(bounds.y() + cornerIntercept.y());
+ return true;
+ }
+ }
+
+ if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) {
+ if (intervalFitsWithinCorners || minY <= bounds.maxY() - cornerIntercept.y() - minIntervalHeight) {
+ result = minY;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/shapes/RectangleShape.h b/Source/WebCore/rendering/shapes/RectangleShape.h
new file mode 100644
index 000000000..e9ecf0504
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/RectangleShape.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RectangleShape_h
+#define RectangleShape_h
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "FloatSize.h"
+#include "Shape.h"
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FloatRoundedRect : public FloatRect {
+public:
+ FloatRoundedRect() { }
+ FloatRoundedRect(const FloatRect& bounds, const FloatSize& radii)
+ : FloatRect(bounds)
+ , m_radii(radii)
+ {
+ }
+
+ float rx() const { return m_radii.width(); }
+ float ry() const { return m_radii.height(); }
+ FloatRoundedRect marginBounds(float margin) const;
+ FloatRoundedRect paddingBounds(float padding) const;
+ FloatPoint cornerInterceptForWidth(float width) const;
+
+private:
+ FloatSize m_radii;
+};
+
+class RectangleShape : public Shape {
+public:
+ RectangleShape(const FloatRect& bounds, const FloatSize& radii)
+ : Shape()
+ , m_bounds(bounds, radii)
+ , m_haveInitializedMarginBounds(false)
+ , m_haveInitializedPaddingBounds(false)
+ {
+ }
+
+ virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapeMarginBounds()); }
+ virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapePaddingBounds()); }
+ virtual bool isEmpty() const OVERRIDE { return m_bounds.isEmpty(); }
+ virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE;
+ virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE;
+ virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE;
+
+private:
+ FloatRoundedRect shapeMarginBounds() const;
+ FloatRoundedRect shapePaddingBounds() const;
+
+ FloatRoundedRect m_bounds;
+ mutable FloatRoundedRect m_marginBounds;
+ mutable FloatRoundedRect m_paddingBounds;
+ mutable bool m_haveInitializedMarginBounds : 1;
+ mutable bool m_haveInitializedPaddingBounds : 1;
+};
+
+} // namespace WebCore
+
+#endif // RectangleShape_h
diff --git a/Source/WebCore/rendering/shapes/Shape.cpp b/Source/WebCore/rendering/shapes/Shape.cpp
new file mode 100644
index 000000000..810ac5544
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/Shape.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Shape.h"
+
+#include "BasicShapeFunctions.h"
+#include "FloatSize.h"
+#include "LengthFunctions.h"
+#include "PolygonShape.h"
+#include "RectangleShape.h"
+#include "WindRule.h"
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+static PassOwnPtr<Shape> createRectangleShape(const FloatRect& bounds, const FloatSize& radii)
+{
+ ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0);
+ return adoptPtr(new RectangleShape(bounds, radii));
+}
+
+static PassOwnPtr<Shape> createShapeCircle(const FloatPoint& center, float radius)
+{
+ ASSERT(radius >= 0);
+ return adoptPtr(new RectangleShape(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius)));
+}
+
+static PassOwnPtr<Shape> createShapeEllipse(const FloatPoint& center, const FloatSize& radii)
+{
+ ASSERT(radii.width() >= 0 && radii.height() >= 0);
+ return adoptPtr(new RectangleShape(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii));
+}
+
+static PassOwnPtr<Shape> createPolygonShape(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule)
+{
+ return adoptPtr(new PolygonShape(vertices, fillRule));
+}
+
+static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode)
+{
+ if (isHorizontalWritingMode(writingMode))
+ return rect;
+ if (isFlippedBlocksWritingMode(writingMode))
+ return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width());
+ return rect.transposedRect();
+}
+
+static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float logicalBoxHeight, WritingMode writingMode)
+{
+ if (isHorizontalWritingMode(writingMode))
+ return point;
+ if (isFlippedBlocksWritingMode(writingMode))
+ return FloatPoint(point.y(), logicalBoxHeight - point.x());
+ return point.transposedPoint();
+}
+
+static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode writingMode)
+{
+ if (isHorizontalWritingMode(writingMode))
+ return size;
+ return size.transposedSize();
+}
+
+static inline void ensureRadiiDoNotOverlap(FloatRect &bounds, FloatSize &radii)
+{
+ float widthRatio = bounds.width() / (2 * radii.width());
+ float heightRatio = bounds.height() / (2 * radii.height());
+ float reductionRatio = std::min<float>(widthRatio, heightRatio);
+ if (reductionRatio < 1) {
+ radii.setWidth(reductionRatio * radii.width());
+ radii.setHeight(reductionRatio * radii.height());
+ }
+}
+
+PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding)
+{
+ ASSERT(basicShape);
+
+ bool horizontalWritingMode = isHorizontalWritingMode(writingMode);
+ float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height();
+ float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width();
+ OwnPtr<Shape> shape;
+
+ switch (basicShape->type()) {
+
+ case BasicShape::BasicShapeRectangleType: {
+ const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape);
+ FloatRect bounds(
+ floatValueForLength(rectangle->x(), boxWidth),
+ floatValueForLength(rectangle->y(), boxHeight),
+ floatValueForLength(rectangle->width(), boxWidth),
+ floatValueForLength(rectangle->height(), boxHeight));
+ FloatSize cornerRadii(
+ floatValueForLength(rectangle->cornerRadiusX(), boxWidth),
+ floatValueForLength(rectangle->cornerRadiusY(), boxHeight));
+ ensureRadiiDoNotOverlap(bounds, cornerRadii);
+ FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode);
+
+ shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
+ break;
+ }
+
+ case BasicShape::BasicShapeCircleType: {
+ const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
+ float centerX = floatValueForLength(circle->centerX(), boxWidth);
+ float centerY = floatValueForLength(circle->centerY(), boxHeight);
+ float radius = floatValueForLength(circle->radius(), std::min(boxHeight, boxWidth));
+ FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
+
+ shape = createShapeCircle(logicalCenter, radius);
+ break;
+ }
+
+ case BasicShape::BasicShapeEllipseType: {
+ const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
+ float centerX = floatValueForLength(ellipse->centerX(), boxWidth);
+ float centerY = floatValueForLength(ellipse->centerY(), boxHeight);
+ float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth);
+ float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
+ FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
+ FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode);
+
+ shape = createShapeEllipse(logicalCenter, logicalRadii);
+ break;
+ }
+
+ case BasicShape::BasicShapePolygonType: {
+ const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape);
+ const Vector<Length>& values = polygon->values();
+ size_t valuesSize = values.size();
+ ASSERT(!(valuesSize % 2));
+ OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2));
+ for (unsigned i = 0; i < valuesSize; i += 2) {
+ FloatPoint vertex(
+ floatValueForLength(values.at(i), boxWidth),
+ floatValueForLength(values.at(i + 1), boxHeight));
+ (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode);
+ }
+
+ shape = createPolygonShape(vertices.release(), polygon->windRule());
+ break;
+ }
+
+ case BasicShape::BasicShapeInsetRectangleType: {
+ const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape);
+ float left = floatValueForLength(rectangle->left(), boxWidth);
+ float top = floatValueForLength(rectangle->top(), boxHeight);
+ FloatRect bounds(
+ left,
+ top,
+ boxWidth - left - floatValueForLength(rectangle->right(), boxWidth),
+ boxHeight - top - floatValueForLength(rectangle->bottom(), boxHeight));
+ FloatSize cornerRadii(
+ floatValueForLength(rectangle->cornerRadiusX(), boxWidth),
+ floatValueForLength(rectangle->cornerRadiusY(), boxHeight));
+ ensureRadiiDoNotOverlap(bounds, cornerRadii);
+ FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode);
+
+ shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
+ break;
+ }
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ shape->m_writingMode = writingMode;
+ shape->m_margin = floatValueForLength(margin, 0);
+ shape->m_padding = floatValueForLength(padding, 0);
+
+ return shape.release();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/ExclusionShape.h b/Source/WebCore/rendering/shapes/Shape.h
index 075c002c7..0d9ecfd72 100644
--- a/Source/WebCore/rendering/ExclusionShape.h
+++ b/Source/WebCore/rendering/shapes/Shape.h
@@ -27,11 +27,11 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ExclusionShape_h
-#define ExclusionShape_h
+#ifndef Shape_h
+#define Shape_h
#include "BasicShapes.h"
-#include "FloatRect.h"
+#include "LayoutRect.h"
#include "WritingMode.h"
#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
@@ -45,8 +45,8 @@ struct LineSegment {
{
}
- float logicalLeft;
- float logicalRight;
+ LayoutUnit logicalLeft;
+ LayoutUnit logicalRight;
};
typedef Vector<LineSegment> SegmentList;
@@ -57,29 +57,29 @@ typedef Vector<LineSegment> SegmentList;
// computed segments are returned as pairs of logical X coordinates. The BasicShape itself is defined in
// physical coordinates.
-class ExclusionShape {
+class Shape {
public:
- static PassOwnPtr<ExclusionShape> createExclusionShape(const BasicShape*, float logicalBoxWidth, float logicalBoxHeight, WritingMode);
+ static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding);
- virtual ~ExclusionShape() { }
+ virtual ~Shape() { }
- virtual FloatRect shapeLogicalBoundingBox() const = 0;
+ virtual LayoutRect shapeMarginLogicalBoundingBox() const = 0;
+ virtual LayoutRect shapePaddingLogicalBoundingBox() const = 0;
virtual bool isEmpty() const = 0;
- virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const = 0;
- virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const = 0;
+ virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const = 0;
+ virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const = 0;
+ virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const = 0;
protected:
- float minYForLogicalLine(float logicalTop, float logicalHeight) const { return (m_writingMode == RightToLeftWritingMode) ? m_logicalBoxHeight - logicalTop - logicalHeight : logicalTop; }
- float maxYForLogicalLine(float logicalTop, float logicalHeight) const { return (m_writingMode == RightToLeftWritingMode) ? m_logicalBoxHeight - logicalTop : logicalTop + logicalHeight; }
- FloatRect internalToLogicalBoundingBox(FloatRect r) const { return (m_writingMode == RightToLeftWritingMode) ? FloatRect(r.x(), m_logicalBoxHeight - r.maxY(), r.width(), r.height()) : r; }
+ float shapeMargin() const { return m_margin; }
+ float shapePadding() const { return m_padding; }
private:
WritingMode m_writingMode;
- float m_logicalBoxWidth;
- float m_logicalBoxHeight;
- FloatRect m_boundingBox;
+ float m_margin;
+ float m_padding;
};
} // namespace WebCore
-#endif // ExclusionShape_h
+#endif // Shape_h
diff --git a/Source/WebCore/rendering/shapes/ShapeInfo.cpp b/Source/WebCore/rendering/shapes/ShapeInfo.cpp
new file mode 100644
index 000000000..e11558321
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/ShapeInfo.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ShapeInfo.h"
+
+#if ENABLE(CSS_SHAPES)
+
+#include "RenderBlock.h"
+#include "RenderBox.h"
+#include "RenderRegion.h"
+#include "RenderStyle.h"
+#include "Shape.h"
+
+namespace WebCore {
+template<class RenderType, ShapeValue* (RenderStyle::*shapeGetter)() const, void (Shape::*intervalGetter)(LayoutUnit, LayoutUnit, SegmentList&) const>
+const Shape* ShapeInfo<RenderType, shapeGetter, intervalGetter>::computedShape() const
+{
+ if (Shape* shape = m_shape.get())
+ return shape;
+
+ ShapeValue* shapeValue = (m_renderer->style()->*shapeGetter)();
+ BasicShape* shape = (shapeValue && shapeValue->type() == ShapeValue::Shape) ? shapeValue->shape() : 0;
+
+ ASSERT(shape);
+
+ m_shape = Shape::createShape(shape, LayoutSize(m_shapeLogicalWidth, m_shapeLogicalHeight), m_renderer->style()->writingMode(), m_renderer->style()->shapeMargin(), m_renderer->style()->shapePadding());
+ ASSERT(m_shape);
+ return m_shape.get();
+}
+
+template<class RenderType, ShapeValue* (RenderStyle::*shapeGetter)() const, void (Shape::*intervalGetter)(LayoutUnit, LayoutUnit, SegmentList&) const>
+bool ShapeInfo<RenderType, shapeGetter, intervalGetter>::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
+{
+ ASSERT(lineHeight >= 0);
+ m_shapeLineTop = lineTop - logicalTopOffset();
+ m_lineHeight = lineHeight;
+ m_segments.clear();
+
+ if (lineOverlapsShapeBounds())
+ (computedShape()->*intervalGetter)(m_shapeLineTop, std::min(m_lineHeight, shapeLogicalBottom() - lineTop), m_segments);
+
+ LayoutUnit logicalLeftOffset = this->logicalLeftOffset();
+ for (size_t i = 0; i < m_segments.size(); i++) {
+ m_segments[i].logicalLeft += logicalLeftOffset;
+ m_segments[i].logicalRight += logicalLeftOffset;
+ }
+
+ return m_segments.size();
+}
+
+template class ShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &Shape::getIncludedIntervals>;
+template class ShapeInfo<RenderBox, &RenderStyle::shapeOutside, &Shape::getExcludedIntervals>;
+}
+#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInfo.h b/Source/WebCore/rendering/shapes/ShapeInfo.h
new file mode 100644
index 000000000..04ee471a8
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/ShapeInfo.h
@@ -0,0 +1,131 @@
+/*
+* Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above
+* copyright notice, this list of conditions and the following
+* disclaimer.
+* 2. Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials
+* provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+*/
+
+#ifndef ShapeInfo_h
+#define ShapeInfo_h
+
+#if ENABLE(CSS_SHAPES)
+
+#include "FloatRect.h"
+#include "LayoutUnit.h"
+#include "RenderStyle.h"
+#include "Shape.h"
+#include "ShapeValue.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+template<class KeyType, class InfoType>
+class MappedInfo {
+public:
+ static InfoType* ensureInfo(const KeyType* key)
+ {
+ InfoMap& infoMap = MappedInfo<KeyType, InfoType>::infoMap();
+ if (InfoType* info = infoMap.get(key))
+ return info;
+ typename InfoMap::AddResult result = infoMap.add(key, InfoType::createInfo(key));
+ return result.iterator->value.get();
+ }
+ static void removeInfo(const KeyType* key) { infoMap().remove(key); }
+ static InfoType* info(const KeyType* key) { return infoMap().get(key); }
+private:
+ typedef HashMap<const KeyType*, OwnPtr<InfoType> > InfoMap;
+ static InfoMap& infoMap()
+ {
+ DEFINE_STATIC_LOCAL(InfoMap, staticInfoMap, ());
+ return staticInfoMap;
+ }
+};
+
+template<class RenderType, ShapeValue* (RenderStyle::*shapeGetter)() const, void (Shape::*intervalGetter)(LayoutUnit, LayoutUnit, SegmentList&) const>
+class ShapeInfo {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ virtual ~ShapeInfo() { }
+
+ void setShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight)
+ {
+ if (m_renderer->style()->boxSizing() == CONTENT_BOX) {
+ logicalWidth -= m_renderer->borderAndPaddingLogicalWidth();
+ logicalHeight -= m_renderer->borderAndPaddingLogicalHeight();
+ }
+
+ if (m_shapeLogicalWidth == logicalWidth && m_shapeLogicalHeight == logicalHeight)
+ return;
+ dirtyShapeSize();
+ m_shapeLogicalWidth = logicalWidth;
+ m_shapeLogicalHeight = logicalHeight;
+ }
+
+ virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);
+ void clearSegments() { m_segments.clear(); }
+
+ LayoutUnit shapeLogicalTop() const { return computedShapeLogicalBoundingBox().y() + logicalTopOffset(); }
+ LayoutUnit shapeLogicalBottom() const { return computedShapeLogicalBoundingBox().maxY() + logicalTopOffset(); }
+ LayoutUnit shapeLogicalLeft() const { return computedShapeLogicalBoundingBox().x() + logicalLeftOffset(); }
+ LayoutUnit shapeLogicalRight() const { return computedShapeLogicalBoundingBox().maxX() + logicalLeftOffset(); }
+ LayoutUnit shapeLogicalWidth() const { return computedShapeLogicalBoundingBox().width(); }
+ LayoutUnit shapeLogicalHeight() const { return computedShapeLogicalBoundingBox().height(); }
+
+ LayoutUnit logicalLineTop() const { return m_shapeLineTop + logicalTopOffset(); }
+ LayoutUnit logicalLineBottom() const { return m_shapeLineTop + m_lineHeight + logicalTopOffset(); }
+
+ LayoutUnit shapeContainingBlockHeight() const { return (m_renderer->style()->boxSizing() == CONTENT_BOX) ? (m_shapeLogicalHeight + m_renderer->borderAndPaddingLogicalHeight()) : m_shapeLogicalHeight; }
+
+ bool lineOverlapsShapeBounds() const { return logicalLineTop() < shapeLogicalBottom() && shapeLogicalTop() <= logicalLineBottom(); }
+
+ void dirtyShapeSize() { m_shape.clear(); }
+ bool shapeSizeDirty() { return !m_shape.get(); }
+ const RenderType* owner() const { return m_renderer; }
+
+protected:
+ ShapeInfo(const RenderType* renderer): m_renderer(renderer) { }
+
+ const Shape* computedShape() const;
+ virtual LayoutRect computedShapeLogicalBoundingBox() const = 0;
+
+ LayoutUnit logicalTopOffset() const { return m_renderer->style()->boxSizing() == CONTENT_BOX ? m_renderer->borderAndPaddingBefore() : LayoutUnit(); };
+ LayoutUnit logicalLeftOffset() const { return (m_renderer->style()->boxSizing() == CONTENT_BOX && !m_renderer->isRenderRegion()) ? m_renderer->borderAndPaddingStart() : LayoutUnit(); }
+
+ LayoutUnit m_shapeLineTop;
+ LayoutUnit m_lineHeight;
+ SegmentList m_segments;
+
+ const RenderType* m_renderer;
+
+private:
+ mutable OwnPtr<Shape> m_shape;
+
+ LayoutUnit m_shapeLogicalWidth;
+ LayoutUnit m_shapeLogicalHeight;
+};
+}
+#endif
+#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp b/Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp
new file mode 100644
index 000000000..d1295d03e
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ShapeInsideInfo.h"
+
+#if ENABLE(CSS_SHAPES)
+
+#include "InlineIterator.h"
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+LineSegmentRange::LineSegmentRange(const InlineIterator& start, const InlineIterator& end)
+ : start(start.root(), start.object(), start.offset())
+ , end(end.root(), end.object(), end.offset())
+ {
+ }
+
+bool ShapeInsideInfo::isEnabledFor(const RenderBlock* renderer)
+{
+ ShapeValue* shapeValue = renderer->style()->resolvedShapeInside();
+ if (!shapeValue || shapeValue->type() != ShapeValue::Shape)
+ return false;
+
+ BasicShape* shape = shapeValue->shape();
+ return shape && shape->type() != BasicShape::BasicShapeInsetRectangleType;
+}
+
+bool ShapeInsideInfo::adjustLogicalLineTop(float minSegmentWidth)
+{
+ const Shape* shape = computedShape();
+ if (!shape || m_lineHeight <= 0 || logicalLineTop() > shapeLogicalBottom())
+ return false;
+
+ LayoutUnit newLineTop;
+ if (shape->firstIncludedIntervalLogicalTop(m_shapeLineTop, LayoutSize(minSegmentWidth, m_lineHeight), newLineTop)) {
+ if (newLineTop > m_shapeLineTop) {
+ m_shapeLineTop = newLineTop;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInsideInfo.h b/Source/WebCore/rendering/shapes/ShapeInsideInfo.h
new file mode 100644
index 000000000..c006b3645
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/ShapeInsideInfo.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ShapeInsideInfo_h
+#define ShapeInsideInfo_h
+
+#if ENABLE(CSS_SHAPES)
+
+#include "ShapeInfo.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class InlineIterator;
+class RenderBlock;
+class RenderObject;
+
+struct LineSegmentIterator {
+ RenderObject* root;
+ RenderObject* object;
+ unsigned offset;
+ LineSegmentIterator(RenderObject* root, RenderObject* object, unsigned offset)
+ : root(root)
+ , object(object)
+ , offset(offset)
+ {
+ }
+};
+
+struct LineSegmentRange {
+ LineSegmentIterator start;
+ LineSegmentIterator end;
+ LineSegmentRange(const InlineIterator& start, const InlineIterator& end);
+};
+
+typedef Vector<LineSegmentRange> SegmentRangeList;
+
+class ShapeInsideInfo : public ShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &Shape::getIncludedIntervals> {
+public:
+ static PassOwnPtr<ShapeInsideInfo> createInfo(const RenderBlock* renderer) { return adoptPtr(new ShapeInsideInfo(renderer)); }
+
+ static bool isEnabledFor(const RenderBlock* renderer);
+
+ virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) OVERRIDE
+ {
+ m_segmentRanges.clear();
+ return ShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &Shape::getIncludedIntervals>::computeSegmentsForLine(lineTop, lineHeight);
+ }
+
+ bool hasSegments() const
+ {
+ return lineOverlapsShapeBounds() && m_segments.size();
+ }
+ const SegmentList& segments() const
+ {
+ ASSERT(hasSegments());
+ return m_segments;
+ }
+ SegmentRangeList& segmentRanges() { return m_segmentRanges; }
+ const SegmentRangeList& segmentRanges() const { return m_segmentRanges; }
+ const LineSegment* currentSegment() const
+ {
+ if (!hasSegments())
+ return 0;
+ ASSERT(m_segmentRanges.size() < m_segments.size());
+ return &m_segments[m_segmentRanges.size()];
+ }
+ bool adjustLogicalLineTop(float minSegmentWidth);
+
+ void setNeedsLayout(bool value) { m_needsLayout = value; }
+ bool needsLayout() { return m_needsLayout; }
+
+protected:
+ virtual LayoutRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapePaddingLogicalBoundingBox(); }
+
+private:
+ ShapeInsideInfo(const RenderBlock* renderer)
+ : ShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &Shape::getIncludedIntervals> (renderer)
+ , m_needsLayout(false)
+ { }
+
+ SegmentRangeList m_segmentRanges;
+ bool m_needsLayout:1;
+};
+
+}
+#endif
+#endif
diff --git a/Source/WebCore/rendering/ExclusionInterval.cpp b/Source/WebCore/rendering/shapes/ShapeInterval.cpp
index 4e0ef7a98..b558038b2 100644
--- a/Source/WebCore/rendering/ExclusionInterval.cpp
+++ b/Source/WebCore/rendering/shapes/ShapeInterval.cpp
@@ -28,20 +28,20 @@
*/
#include "config.h"
-#include "ExclusionInterval.h"
+#include "ShapeInterval.h"
#include <wtf/MathExtras.h>
namespace WebCore {
struct IntervalX1Comparator {
- bool operator() (const ExclusionInterval& i1, const ExclusionInterval& i2) const
+ bool operator() (const ShapeInterval& i1, const ShapeInterval& i2) const
{
return i1.x1 < i2.x1;
}
};
-bool ExclusionInterval::intersect(const ExclusionInterval& i, ExclusionInterval& rv) const
+bool ShapeInterval::intersect(const ShapeInterval& i, ShapeInterval& rv) const
{
if (x2 < i.x1 || x1 > i.x2)
return false;
@@ -50,20 +50,20 @@ bool ExclusionInterval::intersect(const ExclusionInterval& i, ExclusionInterval&
return true;
}
-void sortExclusionIntervals(Vector<ExclusionInterval>& v)
+void sortShapeIntervals(Vector<ShapeInterval>& v)
{
std::sort(v.begin(), v.end(), IntervalX1Comparator());
}
-void mergeExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vector<ExclusionInterval>& v2, Vector<ExclusionInterval>& rv)
+void mergeShapeIntervals(const Vector<ShapeInterval>& v1, const Vector<ShapeInterval>& v2, Vector<ShapeInterval>& rv)
{
if (!v1.size())
rv.appendRange(v2.begin(), v2.end());
else if (!v2.size())
rv.appendRange(v1.begin(), v1.end());
else {
- Vector<ExclusionInterval> v(v1.size() + v2.size());
- ExclusionInterval* interval = 0;
+ Vector<ShapeInterval> v(v1.size() + v2.size());
+ ShapeInterval* interval = 0;
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v.begin(), IntervalX1Comparator());
@@ -83,7 +83,7 @@ void mergeExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vector<E
}
}
-void intersectExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vector<ExclusionInterval>& v2, Vector<ExclusionInterval>& rv)
+void intersectShapeIntervals(const Vector<ShapeInterval>& v1, const Vector<ShapeInterval>& v2, Vector<ShapeInterval>& rv)
{
size_t v1Size = v1.size();
size_t v2Size = v2.size();
@@ -91,13 +91,13 @@ void intersectExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vect
if (!v1Size || !v2Size)
return;
- ExclusionInterval interval;
+ ShapeInterval interval;
bool overlap = false;
size_t i1 = 0;
size_t i2 = 0;
while (i1 < v1Size && i2 < v2Size) {
- ExclusionInterval v12;
+ ShapeInterval v12;
if (v1[i1].intersect(v2[i2], v12)) {
if (!overlap || !v12.intersect(interval, interval)) {
if (overlap)
@@ -124,7 +124,7 @@ void intersectExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vect
rv.append(interval);
}
-void subtractExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vector<ExclusionInterval>& v2, Vector<ExclusionInterval>& rv)
+void subtractShapeIntervals(const Vector<ShapeInterval>& v1, const Vector<ShapeInterval>& v2, Vector<ShapeInterval>& rv)
{
size_t v1Size = v1.size();
size_t v2Size = v2.size();
@@ -139,8 +139,8 @@ void subtractExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vecto
rv.appendRange(v1.begin(), v1.end());
while (i1 < rv.size() && i2 < v2Size) {
- ExclusionInterval& interval1 = rv[i1];
- const ExclusionInterval& interval2 = v2[i2];
+ ShapeInterval& interval1 = rv[i1];
+ const ShapeInterval& interval2 = v2[i2];
if (interval2.x1 <= interval1.x1 && interval2.x2 >= interval1.x2)
rv.remove(i1);
@@ -149,7 +149,7 @@ void subtractExclusionIntervals(const Vector<ExclusionInterval>& v1, const Vecto
else if (interval2.x1 > interval1.x2)
i1 += 1;
else if (interval2.x1 > interval1.x1 && interval2.x2 < interval1.x2) {
- rv.insert(i1, ExclusionInterval(interval1.x1, interval2.x1));
+ rv.insert(i1, ShapeInterval(interval1.x1, interval2.x1));
interval1.x1 = interval2.x2;
i2 += 1;
} else if (interval2.x1 <= interval1.x1) {
diff --git a/Source/WebCore/rendering/ExclusionInterval.h b/Source/WebCore/rendering/shapes/ShapeInterval.h
index 5d31feb18..0ff14d8a5 100644
--- a/Source/WebCore/rendering/ExclusionInterval.h
+++ b/Source/WebCore/rendering/shapes/ShapeInterval.h
@@ -27,32 +27,32 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ExclusionInterval_h
-#define ExclusionInterval_h
+#ifndef ShapeInterval_h
+#define ShapeInterval_h
#include <wtf/Vector.h>
namespace WebCore {
-struct ExclusionInterval {
+struct ShapeInterval {
public:
float x1;
float x2;
- ExclusionInterval(float x1 = 0, float x2 = 0)
+ ShapeInterval(float x1 = 0, float x2 = 0)
: x1(x1)
, x2(x2)
{
}
- bool intersect(const ExclusionInterval&, ExclusionInterval&) const;
+ bool intersect(const ShapeInterval&, ShapeInterval&) const;
};
-void sortExclusionIntervals(Vector<ExclusionInterval>&);
-void mergeExclusionIntervals(const Vector<ExclusionInterval>&, const Vector<ExclusionInterval>&, Vector<ExclusionInterval>&);
-void intersectExclusionIntervals(const Vector<ExclusionInterval>&, const Vector<ExclusionInterval>&, Vector<ExclusionInterval>&);
-void subtractExclusionIntervals(const Vector<ExclusionInterval>&, const Vector<ExclusionInterval>&, Vector<ExclusionInterval>&);
+void sortShapeIntervals(Vector<ShapeInterval>&);
+void mergeShapeIntervals(const Vector<ShapeInterval>&, const Vector<ShapeInterval>&, Vector<ShapeInterval>&);
+void intersectShapeIntervals(const Vector<ShapeInterval>&, const Vector<ShapeInterval>&, Vector<ShapeInterval>&);
+void subtractShapeIntervals(const Vector<ShapeInterval>&, const Vector<ShapeInterval>&, Vector<ShapeInterval>&);
} // namespace WebCore
-#endif // ExclusionInterval_h
+#endif // ShapeInterval_h
diff --git a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
new file mode 100644
index 000000000..9ffe7dc5b
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(CSS_SHAPES)
+
+#include "ShapeOutsideInfo.h"
+
+#include "RenderBox.h"
+
+namespace WebCore {
+bool ShapeOutsideInfo::isEnabledFor(const RenderBox* box)
+{
+ ShapeValue* value = box->style()->shapeOutside();
+ return box->isFloatingWithShapeOutside() && value->type() == ShapeValue::Shape && value->shape();
+}
+
+bool ShapeOutsideInfo::computeSegmentsForContainingBlockLine(LayoutUnit lineTop, LayoutUnit floatTop, LayoutUnit lineHeight)
+{
+ LayoutUnit lineTopInShapeCoordinates = lineTop - floatTop + logicalTopOffset();
+ return computeSegmentsForLine(lineTopInShapeCoordinates, lineHeight);
+}
+
+bool ShapeOutsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
+{
+ if (shapeSizeDirty() || m_lineTop != lineTop || m_lineHeight != lineHeight) {
+ if (ShapeInfo<RenderBox, &RenderStyle::shapeOutside, &Shape::getExcludedIntervals>::computeSegmentsForLine(lineTop, lineHeight)) {
+ m_leftSegmentMarginBoxDelta = m_segments[0].logicalLeft + m_renderer->marginStart();
+ m_rightSegmentMarginBoxDelta = m_segments[m_segments.size()-1].logicalRight - m_renderer->logicalWidth() - m_renderer->marginEnd();
+ } else {
+ m_leftSegmentMarginBoxDelta = m_renderer->logicalWidth() + m_renderer->marginStart();
+ m_rightSegmentMarginBoxDelta = -m_renderer->logicalWidth() - m_renderer->marginEnd();
+ }
+ m_lineTop = lineTop;
+ }
+
+ return m_segments.size();
+}
+
+}
+#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h
new file mode 100644
index 000000000..685b0f94c
--- /dev/null
+++ b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ShapeOutsideInfo_h
+#define ShapeOutsideInfo_h
+
+#if ENABLE(CSS_SHAPES)
+
+#include "LayoutSize.h"
+#include "ShapeInfo.h"
+
+namespace WebCore {
+
+class RenderBox;
+
+class ShapeOutsideInfo : public ShapeInfo<RenderBox, &RenderStyle::shapeOutside, &Shape::getExcludedIntervals>, public MappedInfo<RenderBox, ShapeOutsideInfo> {
+public:
+ LayoutUnit leftSegmentMarginBoxDelta() const { return m_leftSegmentMarginBoxDelta; }
+ LayoutUnit rightSegmentMarginBoxDelta() const { return m_rightSegmentMarginBoxDelta; }
+
+ bool computeSegmentsForContainingBlockLine(LayoutUnit lineTop, LayoutUnit floatTop, LayoutUnit lineHeight);
+ virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) OVERRIDE;
+
+ static PassOwnPtr<ShapeOutsideInfo> createInfo(const RenderBox* renderer) { return adoptPtr(new ShapeOutsideInfo(renderer)); }
+ static bool isEnabledFor(const RenderBox*);
+
+protected:
+ virtual LayoutRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapeMarginLogicalBoundingBox(); }
+
+private:
+ ShapeOutsideInfo(const RenderBox* renderer) : ShapeInfo<RenderBox, &RenderStyle::shapeOutside, &Shape::getExcludedIntervals>(renderer) { }
+
+ LayoutUnit m_leftSegmentMarginBoxDelta;
+ LayoutUnit m_rightSegmentMarginBoxDelta;
+ LayoutUnit m_lineTop;
+};
+
+}
+#endif
+#endif
diff --git a/Source/WebCore/rendering/style/BasicShapes.cpp b/Source/WebCore/rendering/style/BasicShapes.cpp
index b21358fdc..b5927f924 100644
--- a/Source/WebCore/rendering/style/BasicShapes.cpp
+++ b/Source/WebCore/rendering/style/BasicShapes.cpp
@@ -30,6 +30,7 @@
#include "config.h"
#include "BasicShapes.h"
+
#include "FloatRect.h"
#include "LengthFunctions.h"
#include "Path.h"
@@ -43,7 +44,7 @@ bool BasicShape::canBlend(const BasicShape* other) const
return false;
// Just polygons with same number of vertices can be animated.
- if (type() == BasicShape::BASIC_SHAPE_POLYGON
+ if (type() == BasicShape::BasicShapePolygonType
&& static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size())
return false;
@@ -53,12 +54,18 @@ bool BasicShape::canBlend(const BasicShape* other) const
void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox)
{
ASSERT(path.isEmpty());
- path.addRoundedRect(FloatRect(floatValueForLength(m_x, boundingBox.width()) + boundingBox.x(),
- floatValueForLength(m_y, boundingBox.height()) + boundingBox.y(),
- floatValueForLength(m_width, boundingBox.width()),
- floatValueForLength(m_height, boundingBox.height())),
- FloatSize(m_cornerRadiusX.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusX, boundingBox.width()),
- m_cornerRadiusY.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusY, boundingBox.height())));
+ path.addRoundedRect(
+ FloatRect(
+ floatValueForLength(m_x, boundingBox.width()) + boundingBox.x(),
+ floatValueForLength(m_y, boundingBox.height()) + boundingBox.y(),
+ floatValueForLength(m_width, boundingBox.width()),
+ floatValueForLength(m_height, boundingBox.height())
+ ),
+ FloatSize(
+ floatValueForLength(m_cornerRadiusX, boundingBox.width()),
+ floatValueForLength(m_cornerRadiusY, boundingBox.height())
+ )
+ );
}
PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const
@@ -71,10 +78,8 @@ PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, doubl
result->setY(m_y.blend(o->y(), progress));
result->setWidth(m_width.blend(o->width(), progress));
result->setHeight(m_height.blend(o->height(), progress));
- if (!m_cornerRadiusX.isUndefined() && !o->cornerRadiusX().isUndefined())
- result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress));
- if (!m_cornerRadiusY.isUndefined() && !o->cornerRadiusY().isUndefined())
- result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress));
+ result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress));
+ result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress));
return result.release();
}
@@ -85,10 +90,12 @@ void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
float centerX = floatValueForLength(m_centerX, boundingBox.width());
float centerY = floatValueForLength(m_centerY, boundingBox.height());
float radius = floatValueForLength(m_radius, diagonal);
- path.addEllipse(FloatRect(centerX - radius + boundingBox.x(),
- centerY - radius + boundingBox.y(),
- radius * 2,
- radius * 2));
+ path.addEllipse(FloatRect(
+ centerX - radius + boundingBox.x(),
+ centerY - radius + boundingBox.y(),
+ radius * 2,
+ radius * 2
+ ));
}
PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const
@@ -110,10 +117,12 @@ void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
float centerY = floatValueForLength(m_centerY, boundingBox.height());
float radiusX = floatValueForLength(m_radiusX, boundingBox.width());
float radiusY = floatValueForLength(m_radiusY, boundingBox.height());
- path.addEllipse(FloatRect(centerX - radiusX + boundingBox.x(),
- centerY - radiusY + boundingBox.y(),
- radiusX * 2,
- radiusY * 2));
+ path.addEllipse(FloatRect(
+ centerX - radiusX + boundingBox.x(),
+ centerY - radiusY + boundingBox.y(),
+ radiusX * 2,
+ radiusY * 2
+ ));
}
PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const
@@ -169,4 +178,38 @@ PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double
return result.release();
}
+
+void BasicShapeInsetRectangle::path(Path& path, const FloatRect& boundingBox)
+{
+ ASSERT(path.isEmpty());
+ float left = floatValueForLength(m_left, boundingBox.width());
+ float top = floatValueForLength(m_top, boundingBox.height());
+ path.addRoundedRect(
+ FloatRect(
+ left + boundingBox.x(),
+ top + boundingBox.y(),
+ std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0),
+ std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0)
+ ),
+ FloatSize(
+ floatValueForLength(m_cornerRadiusX, boundingBox.width()),
+ floatValueForLength(m_cornerRadiusY, boundingBox.height())
+ )
+ );
+}
+
+PassRefPtr<BasicShape> BasicShapeInsetRectangle::blend(const BasicShape* other, double progress) const
+{
+ ASSERT(type() == other->type());
+
+ const BasicShapeInsetRectangle* o = static_cast<const BasicShapeInsetRectangle*>(other);
+ RefPtr<BasicShapeInsetRectangle> result = BasicShapeInsetRectangle::create();
+ result->setTop(m_top.blend(o->top(), progress));
+ result->setRight(m_right.blend(o->right(), progress));
+ result->setBottom(m_bottom.blend(o->bottom(), progress));
+ result->setLeft(m_left.blend(o->left(), progress));
+ result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress));
+ result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress));
+ return result.release();
+}
}
diff --git a/Source/WebCore/rendering/style/BasicShapes.h b/Source/WebCore/rendering/style/BasicShapes.h
index 171d9c1f6..ec027fe91 100644
--- a/Source/WebCore/rendering/style/BasicShapes.h
+++ b/Source/WebCore/rendering/style/BasicShapes.h
@@ -46,10 +46,11 @@ public:
virtual ~BasicShape() { }
enum Type {
- BASIC_SHAPE_RECTANGLE = 1,
- BASIC_SHAPE_CIRCLE = 2,
- BASIC_SHAPE_ELLIPSE = 3,
- BASIC_SHAPE_POLYGON = 4
+ BasicShapeRectangleType = 1,
+ BasicShapeCircleType = 2,
+ BasicShapeEllipseType = 3,
+ BasicShapePolygonType = 4,
+ BasicShapeInsetRectangleType = 5
};
bool canBlend(const BasicShape*) const;
@@ -78,18 +79,23 @@ public:
void setY(Length y) { m_y = y; }
void setWidth(Length width) { m_width = width; }
void setHeight(Length height) { m_height = height; }
- void setCornerRadiusX(Length radiusX) { m_cornerRadiusX = radiusX; }
- void setCornerRadiusY(Length radiusY) { m_cornerRadiusY = radiusY; }
+ void setCornerRadiusX(Length radiusX)
+ {
+ ASSERT(!radiusX.isUndefined());
+ m_cornerRadiusX = radiusX;
+ }
+ void setCornerRadiusY(Length radiusY)
+ {
+ ASSERT(!radiusY.isUndefined());
+ m_cornerRadiusY = radiusY;
+ }
virtual void path(Path&, const FloatRect&) OVERRIDE;
virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
- virtual Type type() const { return BASIC_SHAPE_RECTANGLE; }
+ virtual Type type() const { return BasicShapeRectangleType; }
private:
- BasicShapeRectangle()
- : m_cornerRadiusX(Undefined)
- , m_cornerRadiusY(Undefined)
- { }
+ BasicShapeRectangle() { }
Length m_y;
Length m_x;
@@ -114,7 +120,7 @@ public:
virtual void path(Path&, const FloatRect&) OVERRIDE;
virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
- virtual Type type() const { return BASIC_SHAPE_CIRCLE; }
+ virtual Type type() const { return BasicShapeCircleType; }
private:
BasicShapeCircle() { }
@@ -140,7 +146,7 @@ public:
virtual void path(Path&, const FloatRect&) OVERRIDE;
virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
- virtual Type type() const { return BASIC_SHAPE_ELLIPSE; }
+ virtual Type type() const { return BasicShapeEllipseType; }
private:
BasicShapeEllipse() { }
@@ -166,7 +172,7 @@ public:
virtual WindRule windRule() const { return m_windRule; }
- virtual Type type() const { return BASIC_SHAPE_POLYGON; }
+ virtual Type type() const { return BasicShapePolygonType; }
private:
BasicShapePolygon()
: m_windRule(RULE_NONZERO)
@@ -175,5 +181,46 @@ private:
WindRule m_windRule;
Vector<Length> m_values;
};
+
+class BasicShapeInsetRectangle : public BasicShape {
+public:
+ static PassRefPtr<BasicShapeInsetRectangle> create() { return adoptRef(new BasicShapeInsetRectangle); }
+
+ Length top() const { return m_top; }
+ Length right() const { return m_right; }
+ Length bottom() const { return m_bottom; }
+ Length left() const { return m_left; }
+ Length cornerRadiusX() const { return m_cornerRadiusX; }
+ Length cornerRadiusY() const { return m_cornerRadiusY; }
+
+ void setTop(Length top) { m_top = top; }
+ void setRight(Length right) { m_right = right; }
+ void setBottom(Length bottom) { m_bottom = bottom; }
+ void setLeft(Length left) { m_left = left; }
+ void setCornerRadiusX(Length radiusX)
+ {
+ ASSERT(!radiusX.isUndefined());
+ m_cornerRadiusX = radiusX;
+ }
+ void setCornerRadiusY(Length radiusY)
+ {
+ ASSERT(!radiusY.isUndefined());
+ m_cornerRadiusY = radiusY;
+ }
+
+ virtual void path(Path&, const FloatRect&) OVERRIDE;
+ virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+
+ virtual Type type() const { return BasicShapeInsetRectangleType; }
+private:
+ BasicShapeInsetRectangle() { }
+
+ Length m_right;
+ Length m_top;
+ Length m_bottom;
+ Length m_left;
+ Length m_cornerRadiusX;
+ Length m_cornerRadiusY;
+};
}
#endif
diff --git a/Source/WebCore/rendering/style/ContentData.cpp b/Source/WebCore/rendering/style/ContentData.cpp
index 9cac254ce..7a115b915 100644
--- a/Source/WebCore/rendering/style/ContentData.cpp
+++ b/Source/WebCore/rendering/style/ContentData.cpp
@@ -69,13 +69,8 @@ PassOwnPtr<ContentData> ContentData::clone() const
RenderObject* ImageContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
{
- RenderImage* image = new (doc->renderArena()) RenderImage(doc);
- // Images are special and must inherit the pseudoStyle so the width and height of
- // the pseudo element don't change the size of the image. In all other cases we
- // can just share the style.
- RefPtr<RenderStyle> style = RenderStyle::create();
- style->inheritFrom(pseudoStyle);
- image->setStyle(style.release());
+ RenderImage* image = RenderImage::createAnonymous(doc);
+ image->setPseudoStyle(pseudoStyle);
if (m_image)
image->setImageResource(RenderImageResourceStyleImage::create(m_image.get()));
else
@@ -86,21 +81,21 @@ RenderObject* ImageContentData::createRenderer(Document* doc, RenderStyle* pseud
RenderObject* TextContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
{
RenderObject* renderer = new (doc->renderArena()) RenderTextFragment(doc, m_text.impl());
- renderer->setStyle(pseudoStyle);
+ renderer->setPseudoStyle(pseudoStyle);
return renderer;
}
RenderObject* CounterContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
{
RenderObject* renderer = new (doc->renderArena()) RenderCounter(doc, *m_counter);
- renderer->setStyle(pseudoStyle);
+ renderer->setPseudoStyle(pseudoStyle);
return renderer;
}
RenderObject* QuoteContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
{
RenderObject* renderer = new (doc->renderArena()) RenderQuote(doc, m_quote);
- renderer->setStyle(pseudoStyle);
+ renderer->setPseudoStyle(pseudoStyle);
return renderer;
}
diff --git a/Source/WebCore/rendering/style/CursorData.h b/Source/WebCore/rendering/style/CursorData.h
index 6d0a273f6..f8f779a28 100644
--- a/Source/WebCore/rendering/style/CursorData.h
+++ b/Source/WebCore/rendering/style/CursorData.h
@@ -51,6 +51,7 @@ public:
StyleImage* image() const { return m_image.get(); }
void setImage(PassRefPtr<StyleImage> image) { m_image = image; }
+ // Hot spot in the image in logical pixels.
const IntPoint& hotSpot() const { return m_hotSpot; }
private:
diff --git a/Source/WebCore/rendering/style/DataRef.h b/Source/WebCore/rendering/style/DataRef.h
index b4d4a7970..c8d8072cb 100644
--- a/Source/WebCore/rendering/style/DataRef.h
+++ b/Source/WebCore/rendering/style/DataRef.h
@@ -62,14 +62,6 @@ public:
return m_data != o.m_data && *m_data != *o.m_data;
}
- // Template helps us to write the implementation without MemoryInstrumentation.h include.
- template<typename MemoryObjectInfo>
- void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
- {
- typename MemoryObjectInfo::ClassInfo info(memoryObjectInfo, this);
- info.addMember(m_data);
- }
-
private:
RefPtr<T> m_data;
};
diff --git a/Source/WebCore/rendering/style/FillLayer.cpp b/Source/WebCore/rendering/style/FillLayer.cpp
index edd3d9a60..b11e24ccd 100644
--- a/Source/WebCore/rendering/style/FillLayer.cpp
+++ b/Source/WebCore/rendering/style/FillLayer.cpp
@@ -34,7 +34,8 @@ struct SameSizeAsFillLayer {
LengthSize m_sizeLength;
- unsigned m_bitfields;
+ unsigned m_bitfields: 32;
+ unsigned m_bitfields2: 1;
};
COMPILE_ASSERT(sizeof(FillLayer) == sizeof(SameSizeAsFillLayer), FillLayer_should_stay_small);
@@ -51,7 +52,8 @@ FillLayer::FillLayer(EFillLayerType type)
, m_repeatX(FillLayer::initialFillRepeatX(type))
, m_repeatY(FillLayer::initialFillRepeatY(type))
, m_composite(FillLayer::initialFillComposite(type))
- , m_sizeType(SizeNone)
+ , m_sizeType(FillLayer::initialFillSizeType(type))
+ , m_blendMode(FillLayer::initialFillBlendMode(type))
, m_imageSet(false)
, m_attachmentSet(false)
, m_clipSet(false)
@@ -60,7 +62,11 @@ FillLayer::FillLayer(EFillLayerType type)
, m_repeatYSet(false)
, m_xPosSet(false)
, m_yPosSet(false)
+ , m_backgroundOriginSet(false)
+ , m_backgroundXOrigin(LeftEdge)
+ , m_backgroundYOrigin(TopEdge)
, m_compositeSet(type == MaskFillLayer)
+ , m_blendModeSet(false)
, m_type(type)
{
}
@@ -78,6 +84,7 @@ FillLayer::FillLayer(const FillLayer& o)
, m_repeatY(o.m_repeatY)
, m_composite(o.m_composite)
, m_sizeType(o.m_sizeType)
+ , m_blendMode(o.m_blendMode)
, m_imageSet(o.m_imageSet)
, m_attachmentSet(o.m_attachmentSet)
, m_clipSet(o.m_clipSet)
@@ -86,7 +93,11 @@ FillLayer::FillLayer(const FillLayer& o)
, m_repeatYSet(o.m_repeatYSet)
, m_xPosSet(o.m_xPosSet)
, m_yPosSet(o.m_yPosSet)
+ , m_backgroundOriginSet(o.m_backgroundOriginSet)
+ , m_backgroundXOrigin(o.m_backgroundXOrigin)
+ , m_backgroundYOrigin(o.m_backgroundYOrigin)
, m_compositeSet(o.m_compositeSet)
+ , m_blendModeSet(o.m_blendModeSet)
, m_type(o.m_type)
{
}
@@ -106,10 +117,14 @@ FillLayer& FillLayer::operator=(const FillLayer& o)
m_image = o.m_image;
m_xPosition = o.m_xPosition;
m_yPosition = o.m_yPosition;
+ m_backgroundXOrigin = o.m_backgroundXOrigin;
+ m_backgroundYOrigin = o.m_backgroundYOrigin;
+ m_backgroundOriginSet = o.m_backgroundOriginSet;
m_sizeLength = o.m_sizeLength;
m_attachment = o.m_attachment;
m_clip = o.m_clip;
m_composite = o.m_composite;
+ m_blendMode = o.m_blendMode;
m_origin = o.m_origin;
m_repeatX = o.m_repeatX;
m_repeatY = o.m_repeatY;
@@ -119,6 +134,7 @@ FillLayer& FillLayer::operator=(const FillLayer& o)
m_attachmentSet = o.m_attachmentSet;
m_clipSet = o.m_clipSet;
m_compositeSet = o.m_compositeSet;
+ m_blendModeSet = o.m_blendModeSet;
m_originSet = o.m_originSet;
m_repeatXSet = o.m_repeatXSet;
m_repeatYSet = o.m_repeatYSet;
@@ -134,11 +150,12 @@ bool FillLayer::operator==(const FillLayer& o) const
{
// We do not check the "isSet" booleans for each property, since those are only used during initial construction
// to propagate patterns into layers. All layer comparisons happen after values have all been filled in anyway.
- return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition &&
- m_attachment == o.m_attachment && m_clip == o.m_clip &&
- m_composite == o.m_composite && m_origin == o.m_origin && m_repeatX == o.m_repeatX &&
- m_repeatY == o.m_repeatY && m_sizeType == o.m_sizeType && m_sizeLength == o.m_sizeLength &&
- m_type == o.m_type && ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
+ return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition
+ && m_backgroundXOrigin == o.m_backgroundXOrigin && m_backgroundYOrigin == o.m_backgroundYOrigin
+ && m_attachment == o.m_attachment && m_clip == o.m_clip && m_composite == o.m_composite
+ && m_blendMode == o.m_blendMode && m_origin == o.m_origin && m_repeatX == o.m_repeatX
+ && m_repeatY == o.m_repeatY && m_sizeType == o.m_sizeType && m_sizeLength == o.m_sizeLength
+ && m_type == o.m_type && ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
}
void FillLayer::fillUnsetProperties()
@@ -149,6 +166,10 @@ void FillLayer::fillUnsetProperties()
// We need to fill in the remaining values with the pattern specified.
for (FillLayer* pattern = this; curr; curr = curr->next()) {
curr->m_xPosition = pattern->m_xPosition;
+ if (pattern->isBackgroundOriginSet()) {
+ curr->m_backgroundXOrigin = pattern->m_backgroundXOrigin;
+ curr->m_backgroundYOrigin = pattern->m_backgroundYOrigin;
+ }
pattern = pattern->next();
if (pattern == curr || !pattern)
pattern = this;
@@ -160,12 +181,16 @@ void FillLayer::fillUnsetProperties()
// We need to fill in the remaining values with the pattern specified.
for (FillLayer* pattern = this; curr; curr = curr->next()) {
curr->m_yPosition = pattern->m_yPosition;
+ if (pattern->isBackgroundOriginSet()) {
+ curr->m_backgroundXOrigin = pattern->m_backgroundXOrigin;
+ curr->m_backgroundYOrigin = pattern->m_backgroundYOrigin;
+ }
pattern = pattern->next();
if (pattern == curr || !pattern)
pattern = this;
}
}
-
+
for (curr = this; curr && curr->isAttachmentSet(); curr = curr->next()) { }
if (curr && curr != this) {
// We need to fill in the remaining values with the pattern specified.
@@ -199,6 +224,17 @@ void FillLayer::fillUnsetProperties()
}
}
+ for (curr = this; curr && curr->isBlendModeSet(); curr = curr->next()) { }
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (FillLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_blendMode = pattern->m_blendMode;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
for (curr = this; curr && curr->isOriginSet(); curr = curr->next()) { }
if (curr && curr != this) {
// We need to fill in the remaining values with the pattern specified.
@@ -258,6 +294,33 @@ void FillLayer::cullEmptyLayers()
}
}
+static EFillBox clipMax(EFillBox clipA, EFillBox clipB)
+{
+ if (clipA == BorderFillBox || clipB == BorderFillBox)
+ return BorderFillBox;
+ if (clipA == PaddingFillBox || clipB == PaddingFillBox)
+ return PaddingFillBox;
+ if (clipA == ContentFillBox || clipB == ContentFillBox)
+ return ContentFillBox;
+ return TextFillBox;
+}
+
+void FillLayer::computeClipMax() const
+{
+ if (m_next) {
+ m_next->computeClipMax();
+ m_clipMax = clipMax(clip(), m_next->clip());
+ } else
+ m_clipMax = m_clip;
+}
+
+bool FillLayer::clipOccludesNextLayers(bool firstLayer) const
+{
+ if (firstLayer)
+ computeClipMax();
+ return m_clip == m_clipMax;
+}
+
bool FillLayer::containsImage(StyleImage* s) const
{
if (!s)
@@ -288,8 +351,11 @@ bool FillLayer::hasOpaqueImage(const RenderObject* renderer) const
if (m_composite == CompositeClear || m_composite == CompositeCopy)
return true;
+ if (m_blendMode != BlendModeNormal)
+ return false;
+
if (m_composite == CompositeSourceOver)
- return !m_image->hasAlpha(renderer);
+ return m_image->knownToBeOpaque(renderer);
return false;
}
diff --git a/Source/WebCore/rendering/style/FillLayer.h b/Source/WebCore/rendering/style/FillLayer.h
index 525f533ab..040a3f125 100644
--- a/Source/WebCore/rendering/style/FillLayer.h
+++ b/Source/WebCore/rendering/style/FillLayer.h
@@ -68,12 +68,15 @@ public:
StyleImage* image() const { return m_image.get(); }
Length xPosition() const { return m_xPosition; }
Length yPosition() const { return m_yPosition; }
+ BackgroundEdgeOrigin backgroundXOrigin() const { return static_cast<BackgroundEdgeOrigin>(m_backgroundXOrigin); }
+ BackgroundEdgeOrigin backgroundYOrigin() const { return static_cast<BackgroundEdgeOrigin>(m_backgroundYOrigin); }
EFillAttachment attachment() const { return static_cast<EFillAttachment>(m_attachment); }
EFillBox clip() const { return static_cast<EFillBox>(m_clip); }
EFillBox origin() const { return static_cast<EFillBox>(m_origin); }
EFillRepeat repeatX() const { return static_cast<EFillRepeat>(m_repeatX); }
EFillRepeat repeatY() const { return static_cast<EFillRepeat>(m_repeatY); }
CompositeOperator composite() const { return static_cast<CompositeOperator>(m_composite); }
+ BlendMode blendMode() const { return static_cast<BlendMode>(m_blendMode); }
LengthSize sizeLength() const { return m_sizeLength; }
EFillSizeType sizeType() const { return static_cast<EFillSizeType>(m_sizeType); }
FillSize size() const { return FillSize(static_cast<EFillSizeType>(m_sizeType), m_sizeLength); }
@@ -84,36 +87,51 @@ public:
bool isImageSet() const { return m_imageSet; }
bool isXPositionSet() const { return m_xPosSet; }
bool isYPositionSet() const { return m_yPosSet; }
+ bool isBackgroundOriginSet() const { return m_backgroundOriginSet; }
bool isAttachmentSet() const { return m_attachmentSet; }
bool isClipSet() const { return m_clipSet; }
bool isOriginSet() const { return m_originSet; }
bool isRepeatXSet() const { return m_repeatXSet; }
bool isRepeatYSet() const { return m_repeatYSet; }
bool isCompositeSet() const { return m_compositeSet; }
+ bool isBlendModeSet() const { return m_blendModeSet; }
bool isSizeSet() const { return m_sizeType != SizeNone; }
void setImage(PassRefPtr<StyleImage> i) { m_image = i; m_imageSet = true; }
void setXPosition(Length l) { m_xPosition = l; m_xPosSet = true; }
void setYPosition(Length l) { m_yPosition = l; m_yPosSet = true; }
+ void setBackgroundXOrigin(BackgroundEdgeOrigin o) { m_backgroundXOrigin = o; m_backgroundOriginSet = true; }
+ void setBackgroundYOrigin(BackgroundEdgeOrigin o) { m_backgroundYOrigin = o; m_backgroundOriginSet = true; }
void setAttachment(EFillAttachment attachment) { m_attachment = attachment; m_attachmentSet = true; }
void setClip(EFillBox b) { m_clip = b; m_clipSet = true; }
void setOrigin(EFillBox b) { m_origin = b; m_originSet = true; }
void setRepeatX(EFillRepeat r) { m_repeatX = r; m_repeatXSet = true; }
void setRepeatY(EFillRepeat r) { m_repeatY = r; m_repeatYSet = true; }
void setComposite(CompositeOperator c) { m_composite = c; m_compositeSet = true; }
+ void setBlendMode(BlendMode b) { m_blendMode = b; m_blendModeSet = true; }
void setSizeType(EFillSizeType b) { m_sizeType = b; }
void setSizeLength(LengthSize l) { m_sizeLength = l; }
void setSize(FillSize f) { m_sizeType = f.type; m_sizeLength = f.size; }
void clearImage() { m_image.clear(); m_imageSet = false; }
- void clearXPosition() { m_xPosSet = false; }
- void clearYPosition() { m_yPosSet = false; }
+ void clearXPosition()
+ {
+ m_xPosSet = false;
+ m_backgroundOriginSet = false;
+ }
+ void clearYPosition()
+ {
+ m_yPosSet = false;
+ m_backgroundOriginSet = false;
+ }
+
void clearAttachment() { m_attachmentSet = false; }
void clearClip() { m_clipSet = false; }
void clearOrigin() { m_originSet = false; }
void clearRepeatX() { m_repeatXSet = false; }
void clearRepeatY() { m_repeatYSet = false; }
void clearComposite() { m_compositeSet = false; }
+ void clearBlendMode() { m_blendModeSet = false; }
void clearSize() { m_sizeType = SizeNone; }
void setNext(FillLayer* n) { if (m_next != n) { delete m_next; m_next = n; } }
@@ -146,6 +164,7 @@ public:
bool hasOpaqueImage(const RenderObject*) const;
bool hasRepeatXY() const;
+ bool clipOccludesNextLayers(bool firstLayer) const;
EFillLayerType type() const { return static_cast<EFillLayerType>(m_type); }
@@ -158,9 +177,10 @@ public:
static EFillRepeat initialFillRepeatX(EFillLayerType) { return RepeatFill; }
static EFillRepeat initialFillRepeatY(EFillLayerType) { return RepeatFill; }
static CompositeOperator initialFillComposite(EFillLayerType) { return CompositeSourceOver; }
- static EFillSizeType initialFillSizeType(EFillLayerType) { return SizeLength; }
+ static BlendMode initialFillBlendMode(EFillLayerType) { return BlendModeNormal; }
+ static EFillSizeType initialFillSizeType(EFillLayerType) { return SizeNone; }
static LengthSize initialFillSizeLength(EFillLayerType) { return LengthSize(); }
- static FillSize initialFillSize(EFillLayerType) { return FillSize(); }
+ static FillSize initialFillSize(EFillLayerType type) { return FillSize(initialFillSizeType(type), initialFillSizeLength(type)); }
static Length initialFillXPosition(EFillLayerType) { return Length(0.0, Percent); }
static Length initialFillYPosition(EFillLayerType) { return Length(0.0, Percent); }
static StyleImage* initialFillImage(EFillLayerType) { return 0; }
@@ -168,6 +188,8 @@ public:
private:
friend class RenderStyle;
+ void computeClipMax() const;
+
FillLayer() { }
FillLayer* m_next;
@@ -186,6 +208,7 @@ private:
unsigned m_repeatY : 3; // EFillRepeat
unsigned m_composite : 4; // CompositeOperator
unsigned m_sizeType : 2; // EFillSizeType
+ unsigned m_blendMode : 5; // BlendMode
unsigned m_imageSet : 1;
unsigned m_attachmentSet : 1;
@@ -195,9 +218,15 @@ private:
unsigned m_repeatYSet : 1;
unsigned m_xPosSet : 1;
unsigned m_yPosSet : 1;
+ unsigned m_backgroundOriginSet : 1;
+ unsigned m_backgroundXOrigin : 2; // BackgroundEdgeOrigin
+ unsigned m_backgroundYOrigin : 2; // BackgroundEdgeOrigin
unsigned m_compositeSet : 1;
+ unsigned m_blendModeSet : 1;
unsigned m_type : 1; // EFillLayerType
+
+ mutable unsigned m_clipMax : 2; // EFillBox, maximum m_clip value from this to bottom layer
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/GridTrackSize.h b/Source/WebCore/rendering/style/GridTrackSize.h
index 1bc1d06a5..72f64a687 100644
--- a/Source/WebCore/rendering/style/GridTrackSize.h
+++ b/Source/WebCore/rendering/style/GridTrackSize.h
@@ -36,40 +36,77 @@
namespace WebCore {
enum GridTrackSizeType {
- LengthTrackSizing
+ LengthTrackSizing,
+ MinMaxTrackSizing
};
class GridTrackSize {
public:
- GridTrackSize()
+ GridTrackSize(LengthType type = Undefined)
: m_type(LengthTrackSizing)
- , m_length(Undefined)
+ , m_minTrackBreadth(type)
+ , m_maxTrackBreadth(type)
{
}
const Length& length() const
{
ASSERT(m_type == LengthTrackSizing);
- ASSERT(!m_length.isUndefined());
- return m_length;
+ ASSERT(!m_minTrackBreadth.isUndefined());
+ ASSERT(m_minTrackBreadth == m_maxTrackBreadth);
+ return m_minTrackBreadth;
}
void setLength(const Length& length)
{
m_type = LengthTrackSizing;
- m_length = length;
+ m_minTrackBreadth = length;
+ m_maxTrackBreadth = length;
+ }
+
+ const Length& minTrackBreadth() const
+ {
+ ASSERT(!m_minTrackBreadth.isUndefined());
+ if (m_minTrackBreadth.isAuto()) {
+ DEFINE_STATIC_LOCAL(Length, minContent, (MinContent));
+ return minContent;
+ }
+ return m_minTrackBreadth;
+ }
+
+ const Length& maxTrackBreadth() const
+ {
+ ASSERT(!m_maxTrackBreadth.isUndefined());
+ if (m_maxTrackBreadth.isAuto()) {
+ DEFINE_STATIC_LOCAL(Length, maxContent, (MaxContent));
+ return maxContent;
+ }
+ return m_maxTrackBreadth;
+ }
+
+ void setMinMax(const Length& minTrackBreadth, const Length& maxTrackBreadth)
+ {
+ m_type = MinMaxTrackSizing;
+ m_minTrackBreadth = minTrackBreadth;
+ m_maxTrackBreadth = maxTrackBreadth;
}
GridTrackSizeType type() const { return m_type; }
bool operator==(const GridTrackSize& other) const
{
- return m_type == other.m_type && m_length == other.m_length;
+ return m_type == other.m_type && m_minTrackBreadth == other.m_minTrackBreadth && m_maxTrackBreadth == other.m_maxTrackBreadth;
}
+ bool hasMinOrMaxContentMinTrackBreadth() const { return minTrackBreadth().isMinContent() || minTrackBreadth().isMaxContent(); }
+ bool hasMaxContentMinTrackBreadth() const { return minTrackBreadth().isMaxContent(); }
+ bool hasMinOrMaxContentMaxTrackBreadth() const { return maxTrackBreadth().isMinContent() || maxTrackBreadth().isMaxContent(); }
+ bool hasMaxContentMaxTrackBreadth() const { return maxTrackBreadth().isMaxContent(); }
+
private:
GridTrackSizeType m_type;
- Length m_length;
+ Length m_minTrackBreadth;
+ Length m_maxTrackBreadth;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/NinePieceImage.cpp b/Source/WebCore/rendering/style/NinePieceImage.cpp
index 18a107e8a..a463d815b 100644
--- a/Source/WebCore/rendering/style/NinePieceImage.cpp
+++ b/Source/WebCore/rendering/style/NinePieceImage.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* (C) 2000 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,16 +26,63 @@
namespace WebCore {
-bool NinePieceImageData::operator==(const NinePieceImageData& o) const
+static DataRef<NinePieceImageData>& defaultData()
{
- return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_imageSlices == o.m_imageSlices && m_fill == o.m_fill
- && m_borderSlices == o.m_borderSlices && m_outset == o.m_outset && m_horizontalRule == o.m_horizontalRule && m_verticalRule == o.m_verticalRule;
+ static DataRef<NinePieceImageData>* data = new DataRef<NinePieceImageData>;
+ if (!data->get())
+ data->init();
+ return *data;
}
-const NinePieceImageData& NinePieceImage::defaultData()
+NinePieceImage::NinePieceImage()
+ : m_data(defaultData())
{
- DEFINE_STATIC_LOCAL(NinePieceImageData, data, ());
- return data;
+}
+
+NinePieceImage::NinePieceImage(PassRefPtr<StyleImage> image, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule horizontalRule, ENinePieceImageRule verticalRule)
+{
+ m_data.init();
+ m_data.access()->image = image;
+ m_data.access()->imageSlices = imageSlices;
+ m_data.access()->borderSlices = borderSlices;
+ m_data.access()->outset = outset;
+ m_data.access()->fill = fill;
+ m_data.access()->horizontalRule = horizontalRule;
+ m_data.access()->verticalRule = verticalRule;
+}
+
+NinePieceImageData::NinePieceImageData()
+ : fill(false)
+ , horizontalRule(StretchImageRule)
+ , verticalRule(StretchImageRule)
+ , image(0)
+ , imageSlices(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent))
+ , borderSlices(Length(1, Relative), Length(1, Relative), Length(1, Relative), Length(1, Relative))
+ , outset(0)
+{
+}
+
+NinePieceImageData::NinePieceImageData(const NinePieceImageData& other)
+ : RefCounted<NinePieceImageData>()
+ , fill(other.fill)
+ , horizontalRule(other.horizontalRule)
+ , verticalRule(other.verticalRule)
+ , image(other.image)
+ , imageSlices(other.imageSlices)
+ , borderSlices(other.borderSlices)
+ , outset(other.outset)
+{
+}
+
+bool NinePieceImageData::operator==(const NinePieceImageData& other) const
+{
+ return StyleImage::imagesEquivalent(image.get(), other.image.get())
+ && imageSlices == other.imageSlices
+ && fill == other.fill
+ && borderSlices == other.borderSlices
+ && outset == other.outset
+ && horizontalRule == other.horizontalRule
+ && verticalRule == other.verticalRule;
}
}
diff --git a/Source/WebCore/rendering/style/NinePieceImage.h b/Source/WebCore/rendering/style/NinePieceImage.h
index fd007cea1..0f3b339ea 100644
--- a/Source/WebCore/rendering/style/NinePieceImage.h
+++ b/Source/WebCore/rendering/style/NinePieceImage.h
@@ -2,7 +2,7 @@
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* (C) 2000 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,6 +24,7 @@
#ifndef NinePieceImage_h
#define NinePieceImage_h
+#include "DataRef.h"
#include "LayoutUnit.h"
#include "LengthBox.h"
#include "StyleImage.h"
@@ -34,149 +35,95 @@ enum ENinePieceImageRule {
StretchImageRule, RoundImageRule, SpaceImageRule, RepeatImageRule
};
-class NinePieceImageData {
- WTF_MAKE_FAST_ALLOCATED;
+class NinePieceImageData : public RefCounted<NinePieceImageData> {
public:
- NinePieceImageData()
- : m_image(0)
- , m_imageSlices(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent))
- , m_borderSlices(Length(1, Relative), Length(1, Relative), Length(1, Relative), Length(1, Relative))
- , m_outset(0)
- , m_fill(false)
- , m_horizontalRule(StretchImageRule)
- , m_verticalRule(StretchImageRule)
- {
- }
-
- NinePieceImageData(PassRefPtr<StyleImage> image, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule h, ENinePieceImageRule v)
- : m_image(image)
- , m_imageSlices(imageSlices)
- , m_borderSlices(borderSlices)
- , m_outset(outset)
- , m_fill(fill)
- , m_horizontalRule(h)
- , m_verticalRule(v)
- {
- }
+ static PassRefPtr<NinePieceImageData> create() { return adoptRef(new NinePieceImageData); }
+ PassRefPtr<NinePieceImageData> copy() const { return adoptRef(new NinePieceImageData(*this)); }
bool operator==(const NinePieceImageData&) const;
bool operator!=(const NinePieceImageData& o) const { return !(*this == o); }
- RefPtr<StyleImage> m_image;
- LengthBox m_imageSlices;
- LengthBox m_borderSlices;
- LengthBox m_outset;
- bool m_fill : 1;
- unsigned m_horizontalRule : 2; // ENinePieceImageRule
- unsigned m_verticalRule : 2; // ENinePieceImageRule
+ bool fill : 1;
+ unsigned horizontalRule : 2; // ENinePieceImageRule
+ unsigned verticalRule : 2; // ENinePieceImageRule
+ RefPtr<StyleImage> image;
+ LengthBox imageSlices;
+ LengthBox borderSlices;
+ LengthBox outset;
+
+private:
+ NinePieceImageData();
+ NinePieceImageData(const NinePieceImageData&);
};
class NinePieceImage {
public:
- NinePieceImage() { }
-
- NinePieceImage(PassRefPtr<StyleImage> image, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule h, ENinePieceImageRule v)
- : m_data(adoptPtr(new NinePieceImageData(image, imageSlices, fill, borderSlices, outset, h, v)))
- { }
+ NinePieceImage();
+ NinePieceImage(PassRefPtr<StyleImage>, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule horizontalRule, ENinePieceImageRule verticalRule);
- NinePieceImage(const NinePieceImage& other)
- {
- *this = other;
- }
-
- void operator=(const NinePieceImage& other)
- {
- if (!other.m_data) {
- m_data.clear();
- return;
- }
- const NinePieceImageData& otherData = other.data();
- m_data = adoptPtr(new NinePieceImageData(otherData.m_image, otherData.m_imageSlices, otherData.m_fill, otherData.m_borderSlices, otherData.m_outset, static_cast<ENinePieceImageRule>(otherData.m_horizontalRule), static_cast<ENinePieceImageRule>(otherData.m_verticalRule)));
- }
-
- bool operator==(const NinePieceImage& other) const { return data() == other.data(); }
- bool operator!=(const NinePieceImage& other) const { return !(*this == other); }
+ bool operator==(const NinePieceImage& other) const { return m_data == other.m_data; }
+ bool operator!=(const NinePieceImage& other) const { return m_data != other.m_data; }
- bool hasImage() const { return m_data && m_data->m_image; }
- StyleImage* image() const { return m_data ? m_data->m_image.get() : 0; }
- void setImage(PassRefPtr<StyleImage> image) { ensureData(); m_data->m_image = image; }
+ bool hasImage() const { return m_data->image; }
+ StyleImage* image() const { return m_data->image.get(); }
+ void setImage(PassRefPtr<StyleImage> image) { m_data.access()->image = image; }
- const LengthBox& imageSlices() const { return data().m_imageSlices; }
- void setImageSlices(const LengthBox& slices) { ensureData(); m_data->m_imageSlices = slices; }
+ const LengthBox& imageSlices() const { return m_data->imageSlices; }
+ void setImageSlices(const LengthBox& slices) { m_data.access()->imageSlices = slices; }
- bool fill() const { return data().m_fill; }
- void setFill(bool fill) { ensureData(); m_data->m_fill = fill; }
+ bool fill() const { return m_data->fill; }
+ void setFill(bool fill) { m_data.access()->fill = fill; }
- const LengthBox& borderSlices() const { return data().m_borderSlices; }
- void setBorderSlices(const LengthBox& slices) { ensureData(); m_data->m_borderSlices = slices; }
+ const LengthBox& borderSlices() const { return m_data->borderSlices; }
+ void setBorderSlices(const LengthBox& slices) { m_data.access()->borderSlices = slices; }
- const LengthBox& outset() const { return data().m_outset; }
- void setOutset(const LengthBox& outset) { ensureData(); m_data->m_outset = outset; }
-
- static LayoutUnit computeOutset(Length outsetSide, LayoutUnit borderSide)
- {
- if (outsetSide.isRelative())
- return outsetSide.value() * borderSide;
- return outsetSide.value();
- }
+ const LengthBox& outset() const { return m_data->outset; }
+ void setOutset(const LengthBox& outset) { m_data.access()->outset = outset; }
- ENinePieceImageRule horizontalRule() const { return static_cast<ENinePieceImageRule>(data().m_horizontalRule); }
- void setHorizontalRule(ENinePieceImageRule rule) { ensureData(); m_data->m_horizontalRule = rule; }
+ ENinePieceImageRule horizontalRule() const { return static_cast<ENinePieceImageRule>(m_data->horizontalRule); }
+ void setHorizontalRule(ENinePieceImageRule rule) { m_data.access()->horizontalRule = rule; }
- ENinePieceImageRule verticalRule() const { return static_cast<ENinePieceImageRule>(data().m_verticalRule); }
- void setVerticalRule(ENinePieceImageRule rule) { ensureData(); m_data->m_verticalRule = rule; }
+ ENinePieceImageRule verticalRule() const { return static_cast<ENinePieceImageRule>(m_data->verticalRule); }
+ void setVerticalRule(ENinePieceImageRule rule) { m_data.access()->verticalRule = rule; }
void copyImageSlicesFrom(const NinePieceImage& other)
{
- ensureData();
- m_data->m_imageSlices = other.data().m_imageSlices;
- m_data->m_fill = other.data().m_fill;
+ m_data.access()->imageSlices = other.m_data->imageSlices;
+ m_data.access()->fill = other.m_data->fill;
}
void copyBorderSlicesFrom(const NinePieceImage& other)
{
- ensureData();
- m_data->m_borderSlices = other.data().m_borderSlices;
+ m_data.access()->borderSlices = other.m_data->borderSlices;
}
void copyOutsetFrom(const NinePieceImage& other)
{
- ensureData();
- m_data->m_outset = other.data().m_outset;
+ m_data.access()->outset = other.m_data->outset;
}
void copyRepeatFrom(const NinePieceImage& other)
{
- ensureData();
- m_data->m_horizontalRule = other.data().m_horizontalRule;
- m_data->m_verticalRule = other.data().m_verticalRule;
+ m_data.access()->horizontalRule = other.m_data->horizontalRule;
+ m_data.access()->verticalRule = other.m_data->verticalRule;
}
void setMaskDefaults()
{
- ensureData();
- m_data->m_imageSlices = LengthBox(0);
- m_data->m_fill = true;
- m_data->m_borderSlices = LengthBox();
+ m_data.access()->imageSlices = LengthBox(0);
+ m_data.access()->fill = true;
+ m_data.access()->borderSlices = LengthBox();
}
-private:
- static const NinePieceImageData& defaultData();
-
- void ensureData()
- {
- if (!m_data)
- m_data = adoptPtr(new NinePieceImageData);
- }
-
- const NinePieceImageData& data() const
+ static LayoutUnit computeOutset(Length outsetSide, LayoutUnit borderSide)
{
- if (m_data)
- return *m_data;
- return defaultData();
+ if (outsetSide.isRelative())
+ return outsetSide.value() * borderSide;
+ return outsetSide.value();
}
- OwnPtr<NinePieceImageData> m_data;
+private:
+ DataRef<NinePieceImageData> m_data;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/QuotesData.cpp b/Source/WebCore/rendering/style/QuotesData.cpp
index a6a7c5ef2..cab873956 100644
--- a/Source/WebCore/rendering/style/QuotesData.cpp
+++ b/Source/WebCore/rendering/style/QuotesData.cpp
@@ -24,53 +24,63 @@
namespace WebCore {
-PassRefPtr<QuotesData> QuotesData::create(String open, String close)
+static size_t sizeForQuotesDataWithQuoteCount(unsigned count)
{
- RefPtr<QuotesData> data = QuotesData::create();
- data->addPair(std::make_pair(open, close));
- return data;
+ return sizeof(QuotesData) + sizeof(std::pair<String, String>) * count;
}
-PassRefPtr<QuotesData> QuotesData::create(String open1, String close1, String open2, String close2)
+PassRefPtr<QuotesData> QuotesData::create(const Vector<std::pair<String, String> >& quotes)
{
- RefPtr<QuotesData> data = QuotesData::create();
- data->addPair(std::make_pair(open1, close1));
- data->addPair(std::make_pair(open2, close2));
- return data;
+ void* slot = fastMalloc(sizeForQuotesDataWithQuoteCount(quotes.size()));
+ return adoptRef(new (NotNull, slot) QuotesData(quotes));
}
-void QuotesData::addPair(std::pair<String, String> quotePair)
+QuotesData::QuotesData(const Vector<std::pair<String, String> >& quotes)
+ : m_quoteCount(quotes.size())
{
- m_quotePairs.append(quotePair);
+ for (unsigned i = 0; i < m_quoteCount; ++i)
+ new (NotNull, &m_quotePairs[i]) std::pair<String, String>(quotes[i]);
}
-const String QuotesData::getOpenQuote(int index) const
+QuotesData::~QuotesData()
{
- ASSERT(index >= 0);
- if (!m_quotePairs.size() || index < 0)
+ for (unsigned i = 0; i < m_quoteCount; ++i)
+ m_quotePairs[i].~pair<String, String>();
+}
+
+const String& QuotesData::openQuote(unsigned index) const
+{
+ if (!m_quoteCount)
return emptyString();
- if ((size_t)index >= m_quotePairs.size())
- return m_quotePairs.last().first;
- return m_quotePairs.at(index).first;
+
+ if (index >= m_quoteCount)
+ return m_quotePairs[m_quoteCount - 1].first;
+
+ return m_quotePairs[index].first;
}
-const String QuotesData::getCloseQuote(int index) const
+const String& QuotesData::closeQuote(unsigned index) const
{
- ASSERT(index >= -1);
- if (!m_quotePairs.size() || index < 0)
+ if (!m_quoteCount)
return emptyString();
- if ((size_t)index >= m_quotePairs.size())
- return m_quotePairs.last().second;
- return m_quotePairs.at(index).second;
+
+ if (index >= m_quoteCount)
+ return m_quotePairs[m_quoteCount - 1].second;
+
+ return m_quotePairs[index].second;
}
-bool QuotesData::equals(const QuotesData* a, const QuotesData* b)
+bool operator==(const QuotesData& a, const QuotesData& b)
{
- if (a == b)
- return true;
- if (!a || !b)
+ if (a.m_quoteCount != b.m_quoteCount)
return false;
- return a->m_quotePairs == b->m_quotePairs;
+
+ for (unsigned i = 0; i < a.m_quoteCount; ++i) {
+ if (a.m_quotePairs[i] != b.m_quotePairs[i])
+ return false;
+ }
+
+ return true;
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/QuotesData.h b/Source/WebCore/rendering/style/QuotesData.h
index 5699f3245..df84d62ae 100644
--- a/Source/WebCore/rendering/style/QuotesData.h
+++ b/Source/WebCore/rendering/style/QuotesData.h
@@ -29,25 +29,37 @@
namespace WebCore {
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
+#endif
+
class QuotesData : public RefCounted<QuotesData> {
public:
- static PassRefPtr<QuotesData> create() { return adoptRef(new QuotesData()); }
- static PassRefPtr<QuotesData> create(const String open, const String close);
- static PassRefPtr<QuotesData> create(const String open1, const String close1, const String open2, const String close2);
+ static PassRefPtr<QuotesData> create(const Vector<std::pair<String, String> >& quotes);
+ ~QuotesData();
- // FIXME: this should be an operator==.
- static bool equals(const QuotesData*, const QuotesData*);
+ friend bool operator==(const QuotesData&, const QuotesData&);
- void addPair(const std::pair<String, String> quotePair);
- const String getOpenQuote(int index) const;
- const String getCloseQuote(int index) const;
+ const String& openQuote(unsigned index) const;
+ const String& closeQuote(unsigned index) const;
private:
- QuotesData() { }
+ explicit QuotesData(const Vector<std::pair<String, String> >& quotes);
- Vector<std::pair<String, String> > m_quotePairs;
+ unsigned m_quoteCount;
+ std::pair<String, String> m_quotePairs[0];
};
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+inline bool operator!=(const QuotesData& a, const QuotesData& b)
+{
+ return !(a == b);
+}
+
} // namespace WebCore
#endif // QuotesData_h
diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp
index 653f30fdf..3e5590c09 100644
--- a/Source/WebCore/rendering/style/RenderStyle.cpp
+++ b/Source/WebCore/rendering/style/RenderStyle.cpp
@@ -28,6 +28,7 @@
#include "CSSPropertyNames.h"
#include "Font.h"
#include "FontSelector.h"
+#include "Pagination.h"
#include "QuotesData.h"
#include "RenderArena.h"
#include "RenderObject.h"
@@ -39,9 +40,7 @@
#if ENABLE(TOUCH_EVENTS)
#include "RenderTheme.h"
#endif
-#include "WebCoreMemoryInstrumentation.h"
-#include <wtf/MemoryInstrumentationVector.h>
-#include <wtf/MemoryObjectInfo.h>
+#include <wtf/MathExtras.h>
#include <wtf/StdLibExtras.h>
#include <algorithm>
@@ -260,6 +259,20 @@ void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
noninherited_flags._pseudoBits |= pseudoBit(pseudo);
}
+bool RenderStyle::hasUniquePseudoStyle() const
+{
+ if (!m_cachedPseudoStyles || styleType() != NOPSEUDO)
+ return false;
+
+ for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
+ RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
+ if (pseudoStyle->unique())
+ return true;
+ }
+
+ return false;
+}
+
RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
{
if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
@@ -328,7 +341,7 @@ bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
&& rareInheritedData.get() == other->rareInheritedData.get();
}
-static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
+static bool positionChangeIsMovementOnly(const LengthBox& a, const LengthBox& b, const Length& width)
{
// If any unit types are different, then we can't guarantee
// that this was just a movement.
@@ -345,44 +358,37 @@ static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
return false;
if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
return false;
+ // If our width is auto and left or right is specified then this
+ // is not just a movement - we need to resize to our container.
+ if ((!a.left().isIntrinsicOrAuto() || !a.right().isIntrinsicOrAuto()) && width.isIntrinsicOrAuto())
+ return false;
// One of the units is fixed or percent in both directions and stayed
// that way in the new style. Therefore all we are doing is moving.
return true;
}
-StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
+bool RenderStyle::changeRequiresLayout(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
{
- changedContextSensitiveProperties = ContextSensitivePropertyNone;
-
-#if ENABLE(SVG)
- StyleDifference svgChange = StyleDifferenceEqual;
- if (m_svgStyle != other->m_svgStyle) {
- svgChange = m_svgStyle->diff(other->m_svgStyle.get());
- if (svgChange == StyleDifferenceLayout)
- return svgChange;
- }
-#endif
-
if (m_box->width() != other->m_box->width()
|| m_box->minWidth() != other->m_box->minWidth()
|| m_box->maxWidth() != other->m_box->maxWidth()
|| m_box->height() != other->m_box->height()
|| m_box->minHeight() != other->m_box->minHeight()
|| m_box->maxHeight() != other->m_box->maxHeight())
- return StyleDifferenceLayout;
+ return true;
if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
- return StyleDifferenceLayout;
+ return true;
if (m_box->boxSizing() != other->m_box->boxSizing())
- return StyleDifferenceLayout;
+ return true;
if (surround->margin != other->surround->margin)
- return StyleDifferenceLayout;
+ return true;
if (surround->padding != other->surround->padding)
- return StyleDifferenceLayout;
+ return true;
if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance
@@ -390,41 +396,41 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse
|| rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp
|| rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
- return StyleDifferenceLayout;
+ return true;
- if (rareNonInheritedData->m_regionOverflow != other->rareNonInheritedData->m_regionOverflow)
- return StyleDifferenceLayout;
+ if (rareNonInheritedData->m_regionFragment != other->rareNonInheritedData->m_regionFragment)
+ return true;
if (rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow
|| rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough
|| rareNonInheritedData->m_shapeMargin != other->rareNonInheritedData->m_shapeMargin
|| rareNonInheritedData->m_shapePadding != other->rareNonInheritedData->m_shapePadding)
- return StyleDifferenceLayout;
+ return true;
if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get()
&& *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other->rareNonInheritedData->m_deprecatedFlexibleBox.get())
- return StyleDifferenceLayout;
+ return true;
if (rareNonInheritedData->m_flexibleBox.get() != other->rareNonInheritedData->m_flexibleBox.get()
&& *rareNonInheritedData->m_flexibleBox.get() != *other->rareNonInheritedData->m_flexibleBox.get())
- return StyleDifferenceLayout;
+ return true;
if (rareNonInheritedData->m_order != other->rareNonInheritedData->m_order
|| rareNonInheritedData->m_alignContent != other->rareNonInheritedData->m_alignContent
|| rareNonInheritedData->m_alignItems != other->rareNonInheritedData->m_alignItems
|| rareNonInheritedData->m_alignSelf != other->rareNonInheritedData->m_alignSelf
|| rareNonInheritedData->m_justifyContent != other->rareNonInheritedData->m_justifyContent)
- return StyleDifferenceLayout;
+ return true;
// FIXME: We should add an optimized form of layout that just recomputes visual overflow.
if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
- return StyleDifferenceLayout;
+ return true;
if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
- return StyleDifferenceLayout;
+ return true;
if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get()
&& *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
- return StyleDifferenceLayout;
+ return true;
if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get()
&& *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) {
@@ -432,13 +438,13 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
changedContextSensitiveProperties |= ContextSensitivePropertyTransform;
// Don't return; keep looking for another change
#else
- return StyleDifferenceLayout;
+ return true;
#endif
}
if (rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get()
- && rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get())
- return StyleDifferenceLayout;
+ || rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get())
+ return true;
#if !USE(ACCELERATED_COMPOSITING)
if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
@@ -447,27 +453,29 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
|| rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
|| rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
- return StyleDifferenceLayout;
+ return true;
}
#endif
#if ENABLE(DASHBOARD_SUPPORT)
// If regions change, trigger a relayout to re-calc regions.
if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions)
- return StyleDifferenceLayout;
+ return true;
#endif
-#if ENABLE(CSS_EXCLUSIONS)
+#if ENABLE(CSS_SHAPES)
if (rareNonInheritedData->m_shapeInside != other->rareNonInheritedData->m_shapeInside)
- return StyleDifferenceLayout;
+ return true;
#endif
}
if (rareInheritedData.get() != other->rareInheritedData.get()) {
if (rareInheritedData->highlight != other->rareInheritedData->highlight
|| rareInheritedData->indent != other->rareInheritedData->indent
+#if ENABLE(CSS3_TEXT)
+ || rareInheritedData->m_textIndentLine != other->rareInheritedData->m_textIndentLine
+#endif
|| rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom
- || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust
|| rareInheritedData->wordBreak != other->rareInheritedData->wordBreak
|| rareInheritedData->overflowWrap != other->rareInheritedData->overflowWrap
|| rareInheritedData->nbspMode != other->rareInheritedData->nbspMode
@@ -482,6 +490,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark
|| rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition
|| rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark
+ || rareInheritedData->m_textOrientation != other->rareInheritedData->m_textOrientation
|| rareInheritedData->m_tabSize != other->rareInheritedData->m_tabSize
|| rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain
|| rareInheritedData->m_lineGrid != other->rareInheritedData->m_lineGrid
@@ -493,18 +502,18 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| rareInheritedData->m_lineSnap != other->rareInheritedData->m_lineSnap
|| rareInheritedData->m_lineAlign != other->rareInheritedData->m_lineAlign
|| rareInheritedData->listStyleImage != other->rareInheritedData->listStyleImage)
- return StyleDifferenceLayout;
+ return true;
if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
- return StyleDifferenceLayout;
+ return true;
if (textStrokeWidth() != other->textStrokeWidth())
- return StyleDifferenceLayout;
+ return true;
}
#if ENABLE(TEXT_AUTOSIZING)
if (visual->m_textAutosizingMultiplier != other->visual->m_textAutosizingMultiplier)
- return StyleDifferenceLayout;
+ return true;
#endif
if (inherited->line_height != other->inherited->line_height
@@ -516,7 +525,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| noninherited_flags._position != other->noninherited_flags._position
|| noninherited_flags._floating != other->noninherited_flags._floating
|| noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay)
- return StyleDifferenceLayout;
+ return true;
if (((int)noninherited_flags._effectiveDisplay) >= TABLE) {
@@ -524,7 +533,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| inherited_flags._empty_cells != other->inherited_flags._empty_cells
|| inherited_flags._caption_side != other->inherited_flags._caption_side
|| noninherited_flags._table_layout != other->noninherited_flags._table_layout)
- return StyleDifferenceLayout;
+ return true;
// In the collapsing border model, 'hidden' suppresses other borders, while 'none'
// does not, so these style differences can be width differences.
@@ -537,13 +546,13 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN)
|| (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE)
|| (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)))
- return StyleDifferenceLayout;
+ return true;
}
if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
if (inherited_flags._list_style_type != other->inherited_flags._list_style_type
|| inherited_flags._list_style_position != other->inherited_flags._list_style_position)
- return StyleDifferenceLayout;
+ return true;
}
if (inherited_flags._text_align != other->inherited_flags._text_align
@@ -552,20 +561,20 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| inherited_flags._white_space != other->inherited_flags._white_space
|| noninherited_flags._clear != other->noninherited_flags._clear
|| noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi)
- return StyleDifferenceLayout;
+ return true;
// Check block flow direction.
if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode)
- return StyleDifferenceLayout;
+ return true;
// Check text combine mode.
if (rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine)
- return StyleDifferenceLayout;
+ return true;
// Overflow returns a layout hint.
if (noninherited_flags._overflowX != other->noninherited_flags._overflowX
|| noninherited_flags._overflowY != other->noninherited_flags._overflowY)
- return StyleDifferenceLayout;
+ return true;
// If our border widths change, then we need to layout. Other changes to borders
// only necessitate a repaint.
@@ -573,16 +582,16 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| borderTopWidth() != other->borderTopWidth()
|| borderBottomWidth() != other->borderBottomWidth()
|| borderRightWidth() != other->borderRightWidth())
- return StyleDifferenceLayout;
+ return true;
// If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
- return StyleDifferenceLayout;
+ return true;
if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
- return StyleDifferenceLayout;
+ return true;
if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1)
|| (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
@@ -591,41 +600,58 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
// to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
// In addition we need to solve the floating object issue when layers come and go. Right now
// a full layout is necessary to keep floating object lists sane.
- return StyleDifferenceLayout;
+ return true;
}
- if (!QuotesData::equals(rareInheritedData->quotes.get(), other->rareInheritedData->quotes.get()))
- return StyleDifferenceLayout;
-
-#if ENABLE(SVG)
- // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
- // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint,
- // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches
- // that are relevant for SVG and might return StyleDifferenceLayout.
- if (svgChange != StyleDifferenceEqual)
- return svgChange;
-#endif
+ const QuotesData* quotesDataA = rareInheritedData->quotes.get();
+ const QuotesData* quotesDataB = other->rareInheritedData->quotes.get();
+ if (!(quotesDataA == quotesDataB || (quotesDataA && quotesDataB && *quotesDataA == *quotesDataB)))
+ return true;
- // Make sure these left/top/right/bottom checks stay below all layout checks and above
- // all visible checks.
if (position() != StaticPosition) {
if (surround->offset != other->surround->offset) {
- // Optimize for the case where a positioned layer is moving but not changing size.
- if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
- return StyleDifferenceLayoutPositionedMovementOnly;
-
// FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
// We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
// to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
- return StyleDifferenceLayout;
- } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex()
- || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
- return StyleDifferenceRepaintLayer;
+ if (position() != AbsolutePosition)
+ return true;
+
+ // Optimize for the case where a positioned layer is moving but not changing size.
+ if (!positionChangeIsMovementOnly(surround->offset, other->surround->offset, m_box->width()))
+ return true;
+ }
}
+ return false;
+}
+
+bool RenderStyle::changeRequiresPositionedLayoutOnly(const RenderStyle* other, unsigned&) const
+{
+ if (position() == StaticPosition)
+ return false;
+
+ if (surround->offset != other->surround->offset) {
+ // Optimize for the case where a positioned layer is moving but not changing size.
+ if (position() == AbsolutePosition && positionChangeIsMovementOnly(surround->offset, other->surround->offset, m_box->width()))
+ return true;
+ }
+
+ return false;
+}
+
+bool RenderStyle::changeRequiresLayerRepaint(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
+{
+ if (position() != StaticPosition) {
+ if (m_box->zIndex() != other->m_box->zIndex()
+ || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex()
+ || visual->clip != other->visual->clip
+ || visual->hasClip != other->visual->hasClip)
+ return true;
+ }
+
#if ENABLE(CSS_COMPOSITING)
if (rareNonInheritedData->m_effectiveBlendMode != other->rareNonInheritedData->m_effectiveBlendMode)
- return StyleDifferenceRepaintLayer;
+ return true;
#endif
if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) {
@@ -633,7 +659,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
changedContextSensitiveProperties |= ContextSensitivePropertyOpacity;
// Don't return; keep looking for another change.
#else
- return StyleDifferenceRepaintLayer;
+ return true;
#endif
}
@@ -644,49 +670,66 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
changedContextSensitiveProperties |= ContextSensitivePropertyFilter;
// Don't return; keep looking for another change.
#else
- return StyleDifferenceRepaintLayer;
+ return true;
#endif
}
#endif
if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask
|| rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
- return StyleDifferenceRepaintLayer;
+ return true;
- if (inherited->color != other->inherited->color
- || inherited_flags._visibility != other->inherited_flags._visibility
- || inherited_flags._text_decorations != other->inherited_flags._text_decorations
+ return false;
+}
+
+bool RenderStyle::changeRequiresRepaint(const RenderStyle* other, unsigned&) const
+{
+ if (inherited_flags._visibility != other->inherited_flags._visibility
|| inherited_flags.m_printColorAdjust != other->inherited_flags.m_printColorAdjust
|| inherited_flags._insideLink != other->inherited_flags._insideLink
|| surround->border != other->surround->border
- || *m_background.get() != *other->m_background.get()
- || visual->textDecoration != other->visual->textDecoration
+ || !m_background->isEquivalentForPainting(*other->m_background)
|| rareInheritedData->userModify != other->rareInheritedData->userModify
|| rareInheritedData->userSelect != other->rareInheritedData->userSelect
|| rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag
|| rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit
+ || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering)
+ return true;
+
+ // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected
+ // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout
+ // the parent container. For sure, I will have to revisit this code, but for now I've added this in order
+ // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ.
+ // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991
+ if (rareNonInheritedData->m_shapeOutside != other->rareNonInheritedData->m_shapeOutside)
+ return true;
+
+ if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath)
+ return true;
+
+ return false;
+}
+
+bool RenderStyle::changeRequiresRepaintIfText(const RenderStyle* other, unsigned&) const
+{
+ if (inherited->color != other->inherited->color
+ || inherited_flags._text_decorations != other->inherited_flags._text_decorations
+ || visual->textDecoration != other->visual->textDecoration
#if ENABLE(CSS3_TEXT)
|| rareNonInheritedData->m_textDecorationStyle != other->rareNonInheritedData->m_textDecorationStyle
+ || rareNonInheritedData->m_textDecorationColor != other->rareNonInheritedData->m_textDecorationColor
#endif // CSS3_TEXT
|| rareInheritedData->textFillColor != other->rareInheritedData->textFillColor
|| rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor
|| rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor
- || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill
- || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering)
- return StyleDifferenceRepaint;
-
- // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected
- // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout
- // the parent container. For sure, I will have to revisit this code, but for now I've added this in order
- // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ.
- // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991
- if (rareNonInheritedData->m_shapeOutside != other->rareNonInheritedData->m_shapeOutside)
- return StyleDifferenceRepaint;
-
- if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath)
- return StyleDifferenceRepaint;
+ || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill)
+ return true;
+ return false;
+}
+bool RenderStyle::changeRequiresRecompositeLayer(const RenderStyle* other, unsigned&) const
+{
#if USE(ACCELERATED_COMPOSITING)
if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D
@@ -694,9 +737,53 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
|| rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
|| rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
|| rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
- return StyleDifferenceRecompositeLayer;
+ return true;
}
#endif
+ return false;
+}
+
+StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
+{
+ changedContextSensitiveProperties = ContextSensitivePropertyNone;
+
+#if ENABLE(SVG)
+ StyleDifference svgChange = StyleDifferenceEqual;
+ if (m_svgStyle != other->m_svgStyle) {
+ svgChange = m_svgStyle->diff(other->m_svgStyle.get());
+ if (svgChange == StyleDifferenceLayout)
+ return svgChange;
+ }
+#endif
+
+ if (changeRequiresLayout(other, changedContextSensitiveProperties))
+ return StyleDifferenceLayout;
+
+#if ENABLE(SVG)
+ // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
+ // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint,
+ // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches
+ // that are relevant for SVG and might return StyleDifferenceLayout.
+ if (svgChange != StyleDifferenceEqual)
+ return svgChange;
+#endif
+
+ if (changeRequiresPositionedLayoutOnly(other, changedContextSensitiveProperties))
+ return StyleDifferenceLayoutPositionedMovementOnly;
+
+ if (changeRequiresLayerRepaint(other, changedContextSensitiveProperties))
+ return StyleDifferenceRepaintLayer;
+
+ if (changeRequiresRepaint(other, changedContextSensitiveProperties))
+ return StyleDifferenceRepaint;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (changeRequiresRecompositeLayer(other, changedContextSensitiveProperties))
+ return StyleDifferenceRecompositeLayer;
+#endif
+
+ if (changeRequiresRepaintIfText(other, changedContextSensitiveProperties))
+ return StyleDifferenceRepaintIfText;
// Cursors are not checked, since they will be set appropriately in response to mouse events,
// so they don't need to cause any repaint or layout.
@@ -706,6 +793,12 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
return StyleDifferenceEqual;
}
+bool RenderStyle::diffRequiresRepaint(const RenderStyle* style) const
+{
+ unsigned changedContextSensitiveProperties = 0;
+ return changeRequiresRepaint(style, changedContextSensitiveProperties);
+}
+
void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
{
StyleVisualData* data = visual.access();
@@ -729,8 +822,9 @@ void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
{
- if (QuotesData::equals(rareInheritedData->quotes.get(), q.get()))
+ if (rareInheritedData->quotes == q || (rareInheritedData->quotes && q && *rareInheritedData->quotes == *q))
return;
+
rareInheritedData.access()->quotes = q;
}
@@ -975,13 +1069,13 @@ void RenderStyle::setListStyleImage(PassRefPtr<StyleImage> v)
Color RenderStyle::color() const { return inherited->color; }
Color RenderStyle::visitedLinkColor() const { return inherited->visitedLinkColor; }
-void RenderStyle::setColor(const Color& v) { SET_VAR(inherited, color, v) };
-void RenderStyle::setVisitedLinkColor(const Color& v) { SET_VAR(inherited, visitedLinkColor, v) }
+void RenderStyle::setColor(const Color& v) { SET_VAR(inherited, color, v); }
+void RenderStyle::setVisitedLinkColor(const Color& v) { SET_VAR(inherited, visitedLinkColor, v); }
short RenderStyle::horizontalBorderSpacing() const { return inherited->horizontal_border_spacing; }
short RenderStyle::verticalBorderSpacing() const { return inherited->vertical_border_spacing; }
-void RenderStyle::setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v) }
-void RenderStyle::setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v) }
+void RenderStyle::setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v); }
+void RenderStyle::setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v); }
RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, RenderView* renderView, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
{
@@ -999,16 +1093,16 @@ RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
{
bool horizontal = isHorizontalWritingMode();
- LayoutUnit leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
- LayoutUnit rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
- LayoutUnit topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
- LayoutUnit bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
+ int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
+ int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
+ int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
+ int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge);
}
RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
- LayoutUnit topWidth, LayoutUnit bottomWidth, LayoutUnit leftWidth, LayoutUnit rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
+ int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
{
LayoutRect innerRect(borderRect.x() + leftWidth,
borderRect.y() + topWidth,
@@ -1025,6 +1119,21 @@ RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
return roundedRect;
}
+static bool allLayersAreFixed(const FillLayer* layer)
+{
+ bool allFixed = true;
+
+ for (const FillLayer* currLayer = layer; currLayer; currLayer = currLayer->next())
+ allFixed &= (currLayer->image() && currLayer->attachment() == FixedBackgroundAttachment);
+
+ return layer && allFixed;
+}
+
+bool RenderStyle::hasEntirelyFixedBackground() const
+{
+ return allLayersAreFixed(backgroundLayers());
+}
+
const CounterDirectiveMap* RenderStyle::counterDirectives() const
{
return rareNonInheritedData->m_counterDirectives.get();
@@ -1273,6 +1382,12 @@ void RenderStyle::setFontSize(float size)
// size must be specifiedSize if Text Autosizing is enabled, but computedSize if text
// zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
+ ASSERT(std::isfinite(size));
+ if (!std::isfinite(size) || size < 0)
+ size = 0;
+ else
+ size = min(maximumAllowedFontSize, size);
+
FontSelector* currentFontSelector = font().fontSelector();
FontDescription desc(fontDescription());
desc.setSpecifiedSize(size);
@@ -1281,7 +1396,8 @@ void RenderStyle::setFontSize(float size)
#if ENABLE(TEXT_AUTOSIZING)
float multiplier = textAutosizingMultiplier();
if (multiplier > 1) {
- desc.setComputedSize(TextAutosizer::computeAutosizedFontSize(size, multiplier));
+ float autosizedFontSize = TextAutosizer::computeAutosizedFontSize(size, multiplier);
+ desc.setComputedSize(min(maximumAllowedFontSize, autosizedFontSize));
}
#endif
@@ -1299,12 +1415,12 @@ void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit &top, Lay
for ( ; shadow; shadow = shadow->next()) {
if (shadow->style() == Inset)
continue;
- int blurAndSpread = shadow->blur() + shadow->spread();
- top = min<LayoutUnit>(top, shadow->y() - blurAndSpread);
- right = max<LayoutUnit>(right, shadow->x() + blurAndSpread);
- bottom = max<LayoutUnit>(bottom, shadow->y() + blurAndSpread);
- left = min<LayoutUnit>(left, shadow->x() - blurAndSpread);
+ int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+ top = min<LayoutUnit>(top, shadow->y() - extentAndSpread);
+ right = max<LayoutUnit>(right, shadow->x() + extentAndSpread);
+ bottom = max<LayoutUnit>(bottom, shadow->y() + extentAndSpread);
+ left = min<LayoutUnit>(left, shadow->x() - extentAndSpread);
}
}
@@ -1318,11 +1434,12 @@ LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowData* shadow) cons
for ( ; shadow; shadow = shadow->next()) {
if (shadow->style() == Normal)
continue;
- int blurAndSpread = shadow->blur() + shadow->spread();
- top = max<LayoutUnit>(top, shadow->y() + blurAndSpread);
- right = min<LayoutUnit>(right, shadow->x() - blurAndSpread);
- bottom = min<LayoutUnit>(bottom, shadow->y() - blurAndSpread);
- left = max<LayoutUnit>(left, shadow->x() + blurAndSpread);
+
+ int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+ top = max<LayoutUnit>(top, shadow->y() + extentAndSpread);
+ right = min<LayoutUnit>(right, shadow->x() - extentAndSpread);
+ bottom = min<LayoutUnit>(bottom, shadow->y() - extentAndSpread);
+ left = max<LayoutUnit>(left, shadow->x() + extentAndSpread);
}
return LayoutBoxExtent(top, right, bottom, left);
@@ -1336,10 +1453,10 @@ void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit
for ( ; shadow; shadow = shadow->next()) {
if (shadow->style() == Inset)
continue;
- int blurAndSpread = shadow->blur() + shadow->spread();
- left = min<LayoutUnit>(left, shadow->x() - blurAndSpread);
- right = max<LayoutUnit>(right, shadow->x() + blurAndSpread);
+ int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+ left = min<LayoutUnit>(left, shadow->x() - extentAndSpread);
+ right = max<LayoutUnit>(right, shadow->x() + extentAndSpread);
}
}
@@ -1351,10 +1468,10 @@ void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit &
for ( ; shadow; shadow = shadow->next()) {
if (shadow->style() == Inset)
continue;
- int blurAndSpread = shadow->blur() + shadow->spread();
- top = min<LayoutUnit>(top, shadow->y() - blurAndSpread);
- bottom = max<LayoutUnit>(bottom, shadow->y() + blurAndSpread);
+ int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+ top = min<LayoutUnit>(top, shadow->y() - extentAndSpread);
+ bottom = max<LayoutUnit>(bottom, shadow->y() + extentAndSpread);
}
}
@@ -1390,6 +1507,11 @@ Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) c
case CSSPropertyWebkitColumnRuleColor:
result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor();
break;
+#if ENABLE(CSS3_TEXT)
+ case CSSPropertyWebkitTextDecorationColor:
+ // Text decoration color fallback is handled in RenderObject::decorationColor.
+ return visitedLink ? visitedLinkTextDecorationColor() : textDecorationColor();
+#endif // CSS3_TEXT
case CSSPropertyWebkitTextEmphasisColor:
result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor();
break;
@@ -1421,6 +1543,12 @@ Color RenderStyle::visitedDependentColor(int colorProperty) const
Color visitedColor = colorIncludingFallback(colorProperty, true);
+#if ENABLE(CSS3_TEXT)
+ // Text decoration color validity is preserved (checked in RenderObject::decorationColor).
+ if (colorProperty == CSSPropertyWebkitTextDecorationColor)
+ return visitedColor;
+#endif // CSS3_TEXT
+
// FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just
// assume that if the background color is transparent that it wasn't set. Note that it's weird that
// we're returning unvisited info for a visited link, but given our restriction that the alpha values
@@ -1582,23 +1710,78 @@ LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const
NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth()));
}
-void RenderStyle::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
- info.addMember(m_box);
- info.addMember(visual);
- // FIXME: m_background contains RefPtr<StyleImage> that might need to be instrumented.
- info.addMember(m_background);
- // FIXME: surrond contains some fields e.g. BorderData that might need to be instrumented.
- info.addMember(surround);
- info.addMember(rareNonInheritedData);
- info.addMember(rareInheritedData);
- // FIXME: inherited contains StyleImage and Font fields that might need to be instrumented.
- info.addMember(inherited);
- info.addMember(m_cachedPseudoStyles);
-#if ENABLE(SVG)
- info.addMember(m_svgStyle);
-#endif
+void RenderStyle::setBorderImageSource(PassRefPtr<StyleImage> image)
+{
+ if (surround->border.m_image.image() == image.get())
+ return;
+ surround.access()->border.m_image.setImage(image);
+}
+
+void RenderStyle::setBorderImageSlices(LengthBox slices)
+{
+ if (surround->border.m_image.imageSlices() == slices)
+ return;
+ surround.access()->border.m_image.setImageSlices(slices);
+}
+
+void RenderStyle::setBorderImageWidth(LengthBox slices)
+{
+ if (surround->border.m_image.borderSlices() == slices)
+ return;
+ surround.access()->border.m_image.setBorderSlices(slices);
+}
+
+void RenderStyle::setBorderImageOutset(LengthBox outset)
+{
+ if (surround->border.m_image.outset() == outset)
+ return;
+ surround.access()->border.m_image.setOutset(outset);
+}
+
+ShapeValue* RenderStyle::initialShapeInside()
+{
+ DEFINE_STATIC_LOCAL(RefPtr<ShapeValue>, sOutsideValue, (ShapeValue::createOutsideValue()));
+ return sOutsideValue.get();
+}
+
+void RenderStyle::setColumnStylesFromPaginationMode(const Pagination::Mode& paginationMode)
+{
+ if (paginationMode == Pagination::Unpaginated)
+ return;
+
+ switch (paginationMode) {
+ case Pagination::LeftToRightPaginated:
+ setColumnAxis(HorizontalColumnAxis);
+ if (isHorizontalWritingMode())
+ setColumnProgression(isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression);
+ else
+ setColumnProgression(isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression);
+ break;
+ case Pagination::RightToLeftPaginated:
+ setColumnAxis(HorizontalColumnAxis);
+ if (isHorizontalWritingMode())
+ setColumnProgression(isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression);
+ else
+ setColumnProgression(isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression);
+ break;
+ case Pagination::TopToBottomPaginated:
+ setColumnAxis(VerticalColumnAxis);
+ if (isHorizontalWritingMode())
+ setColumnProgression(isFlippedBlocksWritingMode() ? ReverseColumnProgression : NormalColumnProgression);
+ else
+ setColumnProgression(isLeftToRightDirection() ? NormalColumnProgression : ReverseColumnProgression);
+ break;
+ case Pagination::BottomToTopPaginated:
+ setColumnAxis(VerticalColumnAxis);
+ if (isHorizontalWritingMode())
+ setColumnProgression(isFlippedBlocksWritingMode() ? NormalColumnProgression : ReverseColumnProgression);
+ else
+ setColumnProgression(isLeftToRightDirection() ? ReverseColumnProgression : NormalColumnProgression);
+ break;
+ case Pagination::Unpaginated:
+ ASSERT_NOT_REACHED();
+ break;
+ }
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h
index 06e5bb269..6a60d7a8a 100644
--- a/Source/WebCore/rendering/style/RenderStyle.h
+++ b/Source/WebCore/rendering/style/RenderStyle.h
@@ -34,7 +34,6 @@
#include "ColorSpace.h"
#include "CounterDirectives.h"
#include "DataRef.h"
-#include "ExclusionShapeValue.h"
#include "FontBaseline.h"
#include "FontDescription.h"
#include "GraphicsTypes.h"
@@ -46,9 +45,11 @@
#include "LineClampValue.h"
#include "NinePieceImage.h"
#include "OutlineValue.h"
+#include "Pagination.h"
#include "RenderStyleConstants.h"
#include "RoundedRect.h"
#include "ShadowData.h"
+#include "ShapeValue.h"
#include "StyleBackgroundData.h"
#include "StyleBoxData.h"
#include "StyleDeprecatedFlexibleBoxData.h"
@@ -64,7 +65,6 @@
#include "StyleTransformData.h"
#include "StyleVisualData.h"
#include "TextDirection.h"
-#include "TextOrientation.h"
#include "ThemeTypes.h"
#include "TransformOperations.h"
#include "UnicodeBidi.h"
@@ -91,11 +91,11 @@ template<typename T, typename U> inline bool compareEqual(const T& t, const U& u
#define SET_VAR(group, variable, value) \
if (!compareEqual(group->variable, value)) \
- group.access()->variable = value;
+ group.access()->variable = value
#define SET_BORDERVALUE_COLOR(group, variable, value) \
if (!compareEqual(group->variable.color(), value)) \
- group.access()->variable.setColor(value);
+ group.access()->variable.setColor(value)
namespace WebCore {
@@ -125,12 +125,12 @@ typedef Vector<RefPtr<RenderStyle>, 4> PseudoStyleCache;
class RenderStyle: public RefCounted<RenderStyle> {
friend class CSSPropertyAnimation; // Used by CSS animations. We can't allow them to animate based off visited colors.
friend class ApplyStyleCommand; // Editing has to only reveal unvisited info.
+ friend class DeprecatedStyleBuilder; // Sets members directly.
friend class EditingStyle; // Editing has to only reveal unvisited info.
- friend class CSSComputedStyleDeclaration; // Ignores visited styles, so needs to be able to see unvisited info.
+ friend class ComputedStyleExtractor; // Ignores visited styles, so needs to be able to see unvisited info.
friend class PropertyWrapperMaybeInvalidColor; // Used by CSS animations. We can't allow them to animate based off visited colors.
friend class RenderSVGResource; // FIXME: Needs to alter the visited state by hand. Should clean the SVG code up and move it into RenderStyle perhaps.
friend class RenderTreeAsText; // FIXME: Only needed so the render tree can keep lying and dump the wrong colors. Rebaselining would allow this to be yanked.
- friend class StyleBuilder; // Sets members directly.
friend class StyleResolver; // Sets members directly.
protected:
@@ -167,6 +167,9 @@ protected:
&& (_text_transform == other._text_transform)
&& (_text_decorations == other._text_decorations)
&& (_cursor_style == other._cursor_style)
+#if ENABLE(CURSOR_VISIBILITY)
+ && (m_cursorVisibility == other.m_cursorVisibility)
+#endif
&& (_direction == other._direction)
&& (_white_space == other._white_space)
&& (_border_collapse == other._border_collapse)
@@ -187,8 +190,11 @@ protected:
unsigned _visibility : 2; // EVisibility
unsigned _text_align : 4; // ETextAlign
unsigned _text_transform : 2; // ETextTransform
- unsigned _text_decorations : ETextDecorationBits;
+ unsigned _text_decorations : TextDecorationBits;
unsigned _cursor_style : 6; // ECursor
+#if ENABLE(CURSOR_VISIBILITY)
+ unsigned m_cursorVisibility : 1; // CursorVisibility
+#endif
unsigned _direction : 1; // TextDirection
unsigned _white_space : 3; // EWhiteSpace
// 32 bits
@@ -294,6 +300,9 @@ protected:
inherited_flags._text_transform = initialTextTransform();
inherited_flags._text_decorations = initialTextDecoration();
inherited_flags._cursor_style = initialCursor();
+#if ENABLE(CURSOR_VISIBILITY)
+ inherited_flags.m_cursorVisibility = initialCursorVisibility();
+#endif
inherited_flags._direction = initialDirection();
inherited_flags._white_space = initialWhiteSpace();
inherited_flags._border_collapse = initialBorderCollapse();
@@ -371,6 +380,8 @@ public:
void setAffectedByActive() { noninherited_flags.setAffectedByActive(true); }
void setAffectedByDrag() { noninherited_flags.setAffectedByDrag(true); }
+ void setColumnStylesFromPaginationMode(const Pagination::Mode&);
+
bool operator==(const RenderStyle& other) const;
bool operator!=(const RenderStyle& other) const { return !(*this == other); }
bool isFloating() const { return noninherited_flags._floating != NoFloat; }
@@ -378,9 +389,14 @@ public:
bool hasBorder() const { return surround->border.hasBorder(); }
bool hasPadding() const { return surround->padding.nonZero(); }
bool hasOffset() const { return surround->offset.nonZero(); }
+ bool hasMarginBeforeQuirk() const { return marginBefore().quirk(); }
+ bool hasMarginAfterQuirk() const { return marginAfter().quirk(); }
bool hasBackgroundImage() const { return m_background->background().hasImage(); }
bool hasFixedBackgroundImage() const { return m_background->background().hasFixedImage(); }
+
+ bool hasEntirelyFixedBackground() const;
+
bool hasAppearance() const { return appearance() != NoControlPart; }
bool hasBackground() const
@@ -407,20 +423,8 @@ public:
}
#if ENABLE(CSS_FILTERS)
- void getFilterOutsets(int& top, int& right, int& bottom, int& left) const
- {
- if (hasFilter())
- filter().getOutsets(top, right, bottom, left);
- else {
- top = 0;
- right = 0;
- bottom = 0;
- left = 0;
- }
- }
bool hasFilterOutsets() const { return hasFilter() && filter().hasOutsets(); }
-#else
- bool hasFilterOutsets() const { return false; }
+ FilterOutsets filterOutsets() const { return hasFilter() ? filter().outsets() : FilterOutsets(); }
#endif
Order rtlOrdering() const { return static_cast<Order>(inherited_flags.m_rtlOrdering); }
@@ -431,6 +435,7 @@ public:
bool hasAnyPublicPseudoStyles() const;
bool hasPseudoStyle(PseudoId pseudo) const;
void setHasPseudoStyle(PseudoId pseudo);
+ bool hasUniquePseudoStyle() const;
// attribute getter methods
@@ -558,13 +563,19 @@ public:
#endif
Length textIndent() const { return rareInheritedData->indent; }
+#if ENABLE(CSS3_TEXT)
+ TextIndentLine textIndentLine() const { return static_cast<TextIndentLine>(rareInheritedData->m_textIndentLine); }
+ TextIndentType textIndentType() const { return static_cast<TextIndentType>(rareInheritedData->m_textIndentType); }
+#endif
ETextAlign textAlign() const { return static_cast<ETextAlign>(inherited_flags._text_align); }
ETextTransform textTransform() const { return static_cast<ETextTransform>(inherited_flags._text_transform); }
- ETextDecoration textDecorationsInEffect() const { return static_cast<ETextDecoration>(inherited_flags._text_decorations); }
- ETextDecoration textDecoration() const { return static_cast<ETextDecoration>(visual->textDecoration); }
+ TextDecoration textDecorationsInEffect() const { return static_cast<TextDecoration>(inherited_flags._text_decorations); }
+ TextDecoration textDecoration() const { return static_cast<TextDecoration>(visual->textDecoration); }
#if ENABLE(CSS3_TEXT)
TextDecorationStyle textDecorationStyle() const { return static_cast<TextDecorationStyle>(rareNonInheritedData->m_textDecorationStyle); }
- ETextAlignLast textAlignLast() const { return static_cast<ETextAlignLast>(rareInheritedData->m_textAlignLast); }
+ TextAlignLast textAlignLast() const { return static_cast<TextAlignLast>(rareInheritedData->m_textAlignLast); }
+ TextJustify textJustify() const { return static_cast<TextJustify>(rareInheritedData->m_textJustify); }
+ TextUnderlinePosition textUnderlinePosition() const { return static_cast<TextUnderlinePosition>(rareInheritedData->m_textUnderlinePosition); }
#else
TextDecorationStyle textDecorationStyle() const { return TextDecorationStyleSolid; }
#endif // CSS3_TEXT
@@ -699,6 +710,9 @@ public:
Length paddingEnd() const { return surround->padding.end(writingMode(), direction()); }
ECursor cursor() const { return static_cast<ECursor>(inherited_flags._cursor_style); }
+#if ENABLE(CURSOR_VISIBILITY)
+ CursorVisibility cursorVisibility() const { return static_cast<CursorVisibility>(inherited_flags.m_cursorVisibility); }
+#endif
CursorList* cursors() const { return rareInheritedData->cursorData.get(); }
@@ -707,6 +721,8 @@ public:
short widows() const { return rareInheritedData->widows; }
short orphans() const { return rareInheritedData->orphans; }
+ bool hasAutoWidows() const { return rareInheritedData->m_hasAutoWidows; }
+ bool hasAutoOrphans() const { return rareInheritedData->m_hasAutoOrphans; }
EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(noninherited_flags._page_break_inside); }
EPageBreak pageBreakBefore() const { return static_cast<EPageBreak>(noninherited_flags._page_break_before); }
EPageBreak pageBreakAfter() const { return static_cast<EPageBreak>(noninherited_flags._page_break_after); }
@@ -760,9 +776,14 @@ public:
const Vector<GridTrackSize>& gridColumns() const { return rareNonInheritedData->m_grid->m_gridColumns; }
const Vector<GridTrackSize>& gridRows() const { return rareNonInheritedData->m_grid->m_gridRows; }
+ GridAutoFlow gridAutoFlow() const { return rareNonInheritedData->m_grid->m_gridAutoFlow; }
+ const GridTrackSize& gridAutoColumns() const { return rareNonInheritedData->m_grid->m_gridAutoColumns; }
+ const GridTrackSize& gridAutoRows() const { return rareNonInheritedData->m_grid->m_gridAutoRows; }
- const GridPosition& gridItemColumn() const { return rareNonInheritedData->m_gridItem->m_gridColumn; }
- const GridPosition& gridItemRow() const { return rareNonInheritedData->m_gridItem->m_gridRow; }
+ const GridPosition& gridItemStart() const { return rareNonInheritedData->m_gridItem->m_gridStart; }
+ const GridPosition& gridItemEnd() const { return rareNonInheritedData->m_gridItem->m_gridEnd; }
+ const GridPosition& gridItemBefore() const { return rareNonInheritedData->m_gridItem->m_gridBefore; }
+ const GridPosition& gridItemAfter() const { return rareNonInheritedData->m_gridItem->m_gridAfter; }
const ShadowData* boxShadow() const { return rareNonInheritedData->m_boxShadow.get(); }
void getBoxShadowExtent(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const { getShadowExtent(boxShadow(), top, right, bottom, left); }
@@ -838,6 +859,8 @@ public:
RubyPosition rubyPosition() const { return static_cast<RubyPosition>(rareInheritedData->m_rubyPosition); }
+ TextOrientation textOrientation() const { return static_cast<TextOrientation>(rareInheritedData->m_textOrientation); }
+
// Return true if any transform related property (currently transform, transformStyle3D or perspective)
// indicates that we are transforming
bool hasTransformRelatedProperty() const { return hasTransform() || preserves3D() || hasPerspective(); }
@@ -858,7 +881,7 @@ public:
const AtomicString& flowThread() const { return rareNonInheritedData->m_flowThread; }
const AtomicString& regionThread() const { return rareNonInheritedData->m_regionThread; }
- RegionOverflow regionOverflow() const { return static_cast<RegionOverflow>(rareNonInheritedData->m_regionOverflow); }
+ RegionFragment regionFragment() const { return static_cast<RegionFragment>(rareNonInheritedData->m_regionFragment); }
const AtomicString& lineGrid() const { return rareInheritedData->m_lineGrid; }
LineSnap lineSnap() const { return static_cast<LineSnap>(rareInheritedData->m_lineSnap); }
@@ -905,7 +928,6 @@ public:
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
bool useTouchOverflowScrolling() const { return rareInheritedData->useTouchOverflowScrolling; }
#endif
- bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
WritingMode writingMode() const { return static_cast<WritingMode>(inherited_flags.m_writingMode); }
@@ -956,18 +978,36 @@ public:
void setPosition(EPosition v) { noninherited_flags._position = v; }
void setFloating(EFloat v) { noninherited_flags._floating = v; }
- void setLeft(Length v) { SET_VAR(surround, offset.m_left, v) }
- void setRight(Length v) { SET_VAR(surround, offset.m_right, v) }
- void setTop(Length v) { SET_VAR(surround, offset.m_top, v) }
- void setBottom(Length v) { SET_VAR(surround, offset.m_bottom, v) }
+ void setLeft(Length v) { SET_VAR(surround, offset.m_left, v); }
+ void setRight(Length v) { SET_VAR(surround, offset.m_right, v); }
+ void setTop(Length v) { SET_VAR(surround, offset.m_top, v); }
+ void setBottom(Length v) { SET_VAR(surround, offset.m_bottom, v); }
- void setWidth(Length v) { SET_VAR(m_box, m_width, v) }
- void setHeight(Length v) { SET_VAR(m_box, m_height, v) }
+ void setWidth(Length v) { SET_VAR(m_box, m_width, v); }
+ void setHeight(Length v) { SET_VAR(m_box, m_height, v); }
- void setMinWidth(Length v) { SET_VAR(m_box, m_minWidth, v) }
- void setMaxWidth(Length v) { SET_VAR(m_box, m_maxWidth, v) }
- void setMinHeight(Length v) { SET_VAR(m_box, m_minHeight, v) }
- void setMaxHeight(Length v) { SET_VAR(m_box, m_maxHeight, v) }
+ void setLogicalWidth(Length v)
+ {
+ if (isHorizontalWritingMode()) {
+ SET_VAR(m_box, m_width, v);
+ } else {
+ SET_VAR(m_box, m_height, v);
+ }
+ }
+
+ void setLogicalHeight(Length v)
+ {
+ if (isHorizontalWritingMode()) {
+ SET_VAR(m_box, m_height, v);
+ } else {
+ SET_VAR(m_box, m_width, v);
+ }
+ }
+
+ void setMinWidth(Length v) { SET_VAR(m_box, m_minWidth, v); }
+ void setMaxWidth(Length v) { SET_VAR(m_box, m_maxWidth, v); }
+ void setMinHeight(Length v) { SET_VAR(m_box, m_minHeight, v); }
+ void setMaxHeight(Length v) { SET_VAR(m_box, m_maxHeight, v); }
#if ENABLE(DASHBOARD_SUPPORT)
Vector<StyleDashboardRegion> dashboardRegions() const { return rareNonInheritedData->m_dashboardRegions; }
@@ -994,34 +1034,34 @@ public:
#endif
void resetBorder() { resetBorderImage(); resetBorderTop(); resetBorderRight(); resetBorderBottom(); resetBorderLeft(); resetBorderRadius(); }
- void resetBorderTop() { SET_VAR(surround, border.m_top, BorderValue()) }
- void resetBorderRight() { SET_VAR(surround, border.m_right, BorderValue()) }
- void resetBorderBottom() { SET_VAR(surround, border.m_bottom, BorderValue()) }
- void resetBorderLeft() { SET_VAR(surround, border.m_left, BorderValue()) }
- void resetBorderImage() { SET_VAR(surround, border.m_image, NinePieceImage()) }
+ void resetBorderTop() { SET_VAR(surround, border.m_top, BorderValue()); }
+ void resetBorderRight() { SET_VAR(surround, border.m_right, BorderValue()); }
+ void resetBorderBottom() { SET_VAR(surround, border.m_bottom, BorderValue()); }
+ void resetBorderLeft() { SET_VAR(surround, border.m_left, BorderValue()); }
+ void resetBorderImage() { SET_VAR(surround, border.m_image, NinePieceImage()); }
void resetBorderRadius() { resetBorderTopLeftRadius(); resetBorderTopRightRadius(); resetBorderBottomLeftRadius(); resetBorderBottomRightRadius(); }
- void resetBorderTopLeftRadius() { SET_VAR(surround, border.m_topLeft, initialBorderRadius()) }
- void resetBorderTopRightRadius() { SET_VAR(surround, border.m_topRight, initialBorderRadius()) }
- void resetBorderBottomLeftRadius() { SET_VAR(surround, border.m_bottomLeft, initialBorderRadius()) }
- void resetBorderBottomRightRadius() { SET_VAR(surround, border.m_bottomRight, initialBorderRadius()) }
+ void resetBorderTopLeftRadius() { SET_VAR(surround, border.m_topLeft, initialBorderRadius()); }
+ void resetBorderTopRightRadius() { SET_VAR(surround, border.m_topRight, initialBorderRadius()); }
+ void resetBorderBottomLeftRadius() { SET_VAR(surround, border.m_bottomLeft, initialBorderRadius()); }
+ void resetBorderBottomRightRadius() { SET_VAR(surround, border.m_bottomRight, initialBorderRadius()); }
- void setBackgroundColor(const Color& v) { SET_VAR(m_background, m_color, v) }
+ void setBackgroundColor(const Color& v) { SET_VAR(m_background, m_color, v); }
- void setBackgroundXPosition(Length l) { SET_VAR(m_background, m_background.m_xPosition, l) }
- void setBackgroundYPosition(Length l) { SET_VAR(m_background, m_background.m_yPosition, l) }
- void setBackgroundSize(EFillSizeType b) { SET_VAR(m_background, m_background.m_sizeType, b) }
- void setBackgroundSizeLength(LengthSize l) { SET_VAR(m_background, m_background.m_sizeLength, l) }
+ void setBackgroundXPosition(Length length) { SET_VAR(m_background, m_background.m_xPosition, length); }
+ void setBackgroundYPosition(Length length) { SET_VAR(m_background, m_background.m_yPosition, length); }
+ void setBackgroundSize(EFillSizeType b) { SET_VAR(m_background, m_background.m_sizeType, b); }
+ void setBackgroundSizeLength(LengthSize s) { SET_VAR(m_background, m_background.m_sizeLength, s); }
- void setBorderImage(const NinePieceImage& b) { SET_VAR(surround, border.m_image, b) }
- void setBorderImageSource(PassRefPtr<StyleImage> v) { surround.access()->border.m_image.setImage(v); }
- void setBorderImageSlices(LengthBox slices) { surround.access()->border.m_image.setImageSlices(slices); }
- void setBorderImageWidth(LengthBox slices) { surround.access()->border.m_image.setBorderSlices(slices); }
- void setBorderImageOutset(LengthBox outset) { surround.access()->border.m_image.setOutset(outset); }
+ void setBorderImage(const NinePieceImage& b) { SET_VAR(surround, border.m_image, b); }
+ void setBorderImageSource(PassRefPtr<StyleImage>);
+ void setBorderImageSlices(LengthBox);
+ void setBorderImageWidth(LengthBox);
+ void setBorderImageOutset(LengthBox);
- void setBorderTopLeftRadius(LengthSize s) { SET_VAR(surround, border.m_topLeft, s) }
- void setBorderTopRightRadius(LengthSize s) { SET_VAR(surround, border.m_topRight, s) }
- void setBorderBottomLeftRadius(LengthSize s) { SET_VAR(surround, border.m_bottomLeft, s) }
- void setBorderBottomRightRadius(LengthSize s) { SET_VAR(surround, border.m_bottomRight, s) }
+ void setBorderTopLeftRadius(LengthSize s) { SET_VAR(surround, border.m_topLeft, s); }
+ void setBorderTopRightRadius(LengthSize s) { SET_VAR(surround, border.m_topRight, s); }
+ void setBorderBottomLeftRadius(LengthSize s) { SET_VAR(surround, border.m_bottomLeft, s); }
+ void setBorderBottomRightRadius(LengthSize s) { SET_VAR(surround, border.m_bottomRight, s); }
void setBorderRadius(LengthSize s)
{
@@ -1039,39 +1079,39 @@ public:
RoundedRect getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const;
RoundedRect getRoundedInnerBorderFor(const LayoutRect& borderRect,
- LayoutUnit topWidth, LayoutUnit bottomWidth, LayoutUnit leftWidth, LayoutUnit rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;
-
- void setBorderLeftWidth(unsigned v) { SET_VAR(surround, border.m_left.m_width, v) }
- void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround, border.m_left.m_style, v) }
- void setBorderLeftColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_left, v) }
- void setBorderRightWidth(unsigned v) { SET_VAR(surround, border.m_right.m_width, v) }
- void setBorderRightStyle(EBorderStyle v) { SET_VAR(surround, border.m_right.m_style, v) }
- void setBorderRightColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_right, v) }
- void setBorderTopWidth(unsigned v) { SET_VAR(surround, border.m_top.m_width, v) }
- void setBorderTopStyle(EBorderStyle v) { SET_VAR(surround, border.m_top.m_style, v) }
- void setBorderTopColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_top, v) }
- void setBorderBottomWidth(unsigned v) { SET_VAR(surround, border.m_bottom.m_width, v) }
- void setBorderBottomStyle(EBorderStyle v) { SET_VAR(surround, border.m_bottom.m_style, v) }
- void setBorderBottomColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_bottom, v) }
-
- void setOutlineWidth(unsigned short v) { SET_VAR(m_background, m_outline.m_width, v) }
- void setOutlineStyleIsAuto(OutlineIsAuto isAuto) { SET_VAR(m_background, m_outline.m_isAuto, isAuto) }
- void setOutlineStyle(EBorderStyle v) { SET_VAR(m_background, m_outline.m_style, v) }
- void setOutlineColor(const Color& v) { SET_BORDERVALUE_COLOR(m_background, m_outline, v) }
+ int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;
+
+ void setBorderLeftWidth(unsigned v) { SET_VAR(surround, border.m_left.m_width, v); }
+ void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround, border.m_left.m_style, v); }
+ void setBorderLeftColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_left, v); }
+ void setBorderRightWidth(unsigned v) { SET_VAR(surround, border.m_right.m_width, v); }
+ void setBorderRightStyle(EBorderStyle v) { SET_VAR(surround, border.m_right.m_style, v); }
+ void setBorderRightColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_right, v); }
+ void setBorderTopWidth(unsigned v) { SET_VAR(surround, border.m_top.m_width, v); }
+ void setBorderTopStyle(EBorderStyle v) { SET_VAR(surround, border.m_top.m_style, v); }
+ void setBorderTopColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_top, v); }
+ void setBorderBottomWidth(unsigned v) { SET_VAR(surround, border.m_bottom.m_width, v); }
+ void setBorderBottomStyle(EBorderStyle v) { SET_VAR(surround, border.m_bottom.m_style, v); }
+ void setBorderBottomColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_bottom, v); }
+
+ void setOutlineWidth(unsigned short v) { SET_VAR(m_background, m_outline.m_width, v); }
+ void setOutlineStyleIsAuto(OutlineIsAuto isAuto) { SET_VAR(m_background, m_outline.m_isAuto, isAuto); }
+ void setOutlineStyle(EBorderStyle v) { SET_VAR(m_background, m_outline.m_style, v); }
+ void setOutlineColor(const Color& v) { SET_BORDERVALUE_COLOR(m_background, m_outline, v); }
void setOverflowX(EOverflow v) { noninherited_flags._overflowX = v; }
void setOverflowY(EOverflow v) { noninherited_flags._overflowY = v; }
void setVisibility(EVisibility v) { inherited_flags._visibility = v; }
void setVerticalAlign(EVerticalAlign v) { noninherited_flags._vertical_align = v; }
- void setVerticalAlignLength(Length length) { setVerticalAlign(LENGTH); SET_VAR(m_box, m_verticalAlign, length) }
+ void setVerticalAlignLength(Length length) { setVerticalAlign(LENGTH); SET_VAR(m_box, m_verticalAlign, length); }
- void setHasClip(bool b = true) { SET_VAR(visual, hasClip, b) }
- void setClipLeft(Length v) { SET_VAR(visual, clip.m_left, v) }
- void setClipRight(Length v) { SET_VAR(visual, clip.m_right, v) }
- void setClipTop(Length v) { SET_VAR(visual, clip.m_top, v) }
- void setClipBottom(Length v) { SET_VAR(visual, clip.m_bottom, v) }
+ void setHasClip(bool b = true) { SET_VAR(visual, hasClip, b); }
+ void setClipLeft(Length v) { SET_VAR(visual, clip.m_left, v); }
+ void setClipRight(Length v) { SET_VAR(visual, clip.m_right, v); }
+ void setClipTop(Length v) { SET_VAR(visual, clip.m_top, v); }
+ void setClipBottom(Length v) { SET_VAR(visual, clip.m_bottom, v); }
void setClip(Length top, Length right, Length bottom, Length left);
- void setClip(LengthBox box) { SET_VAR(visual, clip, box) }
+ void setClip(LengthBox box) { SET_VAR(visual, clip, box); }
void setUnicodeBidi(EUnicodeBidi b) { noninherited_flags._unicodeBidi = b; }
@@ -1085,21 +1125,27 @@ public:
#if ENABLE(TEXT_AUTOSIZING)
void setTextAutosizingMultiplier(float v)
{
- SET_VAR(visual, m_textAutosizingMultiplier, v)
+ SET_VAR(visual, m_textAutosizingMultiplier, v);
setFontSize(fontDescription().specifiedSize());
}
#endif
void setColor(const Color&);
- void setTextIndent(Length v) { SET_VAR(rareInheritedData, indent, v) }
+ void setTextIndent(Length v) { SET_VAR(rareInheritedData, indent, v); }
+#if ENABLE(CSS3_TEXT)
+ void setTextIndentLine(TextIndentLine v) { SET_VAR(rareInheritedData, m_textIndentLine, v); }
+ void setTextIndentType(TextIndentType v) { SET_VAR(rareInheritedData, m_textIndentType, v); }
+#endif
void setTextAlign(ETextAlign v) { inherited_flags._text_align = v; }
void setTextTransform(ETextTransform v) { inherited_flags._text_transform = v; }
- void addToTextDecorationsInEffect(ETextDecoration v) { inherited_flags._text_decorations |= v; }
- void setTextDecorationsInEffect(ETextDecoration v) { inherited_flags._text_decorations = v; }
- void setTextDecoration(ETextDecoration v) { SET_VAR(visual, textDecoration, v); }
+ void addToTextDecorationsInEffect(TextDecoration v) { inherited_flags._text_decorations |= v; }
+ void setTextDecorationsInEffect(TextDecoration v) { inherited_flags._text_decorations = v; }
+ void setTextDecoration(TextDecoration v) { SET_VAR(visual, textDecoration, v); }
#if ENABLE(CSS3_TEXT)
void setTextDecorationStyle(TextDecorationStyle v) { SET_VAR(rareNonInheritedData, m_textDecorationStyle, v); }
- void setTextAlignLast(ETextAlignLast v) { SET_VAR(rareInheritedData, m_textAlignLast, v) }
+ void setTextAlignLast(TextAlignLast v) { SET_VAR(rareInheritedData, m_textAlignLast, v); }
+ void setTextJustify(TextJustify v) { SET_VAR(rareInheritedData, m_textJustify, v); }
+ void setTextUnderlinePosition(TextUnderlinePosition v) { SET_VAR(rareInheritedData, m_textUnderlinePosition, v); }
#endif // CSS3_TEXT
void setDirection(TextDirection v) { inherited_flags._direction = v; }
void setLineHeight(Length specifiedLineHeight);
@@ -1108,15 +1154,15 @@ public:
bool setEffectiveZoom(float);
#if ENABLE(CSS_IMAGE_ORIENTATION)
- void setImageOrientation(ImageOrientationEnum v) { SET_VAR(rareInheritedData, m_imageOrientation, static_cast<int>(v)) }
+ void setImageOrientation(ImageOrientationEnum v) { SET_VAR(rareInheritedData, m_imageOrientation, static_cast<int>(v)); }
#endif
- void setImageRendering(EImageRendering v) { SET_VAR(rareInheritedData, m_imageRendering, v) }
+ void setImageRendering(EImageRendering v) { SET_VAR(rareInheritedData, m_imageRendering, v); }
#if ENABLE(CSS_IMAGE_RESOLUTION)
- void setImageResolutionSource(ImageResolutionSource v) { SET_VAR(rareInheritedData, m_imageResolutionSource, v) }
- void setImageResolutionSnap(ImageResolutionSnap v) { SET_VAR(rareInheritedData, m_imageResolutionSnap, v) }
- void setImageResolution(float f) { SET_VAR(rareInheritedData, m_imageResolution, f) }
+ void setImageResolutionSource(ImageResolutionSource v) { SET_VAR(rareInheritedData, m_imageResolutionSource, v); }
+ void setImageResolutionSnap(ImageResolutionSnap v) { SET_VAR(rareInheritedData, m_imageResolutionSnap, v); }
+ void setImageResolution(float f) { SET_VAR(rareInheritedData, m_imageResolution, f); }
#endif
void setWhiteSpace(EWhiteSpace v) { inherited_flags._white_space = v; }
@@ -1148,11 +1194,11 @@ public:
void setMaskImage(PassRefPtr<StyleImage> v) { rareNonInheritedData.access()->m_mask.setImage(v); }
- void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b) }
+ void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b); }
void setMaskBoxImageSource(PassRefPtr<StyleImage> v) { rareNonInheritedData.access()->m_maskBoxImage.setImage(v); }
- void setMaskXPosition(Length l) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, l) }
- void setMaskYPosition(Length l) { SET_VAR(rareNonInheritedData, m_mask.m_yPosition, l) }
- void setMaskSize(LengthSize l) { SET_VAR(rareNonInheritedData, m_mask.m_sizeLength, l) }
+ void setMaskXPosition(Length length) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, length); }
+ void setMaskYPosition(Length length) { SET_VAR(rareNonInheritedData, m_mask.m_yPosition, length); }
+ void setMaskSize(LengthSize s) { SET_VAR(rareNonInheritedData, m_mask.m_sizeLength, s); }
void setBorderCollapse(EBorderCollapse collapse) { inherited_flags._border_collapse = collapse; }
void setHorizontalBorderSpacing(short);
@@ -1168,26 +1214,30 @@ public:
void setListStyleImage(PassRefPtr<StyleImage>);
void setListStylePosition(EListStylePosition v) { inherited_flags._list_style_position = v; }
- void resetMargin() { SET_VAR(surround, margin, LengthBox(Fixed)) }
- void setMarginTop(Length v) { SET_VAR(surround, margin.m_top, v) }
- void setMarginBottom(Length v) { SET_VAR(surround, margin.m_bottom, v) }
- void setMarginLeft(Length v) { SET_VAR(surround, margin.m_left, v) }
- void setMarginRight(Length v) { SET_VAR(surround, margin.m_right, v) }
+ void resetMargin() { SET_VAR(surround, margin, LengthBox(Fixed)); }
+ void setMarginTop(Length v) { SET_VAR(surround, margin.m_top, v); }
+ void setMarginBottom(Length v) { SET_VAR(surround, margin.m_bottom, v); }
+ void setMarginLeft(Length v) { SET_VAR(surround, margin.m_left, v); }
+ void setMarginRight(Length v) { SET_VAR(surround, margin.m_right, v); }
void setMarginStart(Length);
void setMarginEnd(Length);
- void resetPadding() { SET_VAR(surround, padding, LengthBox(Auto)) }
- void setPaddingBox(const LengthBox& b) { SET_VAR(surround, padding, b) }
- void setPaddingTop(Length v) { SET_VAR(surround, padding.m_top, v) }
- void setPaddingBottom(Length v) { SET_VAR(surround, padding.m_bottom, v) }
- void setPaddingLeft(Length v) { SET_VAR(surround, padding.m_left, v) }
- void setPaddingRight(Length v) { SET_VAR(surround, padding.m_right, v) }
+ void resetPadding() { SET_VAR(surround, padding, LengthBox(Auto)); }
+ void setPaddingBox(const LengthBox& b) { SET_VAR(surround, padding, b); }
+ void setPaddingTop(Length v) { SET_VAR(surround, padding.m_top, v); }
+ void setPaddingBottom(Length v) { SET_VAR(surround, padding.m_bottom, v); }
+ void setPaddingLeft(Length v) { SET_VAR(surround, padding.m_left, v); }
+ void setPaddingRight(Length v) { SET_VAR(surround, padding.m_right, v); }
void setCursor(ECursor c) { inherited_flags._cursor_style = c; }
void addCursor(PassRefPtr<StyleImage>, const IntPoint& hotSpot = IntPoint());
void setCursorList(PassRefPtr<CursorList>);
void clearCursorList();
+#if ENABLE(CURSOR_VISIBILITY)
+ void setCursorVisibility(CursorVisibility c) { inherited_flags.m_cursorVisibility = c; }
+#endif
+
void setInsideLink(EInsideLink insideLink) { inherited_flags._insideLink = insideLink; }
void setIsLink(bool b) { noninherited_flags.setIsLink(b); }
@@ -1195,24 +1245,28 @@ public:
void setPrintColorAdjust(PrintColorAdjust value) { inherited_flags.m_printColorAdjust = value; }
bool hasAutoZIndex() const { return m_box->hasAutoZIndex(); }
- void setHasAutoZIndex() { SET_VAR(m_box, m_hasAutoZIndex, true); SET_VAR(m_box, m_zIndex, 0) }
+ void setHasAutoZIndex() { SET_VAR(m_box, m_hasAutoZIndex, true); SET_VAR(m_box, m_zIndex, 0); }
int zIndex() const { return m_box->zIndex(); }
- void setZIndex(int v) { SET_VAR(m_box, m_hasAutoZIndex, false); SET_VAR(m_box, m_zIndex, v) }
+ void setZIndex(int v) { SET_VAR(m_box, m_hasAutoZIndex, false); SET_VAR(m_box, m_zIndex, v); }
+
+ void setHasAutoWidows() { SET_VAR(rareInheritedData, m_hasAutoWidows, true); SET_VAR(rareInheritedData, widows, initialWidows()); }
+ void setWidows(short w) { SET_VAR(rareInheritedData, m_hasAutoWidows, false); SET_VAR(rareInheritedData, widows, w); }
+
+ void setHasAutoOrphans() { SET_VAR(rareInheritedData, m_hasAutoOrphans, true); SET_VAR(rareInheritedData, orphans, initialOrphans()); }
+ void setOrphans(short o) { SET_VAR(rareInheritedData, m_hasAutoOrphans, false); SET_VAR(rareInheritedData, orphans, o); }
- void setWidows(short w) { SET_VAR(rareInheritedData, widows, w); }
- void setOrphans(short o) { SET_VAR(rareInheritedData, orphans, o); }
// For valid values of page-break-inside see http://www.w3.org/TR/CSS21/page.html#page-break-props
void setPageBreakInside(EPageBreak b) { ASSERT(b == PBAUTO || b == PBAVOID); noninherited_flags._page_break_inside = b; }
void setPageBreakBefore(EPageBreak b) { noninherited_flags._page_break_before = b; }
void setPageBreakAfter(EPageBreak b) { noninherited_flags._page_break_after = b; }
// CSS3 Setters
- void setOutlineOffset(int v) { SET_VAR(m_background, m_outline.m_offset, v) }
+ void setOutlineOffset(int v) { SET_VAR(m_background, m_outline.m_offset, v); }
void setTextShadow(PassOwnPtr<ShadowData>, bool add = false);
- void setTextStrokeColor(const Color& c) { SET_VAR(rareInheritedData, textStrokeColor, c) }
- void setTextStrokeWidth(float w) { SET_VAR(rareInheritedData, textStrokeWidth, w) }
- void setTextFillColor(const Color& c) { SET_VAR(rareInheritedData, textFillColor, c) }
- void setColorSpace(ColorSpace space) { SET_VAR(rareInheritedData, colorSpace, space) }
+ void setTextStrokeColor(const Color& c) { SET_VAR(rareInheritedData, textStrokeColor, c); }
+ void setTextStrokeWidth(float w) { SET_VAR(rareInheritedData, textStrokeWidth, w); }
+ void setTextFillColor(const Color& c) { SET_VAR(rareInheritedData, textFillColor, c); }
+ void setColorSpace(ColorSpace space) { SET_VAR(rareInheritedData, colorSpace, space); }
void setOpacity(float f) { float v = clampTo<float>(f, 0, 1); SET_VAR(rareNonInheritedData, opacity, v); }
void setAppearance(ControlPart a) { SET_VAR(rareNonInheritedData, m_appearance, a); }
// For valid values of box-align see http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment
@@ -1240,12 +1294,17 @@ public:
void setFlexDirection(EFlexDirection direction) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexDirection, direction); }
void setFlexWrap(EFlexWrap w) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexWrap, w); }
void setJustifyContent(EJustifyContent p) { SET_VAR(rareNonInheritedData, m_justifyContent, p); }
+ void setGridAutoColumns(const GridTrackSize& length) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridAutoColumns, length); }
+ void setGridAutoRows(const GridTrackSize& length) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridAutoRows, length); }
void setGridColumns(const Vector<GridTrackSize>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridColumns, lengths); }
void setGridRows(const Vector<GridTrackSize>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridRows, lengths); }
- void setGridItemColumn(const GridPosition& columnPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridColumn, columnPosition); }
- void setGridItemRow(const GridPosition& rowPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridRow, rowPosition); }
+ void setGridAutoFlow(GridAutoFlow flow) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridAutoFlow, flow); }
+ void setGridItemStart(const GridPosition& startPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridStart, startPosition); }
+ void setGridItemEnd(const GridPosition& endPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridEnd, endPosition); }
+ void setGridItemBefore(const GridPosition& beforePosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridBefore, beforePosition); }
+ void setGridItemAfter(const GridPosition& afterPosition) { SET_VAR(rareNonInheritedData.access()->m_gridItem, m_gridAfter, afterPosition); }
- void setMarqueeIncrement(const Length& f) { SET_VAR(rareNonInheritedData.access()->m_marquee, increment, f); }
+ void setMarqueeIncrement(Length f) { SET_VAR(rareNonInheritedData.access()->m_marquee, increment, f); }
void setMarqueeSpeed(int f) { SET_VAR(rareNonInheritedData.access()->m_marquee, speed, f); }
void setMarqueeDirection(EMarqueeDirection d) { SET_VAR(rareNonInheritedData.access()->m_marquee, direction, d); }
void setMarqueeBehavior(EMarqueeBehavior b) { SET_VAR(rareNonInheritedData.access()->m_marquee, behavior, b); }
@@ -1280,7 +1339,7 @@ public:
void setColumnRuleColor(const Color& c) { SET_BORDERVALUE_COLOR(rareNonInheritedData.access()->m_multiCol, m_rule, c); }
void setColumnRuleStyle(EBorderStyle b) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.m_style, b); }
void setColumnRuleWidth(unsigned short w) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.m_width, w); }
- void resetColumnRule() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule, BorderValue()) }
+ void resetColumnRule() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule, BorderValue()); }
void setColumnSpan(ColumnSpan columnSpan) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_columnSpan, columnSpan); }
void setColumnBreakBefore(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakBefore, p); }
// For valid values of column-break-inside see http://www.w3.org/TR/css3-multicol/#break-before-break-after-break-inside
@@ -1296,11 +1355,15 @@ public:
void setTransformOriginZ(float f) { SET_VAR(rareNonInheritedData.access()->m_transform, m_z, f); }
void setSpeak(ESpeak s) { SET_VAR(rareInheritedData, speak, s); }
void setTextCombine(TextCombine v) { SET_VAR(rareNonInheritedData, m_textCombine, v); }
- void setTextEmphasisColor(const Color& c) { SET_VAR(rareInheritedData, textEmphasisColor, c) }
+#if ENABLE(CSS3_TEXT)
+ void setTextDecorationColor(const Color& c) { SET_VAR(rareNonInheritedData, m_textDecorationColor, c); }
+#endif // CSS3_TEXT
+ void setTextEmphasisColor(const Color& c) { SET_VAR(rareInheritedData, textEmphasisColor, c); }
void setTextEmphasisFill(TextEmphasisFill fill) { SET_VAR(rareInheritedData, textEmphasisFill, fill); }
void setTextEmphasisMark(TextEmphasisMark mark) { SET_VAR(rareInheritedData, textEmphasisMark, mark); }
void setTextEmphasisCustomMark(const AtomicString& mark) { SET_VAR(rareInheritedData, textEmphasisCustomMark, mark); }
void setTextEmphasisPosition(TextEmphasisPosition position) { SET_VAR(rareInheritedData, textEmphasisPosition, position); }
+ bool setTextOrientation(TextOrientation);
void setRubyPosition(RubyPosition position) { SET_VAR(rareInheritedData, m_rubyPosition, position); }
@@ -1318,7 +1381,7 @@ public:
void setFlowThread(const AtomicString& flowThread) { SET_VAR(rareNonInheritedData, m_flowThread, flowThread); }
void setRegionThread(const AtomicString& regionThread) { SET_VAR(rareNonInheritedData, m_regionThread, regionThread); }
- void setRegionOverflow(RegionOverflow regionOverflow) { SET_VAR(rareNonInheritedData, m_regionOverflow, regionOverflow); }
+ void setRegionFragment(RegionFragment regionFragment) { SET_VAR(rareNonInheritedData, m_regionFragment, regionFragment); }
void setWrapFlow(WrapFlow wrapFlow) { SET_VAR(rareNonInheritedData, m_wrapFlow, wrapFlow); }
void setWrapThrough(WrapThrough wrapThrough) { SET_VAR(rareNonInheritedData, m_wrapThrough, wrapThrough); }
@@ -1362,7 +1425,6 @@ public:
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
void setUseTouchOverflowScrolling(bool v) { SET_VAR(rareInheritedData, useTouchOverflowScrolling, v); }
#endif
- bool setTextSizeAdjust(bool);
void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); }
#if ENABLE(SVG)
@@ -1403,24 +1465,31 @@ public:
void setKerning(SVGLength k) { accessSVGStyle()->setKerning(k); }
#endif
- void setShapeInside(PassRefPtr<ExclusionShapeValue> value)
+ void setShapeInside(PassRefPtr<ShapeValue> value)
{
if (rareNonInheritedData->m_shapeInside == value)
return;
rareNonInheritedData.access()->m_shapeInside = value;
}
- ExclusionShapeValue* shapeInside() const { return rareNonInheritedData->m_shapeInside.get(); }
+ ShapeValue* shapeInside() const { return rareNonInheritedData->m_shapeInside.get(); }
+ ShapeValue* resolvedShapeInside() const
+ {
+ ShapeValue* shapeInside = this->shapeInside();
+ if (shapeInside && shapeInside->type() == ShapeValue::Outside)
+ return shapeOutside();
+ return shapeInside;
+ }
- void setShapeOutside(PassRefPtr<ExclusionShapeValue> value)
+ void setShapeOutside(PassRefPtr<ShapeValue> value)
{
if (rareNonInheritedData->m_shapeOutside == value)
return;
rareNonInheritedData.access()->m_shapeOutside = value;
}
- ExclusionShapeValue* shapeOutside() const { return rareNonInheritedData->m_shapeOutside.get(); }
+ ShapeValue* shapeOutside() const { return rareNonInheritedData->m_shapeOutside.get(); }
- static ExclusionShapeValue* initialShapeInside() { return 0; }
- static ExclusionShapeValue* initialShapeOutside() { return 0; }
+ static ShapeValue* initialShapeInside();
+ static ShapeValue* initialShapeOutside() { return 0; }
void setClipPath(PassRefPtr<ClipPathOperation> operation)
{
@@ -1461,6 +1530,7 @@ public:
bool inheritedDataShared(const RenderStyle*) const;
StyleDifference diff(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+ bool diffRequiresRepaint(const RenderStyle*) const;
bool isDisplayReplacedType() const { return isDisplayReplacedType(display()); }
bool isDisplayInlineType() const { return isDisplayInlineType(display()); }
@@ -1472,7 +1542,14 @@ public:
|| display() == LIST_ITEM;
}
- void setWritingMode(WritingMode v) { inherited_flags.m_writingMode = v; }
+ bool setWritingMode(WritingMode v)
+ {
+ if (v == writingMode())
+ return false;
+
+ inherited_flags.m_writingMode = v;
+ return true;
+ }
// A unique style is one that has matches something that makes it impossible to share.
bool unique() const { return noninherited_flags.unique; }
@@ -1489,8 +1566,6 @@ public:
void setHasExplicitlyInheritedProperties() { noninherited_flags.explicitInheritance = true; }
bool hasExplicitlyInheritedProperties() const { return noninherited_flags.explicitInheritance; }
-
- void reportMemoryUsage(MemoryObjectInfo*) const;
// Initial values for all the properties
static EBorderCollapse initialBorderCollapse() { return BSEPARATE; }
@@ -1524,6 +1599,9 @@ public:
static short initialHorizontalBorderSpacing() { return 0; }
static short initialVerticalBorderSpacing() { return 0; }
static ECursor initialCursor() { return CURSOR_AUTO; }
+#if ENABLE(CURSOR_VISIBILITY)
+ static CursorVisibility initialCursorVisibility() { return CursorVisibilityAuto; }
+#endif
static Color initialColor() { return Color::black; }
static StyleImage* initialListStyleImage() { return 0; }
static unsigned initialBorderWidth() { return 3; }
@@ -1531,21 +1609,27 @@ public:
static unsigned short initialOutlineWidth() { return 3; }
static int initialLetterWordSpacing() { return 0; }
static Length initialSize() { return Length(); }
- static Length initialMinSize() { return Length(); }
+ static Length initialMinSize() { return Length(Fixed); }
static Length initialMaxSize() { return Length(Undefined); }
static Length initialOffset() { return Length(); }
static Length initialMargin() { return Length(Fixed); }
static Length initialPadding() { return Length(Fixed); }
static Length initialTextIndent() { return Length(Fixed); }
+#if ENABLE(CSS3_TEXT)
+ static TextIndentLine initialTextIndentLine() { return TextIndentFirstLine; }
+ static TextIndentType initialTextIndentType() { return TextIndentNormal; }
+#endif
static EVerticalAlign initialVerticalAlign() { return BASELINE; }
static short initialWidows() { return 2; }
static short initialOrphans() { return 2; }
static Length initialLineHeight() { return Length(-100.0, Percent); }
static ETextAlign initialTextAlign() { return TASTART; }
- static ETextDecoration initialTextDecoration() { return TDNONE; }
+ static TextDecoration initialTextDecoration() { return TextDecorationNone; }
#if ENABLE(CSS3_TEXT)
static TextDecorationStyle initialTextDecorationStyle() { return TextDecorationStyleSolid; }
- static ETextAlignLast initialTextAlignLast() { return TextAlignLastAuto; }
+ static TextAlignLast initialTextAlignLast() { return TextAlignLastAuto; }
+ static TextJustify initialTextJustify() { return TextJustifyAuto; }
+ static TextUnderlinePosition initialTextUnderlinePosition() { return TextUnderlinePositionAuto; }
#endif // CSS3_TEXT
static float initialZoom() { return 1.0f; }
static int initialOutlineOffset() { return 0; }
@@ -1635,9 +1719,13 @@ public:
static Vector<GridTrackSize> initialGridColumns() { return Vector<GridTrackSize>(); }
static Vector<GridTrackSize> initialGridRows() { return Vector<GridTrackSize>(); }
+ static GridAutoFlow initialGridAutoFlow() { return AutoFlowNone; }
+
+ static GridTrackSize initialGridAutoColumns() { return GridTrackSize(Auto); }
+ static GridTrackSize initialGridAutoRows() { return GridTrackSize(Auto); }
+
// 'auto' is the default.
- static GridPosition initialGridItemColumn() { return GridPosition(); }
- static GridPosition initialGridItemRow() { return GridPosition(); }
+ static GridPosition initialGridPosition() { return GridPosition(); }
static unsigned initialTabSize() { return 8; }
@@ -1647,14 +1735,13 @@ public:
static const AtomicString& initialFlowThread() { return nullAtom; }
static const AtomicString& initialRegionThread() { return nullAtom; }
- static RegionOverflow initialRegionOverflow() { return AutoRegionOverflow; }
+ static RegionFragment initialRegionFragment() { return AutoRegionFragment; }
static WrapFlow initialWrapFlow() { return WrapFlowAuto; }
static WrapThrough initialWrapThrough() { return WrapThroughWrap; }
// Keep these at the end.
static LineClampValue initialLineClamp() { return LineClampValue(); }
- static bool initialTextSizeAdjust() { return true; }
static ETextSecurity initialTextSecurity() { return TSNONE; }
#if ENABLE(TOUCH_EVENTS)
static Color initialTapHighlightColor();
@@ -1672,18 +1759,29 @@ public:
#if ENABLE(CSS_COMPOSITING)
static BlendMode initialBlendMode() { return BlendModeNormal; }
#endif
+
private:
+ bool changeRequiresLayout(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+ bool changeRequiresPositionedLayoutOnly(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+ bool changeRequiresLayerRepaint(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+ bool changeRequiresRepaint(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+ bool changeRequiresRepaintIfText(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+ bool changeRequiresRecompositeLayer(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
+
void setVisitedLinkColor(const Color&);
- void setVisitedLinkBackgroundColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBackgroundColor, v) }
- void setVisitedLinkBorderLeftColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderLeftColor, v) }
- void setVisitedLinkBorderRightColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderRightColor, v) }
- void setVisitedLinkBorderBottomColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderBottomColor, v) }
- void setVisitedLinkBorderTopColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderTopColor, v) }
- void setVisitedLinkOutlineColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkOutlineColor, v) }
- void setVisitedLinkColumnRuleColor(const Color& v) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_visitedLinkColumnRuleColor, v) }
- void setVisitedLinkTextEmphasisColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextEmphasisColor, v) }
- void setVisitedLinkTextFillColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextFillColor, v) }
- void setVisitedLinkTextStrokeColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextStrokeColor, v) }
+ void setVisitedLinkBackgroundColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBackgroundColor, v); }
+ void setVisitedLinkBorderLeftColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderLeftColor, v); }
+ void setVisitedLinkBorderRightColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderRightColor, v); }
+ void setVisitedLinkBorderBottomColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderBottomColor, v); }
+ void setVisitedLinkBorderTopColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkBorderTopColor, v); }
+ void setVisitedLinkOutlineColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkOutlineColor, v); }
+ void setVisitedLinkColumnRuleColor(const Color& v) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_visitedLinkColumnRuleColor, v); }
+#if ENABLE(CSS3_TEXT)
+ void setVisitedLinkTextDecorationColor(const Color& v) { SET_VAR(rareNonInheritedData, m_visitedLinkTextDecorationColor, v); }
+#endif // CSS3_TEXT
+ void setVisitedLinkTextEmphasisColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextEmphasisColor, v); }
+ void setVisitedLinkTextFillColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextFillColor, v); }
+ void setVisitedLinkTextStrokeColor(const Color& v) { SET_VAR(rareInheritedData, visitedLinkTextStrokeColor, v); }
void inheritUnicodeBidiFrom(const RenderStyle* parent) { noninherited_flags._unicodeBidi = parent->noninherited_flags._unicodeBidi; }
void getShadowExtent(const ShadowData*, LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const;
@@ -1731,6 +1829,10 @@ private:
Color visitedLinkBorderTopColor() const { return rareNonInheritedData->m_visitedLinkBorderTopColor; }
Color visitedLinkOutlineColor() const { return rareNonInheritedData->m_visitedLinkOutlineColor; }
Color visitedLinkColumnRuleColor() const { return rareNonInheritedData->m_multiCol->m_visitedLinkColumnRuleColor; }
+#if ENABLE(CSS3_TEXT)
+ Color textDecorationColor() const { return rareNonInheritedData->m_textDecorationColor; }
+ Color visitedLinkTextDecorationColor() const { return rareNonInheritedData->m_visitedLinkTextDecorationColor; }
+#endif // CSS3_TEXT
Color visitedLinkTextEmphasisColor() const { return rareInheritedData->visitedLinkTextEmphasisColor; }
Color visitedLinkTextFillColor() const { return rareInheritedData->visitedLinkTextFillColor; }
Color visitedLinkTextStrokeColor() const { return rareInheritedData->visitedLinkTextStrokeColor; }
@@ -1767,6 +1869,13 @@ inline float adjustFloatForAbsoluteZoom(float value, const RenderStyle* style)
return value / style->effectiveZoom();
}
+#if ENABLE(SUBPIXEL_LAYOUT)
+inline LayoutUnit adjustLayoutUnitForAbsoluteZoom(LayoutUnit value, const RenderStyle* style)
+{
+ return value / style->effectiveZoom();
+}
+#endif
+
inline bool RenderStyle::setZoom(float f)
{
if (compareEqual(visual->m_zoom, f))
@@ -1784,11 +1893,12 @@ inline bool RenderStyle::setEffectiveZoom(float f)
return true;
}
-inline bool RenderStyle::setTextSizeAdjust(bool b)
+inline bool RenderStyle::setTextOrientation(TextOrientation textOrientation)
{
- if (compareEqual(rareInheritedData->textSizeAdjust, b))
+ if (compareEqual(rareInheritedData->m_textOrientation, textOrientation))
return false;
- rareInheritedData.access()->textSizeAdjust = b;
+
+ rareInheritedData.access()->m_textOrientation = textOrientation;
return true;
}
diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h
index 341813299..830612e57 100644
--- a/Source/WebCore/rendering/style/RenderStyleConstants.h
+++ b/Source/WebCore/rendering/style/RenderStyleConstants.h
@@ -35,20 +35,22 @@ enum PrintColorAdjust {
};
// The difference between two styles. The following values are used:
-// (1) StyleDifferenceEqual - The two styles are identical
-// (2) StyleDifferenceRecompositeLayer - The layer needs its position and transform updated, but no repaint
-// (3) StyleDifferenceRepaint - The object just needs to be repainted.
-// (4) StyleDifferenceRepaintLayer - The layer and its descendant layers needs to be repainted.
-// (5) StyleDifferenceLayoutPositionedMovementOnly - Only the position of this positioned object has been updated
-// (6) StyleDifferenceSimplifiedLayout - Only overflow needs to be recomputed
-// (7) StyleDifferenceSimplifiedLayoutAndPositionedMovement - Both positioned movement and simplified layout updates are required.
-// (8) StyleDifferenceLayout - A full layout is required.
+// - StyleDifferenceEqual - The two styles are identical
+// - StyleDifferenceRecompositeLayer - The layer needs its position and transform updated, but no repaint
+// - StyleDifferenceRepaint - The object just needs to be repainted.
+// - StyleDifferenceRepaintIfText - The object needs to be repainted if it contains text.
+// - StyleDifferenceRepaintLayer - The layer and its descendant layers needs to be repainted.
+// - StyleDifferenceLayoutPositionedMovementOnly - Only the position of this positioned object has been updated
+// - StyleDifferenceSimplifiedLayout - Only overflow needs to be recomputed
+// - StyleDifferenceSimplifiedLayoutAndPositionedMovement - Both positioned movement and simplified layout updates are required.
+// - StyleDifferenceLayout - A full layout is required.
enum StyleDifference {
StyleDifferenceEqual,
#if USE(ACCELERATED_COMPOSITING)
StyleDifferenceRecompositeLayer,
#endif
StyleDifferenceRepaint,
+ StyleDifferenceRepaintIfText,
StyleDifferenceRepaintLayer,
StyleDifferenceLayoutPositionedMovementOnly,
StyleDifferenceSimplifiedLayout,
@@ -94,7 +96,12 @@ enum EBorderPrecedence { BOFF, BTABLE, BCOLGROUP, BCOL, BROWGROUP, BROW, BCELL }
enum OutlineIsAuto { AUTO_OFF = 0, AUTO_ON };
enum EPosition {
- StaticPosition, RelativePosition, AbsolutePosition, FixedPosition, StickyPosition
+ StaticPosition = 0,
+ RelativePosition = 1,
+ AbsolutePosition = 2,
+ StickyPosition = 3,
+ // This value is required to pack our bits efficiently in RenderObject.
+ FixedPosition = 6
};
enum EFloat {
@@ -153,6 +160,9 @@ enum EFillLayerType {
// CSS3 Background Values
enum EFillSizeType { Contain, Cover, SizeLength, SizeNone };
+// CSS3 Background Position
+enum BackgroundEdgeOrigin { TopEdge, RightEdge, BottomEdge, LeftEdge };
+
// CSS3 Marquee Properties
enum EMarqueeBehavior { MNONE, MSCROLL, MSLIDE, MALTERNATE };
@@ -329,12 +339,12 @@ enum ETextTransform {
CAPITALIZE, UPPERCASE, LOWERCASE, TTNONE
};
-static const size_t ETextDecorationBits = 4;
-enum ETextDecoration {
- TDNONE = 0x0 , UNDERLINE = 0x1, OVERLINE = 0x2, LINE_THROUGH= 0x4, BLINK = 0x8
+static const size_t TextDecorationBits = 4;
+enum TextDecoration {
+ TextDecorationNone = 0x0, TextDecorationUnderline = 0x1, TextDecorationOverline = 0x2, TextDecorationLineThrough = 0x4, TextDecorationBlink = 0x8
};
-inline ETextDecoration operator|(ETextDecoration a, ETextDecoration b) { return ETextDecoration(int(a) | int(b)); }
-inline ETextDecoration& operator|=(ETextDecoration& a, ETextDecoration b) { return a = a | b; }
+inline TextDecoration operator| (TextDecoration a, TextDecoration b) { return TextDecoration(int(a) | int(b)); }
+inline TextDecoration& operator|= (TextDecoration& a, TextDecoration b) { return a = a | b; }
enum TextDecorationStyle {
TextDecorationStyleSolid,
@@ -347,9 +357,18 @@ enum TextDecorationStyle {
};
#if ENABLE(CSS3_TEXT)
-enum ETextAlignLast {
+enum TextAlignLast {
TextAlignLastAuto, TextAlignLastStart, TextAlignLastEnd, TextAlignLastLeft, TextAlignLastRight, TextAlignLastCenter, TextAlignLastJustify
};
+
+enum TextUnderlinePosition {
+ // FIXME: Implement support for 'under left' and 'under right' values.
+ TextUnderlinePositionAuto = 0x1, TextUnderlinePositionAlphabetic = 0x2, TextUnderlinePositionUnder = 0x4
+};
+
+enum TextJustify {
+ TextJustifyAuto, TextJustifyNone, TextJustifyInterWord, TextJustifyInterIdeograph, TextJustifyInterCluster, TextJustifyDistribute, TextJustifyKashida
+};
#endif // CSS3_TEXT
enum EPageBreak {
@@ -410,6 +429,13 @@ enum ECursor {
CURSOR_NONE
};
+#if ENABLE(CURSOR_VISIBILITY)
+enum CursorVisibility {
+ CursorVisibilityAuto,
+ CursorVisibilityAutoHide,
+};
+#endif
+
// The order of this enum must match the order of the display values in CSSValueKeywords.in.
enum EDisplay {
INLINE, BLOCK, LIST_ITEM, RUN_IN, COMPACT, INLINE_BLOCK,
@@ -451,9 +477,11 @@ enum TextEmphasisMark { TextEmphasisMarkNone, TextEmphasisMarkAuto, TextEmphasis
enum TextEmphasisPosition { TextEmphasisPositionOver, TextEmphasisPositionUnder };
+enum TextOrientation { TextOrientationVerticalRight, TextOrientationUpright, TextOrientationSideways, TextOrientationSidewaysRight };
+
enum TextOverflow { TextOverflowClip = 0, TextOverflowEllipsis };
-enum EImageRendering { ImageRenderingAuto, ImageRenderingOptimizeSpeed, ImageRenderingOptimizeQuality, ImageRenderingOptimizeContrast };
+enum EImageRendering { ImageRenderingAuto = 0, ImageRenderingOptimizeSpeed, ImageRenderingOptimizeQuality, ImageRenderingCrispEdges };
enum ImageResolutionSource { ImageResolutionSpecified = 0, ImageResolutionFromImage };
@@ -461,7 +489,7 @@ enum ImageResolutionSnap { ImageResolutionNoSnap = 0, ImageResolutionSnapPixels
enum Order { LogicalOrder = 0, VisualOrder };
-enum RegionOverflow { AutoRegionOverflow, BreakRegionOverflow };
+enum RegionFragment { AutoRegionFragment, BreakRegionFragment };
enum ColumnAxis { HorizontalColumnAxis, VerticalColumnAxis, AutoColumnAxis };
@@ -477,10 +505,20 @@ enum WrapThrough { WrapThroughWrap, WrapThroughNone };
enum RubyPosition { RubyPositionBefore, RubyPositionAfter };
+enum GridAutoFlow { AutoFlowNone, AutoFlowColumn, AutoFlowRow };
+
#if ENABLE(DRAGGABLE_REGION)
enum DraggableRegionMode { DraggableRegionNone, DraggableRegionDrag, DraggableRegionNoDrag };
#endif
+// Reasonable maximum to prevent insane font sizes from causing crashes on some platforms (such as Windows).
+static const float maximumAllowedFontSize = 1000000.0f;
+
+#if ENABLE(CSS3_TEXT)
+enum TextIndentLine { TextIndentFirstLine, TextIndentEachLine };
+enum TextIndentType { TextIndentNormal, TextIndentHanging };
+#endif
+
} // namespace WebCore
#endif // RenderStyleConstants_h
diff --git a/Source/WebCore/rendering/style/SVGRenderStyle.cpp b/Source/WebCore/rendering/style/SVGRenderStyle.cpp
index d74019d1c..cbd16cd42 100644
--- a/Source/WebCore/rendering/style/SVGRenderStyle.cpp
+++ b/Source/WebCore/rendering/style/SVGRenderStyle.cpp
@@ -223,6 +223,9 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const
if (svg_noninherited_flags.f._vectorEffect != other->svg_noninherited_flags.f._vectorEffect)
return StyleDifferenceRepaint;
+ if (svg_noninherited_flags.f.bufferedRendering != other->svg_noninherited_flags.f.bufferedRendering)
+ return StyleDifferenceRepaint;
+
if (svg_noninherited_flags.f.maskType != other->svg_noninherited_flags.f.maskType)
return StyleDifferenceRepaint;
diff --git a/Source/WebCore/rendering/style/SVGRenderStyle.h b/Source/WebCore/rendering/style/SVGRenderStyle.h
index be0a479bc..4a224b76e 100644
--- a/Source/WebCore/rendering/style/SVGRenderStyle.h
+++ b/Source/WebCore/rendering/style/SVGRenderStyle.h
@@ -26,6 +26,7 @@
#if ENABLE(SVG)
#include "CSSValueList.h"
#include "DataRef.h"
+#include "ExceptionCodePlaceholder.h"
#include "GraphicsTypes.h"
#include "Path.h"
#include "RenderStyleConstants.h"
@@ -58,6 +59,7 @@ public:
static EDominantBaseline initialDominantBaseline() { return DB_AUTO; }
static EBaselineShift initialBaselineShift() { return BS_BASELINE; }
static EVectorEffect initialVectorEffect() { return VE_NONE; }
+ static EBufferedRendering initialBufferedRendering() { return BR_AUTO; }
static LineCap initialCapStyle() { return ButtCap; }
static WindRule initialClipRule() { return RULE_NONZERO; }
static EColorInterpolation initialColorInterpolation() { return CI_SRGB; }
@@ -97,36 +99,28 @@ public:
static SVGLength initialBaselineShiftValue()
{
SVGLength length;
- ExceptionCode ec = 0;
- length.newValueSpecifiedUnits(LengthTypeNumber, 0, ec);
- ASSERT(!ec);
+ length.newValueSpecifiedUnits(LengthTypeNumber, 0, ASSERT_NO_EXCEPTION);
return length;
}
static SVGLength initialKerning()
{
SVGLength length;
- ExceptionCode ec = 0;
- length.newValueSpecifiedUnits(LengthTypeNumber, 0, ec);
- ASSERT(!ec);
+ length.newValueSpecifiedUnits(LengthTypeNumber, 0, ASSERT_NO_EXCEPTION);
return length;
}
static SVGLength initialStrokeDashOffset()
{
SVGLength length;
- ExceptionCode ec = 0;
- length.newValueSpecifiedUnits(LengthTypeNumber, 0, ec);
- ASSERT(!ec);
+ length.newValueSpecifiedUnits(LengthTypeNumber, 0, ASSERT_NO_EXCEPTION);
return length;
}
static SVGLength initialStrokeWidth()
{
SVGLength length;
- ExceptionCode ec = 0;
- length.newValueSpecifiedUnits(LengthTypeNumber, 1, ec);
- ASSERT(!ec);
+ length.newValueSpecifiedUnits(LengthTypeNumber, 1, ASSERT_NO_EXCEPTION);
return length;
}
@@ -135,6 +129,7 @@ public:
void setDominantBaseline(EDominantBaseline val) { svg_noninherited_flags.f._dominantBaseline = val; }
void setBaselineShift(EBaselineShift val) { svg_noninherited_flags.f._baselineShift = val; }
void setVectorEffect(EVectorEffect val) { svg_noninherited_flags.f._vectorEffect = val; }
+ void setBufferedRendering(EBufferedRendering val) { svg_noninherited_flags.f.bufferedRendering = val; }
void setCapStyle(LineCap val) { svg_inherited_flags._capStyle = val; }
void setClipRule(WindRule val) { svg_inherited_flags._clipRule = val; }
void setColorInterpolation(EColorInterpolation val) { svg_inherited_flags._colorInterpolation = val; }
@@ -312,6 +307,7 @@ public:
EDominantBaseline dominantBaseline() const { return (EDominantBaseline) svg_noninherited_flags.f._dominantBaseline; }
EBaselineShift baselineShift() const { return (EBaselineShift) svg_noninherited_flags.f._baselineShift; }
EVectorEffect vectorEffect() const { return (EVectorEffect) svg_noninherited_flags.f._vectorEffect; }
+ EBufferedRendering bufferedRendering() const { return (EBufferedRendering) svg_noninherited_flags.f.bufferedRendering; }
LineCap capStyle() const { return (LineCap) svg_inherited_flags._capStyle; }
WindRule clipRule() const { return (WindRule) svg_inherited_flags._clipRule; }
EColorInterpolation colorInterpolation() const { return (EColorInterpolation) svg_inherited_flags._colorInterpolation; }
@@ -419,8 +415,9 @@ protected:
unsigned _dominantBaseline : 4; // EDominantBaseline
unsigned _baselineShift : 2; // EBaselineShift
unsigned _vectorEffect: 1; // EVectorEffect
+ unsigned bufferedRendering: 2; // EBufferedRendering
unsigned maskType: 1; // EMaskType
- // 20 bits unused
+ // 18 bits unused
} f;
uint32_t _niflags;
};
@@ -465,6 +462,7 @@ private:
svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline();
svg_noninherited_flags.f._baselineShift = initialBaselineShift();
svg_noninherited_flags.f._vectorEffect = initialVectorEffect();
+ svg_noninherited_flags.f.bufferedRendering = initialBufferedRendering();
svg_noninherited_flags.f.maskType = initialMaskType();
}
};
diff --git a/Source/WebCore/rendering/style/SVGRenderStyleDefs.h b/Source/WebCore/rendering/style/SVGRenderStyleDefs.h
index e7308ca99..b4c066805 100644
--- a/Source/WebCore/rendering/style/SVGRenderStyleDefs.h
+++ b/Source/WebCore/rendering/style/SVGRenderStyleDefs.h
@@ -83,6 +83,12 @@ namespace WebCore {
VE_NON_SCALING_STROKE
};
+ enum EBufferedRendering {
+ BR_AUTO,
+ BR_DYNAMIC,
+ BR_STATIC
+ };
+
enum EMaskType {
MT_LUMINANCE,
MT_ALPHA
diff --git a/Source/WebCore/rendering/style/ShadowData.cpp b/Source/WebCore/rendering/style/ShadowData.cpp
index 381b59033..edd5b3755 100644
--- a/Source/WebCore/rendering/style/ShadowData.cpp
+++ b/Source/WebCore/rendering/style/ShadowData.cpp
@@ -30,7 +30,7 @@ namespace WebCore {
ShadowData::ShadowData(const ShadowData& o)
: m_location(o.m_location)
- , m_blur(o.m_blur)
+ , m_radius(o.m_radius)
, m_spread(o.m_spread)
, m_color(o.m_color)
, m_style(o.m_style)
@@ -46,7 +46,7 @@ bool ShadowData::operator==(const ShadowData& o) const
return false;
return m_location == o.m_location
- && m_blur == o.m_blur
+ && m_radius == o.m_radius
&& m_spread == o.m_spread
&& m_style == o.m_style
&& m_color == o.m_color
@@ -56,12 +56,12 @@ bool ShadowData::operator==(const ShadowData& o) const
static inline void calculateShadowExtent(const ShadowData* shadow, int additionalOutlineSize, int& shadowLeft, int& shadowRight, int& shadowTop, int& shadowBottom)
{
do {
- int blurAndSpread = shadow->blur() + shadow->spread() + additionalOutlineSize;
+ int extentAndSpread = shadow->paintingExtent() + shadow->spread() + additionalOutlineSize;
if (shadow->style() == Normal) {
- shadowLeft = min(shadow->x() - blurAndSpread, shadowLeft);
- shadowRight = max(shadow->x() + blurAndSpread, shadowRight);
- shadowTop = min(shadow->y() - blurAndSpread, shadowTop);
- shadowBottom = max(shadow->y() + blurAndSpread, shadowBottom);
+ shadowLeft = min(shadow->x() - extentAndSpread, shadowLeft);
+ shadowRight = max(shadow->x() + extentAndSpread, shadowRight);
+ shadowTop = min(shadow->y() - extentAndSpread, shadowTop);
+ shadowBottom = max(shadow->y() + extentAndSpread, shadowBottom);
}
shadow = shadow->next();
diff --git a/Source/WebCore/rendering/style/ShadowData.h b/Source/WebCore/rendering/style/ShadowData.h
index 77d71e997..19be48d6c 100644
--- a/Source/WebCore/rendering/style/ShadowData.h
+++ b/Source/WebCore/rendering/style/ShadowData.h
@@ -41,16 +41,16 @@ class ShadowData {
WTF_MAKE_FAST_ALLOCATED;
public:
ShadowData()
- : m_blur(0)
+ : m_radius(0)
, m_spread(0)
, m_style(Normal)
, m_isWebkitBoxShadow(false)
{
}
- ShadowData(const IntPoint& location, int blur, int spread, ShadowStyle style, bool isWebkitBoxShadow, const Color& color)
+ ShadowData(const IntPoint& location, int radius, int spread, ShadowStyle style, bool isWebkitBoxShadow, const Color& color)
: m_location(location)
- , m_blur(blur)
+ , m_radius(radius)
, m_spread(spread)
, m_color(color)
, m_style(style)
@@ -69,7 +69,15 @@ public:
int x() const { return m_location.x(); }
int y() const { return m_location.y(); }
IntPoint location() const { return m_location; }
- int blur() const { return m_blur; }
+ int radius() const { return m_radius; }
+ int paintingExtent() const
+ {
+ // Blurring uses a Gaussian function whose std. deviation is m_radius/2, and which in theory
+ // extends to infinity. In 8-bit contexts, however, rounding causes the effect to become
+ // undetectable at around 1.4x the radius.
+ const float radiusExtentMultiplier = 1.4;
+ return ceilf(m_radius * radiusExtentMultiplier);
+ }
int spread() const { return m_spread; }
ShadowStyle style() const { return m_style; }
const Color& color() const { return m_color; }
@@ -83,7 +91,7 @@ public:
private:
IntPoint m_location;
- int m_blur;
+ int m_radius; // This is the "blur radius", or twice the standard deviation of the Gaussian blur.
int m_spread;
Color m_color;
ShadowStyle m_style;
diff --git a/Source/WebCore/rendering/style/ExclusionShapeValue.h b/Source/WebCore/rendering/style/ShapeValue.h
index 5a533af8f..674aeeb29 100644
--- a/Source/WebCore/rendering/style/ExclusionShapeValue.h
+++ b/Source/WebCore/rendering/style/ShapeValue.h
@@ -27,41 +27,67 @@
* SUCH DAMAGE.
*/
-#ifndef ExclusionShapeValue_h
-#define ExclusionShapeValue_h
+#ifndef ShapeValue_h
+#define ShapeValue_h
#include "BasicShapes.h"
+#include "StyleImage.h"
#include <wtf/PassRefPtr.h>
namespace WebCore {
-class ExclusionShapeValue : public RefCounted<ExclusionShapeValue> {
+class ShapeValue : public RefCounted<ShapeValue> {
public:
- enum ExclusionShapeValueType {
- // The AUTO value is defined by a null ExclusionShapeValue*
- SHAPE,
- OUTSIDE
+ enum ShapeValueType {
+ // The Auto value is defined by a null ShapeValue*
+ Shape,
+ Outside,
+ Image
};
- static PassRefPtr<ExclusionShapeValue> createShapeValue(PassRefPtr<BasicShape> shape)
+ static PassRefPtr<ShapeValue> createShapeValue(PassRefPtr<BasicShape> shape)
{
- return adoptRef(new ExclusionShapeValue(shape));
+ return adoptRef(new ShapeValue(shape));
}
- static PassRefPtr<ExclusionShapeValue> createOutsideValue()
+ static PassRefPtr<ShapeValue> createOutsideValue()
{
- return adoptRef(new ExclusionShapeValue(OUTSIDE));
+ return adoptRef(new ShapeValue(Outside));
}
- ExclusionShapeValueType type() const { return m_type; }
+ static PassRefPtr<ShapeValue> createImageValue(PassRefPtr<StyleImage> image)
+ {
+ return adoptRef(new ShapeValue(image));
+ }
+
+ ShapeValueType type() const { return m_type; }
BasicShape* shape() const { return m_shape.get(); }
- bool operator==(const ExclusionShapeValue& other) const { return type() == other.type(); }
+ StyleImage* image() const { return m_image.get(); }
+ void setImage(PassRefPtr<StyleImage> image)
+ {
+ if (m_image != image)
+ m_image = image;
+ }
+ bool operator==(const ShapeValue& other) const { return type() == other.type(); }
private:
- ExclusionShapeValue(PassRefPtr<BasicShape> shape) : m_type(SHAPE), m_shape(shape) { }
- ExclusionShapeValue(ExclusionShapeValueType type) : m_type(type) { }
- ExclusionShapeValueType m_type;
+ ShapeValue(PassRefPtr<BasicShape> shape)
+ : m_type(Shape)
+ , m_shape(shape)
+ {
+ }
+ ShapeValue(ShapeValueType type)
+ : m_type(type)
+ {
+ }
+ ShapeValue(PassRefPtr<StyleImage> image)
+ : m_type(Image)
+ , m_image(image)
+ {
+ }
+ ShapeValueType m_type;
RefPtr<BasicShape> m_shape;
+ RefPtr<StyleImage> m_image;
};
}
diff --git a/Source/WebCore/rendering/style/StyleBackgroundData.cpp b/Source/WebCore/rendering/style/StyleBackgroundData.cpp
index 08f5527ad..9407c1283 100644
--- a/Source/WebCore/rendering/style/StyleBackgroundData.cpp
+++ b/Source/WebCore/rendering/style/StyleBackgroundData.cpp
@@ -46,4 +46,13 @@ bool StyleBackgroundData::operator==(const StyleBackgroundData& o) const
return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline;
}
+bool StyleBackgroundData::isEquivalentForPainting(const StyleBackgroundData& other) const
+{
+ if (m_background != other.m_background || m_color != other.m_color)
+ return false;
+ if (!m_outline.isVisible() && !other.m_outline.isVisible())
+ return true;
+ return m_outline == other.m_outline;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/StyleBackgroundData.h b/Source/WebCore/rendering/style/StyleBackgroundData.h
index 48a700ecc..f632ca292 100644
--- a/Source/WebCore/rendering/style/StyleBackgroundData.h
+++ b/Source/WebCore/rendering/style/StyleBackgroundData.h
@@ -45,6 +45,8 @@ public:
return !(*this == o);
}
+ bool isEquivalentForPainting(const StyleBackgroundData&) const;
+
const FillLayer& background() const { return m_background; }
const Color& color() const { return m_color; }
const OutlineValue& outline() const { return m_outline; }
diff --git a/Source/WebCore/rendering/style/StyleCachedImage.cpp b/Source/WebCore/rendering/style/StyleCachedImage.cpp
index 4269edd12..6a71286e0 100644
--- a/Source/WebCore/rendering/style/StyleCachedImage.cpp
+++ b/Source/WebCore/rendering/style/StyleCachedImage.cpp
@@ -106,9 +106,9 @@ PassRefPtr<Image> StyleCachedImage::image(RenderObject* renderer, const IntSize&
return m_image->imageForRenderer(renderer);
}
-bool StyleCachedImage::hasAlpha(const RenderObject* renderer) const
+bool StyleCachedImage::knownToBeOpaque(const RenderObject* renderer) const
{
- return m_image->currentFrameHasAlpha(renderer);
+ return m_image->currentFrameKnownToBeOpaque(renderer);
}
}
diff --git a/Source/WebCore/rendering/style/StyleCachedImage.h b/Source/WebCore/rendering/style/StyleCachedImage.h
index f6c4fda97..b81b43a52 100644
--- a/Source/WebCore/rendering/style/StyleCachedImage.h
+++ b/Source/WebCore/rendering/style/StyleCachedImage.h
@@ -42,8 +42,6 @@ public:
virtual PassRefPtr<CSSValue> cssValue() const;
- CachedImage* cachedImage() const { return m_image.get(); }
-
virtual bool canRender(const RenderObject*, float multiplier) const;
virtual bool isLoaded() const;
virtual bool errorOccurred() const;
@@ -56,7 +54,8 @@ public:
virtual void addClient(RenderObject*);
virtual void removeClient(RenderObject*);
virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const;
- virtual bool hasAlpha(const RenderObject*) const OVERRIDE;
+ virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE;
+ virtual CachedImage* cachedImage() const OVERRIDE { return m_image.get(); }
private:
explicit StyleCachedImage(CachedImage*);
diff --git a/Source/WebCore/rendering/style/StyleCachedImageSet.cpp b/Source/WebCore/rendering/style/StyleCachedImageSet.cpp
index c9f138270..f4f2f8b30 100644
--- a/Source/WebCore/rendering/style/StyleCachedImageSet.cpp
+++ b/Source/WebCore/rendering/style/StyleCachedImageSet.cpp
@@ -116,9 +116,9 @@ PassRefPtr<Image> StyleCachedImageSet::image(RenderObject* renderer, const IntSi
return m_bestFitImage->imageForRenderer(renderer);
}
-bool StyleCachedImageSet::hasAlpha(const RenderObject* renderer) const
+bool StyleCachedImageSet::knownToBeOpaque(const RenderObject* renderer) const
{
- return m_bestFitImage->currentFrameHasAlpha(renderer);
+ return m_bestFitImage->currentFrameKnownToBeOpaque(renderer);
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/StyleCachedImageSet.h b/Source/WebCore/rendering/style/StyleCachedImageSet.h
index 9ffd4b263..21b0e0cab 100644
--- a/Source/WebCore/rendering/style/StyleCachedImageSet.h
+++ b/Source/WebCore/rendering/style/StyleCachedImageSet.h
@@ -56,7 +56,7 @@ public:
// meaningful enough or not.
virtual WrappedImagePtr data() const { return m_bestFitImage.get(); }
- CachedImage* cachedImage() const { return m_bestFitImage.get(); }
+ void clearImageSetValue() { m_imageSetValue = 0; }
virtual bool canRender(const RenderObject*, float multiplier) const;
virtual bool isLoaded() const;
@@ -71,7 +71,8 @@ public:
virtual void removeClient(RenderObject*);
virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const;
virtual float imageScaleFactor() const { return m_imageScaleFactor; }
- virtual bool hasAlpha(const RenderObject*) const OVERRIDE;
+ virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE;
+ virtual CachedImage* cachedImage() const OVERRIDE { return m_bestFitImage.get(); }
private:
StyleCachedImageSet(CachedImage*, float imageScaleFactor, CSSImageSetValue*);
diff --git a/Source/WebCore/rendering/style/StyleCachedShader.h b/Source/WebCore/rendering/style/StyleCachedShader.h
index c2e007756..15234295b 100644
--- a/Source/WebCore/rendering/style/StyleCachedShader.h
+++ b/Source/WebCore/rendering/style/StyleCachedShader.h
@@ -34,6 +34,7 @@
#include "CachedResourceHandle.h"
#include "StyleShader.h"
+#include <wtf/PassRefPtr.h>
namespace WebCore {
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp b/Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp
new file mode 100644
index 000000000..5f4012f3f
--- /dev/null
+++ b/Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(CSS_SHADERS)
+
+#include "StyleCustomFilterProgram.h"
+
+#include "StyleCustomFilterProgramCache.h"
+
+namespace WebCore {
+
+StyleCustomFilterProgram::~StyleCustomFilterProgram()
+{
+ if (m_cache)
+ m_cache->remove(this);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
+
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgram.h b/Source/WebCore/rendering/style/StyleCustomFilterProgram.h
index ae68d954a..26ac02c9b 100644
--- a/Source/WebCore/rendering/style/StyleCustomFilterProgram.h
+++ b/Source/WebCore/rendering/style/StyleCustomFilterProgram.h
@@ -35,6 +35,7 @@
#include "CachedResourceHandle.h"
#include "CachedShader.h"
#include "CustomFilterProgram.h"
+#include "KURL.h"
#include "StyleShader.h"
#include <wtf/FastAllocBase.h>
@@ -42,18 +43,32 @@ namespace WebCore {
// CSS Shaders
+class StyleCustomFilterProgramCache;
+
class StyleCustomFilterProgram : public CustomFilterProgram, public CachedResourceClient {
WTF_MAKE_FAST_ALLOCATED;
public:
- static PassRefPtr<StyleCustomFilterProgram> create(PassRefPtr<StyleShader> vertexShader, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
+ static PassRefPtr<StyleCustomFilterProgram> create(KURL vertexShaderURL, PassRefPtr<StyleShader> vertexShader,
+ KURL fragmentShaderURL, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType,
+ const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
{
- return adoptRef(new StyleCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType));
+ return adoptRef(new StyleCustomFilterProgram(vertexShaderURL, vertexShader, fragmentShaderURL, fragmentShader, programType, mixSettings, meshType));
}
- void setVertexShader(PassRefPtr<StyleShader> shader) { m_vertexShader = shader; }
+ void setVertexShader(PassRefPtr<StyleShader> shader)
+ {
+ // The shader is immutable while in the cache.
+ ASSERT(!m_cache);
+ m_vertexShader = shader;
+ }
StyleShader* vertexShader() const { return m_vertexShader.get(); }
- void setFragmentShader(PassRefPtr<StyleShader> shader) { m_fragmentShader = shader; }
+ void setFragmentShader(PassRefPtr<StyleShader> shader)
+ {
+ // The shader is immutable while in the cache.
+ ASSERT(!m_cache);
+ m_fragmentShader = shader;
+ }
StyleShader* fragmentShader() const { return m_fragmentShader.get(); }
virtual String vertexShaderString() const
@@ -72,6 +87,9 @@ public:
{
// Do not use the CachedResource:isLoaded method here, because it actually means !isLoading(),
// so missing and canceled resources will have isLoaded set to true, even if they are not loaded yet.
+ ASSERT(!m_vertexShader || m_vertexShader->isCachedShader());
+ ASSERT(!m_fragmentShader || m_fragmentShader->isCachedShader());
+ ASSERT(m_cachedVertexShader.get() || m_cachedFragmentShader.get());
return (!m_cachedVertexShader.get() || m_isVertexShaderLoaded)
&& (!m_cachedFragmentShader.get() || m_isFragmentShaderLoaded);
}
@@ -114,36 +132,49 @@ public:
if (isLoaded())
notifyClients();
}
-
- CachedShader* cachedVertexShader() const { return m_vertexShader ? m_vertexShader->cachedShader() : 0; }
- CachedShader* cachedFragmentShader() const { return m_fragmentShader ? m_fragmentShader->cachedShader() : 0; }
-
- virtual bool operator==(const CustomFilterProgram& o) const
- {
- // We don't use the != operator because that would recursively call this method.
- if (!CustomFilterProgram::operator==(o))
- return false;
- // The following cast is ugly, but StyleCustomFilterProgram is the single implementation of CustomFilterProgram.
- const StyleCustomFilterProgram* other = static_cast<const StyleCustomFilterProgram*>(&o);
- return cachedVertexShader() == other->cachedVertexShader() && cachedFragmentShader() == other->cachedFragmentShader();
+ bool hasPendingShaders() const
+ {
+ return (m_vertexShader && m_vertexShader->isPendingShader())
+ || (m_fragmentShader && m_fragmentShader->isPendingShader());
}
+ // StyleCustomFilterProgramCache is responsible with updating the reference to the cache.
+ void setCache(StyleCustomFilterProgramCache* cache) { m_cache = cache; }
+ bool inCache() const { return m_cache; }
+
+ KURL vertexShaderURL() const { return m_vertexShaderURL; }
+ KURL fragmentShaderURL() const { return m_fragmentShaderURL; }
+
private:
- StyleCustomFilterProgram(PassRefPtr<StyleShader> vertexShader, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
+ StyleCustomFilterProgram(KURL vertexShaderURL, PassRefPtr<StyleShader> vertexShader, KURL fragmentShaderURL, PassRefPtr<StyleShader> fragmentShader,
+ CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
: CustomFilterProgram(programType, mixSettings, meshType)
, m_vertexShader(vertexShader)
, m_fragmentShader(fragmentShader)
+ , m_vertexShaderURL(vertexShaderURL)
+ , m_fragmentShaderURL(fragmentShaderURL)
+ , m_cache(0)
, m_isVertexShaderLoaded(false)
, m_isFragmentShaderLoaded(false)
{
}
+
+ ~StyleCustomFilterProgram();
RefPtr<StyleShader> m_vertexShader;
RefPtr<StyleShader> m_fragmentShader;
-
+
CachedResourceHandle<CachedShader> m_cachedVertexShader;
CachedResourceHandle<CachedShader> m_cachedFragmentShader;
+
+ // The URLs form the key of the StyleCustomFilterProgram in the cache and are used
+ // to lookup the StyleCustomFilterProgram when it's removed from the cache.
+ KURL m_vertexShaderURL;
+ KURL m_fragmentShaderURL;
+
+ // The Cache is responsible of invalidating this reference.
+ StyleCustomFilterProgramCache* m_cache;
bool m_isVertexShaderLoaded;
bool m_isFragmentShaderLoaded;
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp b/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp
new file mode 100644
index 000000000..16b579f49
--- /dev/null
+++ b/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(CSS_SHADERS)
+
+#include "StyleCustomFilterProgramCache.h"
+
+#include "CustomFilterProgramInfo.h"
+#include "StyleCustomFilterProgram.h"
+
+namespace WebCore {
+
+static CustomFilterProgramInfo programCacheKey(StyleCustomFilterProgram* program)
+{
+ ASSERT(program->vertexShaderURL().isValid() || program->fragmentShaderURL().isValid());
+ return CustomFilterProgramInfo(program->vertexShaderURL(), program->fragmentShaderURL(),
+ program->programType(), program->mixSettings(), program->meshType());
+}
+
+StyleCustomFilterProgramCache::StyleCustomFilterProgramCache()
+{
+}
+
+StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache()
+{
+ // Make sure the programs are not calling back into this object.
+ for (CacheMap::iterator iter = m_cache.begin(), end = m_cache.end(); iter != end; ++iter)
+ iter->value->setCache(0);
+}
+
+StyleCustomFilterProgram* StyleCustomFilterProgramCache::lookup(const CustomFilterProgramInfo& programInfo) const
+{
+ CacheMap::const_iterator iter = m_cache.find(programInfo);
+ return iter != m_cache.end() ? iter->value : 0;
+}
+
+StyleCustomFilterProgram* StyleCustomFilterProgramCache::lookup(StyleCustomFilterProgram* program) const
+{
+ return lookup(programCacheKey(program));
+}
+
+void StyleCustomFilterProgramCache::add(StyleCustomFilterProgram* program)
+{
+ CustomFilterProgramInfo key = programCacheKey(program);
+ ASSERT(m_cache.find(key) == m_cache.end());
+ m_cache.set(key, program);
+ program->setCache(this);
+}
+
+void StyleCustomFilterProgramCache::remove(StyleCustomFilterProgram* program)
+{
+ CacheMap::iterator iter = m_cache.find(programCacheKey(program));
+ ASSERT(iter != m_cache.end());
+ m_cache.remove(iter);
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
+
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h b/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h
new file mode 100644
index 000000000..e151836ca
--- /dev/null
+++ b/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef StyleCustomFilterProgramCache_h
+#define StyleCustomFilterProgramCache_h
+
+#if ENABLE(CSS_SHADERS)
+#include "CustomFilterProgramInfo.h"
+#include <wtf/FastAllocBase.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class StyleCustomFilterProgram;
+class CustomFilterProgramInfo;
+
+class StyleCustomFilterProgramCache {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ StyleCustomFilterProgramCache();
+ ~StyleCustomFilterProgramCache();
+
+ // Lookups a StyleCustomFilterProgram that has similar parameters with the specified program.
+ StyleCustomFilterProgram* lookup(StyleCustomFilterProgram*) const;
+ StyleCustomFilterProgram* lookup(const CustomFilterProgramInfo&) const;
+
+ void add(StyleCustomFilterProgram*);
+ void remove(StyleCustomFilterProgram*);
+
+private:
+ typedef HashMap<CustomFilterProgramInfo, StyleCustomFilterProgram*> CacheMap;
+ CacheMap m_cache;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
+
+#endif // StyleCustomFilterProgramCache_h
diff --git a/Source/WebCore/rendering/style/StyleGeneratedImage.cpp b/Source/WebCore/rendering/style/StyleGeneratedImage.cpp
index 09781a61a..b8161fefd 100644
--- a/Source/WebCore/rendering/style/StyleGeneratedImage.cpp
+++ b/Source/WebCore/rendering/style/StyleGeneratedImage.cpp
@@ -76,7 +76,7 @@ void StyleGeneratedImage::computeIntrinsicDimensions(const RenderObject* rendere
void StyleGeneratedImage::addClient(RenderObject* renderer)
{
- m_imageGeneratorValue->addClient(renderer, IntSize());
+ m_imageGeneratorValue->addClient(renderer);
}
void StyleGeneratedImage::removeClient(RenderObject* renderer)
@@ -89,9 +89,9 @@ PassRefPtr<Image> StyleGeneratedImage::image(RenderObject* renderer, const IntSi
return m_imageGeneratorValue->image(renderer, size);
}
-bool StyleGeneratedImage::hasAlpha(const RenderObject* renderer) const
+bool StyleGeneratedImage::knownToBeOpaque(const RenderObject* renderer) const
{
- return m_imageGeneratorValue->hasAlpha(renderer);
+ return m_imageGeneratorValue->knownToBeOpaque(renderer);
}
}
diff --git a/Source/WebCore/rendering/style/StyleGeneratedImage.h b/Source/WebCore/rendering/style/StyleGeneratedImage.h
index 7ab70f2db..57f78dd58 100644
--- a/Source/WebCore/rendering/style/StyleGeneratedImage.h
+++ b/Source/WebCore/rendering/style/StyleGeneratedImage.h
@@ -51,7 +51,7 @@ public:
virtual void addClient(RenderObject*);
virtual void removeClient(RenderObject*);
virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const;
- virtual bool hasAlpha(const RenderObject*) const OVERRIDE;
+ virtual bool knownToBeOpaque(const RenderObject*) const OVERRIDE;
private:
StyleGeneratedImage(PassRefPtr<CSSImageGeneratorValue>);
diff --git a/Source/WebCore/rendering/style/StyleGridData.cpp b/Source/WebCore/rendering/style/StyleGridData.cpp
index 7b6bc0a37..9cffeabcf 100644
--- a/Source/WebCore/rendering/style/StyleGridData.cpp
+++ b/Source/WebCore/rendering/style/StyleGridData.cpp
@@ -33,6 +33,9 @@ namespace WebCore {
StyleGridData::StyleGridData()
: m_gridColumns(RenderStyle::initialGridColumns())
, m_gridRows(RenderStyle::initialGridRows())
+ , m_gridAutoFlow(RenderStyle::initialGridAutoFlow())
+ , m_gridAutoRows(RenderStyle::initialGridAutoRows())
+ , m_gridAutoColumns(RenderStyle::initialGridAutoColumns())
{
}
@@ -40,6 +43,9 @@ StyleGridData::StyleGridData(const StyleGridData& o)
: RefCounted<StyleGridData>()
, m_gridColumns(o.m_gridColumns)
, m_gridRows(o.m_gridRows)
+ , m_gridAutoFlow(o.m_gridAutoFlow)
+ , m_gridAutoRows(o.m_gridAutoRows)
+ , m_gridAutoColumns(o.m_gridAutoColumns)
{
}
diff --git a/Source/WebCore/rendering/style/StyleGridData.h b/Source/WebCore/rendering/style/StyleGridData.h
index 18ffcaba6..f6849820c 100644
--- a/Source/WebCore/rendering/style/StyleGridData.h
+++ b/Source/WebCore/rendering/style/StyleGridData.h
@@ -27,6 +27,7 @@
#define StyleGridData_h
#include "GridTrackSize.h"
+#include "RenderStyleConstants.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
@@ -40,7 +41,7 @@ public:
bool operator==(const StyleGridData& o) const
{
- return m_gridColumns == o.m_gridColumns && m_gridRows == o.m_gridRows;
+ return m_gridColumns == o.m_gridColumns && m_gridRows == o.m_gridRows && m_gridAutoFlow == o.m_gridAutoFlow && m_gridAutoRows == o.m_gridAutoRows && m_gridAutoColumns == o.m_gridAutoColumns;
}
bool operator!=(const StyleGridData& o) const
@@ -52,6 +53,11 @@ public:
Vector<GridTrackSize> m_gridColumns;
Vector<GridTrackSize> m_gridRows;
+ GridAutoFlow m_gridAutoFlow;
+
+ GridTrackSize m_gridAutoRows;
+ GridTrackSize m_gridAutoColumns;
+
private:
StyleGridData();
StyleGridData(const StyleGridData&);
diff --git a/Source/WebCore/rendering/style/StyleGridItemData.cpp b/Source/WebCore/rendering/style/StyleGridItemData.cpp
index 4edb9edd4..9a64f051e 100644
--- a/Source/WebCore/rendering/style/StyleGridItemData.cpp
+++ b/Source/WebCore/rendering/style/StyleGridItemData.cpp
@@ -35,15 +35,19 @@
namespace WebCore {
StyleGridItemData::StyleGridItemData()
- : m_gridColumn(RenderStyle::initialGridItemColumn())
- , m_gridRow(RenderStyle::initialGridItemRow())
+ : m_gridStart(RenderStyle::initialGridPosition())
+ , m_gridEnd(RenderStyle::initialGridPosition())
+ , m_gridBefore(RenderStyle::initialGridPosition())
+ , m_gridAfter(RenderStyle::initialGridPosition())
{
}
StyleGridItemData::StyleGridItemData(const StyleGridItemData& o)
: RefCounted<StyleGridItemData>()
- , m_gridColumn(o.m_gridColumn)
- , m_gridRow(o.m_gridRow)
+ , m_gridStart(o.m_gridStart)
+ , m_gridEnd(o.m_gridEnd)
+ , m_gridBefore(o.m_gridBefore)
+ , m_gridAfter(o.m_gridAfter)
{
}
diff --git a/Source/WebCore/rendering/style/StyleGridItemData.h b/Source/WebCore/rendering/style/StyleGridItemData.h
index 2f7487b86..32fcb6f76 100644
--- a/Source/WebCore/rendering/style/StyleGridItemData.h
+++ b/Source/WebCore/rendering/style/StyleGridItemData.h
@@ -46,7 +46,8 @@ public:
bool operator==(const StyleGridItemData& o) const
{
- return m_gridColumn == o.m_gridColumn && m_gridRow == o.m_gridRow;
+ return m_gridStart == o.m_gridStart && m_gridEnd == o.m_gridEnd
+ && m_gridBefore == o.m_gridBefore && m_gridAfter == o.m_gridAfter;
}
bool operator!=(const StyleGridItemData& o) const
@@ -54,8 +55,10 @@ public:
return !(*this == o);
}
- GridPosition m_gridColumn;
- GridPosition m_gridRow;
+ GridPosition m_gridStart;
+ GridPosition m_gridEnd;
+ GridPosition m_gridBefore;
+ GridPosition m_gridAfter;
private:
StyleGridItemData();
diff --git a/Source/WebCore/rendering/style/StyleImage.h b/Source/WebCore/rendering/style/StyleImage.h
index 486ec3dab..70f336088 100644
--- a/Source/WebCore/rendering/style/StyleImage.h
+++ b/Source/WebCore/rendering/style/StyleImage.h
@@ -34,6 +34,7 @@
namespace WebCore {
+class CachedImage;
class CSSValue;
class RenderObject;
@@ -64,7 +65,8 @@ public:
virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const = 0;
virtual WrappedImagePtr data() const = 0;
virtual float imageScaleFactor() const { return 1; }
- virtual bool hasAlpha(const RenderObject*) const = 0;
+ virtual bool knownToBeOpaque(const RenderObject*) const = 0;
+ virtual CachedImage* cachedImage() const { return 0; }
ALWAYS_INLINE bool isCachedImage() const { return m_isCachedImage; }
ALWAYS_INLINE bool isPendingImage() const { return m_isPendingImage; }
diff --git a/Source/WebCore/rendering/style/StylePendingImage.h b/Source/WebCore/rendering/style/StylePendingImage.h
index 192063be7..b689ee779 100644
--- a/Source/WebCore/rendering/style/StylePendingImage.h
+++ b/Source/WebCore/rendering/style/StylePendingImage.h
@@ -26,6 +26,7 @@
#ifndef StylePendingImage_h
#define StylePendingImage_h
+#include "CSSCursorImageValue.h"
#include "CSSImageGeneratorValue.h"
#if ENABLE(CSS_IMAGE_SET)
#include "CSSImageSetValue.h"
@@ -49,6 +50,7 @@ public:
virtual PassRefPtr<CSSValue> cssValue() const { return m_value; }
CSSImageValue* cssImageValue() const { return m_value->isImageValue() ? static_cast<CSSImageValue*>(m_value) : 0; }
CSSImageGeneratorValue* cssImageGeneratorValue() const { return m_value->isImageGeneratorValue() ? static_cast<CSSImageGeneratorValue*>(m_value) : 0; }
+ CSSCursorImageValue* cssCursorImageValue() const { return m_value->isCursorImageValue() ? static_cast<CSSCursorImageValue*>(m_value) : 0; }
#if ENABLE(CSS_IMAGE_SET)
CSSImageSetValue* cssImageSetValue() const { return m_value->isImageSetValue() ? static_cast<CSSImageSetValue*>(m_value) : 0; }
#endif
@@ -66,7 +68,7 @@ public:
ASSERT_NOT_REACHED();
return 0;
}
- virtual bool hasAlpha(const RenderObject*) const { return true; }
+ virtual bool knownToBeOpaque(const RenderObject*) const { return false; }
private:
StylePendingImage(CSSValue* value)
diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp
index 14715e0a5..2e1d9d0a6 100644
--- a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp
+++ b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp
@@ -28,8 +28,6 @@
#include "RenderStyleConstants.h"
#include "ShadowData.h"
#include "StyleImage.h"
-#include "WebCoreMemoryInstrumentation.h"
-#include <wtf/MemoryObjectInfo.h>
namespace WebCore {
@@ -70,13 +68,14 @@ StyleRareInheritedData::StyleRareInheritedData()
, m_effectiveZoom(RenderStyle::initialZoom())
, widows(RenderStyle::initialWidows())
, orphans(RenderStyle::initialOrphans())
+ , m_hasAutoWidows(true)
+ , m_hasAutoOrphans(true)
, textSecurity(RenderStyle::initialTextSecurity())
, userModify(READ_ONLY)
, wordBreak(RenderStyle::initialWordBreak())
, overflowWrap(RenderStyle::initialOverflowWrap())
, nbspMode(NBNORMAL)
, lineBreak(LineBreakAuto)
- , textSizeAdjust(RenderStyle::initialTextSizeAdjust())
, resize(RenderStyle::initialResize())
, userSelect(RenderStyle::initialUserSelect())
, colorSpace(ColorSpaceDeviceRGB)
@@ -85,6 +84,11 @@ StyleRareInheritedData::StyleRareInheritedData()
, textEmphasisFill(TextEmphasisFillFilled)
, textEmphasisMark(TextEmphasisMarkNone)
, textEmphasisPosition(TextEmphasisPositionOver)
+ , m_textOrientation(TextOrientationVerticalRight)
+#if ENABLE(CSS3_TEXT)
+ , m_textIndentLine(RenderStyle::initialTextIndentLine())
+ , m_textIndentType(RenderStyle::initialTextIndentType())
+#endif
, m_lineBoxContain(RenderStyle::initialLineBoxContain())
#if ENABLE(CSS_IMAGE_ORIENTATION)
, m_imageOrientation(RenderStyle::initialImageOrientation())
@@ -101,6 +105,8 @@ StyleRareInheritedData::StyleRareInheritedData()
#endif
#if ENABLE(CSS3_TEXT)
, m_textAlignLast(RenderStyle::initialTextAlignLast())
+ , m_textJustify(RenderStyle::initialTextJustify())
+ , m_textUnderlinePosition(RenderStyle::initialTextUnderlinePosition())
#endif // CSS3_TEXT
, m_rubyPosition(RenderStyle::initialRubyPosition())
, hyphenationLimitBefore(-1)
@@ -137,13 +143,14 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
, m_effectiveZoom(o.m_effectiveZoom)
, widows(o.widows)
, orphans(o.orphans)
+ , m_hasAutoWidows(o.m_hasAutoWidows)
+ , m_hasAutoOrphans(o.m_hasAutoOrphans)
, textSecurity(o.textSecurity)
, userModify(o.userModify)
, wordBreak(o.wordBreak)
, overflowWrap(o.overflowWrap)
, nbspMode(o.nbspMode)
, lineBreak(o.lineBreak)
- , textSizeAdjust(o.textSizeAdjust)
, resize(o.resize)
, userSelect(o.userSelect)
, colorSpace(o.colorSpace)
@@ -152,6 +159,11 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
, textEmphasisFill(o.textEmphasisFill)
, textEmphasisMark(o.textEmphasisMark)
, textEmphasisPosition(o.textEmphasisPosition)
+ , m_textOrientation(o.m_textOrientation)
+#if ENABLE(CSS3_TEXT)
+ , m_textIndentLine(o.m_textIndentLine)
+ , m_textIndentType(o.m_textIndentType)
+#endif
, m_lineBoxContain(o.m_lineBoxContain)
#if ENABLE(CSS_IMAGE_ORIENTATION)
, m_imageOrientation(o.m_imageOrientation)
@@ -168,6 +180,8 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
#endif
#if ENABLE(CSS3_TEXT)
, m_textAlignLast(o.m_textAlignLast)
+ , m_textJustify(o.m_textJustify)
+ , m_textUnderlinePosition(o.m_textUnderlinePosition)
#endif // CSS3_TEXT
, m_rubyPosition(o.m_rubyPosition)
, hyphenationString(o.hyphenationString)
@@ -203,6 +217,15 @@ static bool cursorDataEquivalent(const CursorList* c1, const CursorList* c2)
return (*c1 == *c2);
}
+static bool quotesDataEquivalent(const QuotesData* q1, const QuotesData* q2)
+{
+ if (q1 == q2)
+ return true;
+ if ((!q1 && q2) || (q1 && !q2))
+ return false;
+ return (*q1 == *q2);
+}
+
bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
{
return textStrokeColor == o.textStrokeColor
@@ -222,6 +245,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
&& m_effectiveZoom == o.m_effectiveZoom
&& widows == o.widows
&& orphans == o.orphans
+ && m_hasAutoWidows == o.m_hasAutoWidows
+ && m_hasAutoOrphans == o.m_hasAutoOrphans
&& textSecurity == o.textSecurity
&& userModify == o.userModify
&& wordBreak == o.wordBreak
@@ -231,7 +256,6 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
&& useTouchOverflowScrolling == o.useTouchOverflowScrolling
#endif
- && textSizeAdjust == o.textSizeAdjust
&& resize == o.resize
&& userSelect == o.userSelect
&& colorSpace == o.colorSpace
@@ -243,11 +267,16 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
&& textEmphasisFill == o.textEmphasisFill
&& textEmphasisMark == o.textEmphasisMark
&& textEmphasisPosition == o.textEmphasisPosition
+ && m_textOrientation == o.m_textOrientation
+#if ENABLE(CSS3_TEXT)
+ && m_textIndentLine == o.m_textIndentLine
+ && m_textIndentType == o.m_textIndentType
+#endif
&& m_lineBoxContain == o.m_lineBoxContain
&& hyphenationString == o.hyphenationString
&& locale == o.locale
&& textEmphasisCustomMark == o.textEmphasisCustomMark
- && QuotesData::equals(quotes.get(), o.quotes.get())
+ && quotesDataEquivalent(quotes.get(), o.quotes.get())
&& m_tabSize == o.m_tabSize
&& m_lineGrid == o.m_lineGrid
#if ENABLE(CSS_IMAGE_ORIENTATION)
@@ -261,6 +290,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
#endif
#if ENABLE(CSS3_TEXT)
&& m_textAlignLast == o.m_textAlignLast
+ && m_textJustify == o.m_textJustify
+ && m_textUnderlinePosition == o.m_textUnderlinePosition
#endif // CSS3_TEXT
&& m_rubyPosition == o.m_rubyPosition
&& m_lineSnap == o.m_lineSnap
@@ -280,20 +311,4 @@ bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData&
return true;
}
-void StyleRareInheritedData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
- info.addMember(textShadow);
- info.addMember(highlight);
- info.addMember(cursorData);
- info.addMember(hyphenationString);
- info.addMember(locale);
- info.addMember(textEmphasisCustomMark);
- info.addMember(quotes);
- info.addMember(m_lineGrid);
-#if ENABLE(CSS_VARIABLES)
- info.addMember(m_variables);
-#endif
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.h b/Source/WebCore/rendering/style/StyleRareInheritedData.h
index 216c10179..34b80ea52 100644
--- a/Source/WebCore/rendering/style/StyleRareInheritedData.h
+++ b/Source/WebCore/rendering/style/StyleRareInheritedData.h
@@ -59,8 +59,6 @@ public:
}
bool shadowDataEquivalent(const StyleRareInheritedData&) const;
- void reportMemoryUsage(MemoryObjectInfo*) const;
-
RefPtr<StyleImage> listStyleImage;
Color textStrokeColor;
@@ -82,6 +80,8 @@ public:
// Paged media properties.
short widows;
short orphans;
+ unsigned m_hasAutoWidows : 1;
+ unsigned m_hasAutoOrphans : 1;
unsigned textSecurity : 2; // ETextSecurity
unsigned userModify : 2; // EUserModify (editing)
@@ -89,7 +89,6 @@ public:
unsigned overflowWrap : 1; // EOverflowWrap
unsigned nbspMode : 1; // ENBSPMode
unsigned lineBreak : 3; // LineBreak
- unsigned textSizeAdjust : 1; // An Apple extension.
unsigned resize : 2; // EResize
unsigned userSelect : 2; // EUserSelect
unsigned colorSpace : 1; // ColorSpace
@@ -98,6 +97,11 @@ public:
unsigned textEmphasisFill : 1; // TextEmphasisFill
unsigned textEmphasisMark : 3; // TextEmphasisMark
unsigned textEmphasisPosition : 1; // TextEmphasisPosition
+ unsigned m_textOrientation : 2; // TextOrientation
+#if ENABLE(CSS3_TEXT)
+ unsigned m_textIndentLine : 1; // TextIndentLine
+ unsigned m_textIndentType : 1; // TextIndentType
+#endif
unsigned m_lineBoxContain: 7; // LineBoxContain
// CSS Image Values Level 3
#if ENABLE(CSS_IMAGE_ORIENTATION)
@@ -114,7 +118,9 @@ public:
unsigned m_imageResolutionSnap : 1; // ImageResolutionSnap
#endif
#if ENABLE(CSS3_TEXT)
- unsigned m_textAlignLast : 3; // ETextAlignLast
+ unsigned m_textAlignLast : 3; // TextAlignLast
+ unsigned m_textJustify : 3; // TextJustify
+ unsigned m_textUnderlinePosition : 3; // TextUnderlinePosition
#endif // CSS3_TEXT
unsigned m_rubyPosition : 1; // RubyPosition
diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp
index ed9e9a2ef..966bfcb15 100644
--- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp
+++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp
@@ -30,10 +30,6 @@
#include "StyleTransformData.h"
#include "StyleImage.h"
#include "StyleResolver.h"
-#include "WebCoreMemoryInstrumentation.h"
-#include <wtf/MemoryInstrumentationHashMap.h>
-#include <wtf/MemoryInstrumentationVector.h>
-#include <wtf/MemoryObjectInfo.h>
namespace WebCore {
@@ -59,7 +55,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData()
, m_order(RenderStyle::initialOrder())
, m_flowThread(RenderStyle::initialFlowThread())
, m_regionThread(RenderStyle::initialRegionThread())
- , m_regionOverflow(RenderStyle::initialRegionOverflow())
+ , m_regionFragment(RenderStyle::initialRegionFragment())
, m_regionBreakAfter(RenderStyle::initialPageBreak())
, m_regionBreakBefore(RenderStyle::initialPageBreak())
, m_regionBreakInside(RenderStyle::initialPageBreak())
@@ -129,6 +125,10 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited
, m_shapeMargin(o.m_shapeMargin)
, m_shapePadding(o.m_shapePadding)
, m_clipPath(o.m_clipPath)
+#if ENABLE(CSS3_TEXT)
+ , m_textDecorationColor(o.m_textDecorationColor)
+ , m_visitedLinkTextDecorationColor(o.m_visitedLinkTextDecorationColor)
+#endif // CSS3_TEXT
, m_visitedLinkBackgroundColor(o.m_visitedLinkBackgroundColor)
, m_visitedLinkOutlineColor(o.m_visitedLinkOutlineColor)
, m_visitedLinkBorderLeftColor(o.m_visitedLinkBorderLeftColor)
@@ -138,7 +138,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited
, m_order(o.m_order)
, m_flowThread(o.m_flowThread)
, m_regionThread(o.m_regionThread)
- , m_regionOverflow(o.m_regionOverflow)
+ , m_regionFragment(o.m_regionFragment)
, m_regionBreakAfter(o.m_regionBreakAfter)
, m_regionBreakBefore(o.m_regionBreakBefore)
, m_regionBreakInside(o.m_regionBreakInside)
@@ -214,6 +214,10 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c
&& m_shapeMargin == o.m_shapeMargin
&& m_shapePadding == o.m_shapePadding
&& m_clipPath == o.m_clipPath
+#if ENABLE(CSS3_TEXT)
+ && m_textDecorationColor == o.m_textDecorationColor
+ && m_visitedLinkTextDecorationColor == o.m_visitedLinkTextDecorationColor
+#endif // CSS3_TEXT
&& m_visitedLinkBackgroundColor == o.m_visitedLinkBackgroundColor
&& m_visitedLinkOutlineColor == o.m_visitedLinkOutlineColor
&& m_visitedLinkBorderLeftColor == o.m_visitedLinkBorderLeftColor
@@ -223,7 +227,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c
&& m_order == o.m_order
&& m_flowThread == o.m_flowThread
&& m_regionThread == o.m_regionThread
- && m_regionOverflow == o.m_regionOverflow
+ && m_regionFragment == o.m_regionFragment
&& m_regionBreakAfter == o.m_regionBreakAfter
&& m_regionBreakBefore == o.m_regionBreakBefore
&& m_regionBreakInside == o.m_regionBreakInside
@@ -316,33 +320,4 @@ bool StyleRareNonInheritedData::transitionDataEquivalent(const StyleRareNonInher
return true;
}
-void StyleRareNonInheritedData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
-#if ENABLE(DASHBOARD_SUPPORT)
- info.addMember(m_dashboardRegions);
-#endif
- info.addMember(m_deprecatedFlexibleBox);
- info.addMember(m_flexibleBox);
- info.addMember(m_marquee);
- info.addMember(m_multiCol);
- info.addMember(m_transform);
-#if ENABLE(CSS_FILTERS)
- info.addMember(m_filter);
-#endif
- info.addMember(m_grid);
- info.addMember(m_gridItem);
- info.addMember(m_content);
- info.addMember(m_counterDirectives);
- info.addMember(m_boxShadow);
- info.addMember(m_boxReflect);
- info.addMember(m_animations);
- info.addMember(m_transitions);
- info.addMember(m_shapeInside);
- info.addMember(m_shapeOutside);
- info.addMember(m_clipPath);
- info.addMember(m_flowThread);
- info.addMember(m_regionThread);
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h
index c4ac0f6f3..11625b3de 100644
--- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h
+++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h
@@ -30,10 +30,10 @@
#include "CounterDirectives.h"
#include "CursorData.h"
#include "DataRef.h"
-#include "ExclusionShapeValue.h"
#include "FillLayer.h"
#include "LineClampValue.h"
#include "NinePieceImage.h"
+#include "ShapeValue.h"
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/Vector.h>
@@ -91,8 +91,6 @@ public:
bool animationDataEquivalent(const StyleRareNonInheritedData&) const;
bool transitionDataEquivalent(const StyleRareNonInheritedData&) const;
- void reportMemoryUsage(MemoryObjectInfo*) const;
-
float opacity; // Whether or not we're transparent.
float m_aspectRatioDenominator;
@@ -138,13 +136,17 @@ public:
LengthSize m_pageSize;
- RefPtr<ExclusionShapeValue> m_shapeInside;
- RefPtr<ExclusionShapeValue> m_shapeOutside;
+ RefPtr<ShapeValue> m_shapeInside;
+ RefPtr<ShapeValue> m_shapeOutside;
Length m_shapeMargin;
Length m_shapePadding;
RefPtr<ClipPathOperation> m_clipPath;
+#if ENABLE(CSS3_TEXT)
+ Color m_textDecorationColor;
+ Color m_visitedLinkTextDecorationColor;
+#endif // CSS3_TEXT
Color m_visitedLinkBackgroundColor;
Color m_visitedLinkOutlineColor;
Color m_visitedLinkBorderLeftColor;
@@ -156,7 +158,7 @@ public:
AtomicString m_flowThread;
AtomicString m_regionThread;
- unsigned m_regionOverflow : 1; // RegionOverflow
+ unsigned m_regionFragment : 1; // RegionFragment
unsigned m_regionBreakAfter : 2; // EPageBreak
unsigned m_regionBreakBefore : 2; // EPageBreak
diff --git a/Source/WebCore/rendering/style/StyleVisualData.h b/Source/WebCore/rendering/style/StyleVisualData.h
index b5140a78d..117cff1aa 100644
--- a/Source/WebCore/rendering/style/StyleVisualData.h
+++ b/Source/WebCore/rendering/style/StyleVisualData.h
@@ -52,7 +52,7 @@ public:
LengthBox clip;
bool hasClip : 1;
- unsigned textDecoration : ETextDecorationBits; // Text decorations defined *only* by this element.
+ unsigned textDecoration : TextDecorationBits; // Text decorations defined *only* by this element.
#if ENABLE(TEXT_AUTOSIZING)
float m_textAutosizingMultiplier;
diff --git a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
index a6bcd0296..234e7ce6c 100644
--- a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
@@ -77,3 +77,4 @@
#include "SVGTextMetrics.cpp"
#include "SVGTextMetricsBuilder.cpp"
#include "SVGTextQuery.cpp"
+
diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp
index 9f39357c1..f120b9946 100644
--- a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp
@@ -31,8 +31,8 @@
namespace WebCore {
-RenderSVGBlock::RenderSVGBlock(SVGElement* node)
- : RenderBlock(node)
+RenderSVGBlock::RenderSVGBlock(SVGElement* element)
+ : RenderBlock(element)
{
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.h b/Source/WebCore/rendering/svg/RenderSVGBlock.h
index 222d5ee20..0bd300c1c 100644
--- a/Source/WebCore/rendering/svg/RenderSVGBlock.h
+++ b/Source/WebCore/rendering/svg/RenderSVGBlock.h
@@ -41,6 +41,8 @@ private:
virtual void setStyle(PassRefPtr<RenderStyle>);
virtual void updateFromStyle() OVERRIDE;
+ virtual bool isRenderSVGBlock() const OVERRIDE { return true; };
+
virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const;
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp
index 5069f41aa..9305dc6b3 100644
--- a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp
@@ -35,6 +35,7 @@
#include "SVGResources.h"
#include "SVGResourcesCache.h"
#include "SVGStyledElement.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -137,7 +138,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&)
}
if (continueRendering) {
- childPaintInfo.updatePaintingRootForChildren(this);
+ childPaintInfo.updateSubtreePaintRootForChildren(this);
for (RenderObject* child = firstChild(); child; child = child->nextSibling())
child->paint(childPaintInfo, IntPoint());
}
@@ -150,12 +151,12 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&)
// We should instead disable our clip during PaintPhaseOutline
if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) {
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect));
- paintOutline(paintInfo.context, paintRectInParent);
+ paintOutline(paintInfo, paintRectInParent);
}
}
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
-void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&)
+void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*)
{
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
if (!paintRectInParent.isEmpty())
@@ -186,6 +187,12 @@ bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTest
}
}
+ // Accessibility wants to return SVG containers, if appropriate.
+ if (request.type() & HitTestRequest::AccessibilityHitTest && m_objectBoundingBox.contains(localPoint)) {
+ updateHitTestResult(result, roundedLayoutPoint(localPoint));
+ return true;
+ }
+
// Spec: Only graphical elements can be targeted by the mouse, period.
// 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
return false;
diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h
index 3c0fa9814..70e1ec8d5 100644
--- a/Source/WebCore/rendering/svg/RenderSVGContainer.h
+++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h
@@ -44,6 +44,7 @@ public:
virtual void paint(PaintInfo&, const LayoutPoint&);
virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; }
+ virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesUpdate; }
virtual bool didTransformToRootUpdate() { return false; }
bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; }
@@ -58,7 +59,7 @@ protected:
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE;
virtual void removeChild(RenderObject*) OVERRIDE;
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; }
virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; }
@@ -90,13 +91,13 @@ private:
inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object)
{
- ASSERT(!object || object->isSVGContainer());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGContainer());
return static_cast<RenderSVGContainer*>(object);
}
inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object)
{
- ASSERT(!object || object->isSVGContainer());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGContainer());
return static_cast<const RenderSVGContainer*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp b/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp
index b4a76531e..8c1df2da4 100644
--- a/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp
@@ -31,12 +31,12 @@
#include "SVGCircleElement.h"
#include "SVGEllipseElement.h"
+#include "SVGGraphicsElement.h"
#include "SVGNames.h"
-#include "SVGStyledTransformableElement.h"
namespace WebCore {
-RenderSVGEllipse::RenderSVGEllipse(SVGStyledTransformableElement* node)
+RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement* node)
: RenderSVGShape(node)
, m_usePathFallback(false)
{
diff --git a/Source/WebCore/rendering/svg/RenderSVGEllipse.h b/Source/WebCore/rendering/svg/RenderSVGEllipse.h
index f5129df90..a5af34bc4 100644
--- a/Source/WebCore/rendering/svg/RenderSVGEllipse.h
+++ b/Source/WebCore/rendering/svg/RenderSVGEllipse.h
@@ -29,13 +29,13 @@
#if ENABLE(SVG)
#include "RenderSVGShape.h"
-#include "SVGStyledTransformableElement.h"
+#include "SVGGraphicsElement.h"
namespace WebCore {
class RenderSVGEllipse : public RenderSVGShape {
public:
- explicit RenderSVGEllipse(SVGStyledTransformableElement*);
+ explicit RenderSVGEllipse(SVGGraphicsElement*);
virtual ~RenderSVGEllipse();
private:
diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp
index 408d887f0..9bd4672ed 100644
--- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp
@@ -35,6 +35,7 @@
#include "SVGResourcesCache.h"
#include "SVGSVGElement.h"
#include "TransformState.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -193,9 +194,9 @@ bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&,
return false;
}
-void RenderSVGForeignObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
+void RenderSVGForeignObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const
{
- SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, mode & SnapOffsetForTransforms, wasFixed);
+ SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
}
const RenderObject* RenderSVGForeignObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
index 00979de61..02c29cc05 100644
--- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
+++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
@@ -54,7 +54,7 @@ public:
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
virtual bool isSVGForeignObject() const { return true; }
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp
index 31d5da5ca..9b41ae319 100644
--- a/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp
@@ -27,6 +27,7 @@
#include "SVGNames.h"
#include "SVGResourcesCache.h"
#include "SVGStopElement.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -72,7 +73,7 @@ SVGGradientElement* RenderSVGGradientStop::gradientElement() const
{
ContainerNode* parentNode = node()->parentNode();
if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag))
- return static_cast<SVGGradientElement*>(parentNode);
+ return toSVGGradientElement(parentNode);
return 0;
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
index 1c0e4033b..ac8b97ac9 100644
--- a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
+++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
@@ -47,6 +47,7 @@ public:
virtual FloatRect objectBoundingBox() const { return FloatRect(); }
virtual FloatRect strokeBoundingBox() const { return FloatRect(); }
virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
+ virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) OVERRIDE { return false; }
protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -57,7 +58,7 @@ private:
inline const RenderSVGGradientStop* toRenderSVGGradientStop(const RenderObject* object)
{
- ASSERT(!object || object->isSVGGradientStop());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGGradientStop());
return static_cast<const RenderSVGGradientStop*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp
index 4d37e13d7..2a015a5c0 100644
--- a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp
@@ -24,6 +24,7 @@
#include "RenderSVGPath.h"
#include "SVGStyledElement.h"
+#include <wtf/StackStats.h>
namespace WebCore {
diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.cpp b/Source/WebCore/rendering/svg/RenderSVGImage.cpp
index 45db954df..76d7c5c2e 100644
--- a/Source/WebCore/rendering/svg/RenderSVGImage.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGImage.cpp
@@ -44,6 +44,7 @@
#include "SVGRenderingContext.h"
#include "SVGResources.h"
#include "SVGResourcesCache.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -63,7 +64,7 @@ RenderSVGImage::~RenderSVGImage()
bool RenderSVGImage::updateImageViewport()
{
- SVGImageElement* image = static_cast<SVGImageElement*>(node());
+ SVGImageElement* image = toSVGImageElement(node());
FloatRect oldBoundaries = m_objectBoundingBox;
SVGLengthContext lengthContext(image);
@@ -87,7 +88,7 @@ void RenderSVGImage::layout()
bool transformOrBoundariesUpdate = m_needsTransformUpdate || m_needsBoundariesUpdate;
if (m_needsTransformUpdate) {
- m_localTransform = static_cast<SVGImageElement*>(node())->animatedLocalTransform();
+ m_localTransform = toSVGImageElement(node())->animatedLocalTransform();
m_needsTransformUpdate = false;
}
@@ -132,22 +133,35 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&)
SVGRenderingContext renderingContext(this, childPaintInfo);
if (renderingContext.isRenderingPrepared()) {
- RefPtr<Image> image = m_imageResource->image();
- FloatRect destRect = m_objectBoundingBox;
- FloatRect srcRect(0, 0, image->width(), image->height());
+ if (style()->svgStyle()->bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground))
+ return;
- SVGImageElement* imageElement = static_cast<SVGImageElement*>(node());
- imageElement->preserveAspectRatio().transformRect(destRect, srcRect);
-
- childPaintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect);
+ paintForeground(childPaintInfo);
}
}
if (drawsOutline)
- paintOutline(childPaintInfo.context, IntRect(boundingBox));
+ paintOutline(childPaintInfo, IntRect(boundingBox));
}
}
+void RenderSVGImage::paintForeground(PaintInfo& paintInfo)
+{
+ RefPtr<Image> image = m_imageResource->image();
+ FloatRect destRect = m_objectBoundingBox;
+ FloatRect srcRect(0, 0, image->width(), image->height());
+
+ SVGImageElement* imageElement = toSVGImageElement(node());
+ imageElement->preserveAspectRatio().transformRect(destRect, srcRect);
+
+ paintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect);
+}
+
+void RenderSVGImage::invalidateBufferedForeground()
+{
+ m_bufferedForeground.clear();
+}
+
bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
{
// We only draw in the forground phase, so we only hit-test then.
@@ -188,10 +202,12 @@ void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*)
m_objectBoundingBox = FloatRect();
updateImageViewport();
+ invalidateBufferedForeground();
+
repaint();
}
-void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&)
+void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*)
{
// this is called from paint() after the localTransform has already been applied
IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates());
diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.h b/Source/WebCore/rendering/svg/RenderSVGImage.h
index 905a8d37d..af85b895b 100644
--- a/Source/WebCore/rendering/svg/RenderSVGImage.h
+++ b/Source/WebCore/rendering/svg/RenderSVGImage.h
@@ -43,14 +43,18 @@ public:
bool updateImageViewport();
virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; }
+ virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesUpdate; }
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
RenderImageResource* imageResource() { return m_imageResource.get(); }
const RenderImageResource* imageResource() const { return m_imageResource.get(); }
+ // Note: Assumes the PaintInfo context has had all local transforms applied.
+ void paintForeground(PaintInfo&);
+
private:
virtual const char* renderName() const { return "RenderSVGImage"; }
- virtual bool isSVGImage() const { return true; }
+ virtual bool isSVGImage() const OVERRIDE { return true; }
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
@@ -59,13 +63,15 @@ private:
virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; }
virtual FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const OVERRIDE { return m_repaintBoundingBoxExcludingShadow; }
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
virtual void layout();
virtual void paint(PaintInfo&, const LayoutPoint&);
+ void invalidateBufferedForeground();
+
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
virtual AffineTransform localTransform() const { return m_localTransform; }
@@ -78,17 +84,19 @@ private:
FloatRect m_repaintBoundingBox;
FloatRect m_repaintBoundingBoxExcludingShadow;
OwnPtr<RenderImageResource> m_imageResource;
+
+ OwnPtr<ImageBuffer> m_bufferedForeground;
};
inline RenderSVGImage* toRenderSVGImage(RenderObject* object)
{
- ASSERT(!object || object->isSVGImage());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGImage());
return static_cast<RenderSVGImage*>(object);
}
inline const RenderSVGImage* toRenderSVGImage(const RenderObject* object)
{
- ASSERT(!object || object->isSVGImage());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGImage());
return static_cast<const RenderSVGImage*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp
index 9252c54f3..e8dfe03e4 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp
@@ -32,8 +32,8 @@
namespace WebCore {
-RenderSVGInline::RenderSVGInline(Node* n)
- : RenderInline(n)
+RenderSVGInline::RenderSVGInline(Element* element)
+ : RenderInline(element)
{
setAlwaysCreateLineBoxes();
}
@@ -79,9 +79,9 @@ void RenderSVGInline::computeFloatRectForRepaint(const RenderLayerModelObject* r
SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed);
}
-void RenderSVGInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
+void RenderSVGInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const
{
- SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, mode & SnapOffsetForTransforms, wasFixed);
+ SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
}
const RenderObject* RenderSVGInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h
index 50dec2ddd..dbeb0d3ed 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInline.h
+++ b/Source/WebCore/rendering/svg/RenderSVGInline.h
@@ -30,7 +30,7 @@ namespace WebCore {
class RenderSVGInline : public RenderInline {
public:
- explicit RenderSVGInline(Node*);
+ explicit RenderSVGInline(Element*);
virtual const char* renderName() const { return "RenderSVGInline"; }
virtual bool requiresLayer() const { return false; }
@@ -47,7 +47,7 @@ public:
virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE;
virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE;
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const;
diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
index 2371d1abf..4bf0ec595 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
@@ -185,7 +185,7 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point)
if (!box->isSVGInlineTextBox())
continue;
- SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
+ SVGInlineTextBox* textBox = toSVGInlineTextBox(box);
Vector<SVGTextFragment>& fragments = textBox->textFragments();
unsigned textFragmentsSize = fragments.size();
@@ -228,8 +228,7 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c
Document* document = renderer->document();
ASSERT(document);
- StyleResolver* styleResolver = document->styleResolver();
- ASSERT(styleResolver);
+ StyleResolver* styleResolver = document->ensureStyleResolver();
// Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified
scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer);
diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h
index 7643cf1ab..b6fc83008 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h
@@ -69,13 +69,13 @@ private:
inline RenderSVGInlineText* toRenderSVGInlineText(RenderObject* object)
{
- ASSERT(!object || object->isSVGInlineText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGInlineText());
return static_cast<RenderSVGInlineText*>(object);
}
inline const RenderSVGInlineText* toRenderSVGInlineText(const RenderObject* object)
{
- ASSERT(!object || object->isSVGInlineText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGInlineText());
return static_cast<const RenderSVGInlineText*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp
index 019204e4e..6733a2e05 100644
--- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp
@@ -57,9 +57,9 @@ void RenderSVGModelObject::computeFloatRectForRepaint(const RenderLayerModelObje
SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed);
}
-void RenderSVGModelObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
+void RenderSVGModelObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const
{
- SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, mode & SnapOffsetForTransforms, wasFixed);
+ SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
}
const RenderObject* RenderSVGModelObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
@@ -131,8 +131,8 @@ static void getElementCTM(SVGElement* element, AffineTransform& transform)
Node* current = element;
while (current && current->isSVGElement()) {
- SVGElement* currentElement = static_cast<SVGElement*>(current);
- if (currentElement->isStyled()) {
+ SVGElement* currentElement = toSVGElement(current);
+ if (currentElement->isSVGStyledElement()) {
localTransform = currentElement->renderer()->localToParentTransform();
transform = localTransform.multiply(transform);
}
@@ -140,7 +140,7 @@ static void getElementCTM(SVGElement* element, AffineTransform& transform)
if (currentElement == stopAtElement)
break;
- current = current->parentOrHostNode();
+ current = current->parentOrShadowHostNode();
}
}
@@ -180,7 +180,7 @@ bool RenderSVGModelObject::checkIntersection(RenderObject* renderer, const Float
if (!isGraphicsElement(renderer))
return false;
AffineTransform ctm;
- SVGElement* svgElement = static_cast<SVGElement*>(renderer->node());
+ SVGElement* svgElement = toSVGElement(renderer->node());
getElementCTM(svgElement, ctm);
ASSERT(svgElement->renderer());
return intersectsAllowingEmpty(rect, ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates()));
@@ -193,7 +193,7 @@ bool RenderSVGModelObject::checkEnclosure(RenderObject* renderer, const FloatRec
if (!isGraphicsElement(renderer))
return false;
AffineTransform ctm;
- SVGElement* svgElement = static_cast<SVGElement*>(renderer->node());
+ SVGElement* svgElement = toSVGElement(renderer->node());
getElementCTM(svgElement, ctm);
ASSERT(svgElement->renderer());
return rect.contains(ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates()));
diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h
index dc2d5da39..0511f2772 100644
--- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h
+++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h
@@ -58,7 +58,7 @@ public:
virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const;
virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const;
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp
index cf658359d..97f713012 100644
--- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp
@@ -30,13 +30,13 @@
#if ENABLE(SVG)
#include "RenderSVGPath.h"
+#include "SVGGraphicsElement.h"
#include "SVGPathElement.h"
-#include "SVGStyledTransformableElement.h"
#include "SVGSubpathData.h"
namespace WebCore {
-RenderSVGPath::RenderSVGPath(SVGStyledTransformableElement* node)
+RenderSVGPath::RenderSVGPath(SVGGraphicsElement* node)
: RenderSVGShape(node)
{
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.h b/Source/WebCore/rendering/svg/RenderSVGPath.h
index ab1cf1c0b..674289564 100644
--- a/Source/WebCore/rendering/svg/RenderSVGPath.h
+++ b/Source/WebCore/rendering/svg/RenderSVGPath.h
@@ -33,11 +33,11 @@ namespace WebCore {
class RenderSVGPath : public RenderSVGShape {
public:
- explicit RenderSVGPath(SVGStyledTransformableElement*);
+ explicit RenderSVGPath(SVGGraphicsElement*);
virtual ~RenderSVGPath();
private:
- virtual bool isSVGPath() const { return true; }
+ virtual bool isSVGPath() const OVERRIDE { return true; }
virtual const char* renderName() const { return "RenderSVGPath"; }
virtual void updateShapeFromElement() OVERRIDE;
@@ -54,6 +54,12 @@ private:
Vector<FloatPoint> m_zeroLengthLinecapLocations;
};
+inline RenderSVGPath* toRenderSVGPath(RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGPath());
+ return static_cast<RenderSVGPath*>(object);
+}
+
}
#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGRect.cpp b/Source/WebCore/rendering/svg/RenderSVGRect.cpp
index c7f9c5b7b..1fa46a4a1 100644
--- a/Source/WebCore/rendering/svg/RenderSVGRect.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGRect.cpp
@@ -32,7 +32,6 @@
#include "SVGNames.h"
#include "SVGRectElement.h"
-#include <wtf/Platform.h>
namespace WebCore {
diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.cpp b/Source/WebCore/rendering/svg/RenderSVGResource.cpp
index fd16ef29d..6ced1c79c 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResource.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResource.cpp
@@ -180,7 +180,7 @@ static inline void removeFromCacheAndInvalidateDependencies(RenderObject* object
if (!object->node() || !object->node()->isSVGElement())
return;
- HashSet<SVGElement*>* dependencies = object->document()->accessSVGExtensions()->setOfElementsReferencingTarget(static_cast<SVGElement*>(object->node()));
+ HashSet<SVGElement*>* dependencies = object->document()->accessSVGExtensions()->setOfElementsReferencingTarget(toSVGElement(object->node()));
if (!dependencies)
return;
HashSet<SVGElement*>::iterator end = dependencies->end();
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
index 7339e2859..9967d70ed 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
@@ -39,16 +39,15 @@
#include "RenderStyle.h"
#include "SVGClipPathElement.h"
#include "SVGElement.h"
+#include "SVGGraphicsElement.h"
#include "SVGNames.h"
#include "SVGRenderSupport.h"
#include "SVGRenderingContext.h"
#include "SVGResources.h"
#include "SVGResourcesCache.h"
#include "SVGStyledElement.h"
-#include "SVGStyledTransformableElement.h"
#include "SVGUnitTypes.h"
#include "SVGUseElement.h"
-#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -117,9 +116,9 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const
// Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts.
if (renderer->isSVGText())
return false;
- if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable())
+ if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGGraphicsElement())
continue;
- SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode);
+ SVGGraphicsElement* styled = toSVGGraphicsElement(childNode);
RenderStyle* style = renderer->style();
if (!style || style->display() == NONE || style->visibility() != VISIBLE)
continue;
@@ -169,7 +168,7 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons
}
AffineTransform absoluteTransform;
- SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+ SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
if (shouldCreateClipData && !repaintRect.isEmpty()) {
if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated))
@@ -234,7 +233,7 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
// Draw all clipPath children into a global mask.
for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
RenderObject* renderer = childNode->renderer();
- if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGStyledElement() || !renderer)
continue;
if (renderer->needsLayout()) {
frame()->view()->setPaintBehavior(oldBehavior);
@@ -247,7 +246,7 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
WindRule newClipRule = style->svgStyle()->clipRule();
bool isUseElement = childNode->hasTagName(SVGNames::useTag);
if (isUseElement) {
- SVGUseElement* useElement = static_cast<SVGUseElement*>(childNode);
+ SVGUseElement* useElement = toSVGUseElement(childNode);
renderer = useElement->rendererClipChild();
if (!renderer)
continue;
@@ -276,7 +275,7 @@ void RenderSVGResourceClipper::calculateClipContentRepaintRect()
// This is a rough heuristic to appraise the clip size and doesn't consider clip on clip.
for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
RenderObject* renderer = childNode->renderer();
- if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGStyledElement() || !renderer)
continue;
if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag))
continue;
@@ -306,13 +305,13 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin
for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
RenderObject* renderer = childNode->renderer();
- if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGStyledElement() || !renderer)
continue;
if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag))
continue;
IntPoint hitPoint;
HitTestResult result(hitPoint);
- if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent), result, point, HitTestForeground))
+ if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent | HitTestRequest::DisallowShadowContent), result, point, HitTestForeground))
return true;
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
index e311c1c21..38bd67a63 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
@@ -25,9 +25,10 @@
#include "RenderLayer.h"
#include "RenderSVGRoot.h"
#include "RenderView.h"
+#include "SVGGraphicsElement.h"
#include "SVGRenderingContext.h"
#include "SVGResourcesCache.h"
-#include "SVGStyledTransformableElement.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -86,7 +87,7 @@ void RenderSVGResourceContainer::idChanged()
// Remove old id, that is guaranteed to be present in cache.
SVGDocumentExtensions* extensions = svgExtensionsFromNode(node());
extensions->removeResource(m_id);
- m_id = static_cast<Element*>(node())->getIdAttribute();
+ m_id = toElement(node())->getIdAttribute();
registerResource();
}
@@ -114,13 +115,18 @@ void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode
RenderSVGResource::markForLayoutAndParentResourceInvalidation(client, needsLayout);
}
+ markAllClientLayersForInvalidation();
+
+ m_isInvalidating = false;
+}
+
+void RenderSVGResourceContainer::markAllClientLayersForInvalidation()
+{
#if ENABLE(CSS_FILTERS)
HashSet<RenderLayer*>::iterator layerEnd = m_clientLayers.end();
for (HashSet<RenderLayer*>::iterator it = m_clientLayers.begin(); it != layerEnd; ++it)
(*it)->filterNeedsRepaint();
#endif
-
- m_isInvalidating = false;
}
void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode)
@@ -184,7 +190,7 @@ void RenderSVGResourceContainer::registerResource()
const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
ASSERT((*it)->hasPendingResources());
- (*it)->clearHasPendingResourcesIfPossible();
+ extensions->clearHasPendingResourcesIfPossible(*it);
RenderObject* renderer = (*it)->renderer();
if (!renderer)
continue;
@@ -220,7 +226,7 @@ AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderOb
if (!object->isSVGShape())
return resourceTransform;
- SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node());
+ SVGGraphicsElement* element = toSVGGraphicsElement(object->node());
AffineTransform transform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate);
transform *= resourceTransform;
return transform;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
index 0f074863b..0f425cd45 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
@@ -57,6 +57,7 @@ protected:
// Used from the invalidateClient/invalidateClients methods from classes, inheriting from us.
void markAllClientsForInvalidation(InvalidationMode);
+ void markAllClientLayersForInvalidation();
void markClientForInvalidation(RenderObject*, InvalidationMode);
private:
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
index 7d4eedfc9..c5e6bbb26 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
@@ -49,8 +49,6 @@
#include "Settings.h"
#include "SourceAlpha.h"
#include "SourceGraphic.h"
-
-#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
using namespace std;
@@ -99,7 +97,7 @@ void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool m
PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter)
{
- SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node());
+ SVGFilterElement* filterElement = toSVGFilterElement(node());
FloatRect targetBoundingBox = filter->targetBoundingBox();
// Add effects to the builder
@@ -108,7 +106,7 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter*
if (!node->isSVGElement())
continue;
- SVGElement* element = static_cast<SVGElement*>(node);
+ SVGElement* element = toSVGElement(node);
if (!element->isFilterEffect())
continue;
@@ -121,8 +119,8 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter*
builder->appendEffectToEffectReferences(effect, effectElement->renderer());
effectElement->setStandardAttributes(effect.get());
effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits(), targetBoundingBox));
- effect->setColorSpace(effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB
- ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
+ effect->setOperatingColorSpace(
+ effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
builder->add(effectElement->result(), effect);
}
return builder.release();
@@ -159,14 +157,14 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
OwnPtr<FilterData> filterData(adoptPtr(new FilterData));
FloatRect targetBoundingBox = object->objectBoundingBox();
- SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node());
+ SVGFilterElement* filterElement = toSVGFilterElement(node());
filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnits(), targetBoundingBox);
if (filterData->boundaries.isEmpty())
return false;
// Determine absolute transformation matrix for filter.
AffineTransform absoluteTransform;
- SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+ SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
if (!absoluteTransform.isInvertible())
return false;
@@ -175,9 +173,9 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
// Determine absolute boundaries of the filter and the drawing region.
FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries);
- FloatRect drawingRegion = object->strokeBoundingBox();
- drawingRegion.intersect(filterData->boundaries);
- FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(drawingRegion);
+ filterData->drawingRegion = object->strokeBoundingBox();
+ filterData->drawingRegion.intersect(filterData->boundaries);
+ FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion);
// Create the SVGFilter object.
bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
@@ -222,7 +220,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
// If the drawingRegion is empty, we have something like <g filter=".."/>.
// Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
- if (drawingRegion.isEmpty()) {
+ if (filterData->drawingRegion.isEmpty()) {
ASSERT(!m_filter.contains(object));
filterData->savedContext = context;
m_filter.set(object, filterData.leakPtr());
@@ -236,7 +234,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
OwnPtr<ImageBuffer> sourceGraphic;
RenderingMode renderingMode = object->document()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
- if (!SVGRenderingContext::createImageBuffer(drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) {
+ if (!SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) {
ASSERT(!m_filter.contains(object));
filterData->savedContext = context;
m_filter.set(object, filterData.leakPtr());
@@ -309,13 +307,9 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
// Always true if filterData is just built (filterData->state == FilterData::Built).
if (!lastEffect->hasResult()) {
filterData->state = FilterData::Applying;
- lastEffect->apply();
+ lastEffect->applyAll();
lastEffect->correctFilterResultIfNeeded();
-#if !USE(CG)
- ImageBuffer* resultImage = lastEffect->asImageBuffer();
- if (resultImage)
- resultImage->transformColorSpace(lastEffect->colorSpace(), ColorSpaceDeviceRGB);
-#endif
+ lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB);
}
filterData->state = FilterData::Built;
@@ -335,7 +329,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object)
{
- if (SVGFilterElement* element = static_cast<SVGFilterElement*>(node()))
+ if (SVGFilterElement* element = toSVGFilterElement(node()))
return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnits(), object->objectBoundingBox());
return FloatRect();
@@ -365,6 +359,13 @@ void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, co
// Repaint the image on the screen.
markClientForInvalidation(it->key, RepaintInvalidation);
}
+ markAllClientLayersForInvalidation();
+}
+
+FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const
+{
+ FilterData* filterData = m_filter.get(object);
+ return filterData ? filterData->drawingRegion : FloatRect();
}
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h
index db422c17e..4ad9ad037 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h
@@ -56,6 +56,7 @@ public:
GraphicsContext* savedContext;
AffineTransform shearFreeAbsoluteTransform;
FloatRect boundaries;
+ FloatRect drawingRegion;
FloatSize scale;
FilterDataState state;
};
@@ -68,7 +69,7 @@ public:
virtual ~RenderSVGResourceFilter();
virtual const char* renderName() const { return "RenderSVGResourceFilter"; }
- virtual bool isSVGResourceFilter() const { return true; }
+ virtual bool isSVGResourceFilter() const OVERRIDE { return true; }
virtual void removeAllClientsFromCache(bool markForInvalidation = true);
virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true);
@@ -80,20 +81,27 @@ public:
PassRefPtr<SVGFilterBuilder> buildPrimitives(SVGFilter*);
- SVGUnitTypes::SVGUnitType filterUnits() const { return static_cast<SVGFilterElement*>(node())->filterUnits(); }
- SVGUnitTypes::SVGUnitType primitiveUnits() const { return static_cast<SVGFilterElement*>(node())->primitiveUnits(); }
+ SVGUnitTypes::SVGUnitType filterUnits() const { return toSVGFilterElement(node())->filterUnits(); }
+ SVGUnitTypes::SVGUnitType primitiveUnits() const { return toSVGFilterElement(node())->primitiveUnits(); }
void primitiveAttributeChanged(RenderObject*, const QualifiedName&);
virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
static RenderSVGResourceType s_resourceType;
+ FloatRect drawingRegion(RenderObject*) const;
private:
bool fitsInMaximumImageSize(const FloatSize&, FloatSize&);
HashMap<RenderObject*, FilterData*> m_filter;
};
+inline RenderSVGResourceFilter* toRenderSVGFilter(RenderObject* object)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGResourceFilter());
+ return static_cast<RenderSVGResourceFilter*>(object);
+}
+
}
#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
index f3da929ef..b5177fad9 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
@@ -53,12 +53,12 @@ void RenderSVGResourceFilterPrimitive::styleDidChange(StyleDifference diff, cons
const SVGRenderStyle* newStyle = this->style()->svgStyle();
if (node()->hasTagName(SVGNames::feFloodTag)) {
if (newStyle->floodColor() != oldStyle->svgStyle()->floodColor())
- static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr);
+ toRenderSVGFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr);
if (newStyle->floodOpacity() != oldStyle->svgStyle()->floodOpacity())
- static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr);
+ toRenderSVGFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr);
} else if (node()->hasTagName(SVGNames::feDiffuseLightingTag) || node()->hasTagName(SVGNames::feSpecularLightingTag)) {
if (newStyle->lightingColor() != oldStyle->svgStyle()->lightingColor())
- static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr);
+ toRenderSVGFilter(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr);
}
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
index 30ce1b8cb..25a61239f 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
@@ -31,7 +31,6 @@
#include "RenderSVGText.h"
#include "SVGRenderSupport.h"
#include "SVGRenderingContext.h"
-#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -68,7 +67,7 @@ static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& con
ASSERT(textRootBlock);
AffineTransform absoluteTransform;
- SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+ SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(textRootBlock, absoluteTransform);
FloatRect repaintRect = textRootBlock->repaintRectInLocalCoordinates();
OwnPtr<ImageBuffer> maskImage;
@@ -95,7 +94,7 @@ static inline AffineTransform clipToTextMask(GraphicsContext* context,
ASSERT(textRootBlock);
AffineTransform absoluteTransform;
- SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+ SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(textRootBlock, absoluteTransform);
targetRect = textRootBlock->repaintRectInLocalCoordinates();
SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, targetRect, imageBuffer, false);
@@ -122,12 +121,12 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
// Otherwhise the call to collectGradientAttributes() in createTileImage(), may cause the SVG DOM property
// synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our
// GradientData object! Leaving out the line below will cause svg/dynamic-updates/SVG*GradientElement-svgdom* to crash.
- SVGGradientElement* gradientElement = static_cast<SVGGradientElement*>(node());
+ SVGGradientElement* gradientElement = toSVGGradientElement(node());
if (!gradientElement)
return false;
if (m_shouldCollectGradientAttributes) {
- gradientElement->updateAnimatedSVGAttribute(anyQName());
+ gradientElement->synchronizeAnimatedSVGAttribute(anyQName());
if (!collectGradientAttributes(gradientElement))
return false;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp
index 7aaef0e9e..bcf517aef 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp
@@ -28,10 +28,11 @@
#include "RenderSVGContainer.h"
#include "RenderSVGRoot.h"
#include "SVGElement.h"
+#include "SVGGraphicsElement.h"
#include "SVGMarkerElement.h"
#include "SVGRenderSupport.h"
#include "SVGStyledElement.h"
-#include "SVGStyledTransformableElement.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -96,7 +97,7 @@ const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const
FloatPoint RenderSVGResourceMarker::referencePoint() const
{
- SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ SVGMarkerElement* marker = toSVGMarkerElement(node());
ASSERT(marker);
SVGLengthContext lengthContext(marker);
@@ -105,7 +106,7 @@ FloatPoint RenderSVGResourceMarker::referencePoint() const
float RenderSVGResourceMarker::angle() const
{
- SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ SVGMarkerElement* marker = toSVGMarkerElement(node());
ASSERT(marker);
float angle = -1;
@@ -117,7 +118,7 @@ float RenderSVGResourceMarker::angle() const
AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const
{
- SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ SVGMarkerElement* marker = toSVGMarkerElement(node());
ASSERT(marker);
float markerAngle = angle();
@@ -132,6 +133,12 @@ AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint&
void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& transform)
{
+ // An empty viewBox disables rendering.
+ SVGMarkerElement* marker = toSVGMarkerElement(toSVGElement(node()));
+ ASSERT(marker);
+ if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBoxIsValid() && marker->viewBox().isEmpty())
+ return;
+
PaintInfo info(paintInfo);
GraphicsContextStateSaver stateSaver(*info.context);
info.applyTransform(transform);
@@ -153,7 +160,7 @@ AffineTransform RenderSVGResourceMarker::markerContentTransformation(const Affin
AffineTransform RenderSVGResourceMarker::viewportTransform() const
{
- SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ SVGMarkerElement* marker = toSVGMarkerElement(node());
ASSERT(marker);
return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
@@ -164,7 +171,7 @@ void RenderSVGResourceMarker::calcViewport()
if (!selfNeedsLayout())
return;
- SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
+ SVGMarkerElement* marker = toSVGMarkerElement(node());
ASSERT(marker);
SVGLengthContext lengthContext(marker);
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h
index 26fbc6f93..1838450cf 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h
@@ -60,7 +60,7 @@ public:
FloatPoint referencePoint() const;
float angle() const;
- SVGMarkerUnitsType markerUnits() const { return static_cast<SVGMarkerElement*>(node())->markerUnits(); }
+ SVGMarkerUnitsType markerUnits() const { return toSVGMarkerElement(node())->markerUnits(); }
virtual RenderSVGResourceType resourceType() const { return s_resourceType; }
static RenderSVGResourceType s_resourceType;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
index 1f501a88b..fa66dfa7b 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
@@ -36,8 +36,6 @@
#include "SVGRenderingContext.h"
#include "SVGStyledElement.h"
#include "SVGUnitTypes.h"
-
-#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
namespace WebCore {
@@ -92,7 +90,7 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
MaskerData* maskerData = m_masker.get(object);
AffineTransform absoluteTransform;
- SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+ SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
FloatRect repaintRect = object->repaintRectInLocalCoordinates();
@@ -137,7 +135,7 @@ bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, C
// Draw the content into the ImageBuffer.
for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) {
RenderObject* renderer = node->renderer();
- if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer)
+ if (!node->isSVGElement() || !toSVGElement(node)->isSVGStyledElement() || !renderer)
continue;
if (renderer->needsLayout())
return false;
@@ -166,7 +164,7 @@ void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
{
for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
RenderObject* renderer = childNode->renderer();
- if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer)
+ if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGStyledElement() || !renderer)
continue;
RenderStyle* style = renderer->style();
if (!style || style->display() == NONE || style->visibility() != VISIBLE)
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
index 55dbb8319..4df4c22a9 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
@@ -66,7 +66,7 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign
return 0;
if (m_shouldCollectPatternAttributes) {
- patternElement->updateAnimatedSVGAttribute(anyQName());
+ patternElement->synchronizeAnimatedSVGAttribute(anyQName());
m_attributes = PatternAttributes();
patternElement->collectPatternAttributes(m_attributes);
@@ -77,6 +77,10 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign
if (!m_attributes.patternContentElement())
return 0;
+ // An empty viewBox disables rendering.
+ if (m_attributes.hasViewBox() && m_attributes.viewBox().isEmpty())
+ return 0;
+
// Compute all necessary transformations to build the tile image & the pattern.
FloatRect tileBoundaries;
AffineTransform tileImageTransform;
@@ -84,7 +88,7 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign
return 0;
AffineTransform absoluteTransformIgnoringRotation;
- SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation);
+ SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransformIgnoringRotation);
// Ignore 2D rotation, as it doesn't affect the size of the tile.
SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
@@ -269,7 +273,7 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA
// Draw the content into the ImageBuffer.
for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
- if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer())
+ if (!node->isSVGElement() || !toSVGElement(node)->isSVGStyledElement() || !node->renderer())
continue;
if (node->renderer()->needsLayout())
return nullptr;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
index a81c3698d..ca5cad4c5 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
@@ -29,10 +29,6 @@
#include "RenderStyle.h"
#include "SVGRenderSupport.h"
-#if USE(SKIA)
-#include "PlatformContextSkia.h"
-#endif
-
namespace WebCore {
RenderSVGResourceType RenderSVGResourceSolidColor::s_resourceType = SolidColorResourceType;
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
index 048c4f604..c3d159734 100644
--- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
@@ -46,6 +46,7 @@
#include "SVGStyledElement.h"
#include "SVGViewSpec.h"
#include "TransformState.h"
+#include <wtf/StackStats.h>
#if ENABLE(FILTERS)
#include "RenderSVGResourceFilter.h"
@@ -77,7 +78,8 @@ void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, d
// the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height,
// and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion
// of the viewport that is actually covered by image data.
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
+ ASSERT(svg);
Length intrinsicWidthAttribute = svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties);
Length intrinsicHeightAttribute = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties);
@@ -128,10 +130,10 @@ bool RenderSVGRoot::isEmbeddedThroughSVGImage() const
return false;
// Test whether we're embedded through an img.
- if (!frame->page() || !frame->page()->chrome())
+ if (!frame->page())
return false;
- ChromeClient* chromeClient = frame->page()->chrome()->client();
+ ChromeClient* chromeClient = frame->page()->chrome().client();
if (!chromeClient || !chromeClient->isSVGImageChromeClient())
return false;
@@ -159,9 +161,9 @@ static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, floa
return static_cast<LayoutUnit>(valueForLength(length, maxSize, renderView) * (length.isFixed() ? scale : 1));
}
-LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) const
+LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
{
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
ASSERT(svg);
// When we're embedded through SVGImage (border-image/background-image/<html:img>/...) we're forced to resize to a specific size.
@@ -169,7 +171,7 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) cons
return m_containerSize.width();
if (style()->logicalWidth().isSpecified() || style()->logicalMaxWidth().isSpecified())
- return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
+ return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
if (svg->widthAttributeEstablishesViewport())
return resolveLengthAttributeForSVG(svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style()->effectiveZoom(), containingBlock()->availableLogicalWidth(), view());
@@ -179,12 +181,12 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) cons
return document()->frame()->ownerRenderer()->availableLogicalWidth();
// SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
- return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
+ return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred);
}
LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const
{
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
ASSERT(svg);
// When we're embedded through SVGImage (border-image/background-image/<html:img>/...) we're forced to resize to a specific size.
@@ -206,12 +208,12 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const
} else
RenderBlock::removePercentHeightDescendant(const_cast<RenderSVGRoot*>(this));
- return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight(), view());
+ return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding), view());
}
// SVG embedded through object/embed/iframe.
if (isEmbeddedThroughFrameContainingSVGDocument())
- return document()->frame()->ownerRenderer()->availableLogicalHeight();
+ return document()->frame()->ownerRenderer()->availableLogicalHeight(IncludeMarginBorderPadding);
// SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
return RenderReplaced::computeReplacedLogicalHeight();
@@ -235,7 +237,8 @@ void RenderSVGRoot::layout()
updateLogicalHeight();
buildLocalToBorderBoxTransform();
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
+ ASSERT(svg);
m_isLayoutSizeChanged = needsLayout || (svg->hasRelativeLengths() && oldSize != size());
SVGRenderSupport::layoutChildren(this, needsLayout || SVGRenderSupport::filtersForceContainerLayout(this));
@@ -256,6 +259,8 @@ void RenderSVGRoot::layout()
m_needsBoundariesOrTransformUpdate = false;
}
+ updateLayerTransform();
+
repainter.repaintAfterLayout();
setNeedsLayout(false);
@@ -267,10 +272,17 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint
if (pixelSnappedBorderBoxRect().isEmpty())
return;
- // Don't paint, if the context explicitely disabled it.
+ // Don't paint, if the context explicitly disabled it.
if (paintInfo.context->paintingDisabled())
return;
+ // An empty viewBox also disables rendering.
+ // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute)
+ SVGSVGElement* svg = toSVGSVGElement(node());
+ ASSERT(svg);
+ if (svg->hasEmptyViewBox())
+ return;
+
Page* page = 0;
if (Frame* frame = this->frame())
page = frame->page();
@@ -354,12 +366,13 @@ void RenderSVGRoot::removeChild(RenderObject* child)
// relative to our borderBox origin. This method gives us exactly that.
void RenderSVGRoot::buildLocalToBorderBoxTransform()
{
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
+ ASSERT(svg);
float scale = style()->effectiveZoom();
- FloatPoint translate = svg->currentTranslate();
+ SVGPoint translate = svg->currentTranslate();
LayoutSize borderAndPadding(borderLeft() + paddingLeft(), borderTop() + paddingTop());
m_localToBorderBoxTransform = svg->viewBoxToViewTransform(contentWidth() / scale, contentHeight() / scale);
- if (borderAndPadding.isEmpty() && scale == 1 && translate == FloatPoint::zero())
+ if (borderAndPadding.isEmpty() && scale == 1 && translate == SVGPoint::zero())
return;
m_localToBorderBoxTransform = AffineTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()) * m_localToBorderBoxTransform;
}
@@ -463,15 +476,22 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
bool RenderSVGRoot::hasRelativeDimensions() const
{
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
ASSERT(svg);
return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent() || svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent();
}
+bool RenderSVGRoot::hasRelativeIntrinsicLogicalWidth() const
+{
+ SVGSVGElement* svg = toSVGSVGElement(node());
+ ASSERT(svg);
+ return svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent();
+}
+
bool RenderSVGRoot::hasRelativeLogicalHeight() const
{
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
ASSERT(svg);
return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent();
@@ -484,7 +504,7 @@ void RenderSVGRoot::addResourceForClientInvalidation(RenderSVGResourceContainer*
svgRoot = svgRoot->parent();
if (!svgRoot)
return;
- static_cast<RenderSVGRoot*>(svgRoot)->m_resourcesNeedingToInvalidateClients.add(resource);
+ toRenderSVGRoot(svgRoot)->m_resourcesNeedingToInvalidateClients.add(resource);
}
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h
index 38e89179e..e218e291e 100644
--- a/Source/WebCore/rendering/svg/RenderSVGRoot.h
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h
@@ -52,13 +52,15 @@ public:
bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; }
virtual void setNeedsBoundariesUpdate() { m_needsBoundariesOrTransformUpdate = true; }
+ virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesOrTransformUpdate; }
virtual void setNeedsTransformUpdate() { m_needsBoundariesOrTransformUpdate = true; }
IntSize containerSize() const { return m_containerSize; }
void setContainerSize(const IntSize& containerSize) { m_containerSize = containerSize; }
- virtual bool hasRelativeDimensions() const;
- virtual bool hasRelativeLogicalHeight() const;
+ virtual bool hasRelativeDimensions() const OVERRIDE;
+ virtual bool hasRelativeIntrinsicLogicalWidth() const OVERRIDE;
+ virtual bool hasRelativeLogicalHeight() const OVERRIDE;
// localToBorderBoxTransform maps local SVG viewport coordinates to local CSS box coordinates.
const AffineTransform& localToBorderBoxTransform() const { return m_localToBorderBoxTransform; }
@@ -77,7 +79,7 @@ private:
virtual bool isSVGRoot() const { return true; }
virtual const char* renderName() const { return "RenderSVGRoot"; }
- virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
+ virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE;
virtual LayoutUnit computeReplacedLogicalHeight() const;
virtual void layout();
virtual void paintReplaced(PaintInfo&, const LayoutPoint&);
@@ -103,7 +105,7 @@ private:
virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE;
virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const OVERRIDE;
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual bool canBeSelectionLeaf() const { return false; }
@@ -129,13 +131,13 @@ private:
inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object)
{
- ASSERT(!object || object->isSVGRoot());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGRoot());
return static_cast<RenderSVGRoot*>(object);
}
inline const RenderSVGRoot* toRenderSVGRoot(const RenderObject* object)
{
- ASSERT(!object || object->isSVGRoot());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGRoot());
return static_cast<const RenderSVGRoot*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.cpp b/Source/WebCore/rendering/svg/RenderSVGShape.cpp
index 7e329b2b7..8070a392a 100644
--- a/Source/WebCore/rendering/svg/RenderSVGShape.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGShape.cpp
@@ -39,23 +39,24 @@
#include "RenderSVGContainer.h"
#include "RenderSVGResourceMarker.h"
#include "RenderSVGResourceSolidColor.h"
+#include "SVGGraphicsElement.h"
#include "SVGPathData.h"
#include "SVGRenderingContext.h"
#include "SVGResources.h"
#include "SVGResourcesCache.h"
-#include "SVGStyledTransformableElement.h"
#include "SVGTransformList.h"
#include "SVGURIReference.h"
#include "StrokeStyleApplier.h"
#include <wtf/MathExtras.h>
+#include <wtf/StackStats.h>
namespace WebCore {
-RenderSVGShape::RenderSVGShape(SVGStyledTransformableElement* node)
+RenderSVGShape::RenderSVGShape(SVGGraphicsElement* node)
: RenderSVGModelObject(node)
, m_needsBoundariesUpdate(false) // Default is false, the cached rects are empty from the beginning.
- , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGStyledTransformableElement.
- , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGStyledTransformableElement.
+ , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGGraphicsElement.
+ , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGGraphicsElement.
{
}
@@ -69,7 +70,7 @@ void RenderSVGShape::updateShapeFromElement()
m_path = adoptPtr(new Path);
ASSERT(RenderSVGShape::isEmpty());
- SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
+ SVGGraphicsElement* element = toSVGGraphicsElement(node());
updatePathFromGraphicsElement(element, path());
processMarkerPositions();
@@ -146,7 +147,7 @@ void RenderSVGShape::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) && selfNeedsLayout());
- SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
+ SVGGraphicsElement* element = toSVGGraphicsElement(node());
bool updateCachedBoundariesInParents = false;
@@ -198,7 +199,7 @@ bool RenderSVGShape::setupNonScalingStrokeContext(AffineTransform& strokeTransfo
AffineTransform RenderSVGShape::nonScalingStrokeTransform() const
{
- SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
+ SVGGraphicsElement* element = toSVGGraphicsElement(node());
return element->getScreenCTM(SVGLocatable::DisallowStyleUpdate);
}
@@ -207,7 +208,7 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const
if (!style()->svgStyle()->hasMarkers())
return false;
- SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
+ SVGGraphicsElement* element = toSVGGraphicsElement(node());
if (!element->supportsMarkers())
return false;
@@ -258,7 +259,6 @@ void RenderSVGShape::fillAndStrokeShape(GraphicsContext* context)
return;
GraphicsContextStateSaver stateSaver(*context, false);
- AffineTransform nonScalingTransform;
if (hasNonScalingStroke()) {
AffineTransform nonScalingTransform = nonScalingStrokeTransform();
@@ -298,13 +298,13 @@ void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&)
}
if (drawsOutline)
- paintOutline(childPaintInfo.context, IntRect(boundingBox));
+ paintOutline(childPaintInfo, IntRect(boundingBox));
}
}
// This method is called from inside paintOutline() since we call paintOutline()
// while transformed to our coord system, return local coords
-void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&)
+void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*)
{
IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates());
if (!rect.isEmpty())
@@ -416,7 +416,7 @@ void RenderSVGShape::updateRepaintBoundingBox()
float RenderSVGShape::strokeWidth() const
{
- SVGElement* svgElement = static_cast<SVGElement*>(node());
+ SVGElement* svgElement = toSVGElement(node());
SVGLengthContext lengthContext(svgElement);
return style()->svgStyle()->strokeWidth().value(lengthContext);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.h b/Source/WebCore/rendering/svg/RenderSVGShape.h
index 60a2daeb4..289369698 100644
--- a/Source/WebCore/rendering/svg/RenderSVGShape.h
+++ b/Source/WebCore/rendering/svg/RenderSVGShape.h
@@ -42,7 +42,7 @@ class GraphicsContextStateSaver;
class RenderSVGContainer;
class RenderSVGPath;
class RenderSVGResource;
-class SVGStyledTransformableElement;
+class SVGGraphicsElement;
class BoundingRectStrokeStyleApplier : public StrokeStyleApplier {
public:
@@ -66,16 +66,18 @@ private:
class RenderSVGShape : public RenderSVGModelObject {
public:
- explicit RenderSVGShape(SVGStyledTransformableElement*);
- RenderSVGShape(SVGStyledTransformableElement*, Path*, bool);
+ explicit RenderSVGShape(SVGGraphicsElement*);
+ RenderSVGShape(SVGGraphicsElement*, Path*, bool);
virtual ~RenderSVGShape();
void setNeedsShapeUpdate() { m_needsShapeUpdate = true; }
virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; }
+ virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesUpdate; }
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
virtual void fillShape(GraphicsContext*) const;
virtual void strokeShape(GraphicsContext*) const;
+ bool hasPath() const { return m_path.get(); }
Path& path() const
{
ASSERT(m_path);
@@ -88,7 +90,6 @@ protected:
virtual bool shapeDependentStrokeContains(const FloatPoint&);
virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
float strokeWidth() const;
- bool hasPath() const { return m_path.get(); }
bool hasSmoothStroke() const;
bool hasNonScalingStroke() const { return style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; }
@@ -113,7 +114,7 @@ private:
virtual void layout();
virtual void paint(PaintInfo&, const LayoutPoint&);
- virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&);
+ virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE;
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
@@ -148,13 +149,13 @@ private:
inline RenderSVGShape* toRenderSVGShape(RenderObject* object)
{
- ASSERT(!object || object->isSVGShape());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGShape());
return static_cast<RenderSVGShape*>(object);
}
inline const RenderSVGShape* toRenderSVGShape(const RenderObject* object)
{
- ASSERT(!object || object->isSVGShape());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGShape());
return static_cast<const RenderSVGShape*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp b/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp
index 872d07642..0831b2409 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp
@@ -27,8 +27,8 @@
namespace WebCore {
-RenderSVGTSpan::RenderSVGTSpan(Node* n)
- : RenderSVGInline(n)
+RenderSVGTSpan::RenderSVGTSpan(Element* element)
+ : RenderSVGInline(element)
{
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.h b/Source/WebCore/rendering/svg/RenderSVGTSpan.h
index d5e2ed768..bd9ce9abe 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTSpan.h
+++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.h
@@ -28,7 +28,7 @@
namespace WebCore {
class RenderSVGTSpan : public RenderSVGInline {
public:
- explicit RenderSVGTSpan(Node*);
+ explicit RenderSVGTSpan(Element*);
virtual const char* renderName() const { return "RenderSVGTSpan"; }
};
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp
index fd49f9b46..a65a3e498 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp
@@ -52,6 +52,7 @@
#include "SimpleFontData.h"
#include "TransformState.h"
#include "VisiblePosition.h"
+#include <wtf/StackStats.h>
namespace WebCore {
@@ -111,9 +112,9 @@ void RenderSVGText::computeFloatRectForRepaint(const RenderLayerModelObject* rep
SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed);
}
-void RenderSVGText::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
+void RenderSVGText::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const
{
- SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, mode & SnapOffsetForTransforms, wasFixed);
+ SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
}
const RenderObject* RenderSVGText::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
@@ -472,7 +473,7 @@ VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInConten
if (!rootBox)
return createVisiblePosition(0, DOWNSTREAM);
- ASSERT(rootBox->isSVGRootInlineBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(rootBox->isSVGRootInlineBox());
ASSERT(!rootBox->nextRootBox());
ASSERT(childrenInline());
@@ -513,7 +514,7 @@ FloatRect RenderSVGText::strokeBoundingBox() const
ASSERT(node());
ASSERT(node()->isSVGElement());
- SVGLengthContext lengthContext(static_cast<SVGElement*>(node()));
+ SVGLengthContext lengthContext(toSVGElement(node()));
strokeBoundaries.inflate(svgStyle->strokeWidth().value(lengthContext));
return strokeBoundaries;
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h
index cae5ba721..4d4f4ae3d 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGText.h
@@ -75,7 +75,7 @@ private:
virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE;
virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE;
- virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE;
+ virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
virtual void removeChild(RenderObject*) OVERRIDE;
@@ -104,13 +104,13 @@ private:
inline RenderSVGText* toRenderSVGText(RenderObject* object)
{
- ASSERT(!object || object->isSVGText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGText());
return static_cast<RenderSVGText*>(object);
}
inline const RenderSVGText* toRenderSVGText(const RenderObject* object)
{
- ASSERT(!object || object->isSVGText());
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGText());
return static_cast<const RenderSVGText*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
index 15b48f590..e816f9e47 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp
@@ -34,8 +34,8 @@
namespace WebCore {
-RenderSVGTextPath::RenderSVGTextPath(Node* n)
- : RenderSVGInline(n)
+RenderSVGTextPath::RenderSVGTextPath(Element* element)
+ : RenderSVGInline(element)
{
}
@@ -46,7 +46,7 @@ Path RenderSVGTextPath::layoutPath() const
if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag))
return Path();
- SVGPathElement* pathElement = static_cast<SVGPathElement*>(targetElement);
+ SVGPathElement* pathElement = toSVGPathElement(targetElement);
Path pathData;
updatePathFromGraphicsElement(pathElement, pathData);
diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.h b/Source/WebCore/rendering/svg/RenderSVGTextPath.h
index 2758a0692..f1c872138 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTextPath.h
+++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.h
@@ -28,7 +28,7 @@ namespace WebCore {
class RenderSVGTextPath : public RenderSVGInline {
public:
- RenderSVGTextPath(Node*);
+ RenderSVGTextPath(Element*);
Path layoutPath() const;
float startOffset() const;
@@ -45,7 +45,7 @@ private:
inline RenderSVGTextPath* toRenderSVGTextPath(RenderObject* object)
{
- ASSERT(!object || !strcmp(object->renderName(), "RenderSVGTextPath"));
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGTextPath());
return static_cast<RenderSVGTextPath*>(object);
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp
index ee4d74e24..06df24dc6 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp
@@ -24,14 +24,14 @@
#if ENABLE(SVG)
#include "RenderSVGTransformableContainer.h"
+#include "SVGGraphicsElement.h"
#include "SVGNames.h"
#include "SVGRenderSupport.h"
-#include "SVGStyledTransformableElement.h"
#include "SVGUseElement.h"
namespace WebCore {
-RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransformableElement* node)
+RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGGraphicsElement* node)
: RenderSVGContainer(node)
, m_needsTransformUpdate(true)
, m_didTransformToRootUpdate(false)
@@ -40,18 +40,18 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf
bool RenderSVGTransformableContainer::calculateLocalTransform()
{
- SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
+ SVGGraphicsElement* element = toSVGGraphicsElement(node());
// If we're either the renderer for a <use> element, or for any <g> element inside the shadow
// tree, that was created during the use/symbol/svg expansion in SVGUseElement. These containers
// need to respect the translations induced by their corresponding use elements x/y attributes.
SVGUseElement* useElement = 0;
if (element->hasTagName(SVGNames::useTag))
- useElement = static_cast<SVGUseElement*>(element);
+ useElement = toSVGUseElement(element);
else if (element->isInShadowTree() && element->hasTagName(SVGNames::gTag)) {
SVGElement* correspondingElement = element->correspondingElement();
if (correspondingElement && correspondingElement->hasTagName(SVGNames::useTag))
- useElement = static_cast<SVGUseElement*>(correspondingElement);
+ useElement = toSVGUseElement(correspondingElement);
}
if (useElement) {
diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h
index c10a08dc2..b59327efd 100644
--- a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h
+++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h
@@ -26,10 +26,10 @@
namespace WebCore {
-class SVGStyledTransformableElement;
+class SVGGraphicsElement;
class RenderSVGTransformableContainer : public RenderSVGContainer {
public:
- explicit RenderSVGTransformableContainer(SVGStyledTransformableElement*);
+ explicit RenderSVGTransformableContainer(SVGGraphicsElement*);
virtual bool isSVGTransformableContainer() const { return true; }
virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
index 27a319f28..834452d20 100644
--- a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp
@@ -47,7 +47,7 @@ void RenderSVGViewportContainer::determineIfLayoutSizeChanged()
if (!node()->hasTagName(SVGNames::svgTag))
return;
- m_isLayoutSizeChanged = static_cast<SVGSVGElement*>(node())->hasRelativeLengths() && selfNeedsLayout();
+ m_isLayoutSizeChanged = toSVGSVGElement(node())->hasRelativeLengths() && selfNeedsLayout();
}
void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo)
@@ -58,10 +58,10 @@ void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo)
void RenderSVGViewportContainer::calcViewport()
{
- SVGElement* element = static_cast<SVGElement*>(node());
+ SVGElement* element = toSVGElement(node());
if (!element->hasTagName(SVGNames::svgTag))
return;
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(element);
+ SVGSVGElement* svg = toSVGSVGElement(element);
FloatRect oldViewport = m_viewport;
SVGLengthContext lengthContext(element);
@@ -133,7 +133,7 @@ bool RenderSVGViewportContainer::calculateLocalTransform()
AffineTransform RenderSVGViewportContainer::viewportTransform() const
{
if (node()->hasTagName(SVGNames::svgTag)) {
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
+ SVGSVGElement* svg = toSVGSVGElement(node());
return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
}
@@ -149,6 +149,17 @@ bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& poi
return m_viewport.contains(pointInParent);
}
+void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ // An empty viewBox disables rendering.
+ if (node()->hasTagName(SVGNames::svgTag)) {
+ if (toSVGSVGElement(node())->hasEmptyViewBox())
+ return;
+ }
+
+ RenderSVGContainer::paint(paintInfo, paintOffset);
+}
+
}
#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h
index eb7041a30..427e423da 100644
--- a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h
+++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h
@@ -41,6 +41,8 @@ public:
virtual void determineIfLayoutSizeChanged();
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
+ virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE;
+
private:
virtual bool isSVGViewportContainer() const { return true; }
virtual const char* renderName() const { return "RenderSVGViewportContainer"; }
@@ -63,13 +65,13 @@ private:
inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object)
{
- ASSERT(!object || !strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGViewportContainer());
return static_cast<RenderSVGViewportContainer*>(object);
}
inline const RenderSVGViewportContainer* toRenderSVGViewportContainer(const RenderObject* object)
{
- ASSERT(!object || !strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isSVGViewportContainer());
return static_cast<const RenderSVGViewportContainer*>(object);
}
diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
index 21a909224..3e97b6722 100644
--- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
@@ -43,9 +43,9 @@ void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo)
PaintInfo childPaintInfo(paintInfo);
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
if (child->isSVGInlineTextBox())
- static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo);
+ toSVGInlineTextBox(child)->paintSelectionBackground(childPaintInfo);
else if (child->isSVGInlineFlowBox())
- static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo);
+ toSVGInlineFlowBox(child)->paintSelectionBackground(childPaintInfo);
}
}
@@ -61,7 +61,7 @@ void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni
if (renderingContext.isRenderingPrepared()) {
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
if (child->isSVGInlineTextBox())
- computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
+ computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(toSVGInlineTextBox(child)->textRenderer()));
child->paint(paintInfo, LayoutPoint(), 0, 0);
}
@@ -107,7 +107,7 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText
if (!box->isSVGInlineTextBox())
continue;
- SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
+ SVGInlineTextBox* textBox = toSVGInlineTextBox(box);
int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0);
int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len());
diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
index bc44c7e55..18b8a527f 100644
--- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
+++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
@@ -28,7 +28,7 @@ namespace WebCore {
class RenderSVGInlineText;
-class SVGInlineFlowBox : public InlineFlowBox {
+class SVGInlineFlowBox FINAL : public InlineFlowBox {
public:
SVGInlineFlowBox(RenderObject* obj)
: InlineFlowBox(obj)
@@ -51,6 +51,12 @@ private:
float m_logicalHeight;
};
+inline SVGInlineFlowBox* toSVGInlineFlowBox(InlineBox* box)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!box || box->isSVGInlineFlowBox());
+ return static_cast<SVGInlineFlowBox*>(box);
+}
+
} // namespace WebCore
#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
index 7864d4ee8..08a9e14c7 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
@@ -318,10 +318,10 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni
// Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations.
int decorations = style->textDecorationsInEffect();
- if (decorations & UNDERLINE)
- paintDecoration(paintInfo.context, UNDERLINE, fragment);
- if (decorations & OVERLINE)
- paintDecoration(paintInfo.context, OVERLINE, fragment);
+ if (decorations & TextDecorationUnderline)
+ paintDecoration(paintInfo.context, TextDecorationUnderline, fragment);
+ if (decorations & TextDecorationOverline)
+ paintDecoration(paintInfo.context, TextDecorationOverline, fragment);
// Fill text
if (hasFill) {
@@ -336,8 +336,8 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni
}
// Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text.
- if (decorations & LINE_THROUGH)
- paintDecoration(paintInfo.context, LINE_THROUGH, fragment);
+ if (decorations & TextDecorationLineThrough)
+ paintDecoration(paintInfo.context, TextDecorationLineThrough, fragment);
m_paintingResourceMode = ApplyToDefaultMode;
}
@@ -478,22 +478,22 @@ bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGText
return true;
}
-static inline float positionOffsetForDecoration(ETextDecoration decoration, const FontMetrics& fontMetrics, float thickness)
+static inline float positionOffsetForDecoration(TextDecoration decoration, const FontMetrics& fontMetrics, float thickness)
{
// FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified.
// Compatible with Batik/Opera.
- if (decoration == UNDERLINE)
+ if (decoration == TextDecorationUnderline)
return fontMetrics.floatAscent() + thickness * 1.5f;
- if (decoration == OVERLINE)
+ if (decoration == TextDecorationOverline)
return thickness;
- if (decoration == LINE_THROUGH)
+ if (decoration == TextDecorationLineThrough)
return fontMetrics.floatAscent() * 5 / 8.0f;
ASSERT_NOT_REACHED();
return 0.0f;
}
-static inline float thicknessForDecoration(ETextDecoration, const Font& font)
+static inline float thicknessForDecoration(TextDecoration, const Font& font)
{
// FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified.
// Compatible with Batik/Opera
@@ -507,7 +507,7 @@ static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowB
while (parentBox) {
renderer = parentBox->renderer();
- if (renderer->style() && renderer->style()->textDecoration() != TDNONE)
+ if (renderer->style() && renderer->style()->textDecoration() != TextDecorationNone)
break;
parentBox = parentBox->parent();
@@ -517,9 +517,9 @@ static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowB
return renderer;
}
-void SVGInlineTextBox::paintDecoration(GraphicsContext* context, ETextDecoration decoration, const SVGTextFragment& fragment)
+void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment)
{
- if (textRenderer()->style()->textDecorationsInEffect() == TDNONE)
+ if (textRenderer()->style()->textDecorationsInEffect() == TextDecorationNone)
return;
// Find out which render style defined the text-decoration, as its fill/stroke properties have to be used for drawing instead of ours.
@@ -547,7 +547,7 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, ETextDecoration
}
}
-void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextDecoration decoration, const SVGTextFragment& fragment, RenderObject* decorationRenderer)
+void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment, RenderObject* decorationRenderer)
{
ASSERT(!m_paintingResource);
ASSERT(m_paintingResourceMode != ApplyToDefaultMode);
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h
index ef399c724..6fea28db3 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h
@@ -31,7 +31,7 @@ namespace WebCore {
class RenderSVGResource;
class SVGRootInlineBox;
-class SVGInlineTextBox : public InlineTextBox {
+class SVGInlineTextBox FINAL : public InlineTextBox {
public:
SVGInlineTextBox(RenderObject*);
@@ -57,7 +57,7 @@ public:
Vector<SVGTextFragment>& textFragments() { return m_textFragments; }
const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; }
- void dirtyLineBoxes() OVERRIDE;
+ virtual void dirtyLineBoxes() OVERRIDE;
bool startsNewTextChunk() const { return m_startsNewTextChunk; }
void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; }
@@ -74,8 +74,8 @@ private:
bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, RenderStyle*);
void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&);
- void paintDecoration(GraphicsContext*, ETextDecoration, const SVGTextFragment&);
- void paintDecorationWithStyle(GraphicsContext*, ETextDecoration, const SVGTextFragment&, RenderObject* decorationRenderer);
+ void paintDecoration(GraphicsContext*, TextDecoration, const SVGTextFragment&);
+ void paintDecorationWithStyle(GraphicsContext*, TextDecoration, const SVGTextFragment&, RenderObject* decorationRenderer);
void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, int startPosition, int endPosition);
void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly);
@@ -89,6 +89,12 @@ private:
Vector<SVGTextFragment> m_textFragments;
};
+inline SVGInlineTextBox* toSVGInlineTextBox(InlineBox* box)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!box || box->isSVGInlineTextBox());
+ return static_cast<SVGInlineTextBox*>(box);
+}
+
} // namespace WebCore
#endif
diff --git a/Source/WebCore/rendering/svg/SVGMarkerData.h b/Source/WebCore/rendering/svg/SVGMarkerData.h
index 7e2ce0edc..6c70f4297 100644
--- a/Source/WebCore/rendering/svg/SVGMarkerData.h
+++ b/Source/WebCore/rendering/svg/SVGMarkerData.h
@@ -82,19 +82,23 @@ public:
private:
float currentAngle(SVGMarkerType type) const
{
- FloatSize inslopeChange = m_inslopePoints[1] - m_inslopePoints[0];
- FloatSize outslopeChange = m_outslopePoints[1] - m_outslopePoints[0];
+ // For details of this calculation, see: http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
+ FloatPoint inSlope(m_inslopePoints[1] - m_inslopePoints[0]);
+ FloatPoint outSlope(m_outslopePoints[1] - m_outslopePoints[0]);
- double inslope = rad2deg(atan2(inslopeChange.height(), inslopeChange.width()));
- double outslope = rad2deg(atan2(outslopeChange.height(), outslopeChange.width()));
+ double inAngle = rad2deg(inSlope.slopeAngleRadians());
+ double outAngle = rad2deg(outSlope.slopeAngleRadians());
switch (type) {
case StartMarker:
- return narrowPrecisionToFloat(outslope);
+ return narrowPrecisionToFloat(outAngle);
case MidMarker:
- return narrowPrecisionToFloat((inslope + outslope) / 2);
+ // WK193015: Prevent bugs due to angles being non-continuous.
+ if (fabs(inAngle - outAngle) > 180)
+ inAngle += 360;
+ return narrowPrecisionToFloat((inAngle + outAngle) / 2);
case EndMarker:
- return narrowPrecisionToFloat(inslope);
+ return narrowPrecisionToFloat(inAngle);
}
ASSERT_NOT_REACHED();
diff --git a/Source/WebCore/rendering/svg/SVGPathData.cpp b/Source/WebCore/rendering/svg/SVGPathData.cpp
index 98c80b22f..234122510 100644
--- a/Source/WebCore/rendering/svg/SVGPathData.cpp
+++ b/Source/WebCore/rendering/svg/SVGPathData.cpp
@@ -73,8 +73,7 @@ static void updatePathFromLineElement(SVGElement* element, Path& path)
static void updatePathFromPathElement(SVGElement* element, Path& path)
{
- ASSERT(element->hasTagName(SVGNames::pathTag));
- buildPathFromByteStream(static_cast<SVGPathElement*>(element)->pathByteStream(), path);
+ buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path);
}
static void updatePathFromPolygonElement(SVGElement* element, Path& path)
diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp
index c75015d57..4fba77407 100644
--- a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp
+++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp
@@ -42,7 +42,6 @@
#include "SVGResourcesCache.h"
#include "SVGStyledElement.h"
#include "TransformState.h"
-#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -50,6 +49,7 @@ FloatRect SVGRenderSupport::repaintRectForRendererInLocalCoordinatesExcludingSVG
{
// FIXME: Add support for RenderSVGBlock.
+ // FIXME: This should use a safer cast such as toRenderSVGModelObject().
if (object->isSVGShape() || object->isSVGImage() || object->isSVGContainer())
return static_cast<const RenderSVGModelObject*>(object)->repaintRectInLocalCoordinatesExcludingSVGShadow();
@@ -84,7 +84,7 @@ void SVGRenderSupport::computeFloatRectForRepaint(const RenderObject* object, co
object->parent()->computeFloatRectForRepaint(repaintContainer, repaintRect, fixed);
}
-void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool snapOffsetForTransforms, bool* wasFixed)
+void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed)
{
transformState.applyTransform(object->localToParentTransform());
@@ -97,8 +97,6 @@ void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const Ren
transformState.applyTransform(toRenderSVGRoot(parent)->localToBorderBoxTransform());
MapCoordinatesFlags mode = UseTransforms;
- if (snapOffsetForTransforms)
- mode |= SnapOffsetForTransforms;
parent->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
}
@@ -231,12 +229,21 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
{
bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start);
bool transformChanged = transformToRootChanged(start);
+ bool hasSVGShadow = rendererHasSVGShadow(start);
+ bool needsBoundariesUpdate = start->needsBoundariesUpdate();
HashSet<RenderObject*> notlayoutedObjects;
for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
bool needsLayout = selfNeedsLayout;
bool childEverHadLayout = child->everHadLayout();
+ if (needsBoundariesUpdate && hasSVGShadow) {
+ // If we have a shadow, our shadow is baked into our children's cached boundaries,
+ // so they need to update.
+ child->setNeedsBoundariesUpdate();
+ needsLayout = true;
+ }
+
if (transformChanged) {
// If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true).
if (child->isSVGText())
@@ -246,8 +253,8 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout)
if (layoutSizeChanged) {
// When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths
- if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
- if (element->isStyled() && static_cast<SVGStyledElement*>(element)->hasRelativeLengths()) {
+ if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) {
+ if (element->isSVGStyledElement() && toSVGStyledElement(element)->hasRelativeLengths()) {
// When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object
if (child->isSVGShape())
toRenderSVGShape(child)->setNeedsShapeUpdate();
@@ -307,11 +314,12 @@ bool SVGRenderSupport::rendererHasSVGShadow(const RenderObject* object)
{
// FIXME: Add support for RenderSVGBlock.
+ // FIXME: This should use a safer cast such as toRenderSVGModelObject().
if (object->isSVGShape() || object->isSVGImage() || object->isSVGContainer())
return static_cast<const RenderSVGModelObject*>(object)->hasSVGShadow();
if (object->isSVGRoot())
- return static_cast<const RenderSVGRoot*>(object)->hasSVGShadow();
+ return toRenderSVGRoot(object)->hasSVGShadow();
return false;
}
@@ -320,6 +328,7 @@ void SVGRenderSupport::setRendererHasSVGShadow(RenderObject* object, bool hasSha
{
// FIXME: Add support for RenderSVGBlock.
+ // FIXME: This should use a safer cast such as toRenderSVGModelObject().
if (object->isSVGShape() || object->isSVGImage() || object->isSVGContainer())
return static_cast<RenderSVGModelObject*>(object)->setHasSVGShadow(hasShadow);
@@ -424,7 +433,7 @@ void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const
const SVGRenderStyle* svgStyle = style->svgStyle();
ASSERT(svgStyle);
- SVGLengthContext lengthContext(static_cast<SVGElement*>(object->node()));
+ SVGLengthContext lengthContext(toSVGElement(object->node()));
context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext));
context->setLineCap(svgStyle->capStyle());
context->setLineJoin(svgStyle->joinStyle());
diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.h b/Source/WebCore/rendering/svg/SVGRenderSupport.h
index f7375e43b..0b1871617 100644
--- a/Source/WebCore/rendering/svg/SVGRenderSupport.h
+++ b/Source/WebCore/rendering/svg/SVGRenderSupport.h
@@ -68,7 +68,7 @@ public:
static FloatRect repaintRectForRendererInLocalCoordinatesExcludingSVGShadow(const RenderObject*);
static LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer);
static void computeFloatRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed);
- static void mapLocalToContainer(const RenderObject*, const RenderLayerModelObject* repaintContainer, TransformState&, bool snapOffsetForTransforms = true, bool* wasFixed = 0);
+ static void mapLocalToContainer(const RenderObject*, const RenderLayerModelObject* repaintContainer, TransformState&, bool* wasFixed = 0);
static const RenderObject* pushMappingToContainer(const RenderObject*, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&);
static bool checkForSVGRepaintDuringLayout(RenderObject*);
diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
index 12352ae72..532db27c6 100644
--- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
+++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
@@ -262,7 +262,7 @@ static void writeSVGPaintingResource(TextStream& ts, RenderSVGResource* resource
else if (resource->resourceType() == RadialGradientResourceType)
ts << "[type=RADIAL-GRADIENT]";
- ts << " [id=\"" << static_cast<SVGElement*>(node)->getIdAttribute() << "\"]";
+ ts << " [id=\"" << toSVGElement(node)->getIdAttribute() << "\"]";
}
static void writeStyle(TextStream& ts, const RenderObject& object)
@@ -285,7 +285,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object)
ts << " [stroke={" << s;
writeSVGPaintingResource(ts, strokePaintingResource);
- SVGLengthContext lengthContext(static_cast<SVGElement*>(shape.node()));
+ SVGLengthContext lengthContext(toSVGElement(shape.node()));
double dashOffset = svgStyle->strokeDashOffset().value(lengthContext);
double strokeWidth = svgStyle->strokeWidth().value(lengthContext);
const Vector<SVGLength>& dashes = svgStyle->strokeDashArray();
@@ -336,7 +336,7 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape)
writePositionAndStyle(ts, shape);
ASSERT(shape.node()->isSVGElement());
- SVGElement* svgElement = static_cast<SVGElement*>(shape.node());
+ SVGElement* svgElement = toSVGElement(shape.node());
SVGLengthContext lengthContext(svgElement);
if (svgElement->hasTagName(SVGNames::rectTag)) {
@@ -366,7 +366,7 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape)
SVGPolyElement* element = static_cast<SVGPolyElement*>(svgElement);
writeNameAndQuotedValue(ts, "points", element->pointList().valueAsString());
} else if (svgElement->hasTagName(SVGNames::pathTag)) {
- SVGPathElement* element = static_cast<SVGPathElement*>(svgElement);
+ SVGPathElement* element = toSVGPathElement(svgElement);
String pathString;
// FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests.
buildStringFromByteStream(element->pathByteStream(), pathString, NormalizedParsing);
@@ -459,7 +459,7 @@ static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& tex
if (!box->isSVGInlineTextBox())
continue;
- writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent);
+ writeSVGInlineTextBox(ts, toSVGInlineTextBox(box), indent);
}
}
@@ -493,7 +493,7 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i
{
writeStandardPrefix(ts, object, indent);
- Element* element = static_cast<Element*>(object.node());
+ Element* element = toElement(object.node());
const AtomicString& id = element->getIdAttribute();
writeNameAndQuotedValue(ts, "id", id);
diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp
index 041aed418..a65d39fe6 100644
--- a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp
+++ b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp
@@ -30,6 +30,8 @@
#include "BasicShapes.h"
#include "Frame.h"
#include "FrameView.h"
+#include "RenderLayer.h"
+#include "RenderSVGImage.h"
#include "RenderSVGResource.h"
#include "RenderSVGResourceClipper.h"
#include "RenderSVGResourceFilter.h"
@@ -59,8 +61,9 @@ SVGRenderingContext::~SVGRenderingContext()
#if ENABLE(FILTERS)
if (m_renderingFlags & EndFilterLayer) {
ASSERT(m_filter);
- m_filter->postApplyResource(static_cast<RenderSVGShape*>(m_object), m_paintInfo->context, ApplyToDefaultMode, 0, 0);
+ m_filter->postApplyResource(m_object, m_paintInfo->context, ApplyToDefaultMode, 0, 0);
m_paintInfo->context = m_savedContext;
+ m_paintInfo->rect = m_savedPaintRect;
}
#endif
@@ -117,7 +120,7 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI
if (shadow) {
m_paintInfo->context->clip(repaintRect);
- m_paintInfo->context->setShadow(IntSize(roundToInt(shadow->x()), roundToInt(shadow->y())), shadow->blur(), shadow->color(), style->colorSpace());
+ m_paintInfo->context->setShadow(IntSize(roundToInt(shadow->x()), roundToInt(shadow->y())), shadow->radius(), shadow->color(), style->colorSpace());
m_paintInfo->context->beginTransparencyLayer(1);
m_renderingFlags |= EndShadowLayer;
}
@@ -157,11 +160,18 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI
m_filter = resources->filter();
if (m_filter) {
m_savedContext = m_paintInfo->context;
+ m_savedPaintRect = m_paintInfo->rect;
// Return with false here may mean that we don't need to draw the content
// (because it was either drawn before or empty) but we still need to apply the filter.
m_renderingFlags |= EndFilterLayer;
if (!m_filter->applyResource(m_object, style, m_paintInfo->context, ApplyToDefaultMode))
return;
+
+ // Since we're caching the resulting bitmap and do not invalidate it on repaint rect
+ // changes, we need to paint the whole filter region. Otherwise, elements not visible
+ // at the time of the initial paint (due to scrolling, window size, etc.) will never
+ // be drawn.
+ m_paintInfo->rect = IntRect(m_filter->drawingRegion(m_object));
}
}
#endif
@@ -180,21 +190,34 @@ float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObje
ASSERT(renderer);
AffineTransform ctm;
- calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm);
+ calculateTransformationToOutermostCoordinateSystem(renderer, ctm);
return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2));
}
-void SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform)
+void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform)
{
- const RenderObject* current = renderer;
- ASSERT(current);
-
+ ASSERT(renderer);
absoluteTransform = currentContentTransformation();
- while (current) {
- absoluteTransform = current->localToParentTransform() * absoluteTransform;
- if (current->isSVGRoot())
+
+ // Walk up the render tree, accumulating SVG transforms.
+ while (renderer) {
+ absoluteTransform = renderer->localToParentTransform() * absoluteTransform;
+ if (renderer->isSVGRoot())
break;
- current = current->parent();
+ renderer = renderer->parent();
+ }
+
+ // Continue walking up the layer tree, accumulating CSS transforms.
+ RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
+ while (layer) {
+ if (TransformationMatrix* layerTransform = layer->transform())
+ absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform;
+
+ // We can stop at compositing layers, to match the backing resolution.
+ if (layer->isComposited())
+ break;
+
+ layer = layer->parent();
}
}
@@ -251,7 +274,7 @@ void SVGRenderingContext::renderSubtreeToImageBuffer(ImageBuffer* image, RenderO
ASSERT(image);
ASSERT(image->context());
- PaintInfo info(image->context(), PaintInfo::infiniteRect(), PaintPhaseForeground, 0, 0, 0, 0);
+ PaintInfo info(image->context(), PaintInfo::infiniteRect(), PaintPhaseForeground, PaintBehaviorNormal);
AffineTransform& contentTransformation = currentContentTransformation();
AffineTransform savedContentTransformation = contentTransformation;
@@ -302,6 +325,37 @@ void SVGRenderingContext::clear2DRotation(AffineTransform& transform)
transform.recompose(decomposition);
}
+bool SVGRenderingContext::bufferForeground(OwnPtr<ImageBuffer>& imageBuffer)
+{
+ ASSERT(m_paintInfo);
+ ASSERT(m_object->isSVGImage());
+ FloatRect boundingBox = m_object->objectBoundingBox();
+
+ // Invalidate an existing buffer if the scale is not correct.
+ if (imageBuffer) {
+ AffineTransform transform = m_paintInfo->context->getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
+ IntSize expandedBoundingBox = expandedIntSize(boundingBox.size());
+ IntSize bufferSize(static_cast<int>(ceil(expandedBoundingBox.width() * transform.xScale())), static_cast<int>(ceil(expandedBoundingBox.height() * transform.yScale())));
+ if (bufferSize != imageBuffer->internalSize())
+ imageBuffer.clear();
+ }
+
+ // Create a new buffer and paint the foreground into it.
+ if (!imageBuffer) {
+ if ((imageBuffer = m_paintInfo->context->createCompatibleBuffer(expandedIntSize(boundingBox.size()), true))) {
+ GraphicsContext* bufferedRenderingContext = imageBuffer->context();
+ bufferedRenderingContext->translate(-boundingBox.x(), -boundingBox.y());
+ PaintInfo bufferedInfo(*m_paintInfo);
+ bufferedInfo.context = bufferedRenderingContext;
+ toRenderSVGImage(m_object)->paintForeground(bufferedInfo);
+ } else
+ return false;
+ }
+
+ m_paintInfo->context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, boundingBox);
+ return true;
+}
+
}
#endif
diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.h b/Source/WebCore/rendering/svg/SVGRenderingContext.h
index c88168968..1fc3f1a2e 100644
--- a/Source/WebCore/rendering/svg/SVGRenderingContext.h
+++ b/Source/WebCore/rendering/svg/SVGRenderingContext.h
@@ -83,7 +83,7 @@ public:
static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& targetRect, OwnPtr<ImageBuffer>&, bool safeToClear);
static float calculateScreenFontSizeScalingFactor(const RenderObject*);
- static void calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform);
+ static void calculateTransformationToOutermostCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform);
static IntSize clampedAbsoluteSize(const IntSize&);
static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect);
static void clear2DRotation(AffineTransform&);
@@ -93,6 +93,9 @@ public:
return enclosingIntRect(absoluteTransform.mapRect(targetRect));
}
+ // Support for the buffered-rendering hint.
+ bool bufferForeground(OwnPtr<ImageBuffer>&);
+
private:
// To properly revert partially successful initializtions in the destructor, we record all successful steps.
enum RenderingFlags {
@@ -111,6 +114,7 @@ private:
RenderObject* m_object;
PaintInfo* m_paintInfo;
GraphicsContext* m_savedContext;
+ IntRect m_savedPaintRect;
#if ENABLE(FILTERS)
RenderSVGResourceFilter* m_filter;
#endif
diff --git a/Source/WebCore/rendering/svg/SVGResources.cpp b/Source/WebCore/rendering/svg/SVGResources.cpp
index d9097409d..015190d27 100644
--- a/Source/WebCore/rendering/svg/SVGResources.cpp
+++ b/Source/WebCore/rendering/svg/SVGResources.cpp
@@ -146,10 +146,10 @@ static inline String targetReferenceFromResource(SVGElement* element)
if (element->hasTagName(SVGNames::patternTag))
target = static_cast<SVGPatternElement*>(element)->href();
else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
- target = static_cast<SVGGradientElement*>(element)->href();
+ target = toSVGGradientElement(element)->href();
#if ENABLE(FILTERS)
else if (element->hasTagName(SVGNames::filterTag))
- target = static_cast<SVGFilterElement*>(element)->href();
+ target = toSVGFilterElement(element)->href();
#endif
else
ASSERT_NOT_REACHED();
@@ -179,8 +179,8 @@ static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document*
static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element)
{
ASSERT(element);
- ASSERT(element->isStyled());
- extensions->addPendingResource(id, static_cast<SVGStyledElement*>(element));
+ ASSERT_WITH_SECURITY_IMPLICATION(element->isSVGStyledElement());
+ extensions->addPendingResource(id, toSVGStyledElement(element));
}
bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style)
@@ -190,9 +190,9 @@ bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRen
Node* node = object->node();
ASSERT(node);
- ASSERT(node->isSVGElement());
+ ASSERT_WITH_SECURITY_IMPLICATION(node->isSVGElement());
- SVGElement* element = static_cast<SVGElement*>(node);
+ SVGElement* element = toSVGElement(node);
if (!element)
return false;
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
index 8b48cf53e..3f6e7dee1 100644
--- a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
+++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
@@ -36,7 +36,6 @@ SVGResourcesCache::SVGResourcesCache()
SVGResourcesCache::~SVGResourcesCache()
{
- deleteAllValues(m_cache);
}
void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style)
@@ -49,14 +48,12 @@ void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const
ASSERT(svgStyle);
// Build a list of all resources associated with the passed RenderObject
- SVGResources* resources = new SVGResources;
- if (!resources->buildCachedResources(object, svgStyle)) {
- delete resources;
+ OwnPtr<SVGResources> newResources = adoptPtr(new SVGResources);
+ if (!newResources->buildCachedResources(object, svgStyle))
return;
- }
// Put object in cache.
- m_cache.set(object, resources);
+ SVGResources* resources = m_cache.set(object, newResources.release()).iterator->value.get();
// Run cycle-detection _afterwards_, so self-references can be caught as well.
SVGResourcesCycleSolver solver(object, resources);
@@ -76,7 +73,7 @@ void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object)
if (!m_cache.contains(object))
return;
- SVGResources* resources = m_cache.get(object);
+ OwnPtr<SVGResources> resources = m_cache.take(object);
// Walk resources and register the render object at each resources.
HashSet<RenderSVGResourceContainer*> resourceSet;
@@ -85,8 +82,6 @@ void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object)
HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
(*it)->removeClient(object);
-
- delete m_cache.take(object);
}
static inline SVGResourcesCache* resourcesCacheFromRenderObject(const RenderObject* renderer)
@@ -106,11 +101,7 @@ static inline SVGResourcesCache* resourcesCacheFromRenderObject(const RenderObje
SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(const RenderObject* renderer)
{
ASSERT(renderer);
- SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
- if (!cache->m_cache.contains(renderer))
- return 0;
-
- return cache->m_cache.get(renderer);
+ return resourcesCacheFromRenderObject(renderer)->m_cache.get(renderer);
}
void SVGResourcesCache::clientLayoutChanged(RenderObject* object)
@@ -125,6 +116,12 @@ void SVGResourcesCache::clientLayoutChanged(RenderObject* object)
resources->removeClientFromCache(object);
}
+static inline bool rendererCanHaveResources(RenderObject* renderer)
+{
+ ASSERT(renderer);
+ return renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGInlineText();
+}
+
void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle)
{
ASSERT(renderer);
@@ -132,24 +129,22 @@ void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifferen
return;
// In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint.
- if (renderer->isSVGResourceFilterPrimitive() && diff == StyleDifferenceRepaint)
+ if (renderer->isSVGResourceFilterPrimitive() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfText))
return;
// Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer.
// FIXME: Avoid passing in a useless StyleDifference, but instead compare oldStyle/newStyle to see which resources changed
// to be able to selectively rebuild individual resources, instead of all of them.
- SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
- cache->removeResourcesFromRenderObject(renderer);
- cache->addResourcesFromRenderObject(renderer, newStyle);
+ if (rendererCanHaveResources(renderer)) {
+ SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+ cache->removeResourcesFromRenderObject(renderer);
+ cache->addResourcesFromRenderObject(renderer, newStyle);
+ }
RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
-}
-static inline bool rendererCanHaveResources(RenderObject* renderer)
-{
- ASSERT(renderer);
- ASSERT(renderer->parent());
- return renderer->node() && !renderer->isSVGInlineText();
+ if (renderer->node() && !renderer->node()->isSVGElement())
+ renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
}
void SVGResourcesCache::clientWasAddedToTree(RenderObject* renderer, const RenderStyle* newStyle)
@@ -196,13 +191,13 @@ void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource)
// The resource itself may have clients, that need to be notified.
cache->removeResourcesFromRenderObject(resource);
- HashMap<const RenderObject*, SVGResources*>::iterator end = cache->m_cache.end();
- for (HashMap<const RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it) {
+ CacheMap::iterator end = cache->m_cache.end();
+ for (CacheMap::iterator it = cache->m_cache.begin(); it != end; ++it) {
it->value->resourceDestroyed(resource);
// Mark users of destroyed resources as pending resolution based on the id of the old resource.
Element* resourceElement = toElement(resource->node());
- SVGStyledElement* clientElement = toSVGStyledElement(it->key->node());
+ Element* clientElement = toElement(it->key->node());
SVGDocumentExtensions* extensions = clientElement->document()->accessSVGExtensions();
extensions->addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement);
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.h b/Source/WebCore/rendering/svg/SVGResourcesCache.h
index 633fcd73d..67a01059c 100644
--- a/Source/WebCore/rendering/svg/SVGResourcesCache.h
+++ b/Source/WebCore/rendering/svg/SVGResourcesCache.h
@@ -23,6 +23,7 @@
#if ENABLE(SVG)
#include "RenderStyleConstants.h"
#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
namespace WebCore {
@@ -61,7 +62,8 @@ private:
void addResourcesFromRenderObject(RenderObject*, const RenderStyle*);
void removeResourcesFromRenderObject(RenderObject*);
- HashMap<const RenderObject*, SVGResources*> m_cache;
+ typedef HashMap<const RenderObject*, OwnPtr<SVGResources> > CacheMap;
+ CacheMap m_cache;
};
}
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
index 546fec26c..d2df3f16d 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
@@ -51,9 +51,9 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni
if (hasSelection) {
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
if (child->isSVGInlineTextBox())
- static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo);
+ toSVGInlineTextBox(child)->paintSelectionBackground(childPaintInfo);
else if (child->isSVGInlineFlowBox())
- static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo);
+ toSVGInlineFlowBox(child)->paintSelectionBackground(childPaintInfo);
}
}
@@ -61,7 +61,7 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni
if (renderingContext.isRenderingPrepared()) {
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
if (child->isSVGInlineTextBox())
- SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
+ SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(toSVGInlineTextBox(child)->textRenderer()));
child->paint(paintInfo, LayoutPoint(), 0, 0);
}
@@ -101,7 +101,7 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText
ASSERT(child->renderer());
ASSERT(child->renderer()->isSVGInlineText());
- SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
+ SVGInlineTextBox* textBox = toSVGInlineTextBox(child);
characterLayout.layoutInlineTextBox(textBox);
} else {
// Skip generated content.
@@ -109,9 +109,9 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText
if (!node)
continue;
- ASSERT(child->isInlineFlowBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox());
- SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
+ SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child);
bool isTextPath = node->hasTagName(SVGNames::textPathTag);
if (isTextPath) {
// Build text chunks for all <textPath> children, using the line layout algorithm.
@@ -138,7 +138,7 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe
ASSERT(child->renderer());
ASSERT(child->renderer()->isSVGInlineText());
- SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
+ SVGInlineTextBox* textBox = toSVGInlineTextBox(child);
boxRect = textBox->calculateBoundaries();
textBox->setX(boxRect.x());
textBox->setY(boxRect.y());
@@ -149,9 +149,9 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe
if (!child->renderer()->node())
continue;
- ASSERT(child->isInlineFlowBox());
+ ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox());
- SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
+ SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child);
layoutChildBoxes(flowBox);
boxRect = flowBox->calculateBoundaries();
@@ -171,9 +171,9 @@ void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect)
ASSERT(parentBlock);
// Finally, assign the root block position, now that all content is laid out.
- IntRect roundedChildRect = enclosingIntRect(childRect);
- parentBlock->setLocation(roundedChildRect.location());
- parentBlock->setSize(roundedChildRect.size());
+ LayoutRect boundingRect = enclosingLayoutRect(childRect);
+ parentBlock->setLocation(boundingRect.location());
+ parentBlock->setSize(boundingRect.size());
// Position all children relative to the parent block.
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
@@ -188,7 +188,7 @@ void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect)
setY(0);
setLogicalWidth(childRect.width());
setLogicalHeight(childRect.height());
- setLineTopBottomPositions(0, roundedChildRect.height(), 0, roundedChildRect.height());
+ setLineTopBottomPositions(0, boundingRect.height(), 0, boundingRect.height());
}
InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const LayoutPoint& point)
@@ -278,8 +278,8 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve
continue;
}
- SVGInlineTextBox* firstTextBox = static_cast<SVGInlineTextBox*>(*first);
- SVGInlineTextBox* lastTextBox = static_cast<SVGInlineTextBox*>(*last);
+ SVGInlineTextBox* firstTextBox = toSVGInlineTextBox(*first);
+ SVGInlineTextBox* lastTextBox = toSVGInlineTextBox(*last);
// Reordering is only necessary for BiDi text that is _absolutely_ positioned.
if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) {
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
index 7aec8d888..5bab4f784 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
@@ -32,7 +32,7 @@ namespace WebCore {
class SVGInlineTextBox;
-class SVGRootInlineBox : public RootInlineBox {
+class SVGRootInlineBox FINAL : public RootInlineBox {
public:
SVGRootInlineBox(RenderBlock* block)
: RootInlineBox(block)
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
index ba2b7639d..e31104575 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
@@ -171,6 +171,8 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou
RenderSVGTextPath* textPath = toRenderSVGTextPath(object);
m_textPath = textPath->layoutPath();
+ if (m_textPath.isEmpty())
+ return;
m_textPathStartOffset = textPath->startOffset();
m_textPathLength = m_textPath.length();
if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1)
@@ -423,7 +425,10 @@ void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& vis
void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style)
{
- SVGElement* lengthContext = static_cast<SVGElement*>(text->parent()->node());
+ if (m_inPathLayout && m_textPath.isEmpty())
+ return;
+
+ SVGElement* lengthContext = toSVGElement(text->parent()->node());
RenderObject* textParent = text->parent();
bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false;
@@ -578,20 +583,9 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
y += m_dy;
}
- // Determine wheter we have to start a new fragment.
- bool shouldStartNewFragment = false;
-
- if (m_dx || m_dy)
- shouldStartNewFragment = true;
-
- if (!shouldStartNewFragment && (m_isVerticalText || m_inPathLayout))
- shouldStartNewFragment = true;
-
- if (!shouldStartNewFragment && (angle || angle != lastAngle || orientationAngle))
- shouldStartNewFragment = true;
-
- if (!shouldStartNewFragment && (kerning || applySpacingToNextCharacter || definesTextLength))
- shouldStartNewFragment = true;
+ // Determine whether we have to start a new fragment.
+ bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPathLayout || angle || angle != lastAngle
+ || orientationAngle || kerning || applySpacingToNextCharacter || definesTextLength;
// If we already started a fragment, close it now.
if (didStartTextFragment && shouldStartNewFragment) {
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp
index 074a8ea66..f0107c4ab 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp
@@ -30,8 +30,6 @@
#include "SVGFontData.h"
#include "SVGFontElement.h"
#include "SVGFontFaceElement.h"
-#else
-#include <wtf/UnusedParam.h>
#endif
namespace WebCore {
diff --git a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp
index dfeebb2f8..901ec8179 100644
--- a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp
@@ -65,9 +65,6 @@ void SVGTextMetricsBuilder::advanceSimpleText()
return;
}
- if (currentCharacterStartsSurrogatePair())
- ASSERT(metricsLength == 2);
-
float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth;
m_totalWidth = m_simpleWidthIterator->runWidthSoFar();
diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
index a7ee787c4..bcc8d87ba 100644
--- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
@@ -101,7 +101,7 @@ void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox)
}
if (child->isSVGInlineTextBox())
- m_textBoxes.append(static_cast<SVGInlineTextBox*>(child));
+ m_textBoxes.append(toSVGInlineTextBox(child));
}
}
@@ -352,10 +352,10 @@ bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTe
return true;
}
-FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const
+SVGPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const
{
if (m_textBoxes.isEmpty())
- return FloatPoint();
+ return SVGPoint();
StartPositionOfCharacterData data(position);
executeQuery(&data, &SVGTextQuery::startPositionOfCharacterCallback);
@@ -399,10 +399,10 @@ bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGText
return true;
}
-FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const
+SVGPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const
{
if (m_textBoxes.isEmpty())
- return FloatPoint();
+ return SVGPoint();
EndPositionOfCharacterData data(position);
executeQuery(&data, &SVGTextQuery::endPositionOfCharacterCallback);
@@ -543,7 +543,7 @@ bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGT
return false;
}
-int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const
+int SVGTextQuery::characterNumberAtPosition(const SVGPoint& position) const
{
if (m_textBoxes.isEmpty())
return -1;
diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.h b/Source/WebCore/rendering/svg/SVGTextQuery.h
index 331dd945c..bf60a6da6 100644
--- a/Source/WebCore/rendering/svg/SVGTextQuery.h
+++ b/Source/WebCore/rendering/svg/SVGTextQuery.h
@@ -22,6 +22,7 @@
#if ENABLE(SVG)
#include "FloatRect.h"
+#include "SVGPoint.h"
#include "SVGTextFragment.h"
#include <wtf/Vector.h>
@@ -38,11 +39,11 @@ public:
unsigned numberOfCharacters() const;
float textLength() const;
float subStringLength(unsigned startPosition, unsigned length) const;
- FloatPoint startPositionOfCharacter(unsigned position) const;
- FloatPoint endPositionOfCharacter(unsigned position) const;
+ SVGPoint startPositionOfCharacter(unsigned position) const;
+ SVGPoint endPositionOfCharacter(unsigned position) const;
float rotationOfCharacter(unsigned position) const;
FloatRect extentOfCharacter(unsigned position) const;
- int characterNumberAtPosition(const FloatPoint&) const;
+ int characterNumberAtPosition(const SVGPoint&) const;
// Public helper struct. Private classes in SVGTextQuery inherit from it.
struct Data;
diff --git a/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp b/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp
index 7dd60d49e..f94b283e6 100644
--- a/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp
@@ -126,7 +126,7 @@ void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const T
if (!glyph)
continue;
- float advance = glyphBuffer.advanceAt(from + i);
+ float advance = glyphBuffer.advanceAt(from + i).width();
SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
ASSERT(!svgGlyph.isPartOfLigature);
ASSERT(svgGlyph.tableEntry == glyph);
@@ -174,7 +174,7 @@ GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co
const SimpleFontData* primaryFont = font.primaryFont();
ASSERT(primaryFont);
- pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror);
+ pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror, AutoVariant);
GlyphData glyphData = pair.first;
// Check if we have the missing glyph data, in which case we can just return.
@@ -186,9 +186,9 @@ GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co
// Save data fromt he font fallback list because we may modify it later. Do this before the
// potential change to glyphData.fontData below.
- FontFallbackList* fontList = font.fontList();
- ASSERT(fontList);
- FontFallbackList::GlyphPagesStateSaver glyphPagesSaver(*fontList);
+ FontGlyphs* glyph = font.glyphs();
+ ASSERT(glyph);
+ FontGlyphs::GlyphPagesStateSaver glyphPagesSaver(*glyph);
// Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage.
const SimpleFontData* originalFontData = glyphData.fontData;
@@ -230,7 +230,7 @@ GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co
// No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.)
// Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily
// remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly.
- page->setGlyphDataForCharacter(character, glyphData.glyph, 0);
+ page->setGlyphDataForCharacter(character, 0, 0);
// Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before.
GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror);