WebKit Bugzilla
Attachment 341096 Details for
Bug 185898
: [LFC] Move sizing/positioning logic to helper classes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-185898-20180523091715.patch (text/plain), 90.02 KB, created by
zalan
on 2018-05-23 09:17:16 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2018-05-23 09:17:16 PDT
Size:
90.02 KB
patch
obsolete
>Subversion Revision: 232109 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 9a1404363b47fb436e0134418cf94988d68536b5..285dd05f1c63c4bdd2f776fa7a21ecffd508ed24 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,69 @@ >+2018-05-23 Zalan Bujtas <zalan@apple.com> >+ >+ [LFC] Move sizing/positioning logic to helper classes >+ https://bugs.webkit.org/show_bug.cgi?id=185898 >+ >+ Reviewed by Antti Koivisto. >+ >+ The idea here is to move all the sizing and positioning logic to helper classes so that >+ the formatting context code stays lean. >+ This is similar to the dedicated BlockMarginCollapse class for the collapsing logic. >+ The helper classes have only static functions. These static functions do not mutate the associated DisplayBoxes, >+ but instead they simply retun the computed values. >+ >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ * layout/FormattingContext.cpp: >+ (WebCore::Layout::FormattingContext::computeOutOfFlowPosition const): >+ (WebCore::Layout::FormattingContext::computeOutOfFlowWidth const): >+ (WebCore::Layout::FormattingContext::computeFloatingWidth const): >+ (WebCore::Layout::FormattingContext::computeOutOfFlowHeight const): >+ (WebCore::Layout::FormattingContext::computeFloatingHeight const): >+ (WebCore::Layout::FormattingContext::computeOutOfFlowNonReplacedHeight const): Deleted. >+ (WebCore::Layout::FormattingContext::computeFloatingNonReplacedHeight const): Deleted. >+ (WebCore::Layout::FormattingContext::computeReplacedHeight const): Deleted. >+ (WebCore::Layout::FormattingContext::computeReplacedWidth const): Deleted. >+ (WebCore::Layout::FormattingContext::contentHeightForFormattingContextRoot const): Deleted. >+ (WebCore::Layout::FormattingContext::computeFloatingNonReplacedWidth const): Deleted. >+ (WebCore::Layout::FormattingContext::computeOutOfFlowNonReplacedWidth const): Deleted. >+ (WebCore::Layout::FormattingContext::computeOutOfFlowReplacedHeight const): Deleted. >+ (WebCore::Layout::FormattingContext::computeOutOfFlowReplacedWidth const): Deleted. >+ (WebCore::Layout::FormattingContext::computeOutOfFlowNonReplacedPosition const): Deleted. >+ (WebCore::Layout::FormattingContext::computeOutOfFlowReplacedPosition const): Deleted. >+ (WebCore::Layout::FormattingContext::shrinkToFitWidth const): Deleted. >+ * layout/FormattingContext.h: >+ * layout/FormattingContextGeometry.cpp: Copied from Source/WebCore/layout/FormattingContext.cpp. >+ (WebCore::Layout::contentHeightForFormattingContextRoot): >+ (WebCore::Layout::shrinkToFitWidth): >+ (WebCore::Layout::FormattingContextGeometry::outOfFlowNonReplacedHeight): >+ (WebCore::Layout::FormattingContextGeometry::outOfFlowNonReplacedWidth): >+ (WebCore::Layout::FormattingContextGeometry::outOfFlowReplacedHeight): >+ (WebCore::Layout::FormattingContextGeometry::outOfFlowReplacedWidth): >+ (WebCore::Layout::FormattingContextGeometry::floatingNonReplacedHeight): >+ (WebCore::Layout::FormattingContextGeometry::floatingNonReplacedWidth): >+ (WebCore::Layout::FormattingContextGeometry::floatingReplacedHeight): >+ (WebCore::Layout::FormattingContextGeometry::floatingReplacedWidth): >+ (WebCore::Layout::FormattingContextGeometry::outOfFlowNonReplacedPosition): >+ (WebCore::Layout::FormattingContextGeometry::outOfFlowReplacedPosition): >+ (WebCore::Layout::FormattingContextGeometry::replacedHeight): >+ (WebCore::Layout::FormattingContextGeometry::replacedWidth): >+ * layout/FormattingContextGeometry.h: Copied from Source/WebCore/layout/blockformatting/BlockFormattingContext.h. >+ * layout/blockformatting/BlockFormattingContext.cpp: >+ (WebCore::Layout::BlockFormattingContext::computeStaticPosition const): >+ (WebCore::Layout::BlockFormattingContext::computeInFlowHeight const): >+ (WebCore::Layout::BlockFormattingContext::computeInFlowWidth const): >+ (WebCore::Layout::BlockFormattingContext::computeInFlowNonReplacedWidth const): Deleted. >+ (WebCore::Layout::BlockFormattingContext::computeInFlowNonReplacedHeight const): Deleted. >+ * layout/blockformatting/BlockFormattingContext.h: >+ * layout/blockformatting/BlockFormattingContextGeometry.cpp: Added. >+ (WebCore::Layout::BlockFormattingContextGeometry::inFlowNonReplacedHeight): >+ (WebCore::Layout::BlockFormattingContextGeometry::inFlowNonReplacedWidth): >+ (WebCore::Layout::BlockFormattingContextGeometry::inFlowReplacedHeight): >+ (WebCore::Layout::BlockFormattingContextGeometry::inFlowReplacedWidth): >+ (WebCore::Layout::BlockFormattingContextGeometry::staticPosition): >+ * layout/blockformatting/BlockFormattingContextGeometry.h: Copied from Source/WebCore/layout/blockformatting/BlockFormattingContext.h. >+ * layout/displaytree/DisplayBox.h: >+ > 2018-05-23 Zalan Bujtas <zalan@apple.com> > > [LFC] Implement positioning for replaced out-of-flow elements >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index db31065e2fe7a26c0831194f33ebc67b8d326a7b..5ae1faa7eec48e67b01c878c2661cac2872cd362 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1216,9 +1216,11 @@ inspector/agents/worker/WorkerRuntimeAgent.cpp > layout/FloatingContext.cpp > layout/FloatingState.cpp > layout/FormattingContext.cpp >+layout/FormattingContextGeometry.cpp > layout/FormattingState.cpp > layout/LayoutContext.cpp > layout/blockformatting/BlockFormattingContext.cpp >+layout/blockformatting/BlockFormattingContextGeometry.cpp > layout/blockformatting/BlockFormattingState.cpp > layout/blockformatting/BlockMarginCollapse.cpp > layout/blockformatting/BlockInvalidation.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 53a499bf37fe778ef2b9fe889d45ba1bcc74f8cd..17d28949f5daf1c8ae92137fc31b0aaeac188af9 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -8886,6 +8886,7 @@ > 6ED8C378183BFF8C009E53BD /* BoxShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoxShape.h; sourceTree = "<group>"; }; > 6EE8A77010F803F3005A4A24 /* JSWebGLContextAttributes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLContextAttributes.cpp; sourceTree = "<group>"; }; > 6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLContextAttributes.h; sourceTree = "<group>"; }; >+ 6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlockFormattingContextGeometry.cpp; sourceTree = "<group>"; }; > 6F222B741AB52D640094651A /* WebGLVertexArrayObjectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGLVertexArrayObjectBase.h; sourceTree = "<group>"; }; > 6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebGLVertexArrayObjectBase.cpp; sourceTree = "<group>"; }; > 6F7CA3C4208C2956002F29AB /* LayoutContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutContext.h; sourceTree = "<group>"; }; >@@ -8917,6 +8918,7 @@ > 6F995A2E1A70833700A735F4 /* JSWebGLTransformFeedback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLTransformFeedback.h; sourceTree = "<group>"; }; > 6F995A2F1A70833700A735F4 /* JSWebGLVertexArrayObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLVertexArrayObject.cpp; sourceTree = "<group>"; }; > 6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLVertexArrayObject.h; sourceTree = "<group>"; }; >+ 6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormattingContextGeometry.cpp; sourceTree = "<group>"; }; > 709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleFetchFailureKind.h; sourceTree = "<group>"; }; > 71004B9D1DC1398800A52A38 /* playback-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "playback-support.js"; sourceTree = "<group>"; }; > 71025EC21F99F096004A250C /* WebAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAnimation.h; sourceTree = "<group>"; }; >@@ -15678,6 +15680,7 @@ > 115CFA80208B8EDA001E6991 /* FloatingState.h */, > 115CFA69208AF7D0001E6991 /* FormattingContext.cpp */, > 115CFA68208AF7D0001E6991 /* FormattingContext.h */, >+ 6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */, > 115CFA75208AFE30001E6991 /* FormattingState.cpp */, > 115CFA74208AFE30001E6991 /* FormattingState.h */, > 115F7805209CBCBD00739C13 /* Invalidation.h */, >@@ -15717,6 +15720,7 @@ > children = ( > 115CFA6D208AFAB6001E6991 /* BlockFormattingContext.cpp */, > 115CFA6C208AFAB6001E6991 /* BlockFormattingContext.h */, >+ 6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */, > 115CFA79208B8D9D001E6991 /* BlockFormattingState.cpp */, > 115CFA78208B8D9D001E6991 /* BlockFormattingState.h */, > 1123AFDA209ABB2000736ACC /* BlockInvalidation.cpp */, >diff --git a/Source/WebCore/layout/FormattingContext.cpp b/Source/WebCore/layout/FormattingContext.cpp >index 9c73f446f55fbbfcefc7b0243ca94d8d7ee2b932..35c6050f7d2c18b545a7228cecbe39473a3a3b2d 100644 >--- a/Source/WebCore/layout/FormattingContext.cpp >+++ b/Source/WebCore/layout/FormattingContext.cpp >@@ -59,11 +59,14 @@ void FormattingContext::computeInFlowPositionedPosition(const Box&, Display::Box > > void FormattingContext::computeOutOfFlowPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- if (!layoutBox.replaced()) { >- computeOutOfFlowNonReplacedPosition(layoutContext, layoutBox, displayBox); >- return; >- } >- computeOutOfFlowReplacedPosition(layoutContext, layoutBox, displayBox); >+ LayoutPoint computedTopLeft; >+ >+ if (layoutBox.replaced()) >+ computedTopLeft = Geometry::outOfFlowReplacedPosition(layoutContext, layoutBox); >+ else >+ computedTopLeft = Geometry::outOfFlowNonReplacedPosition(layoutContext, layoutBox); >+ >+ displayBox.setTopLeft(computedTopLeft); > } > > void FormattingContext::computeWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >@@ -86,38 +89,50 @@ void FormattingContext::computeHeight(LayoutContext& layoutContext, const Box& l > > void FormattingContext::computeOutOfFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- if (!layoutBox.replaced()) { >- computeOutOfFlowNonReplacedWidth(layoutContext, layoutBox, displayBox); >- return; >- } >- computeOutOfFlowReplacedWidth(layoutContext, layoutBox, displayBox); >+ LayoutUnit computedWidth; >+ >+ if (layoutBox.replaced()) >+ computedWidth = Geometry::outOfFlowReplacedWidth(layoutContext, layoutBox); >+ else >+ computedWidth = Geometry::outOfFlowNonReplacedWidth(layoutContext, layoutBox); >+ >+ displayBox.setWidth(computedWidth); > } > > void FormattingContext::computeFloatingWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- if (!layoutBox.replaced()) { >- computeFloatingNonReplacedWidth(layoutContext, layoutBox, displayBox); >- return; >- } >- computeReplacedWidth(layoutContext, layoutBox, displayBox); >+ LayoutUnit computedWidth; >+ >+ if (layoutBox.replaced()) >+ computedWidth = Geometry::floatingReplacedWidth(layoutContext, layoutBox); >+ else >+ computedWidth = Geometry::floatingNonReplacedWidth(layoutContext, layoutBox); >+ >+ displayBox.setWidth(computedWidth); > } > > void FormattingContext::computeOutOfFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- if (!layoutBox.replaced()) { >- computeOutOfFlowNonReplacedHeight(layoutContext, layoutBox, displayBox); >- return; >- } >- computeOutOfFlowReplacedHeight(layoutContext, layoutBox, displayBox); >+ LayoutUnit computedHeight; >+ >+ if (layoutBox.replaced()) >+ computedHeight = Geometry::outOfFlowReplacedHeight(layoutContext, layoutBox); >+ else >+ computedHeight = Geometry::outOfFlowNonReplacedHeight(layoutContext, layoutBox); >+ >+ displayBox.setHeight(computedHeight); > } > > void FormattingContext::computeFloatingHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- if (!layoutBox.replaced()) { >- computeFloatingNonReplacedHeight(layoutContext, layoutBox, displayBox); >- return; >- } >- computeReplacedHeight(layoutContext, layoutBox, displayBox); >+ LayoutUnit computedHeight; >+ >+ if (layoutBox.replaced()) >+ computedHeight = Geometry::floatingReplacedHeight(layoutContext, layoutBox); >+ else >+ computedHeight = Geometry::floatingNonReplacedHeight(layoutContext, layoutBox); >+ >+ displayBox.setHeight(computedHeight); > } > > LayoutUnit FormattingContext::marginTop(const Box&) const >@@ -168,476 +183,6 @@ void FormattingContext::layoutOutOfFlowDescendants(LayoutContext& layoutContext) > } > } > >-void FormattingContext::computeOutOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()); >- >- // 10.6.4 Absolutely positioned, non-replaced elements >- // >- // For absolutely positioned elements, the used values of the vertical dimensions must satisfy this constraint: >- // 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' >- // = height of containing block >- >- // If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and apply rule number three below. >- >- // If none of the three are 'auto': If both 'margin-top' and 'margin-bottom' are 'auto', solve the equation under the extra >- // constraint that the two margins get equal values. If one of 'margin-top' or 'margin-bottom' is 'auto', solve the equation for that value. >- // If the values are over-constrained, ignore the value for 'bottom' and solve for that value. >- >- // Otherwise, pick the one of the following six rules that applies. >- >- // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7, >- // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >- // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for >- // 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >- // 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content per 10.6.7, set 'auto' >- // values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >- // 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >- // 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', then 'auto' values for 'margin-top' and 'margin-bottom' are set to 0 and solve for 'height' >- // 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0 and solve for 'bottom' >- auto& style = layoutBox.style(); >- auto top = style.logicalTop(); >- auto bottom = style.logicalBottom(); >- auto height = style.logicalHeight(); >- >- auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height(); >- LayoutUnit computedHeightValue; >- >- if ((top.isAuto() && height.isAuto() && bottom.isAuto()) >- || (top.isAuto() && height.isAuto() && !bottom.isAuto()) >- || (!top.isAuto() && height.isAuto() && bottom.isAuto())) { >- // All auto (#3), #1 and #3 >- computedHeightValue = contentHeightForFormattingContextRoot(layoutContext, layoutBox); >- } else if (!top.isAuto() && height.isAuto() && !bottom.isAuto()) { >- // #5 >- auto marginTop = displayBox.marginTop(); >- auto marginBottom = displayBox.marginBottom(); >- >- auto paddingTop = displayBox.paddingTop(); >- auto paddingBottom = displayBox.paddingBottom(); >- >- auto borderTop = displayBox.borderTop(); >- auto borderBottom = displayBox.borderBottom(); >- >- computedHeightValue = containingBlockHeight - (top.value() + marginTop + borderTop + paddingTop + paddingBottom + borderBottom + marginBottom + bottom.value()); >- } else if (!height.isAuto()) >- computedHeightValue = valueForLength(height, containingBlockHeight); >- else >- ASSERT_NOT_REACHED(); >- >- displayBox.setHeight(computedHeightValue); >-} >- >-void FormattingContext::computeFloatingNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced()); >- // 10.6.6 Complicated cases >- // >- // Floating, non-replaced elements. >- // >- // If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. >- auto height = layoutBox.style().logicalHeight(); >- displayBox.setHeight(height.isAuto() ? contentHeightForFormattingContextRoot(layoutContext, layoutBox) : LayoutUnit(height.value())); >-} >- >-void FormattingContext::computeReplacedHeight(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced()); >- // 10.6.5 Absolutely positioned, replaced elements. The used value of 'height' is determined as for inline replaced elements. >- >- // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements >- // >- // 1. If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'. >- // >- // 2. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is: >- // (used width) / (intrinsic ratio) >- // >- // 3. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'. >- // >- // 4. Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to >- // the height of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width. >- auto& style = layoutBox.style(); >- auto width = style.logicalWidth(); >- auto height = style.logicalHeight(); >- >- LayoutUnit computedHeightValue; >- auto replaced = layoutBox.replaced(); >- ASSERT(replaced); >- >- if (height.isAuto()) { >- if (width.isAuto() && replaced->hasIntrinsicHeight()) { >- // #1 >- computedHeightValue = replaced->intrinsicHeight(); >- } else if (replaced->hasIntrinsicRatio()) { >- // #2 >- computedHeightValue = width.value() / replaced->intrinsicRatio(); >- } else if (replaced->hasIntrinsicHeight()) { >- // #3 >- computedHeightValue = replaced->intrinsicHeight(); >- } else { >- // #4 >- computedHeightValue = 150; >- } >- } else >- computedHeightValue = height.value(); >- >- displayBox.setHeight(computedHeightValue); >-} >- >-void FormattingContext::computeReplacedWidth(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced()); >- >- // 10.3.4 Block-level, replaced elements in normal flow: The used value of 'width' is determined as for inline replaced elements. >- // 10.3.6 Floating, replaced elements: The used value of 'width' is determined as for inline replaced elements. >- // 10.3.8 Absolutely positioned, replaced elements: The used value of 'width' is determined as for inline replaced elements. >- >- // 10.3.2 Inline, replaced elements >- // >- // 1. 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'. >- // >- // 2. If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio; >- // 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) >- // >- // 3. 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 'width' is undefined in CSS 2.2. However, it is suggested that, if the containing block's width does not itself depend on the replaced >- // element's width, then the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow. >- // >- // 4. 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'. >- // >- // 5. 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. >- auto& style = layoutBox.style(); >- auto width = style.logicalWidth(); >- auto height = style.logicalHeight(); >- >- LayoutUnit computedWidthValue; >- auto replaced = layoutBox.replaced(); >- ASSERT(replaced); >- >- if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicWidth()) { >- // #1 >- computedWidthValue = replaced->intrinsicWidth(); >- } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) { >- // #2 >- auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight(); >- computedWidthValue = usedHeight * replaced->intrinsicRatio(); >- } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) { >- // #3 >- // FIXME: undefined but surely doable. >- ASSERT_NOT_IMPLEMENTED_YET(); >- } else if (width.isAuto() && replaced->hasIntrinsicWidth()) { >- // #4 >- computedWidthValue = replaced->intrinsicWidth(); >- } else { >- // #5 >- computedWidthValue = 300; >- } >- >- displayBox.setWidth(computedWidthValue); >-} >- >-LayoutUnit FormattingContext::contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox) const >-{ >- ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext()); >- // 10.6.7 'Auto' heights for block formatting context roots >- >- // If it only has inline-level children, the height is the distance between the top of the topmost line box and the bottom of the bottommost line box. >- // If it has block-level children, the height is the distance between the top margin-edge of the topmost block-level >- // child box and the bottom margin-edge of the bottommost block-level child box. >- >- // In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge, >- // then the height is increased to include those edges. Only floats that participate in this block formatting context are taken >- // into account, e.g., floats inside absolutely positioned descendants or other floats are not. >- if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild()) >- return 0; >- >- auto& formattingRootContainer = downcast<Container>(layoutBox); >- if (formattingRootContainer.establishesInlineFormattingContext()) >- return 0; >- >- auto* firstDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild()); >- auto* lastDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.lastInFlowChild()); >- >- auto top = firstDisplayBox->marginBox().y(); >- auto bottom = lastDisplayBox->marginBox().maxY(); >- // FIXME: add floating support. >- return bottom - top; >-} >- >-void FormattingContext::computeFloatingNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced()); >- // 10.3.5 Floating, non-replaced elements >- >- // If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width. >- auto width = layoutBox.style().logicalWidth(); >- displayBox.setWidth(width.isAuto() ? shrinkToFitWidth(layoutContext, layoutBox) : LayoutUnit(width.value())); >-} >- >-void FormattingContext::computeOutOfFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()); >- >- // 10.3.7 Absolutely positioned, non-replaced elements >- // >- // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' >- // = width of containing block >- >- // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. >- // Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static >- // position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below. >- >- // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left' >- // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position >- // containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. >- // Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr'). >- // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right' >- // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left' >- // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width' >- // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right' >- auto& style = layoutBox.style(); >- auto left = style.logicalLeft(); >- auto right = style.logicalRight(); >- auto width = style.logicalWidth(); >- >- auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >- LayoutUnit computedWidthValue; >- >- if ((left.isAuto() && width.isAuto() && right.isAuto()) >- || (left.isAuto() && width.isAuto() && !right.isAuto()) >- || (!left.isAuto() && width.isAuto() && right.isAuto())) { >- // All auto (#1), #1 and #3 >- computedWidthValue = shrinkToFitWidth(layoutContext, layoutBox); >- } else if (!left.isAuto() && width.isAuto() && !right.isAuto()) { >- // #5 >- auto marginLeft = displayBox.marginLeft(); >- auto marginRight = displayBox.marginRight(); >- >- auto paddingLeft = displayBox.paddingLeft(); >- auto paddingRight = displayBox.paddingRight(); >- >- auto borderLeft = displayBox.borderLeft(); >- auto borderRight = displayBox.borderRight(); >- >- computedWidthValue = containingBlockWidth - (left.value() + marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight + right.value()); >- } else if (!width.isAuto()) >- computedWidthValue = valueForLength(width, containingBlockWidth); >- else >- ASSERT_NOT_REACHED(); >- >- displayBox.setWidth(computedWidthValue); >-} >- >-void FormattingContext::computeOutOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced()); >- // 10.6.5 Absolutely positioned, replaced elements >- // >- // The used value of 'height' is determined as for inline replaced elements. >- computeReplacedHeight(layoutContext, layoutBox, displayBox); >-} >- >-void FormattingContext::computeOutOfFlowReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced()); >- // 10.3.8 Absolutely positioned, replaced elements >- // >- // The used value of 'width' is determined as for inline replaced elements. >- computeReplacedWidth(layoutContext, layoutBox, displayBox); >-} >- >-void FormattingContext::computeOutOfFlowNonReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- // 10.3.7 Absolutely positioned, non-replaced elements (left/right) >- // 10.6.4 Absolutely positioned, non-replaced elements (top/bottom) >- >- // At this point we've the size computed. >- auto size = displayBox.size(); >- auto& style = layoutBox.style(); >- >- // 10.6.4 Absolutely positioned, non-replaced elements >- auto top = style.logicalTop(); >- auto bottom = style.logicalBottom(); >- auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height(); >- >- // 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' >- // = height of containing block >- // >- // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7, >- // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >- // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for >- // 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >- // 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content per 10.6.7, set 'auto' >- // values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >- // 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >- // 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', then 'auto' values for 'margin-top' and 'margin-bottom' are set to 0 and solve for 'height' >- // 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0 and solve for 'bottom' >- LayoutUnit computedTopValue; >- if (top.isAuto() && !bottom.isAuto()) { >- // #1 #4 >- auto marginTop = displayBox.marginTop(); >- auto marginBottom = displayBox.marginBottom(); >- >- auto paddingTop = displayBox.paddingTop(); >- auto paddingBottom = displayBox.paddingBottom(); >- >- auto borderTop = displayBox.borderTop(); >- auto borderBottom = displayBox.borderBottom(); >- >- computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value()); >- } else if (top.isAuto() && bottom.isAuto()) { >- // #2 >- // Already computed as part of the computeStaticPosition(); >- computedTopValue = displayBox.top(); >- } else { >- // #3 #5 #6 have top != auto >- computedTopValue = valueForLength(top, containingBlockHeight); >- } >- >- displayBox.setTop(computedTopValue); >- >- // 10.3.7 Absolutely positioned, non-replaced elements >- auto left = style.logicalLeft(); >- auto right = style.logicalRight(); >- auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >- >- // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' >- // = width of containing block >- // >- // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. >- // Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static >- // position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below. >- >- // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left' >- // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position >- // containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. >- // Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr'). >- // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right' >- // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left' >- // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width' >- // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right' >- LayoutUnit computedLeftValue; >- if (left.isAuto() && !right.isAuto()) { >- // #1 #4 >- auto marginLeft = displayBox.marginLeft(); >- auto marginRight = displayBox.marginRight(); >- >- auto paddingLeft = displayBox.paddingLeft(); >- auto paddingRight = displayBox.paddingRight(); >- >- auto borderLeft = displayBox.borderLeft(); >- auto borderRight = displayBox.borderRight(); >- >- computedLeftValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + size.width() + paddingRight + borderRight + marginRight + right.value()); >- } else if (left.isAuto() && right.isAuto()) { >- // #2 >- // FIXME: rtl >- computedLeftValue = displayBox.left(); >- } else { >- // #3 #5 #6 have left != auto >- computedLeftValue = valueForLength(left, containingBlockWidth); >- } >- >- displayBox.setLeft(computedLeftValue); >-} >- >-void FormattingContext::computeOutOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- // 10.6.5 Absolutely positioned, replaced elements (top/bottom) >- // 10.3.8 Absolutely positioned, replaced elements (left/right) >- >- // At this point we've the size computed. >- auto size = displayBox.size(); >- auto& style = layoutBox.style(); >- >- // 10.6.5 Absolutely positioned, replaced elements >- // >- // This situation is similar to the previous one, except that the element has an intrinsic height. The sequence of substitutions is now: >- // The used value of 'height' is determined as for inline replaced elements. If 'margin-top' or 'margin-bottom' is specified as 'auto' >- // its used value is determined by the rules below. >- // >- // 1. If both 'top' and 'bottom' have the value 'auto', replace 'top' with the element's static position. >- // 2. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or 'margin-bottom' with '0'. >- // 3. If at this point both 'margin-top' and 'margin-bottom' are still 'auto', solve the equation under the extra constraint that the two margins must get equal values. >- // 4. If at this point there is only one 'auto' left, solve the equation for that value. >- // 5. If at this point the values are over-constrained, ignore the value for 'bottom' and solve for that value. >- auto top = style.logicalTop(); >- auto bottom = style.logicalBottom(); >- auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height(); >- LayoutUnit computedTopValue; >- >- if (!top.isAuto()) >- computedTopValue = valueForLength(top, containingBlockHeight); >- else if (bottom.isAuto()) { >- // #1 >- computedTopValue = displayBox.top(); >- } else { >- // #4 >- auto marginTop = displayBox.marginTop(); >- auto marginBottom = displayBox.marginBottom(); >- >- auto paddingTop = displayBox.paddingTop(); >- auto paddingBottom = displayBox.paddingBottom(); >- >- auto borderTop = displayBox.borderTop(); >- auto borderBottom = displayBox.borderBottom(); >- >- computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value()); >- } >- >- displayBox.setTop(computedTopValue); >- >- >- // 10.3.8 Absolutely positioned, replaced elements >- // >- // In this case, section 10.3.7 applies up through and including the constraint equation, but the rest of section 10.3.7 is replaced by the following rules: >- // >- // The used value of 'width' is determined as for inline replaced elements. >- // >- // 1. If 'margin-left' or 'margin-right' is specified as 'auto' its used value is determined by the rules below. >- // 2. If both 'left' and 'right' have the value 'auto', then if the 'direction' property of the element establishing the >- // static-position containing block is 'ltr', set 'left' to the static position; else if 'direction' is 'rtl', set 'right' to the static position. >- // 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' or 'margin-right' with '0'. >- // 4. If at this point both 'margin-left' and 'margin-right' are still 'auto', solve the equation under the extra constraint >- // that the two margins must get equal values, unless this would make them negative, in which case when the direction of >- // the containing block is 'ltr' ('rtl'), set 'margin-left' ('margin-right') to zero and solve for 'margin-right' ('margin-left'). >- // 5. If at this point there is an 'auto' left, solve the equation for that value. >- // 6. If at this point the values are over-constrained, ignore the value for either 'left' (in case the 'direction' >- // property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value. >- auto left = style.logicalLeft(); >- auto right = style.logicalRight(); >- auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >- LayoutUnit computedLeftValue; >- >- if (!left.isAuto()) >- computedLeftValue = valueForLength(left, containingBlockWidth); >- else if (right.isAuto()) { >- // FIXME: take direction into account >- computedLeftValue = displayBox.left(); >- } else { >- // #5 >- auto marginLeft = displayBox.marginLeft(); >- auto marginRight = displayBox.marginRight(); >- >- auto paddingLeft = displayBox.paddingLeft(); >- auto paddingRight = displayBox.paddingRight(); >- >- auto borderLeft = displayBox.borderLeft(); >- auto borderRight = displayBox.borderRight(); >- >- computedLeftValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + size.width() + paddingRight + borderRight + marginRight + right.value()); >- } >- >- displayBox.setLeft(computedLeftValue); >-} >- >-LayoutUnit FormattingContext::shrinkToFitWidth(LayoutContext&, const Box&) const >-{ >- return 0; >-} >- > #ifndef NDEBUG > void FormattingContext::validateGeometryConstraintsAfterLayout(const LayoutContext& layoutContext) const > { >diff --git a/Source/WebCore/layout/FormattingContext.h b/Source/WebCore/layout/FormattingContext.h >index 3ec2ef77c9063b9d434f41b7181b2d1516520df7..c3d3c9c9a716c2f4cdb1350606bdeba8cd221f18 100644 >--- a/Source/WebCore/layout/FormattingContext.h >+++ b/Source/WebCore/layout/FormattingContext.h >@@ -28,12 +28,14 @@ > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > > #include "FloatingState.h" >-#include "LayoutUnit.h" > #include <wtf/IsoMalloc.h> > #include <wtf/WeakPtr.h> > > namespace WebCore { > >+class LayoutPoint; >+class LayoutUnit; >+ > namespace Display { > class Box; > } >@@ -87,28 +89,33 @@ protected: > void placeInFlowPositionedChildren(const Container&) const; > void layoutOutOfFlowDescendants(LayoutContext&s) const; > >- void computeReplacedHeight(LayoutContext&, const Box&, Display::Box&) const; >- void computeReplacedWidth(LayoutContext&, const Box&, Display::Box&) const; >- > #ifndef NDEBUG > virtual void validateGeometryConstraintsAfterLayout(const LayoutContext&) const; > #endif > >-private: >- void computeOutOfFlowNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const; >- void computeOutOfFlowNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const; >- void computeOutOfFlowReplacedHeight(LayoutContext&, const Box&, Display::Box&) const; >- void computeOutOfFlowReplacedWidth(LayoutContext&, const Box&, Display::Box&) const; >+ // This class implements generic positioning and sizing. >+ class Geometry { >+ public: >+ static LayoutUnit outOfFlowNonReplacedHeight(LayoutContext&, const Box&); >+ static LayoutUnit outOfFlowNonReplacedWidth(LayoutContext&, const Box&); >+ >+ static LayoutUnit outOfFlowReplacedHeight(LayoutContext&, const Box&); >+ static LayoutUnit outOfFlowReplacedWidth(LayoutContext&, const Box&); > >- void computeOutOfFlowNonReplacedPosition(LayoutContext&, const Box&, Display::Box&) const; >- void computeOutOfFlowReplacedPosition(LayoutContext&, const Box&, Display::Box&) const; >+ static LayoutUnit floatingNonReplacedHeight(LayoutContext&, const Box&); >+ static LayoutUnit floatingNonReplacedWidth(LayoutContext&, const Box&); > >- void computeFloatingNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const; >- void computeFloatingNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const; >+ static LayoutUnit floatingReplacedHeight(LayoutContext&, const Box&); >+ static LayoutUnit floatingReplacedWidth(LayoutContext&, const Box&); > >- LayoutUnit contentHeightForFormattingContextRoot(LayoutContext&, const Box&) const; >- LayoutUnit shrinkToFitWidth(LayoutContext&, const Box&) const; >+ static LayoutPoint outOfFlowNonReplacedPosition(LayoutContext&, const Box&); >+ static LayoutPoint outOfFlowReplacedPosition(LayoutContext&, const Box&); > >+ static LayoutUnit replacedHeight(LayoutContext&, const Box&); >+ static LayoutUnit replacedWidth(LayoutContext&, const Box&); >+ }; >+ >+private: > WeakPtr<Box> m_root; > }; > >diff --git a/Source/WebCore/layout/FormattingContextGeometry.cpp b/Source/WebCore/layout/FormattingContextGeometry.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..a464b38aa960f31e677f737c236ce79cb40f77e4 >--- /dev/null >+++ b/Source/WebCore/layout/FormattingContextGeometry.cpp >@@ -0,0 +1,530 @@ >+/* >+ * Copyright (C) 2018 Apple 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. 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 INC. 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 "FormattingContext.h" >+ >+#if ENABLE(LAYOUT_FORMATTING_CONTEXT) >+ >+namespace WebCore { >+namespace Layout { >+ >+static LayoutUnit contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext()); >+ // 10.6.7 'Auto' heights for block formatting context roots >+ >+ // If it only has inline-level children, the height is the distance between the top of the topmost line box and the bottom of the bottommost line box. >+ // If it has block-level children, the height is the distance between the top margin-edge of the topmost block-level >+ // child box and the bottom margin-edge of the bottommost block-level child box. >+ >+ // In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge, >+ // then the height is increased to include those edges. Only floats that participate in this block formatting context are taken >+ // into account, e.g., floats inside absolutely positioned descendants or other floats are not. >+ if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild()) >+ return 0; >+ >+ auto& formattingRootContainer = downcast<Container>(layoutBox); >+ if (formattingRootContainer.establishesInlineFormattingContext()) >+ return 0; >+ >+ auto* firstDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild()); >+ auto* lastDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.lastInFlowChild()); >+ >+ auto top = firstDisplayBox->marginBox().y(); >+ auto bottom = lastDisplayBox->marginBox().maxY(); >+ // FIXME: add floating support. >+ return bottom - top; >+} >+ >+static LayoutUnit shrinkToFitWidth(LayoutContext&, const Box&) >+{ >+ return { }; >+} >+ >+LayoutUnit FormattingContext::Geometry::outOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()); >+ >+ // 10.6.4 Absolutely positioned, non-replaced elements >+ // >+ // For absolutely positioned elements, the used values of the vertical dimensions must satisfy this constraint: >+ // 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' >+ // = height of containing block >+ >+ // If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and apply rule number three below. >+ >+ // If none of the three are 'auto': If both 'margin-top' and 'margin-bottom' are 'auto', solve the equation under the extra >+ // constraint that the two margins get equal values. If one of 'margin-top' or 'margin-bottom' is 'auto', solve the equation for that value. >+ // If the values are over-constrained, ignore the value for 'bottom' and solve for that value. >+ >+ // Otherwise, pick the one of the following six rules that applies. >+ >+ // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7, >+ // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >+ // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for >+ // 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >+ // 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content per 10.6.7, set 'auto' >+ // values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >+ // 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >+ // 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', then 'auto' values for 'margin-top' and 'margin-bottom' are set to 0 and solve for 'height' >+ // 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0 and solve for 'bottom' >+ auto& style = layoutBox.style(); >+ auto top = style.logicalTop(); >+ auto bottom = style.logicalBottom(); >+ auto height = style.logicalHeight(); >+ >+ auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height(); >+ LayoutUnit computedHeightValue; >+ >+ if (!height.isAuto()) >+ computedHeightValue = valueForLength(height, containingBlockHeight); >+ else if ((top.isAuto() && bottom.isAuto()) >+ || (top.isAuto() && !bottom.isAuto()) >+ || (!top.isAuto() && bottom.isAuto())) { >+ // All auto (#3), #1 and #3 >+ computedHeightValue = contentHeightForFormattingContextRoot(layoutContext, layoutBox); >+ } else if (!top.isAuto() && !bottom.isAuto()) { >+ // #5 >+ auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); >+ >+ auto marginTop = displayBox.marginTop(); >+ auto marginBottom = displayBox.marginBottom(); >+ >+ auto paddingTop = displayBox.paddingTop(); >+ auto paddingBottom = displayBox.paddingBottom(); >+ >+ auto borderTop = displayBox.borderTop(); >+ auto borderBottom = displayBox.borderBottom(); >+ >+ computedHeightValue = containingBlockHeight - (top.value() + marginTop + borderTop + paddingTop + paddingBottom + borderBottom + marginBottom + bottom.value()); >+ } else { >+ // #2 #4 #6 have height != auto >+ ASSERT_NOT_REACHED(); >+ } >+ >+ return computedHeightValue; >+} >+ >+LayoutUnit FormattingContext::Geometry::outOfFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()); >+ >+ // 10.3.7 Absolutely positioned, non-replaced elements >+ // >+ // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' >+ // = width of containing block >+ >+ // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. >+ // Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static >+ // position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below. >+ >+ // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left' >+ // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position >+ // containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. >+ // Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr'). >+ // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right' >+ // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left' >+ // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width' >+ // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right' >+ auto& style = layoutBox.style(); >+ auto left = style.logicalLeft(); >+ auto right = style.logicalRight(); >+ auto width = style.logicalWidth(); >+ >+ auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >+ LayoutUnit computedWidthValue; >+ >+ if (!width.isAuto()) >+ computedWidthValue = valueForLength(width, containingBlockWidth); >+ else if ((left.isAuto() && right.isAuto()) >+ || (left.isAuto() && !right.isAuto()) >+ || (!left.isAuto() && right.isAuto())) { >+ // All auto (#1), #1 and #3 >+ computedWidthValue = shrinkToFitWidth(layoutContext, layoutBox); >+ } else if (!left.isAuto() && !right.isAuto()) { >+ // #5 >+ auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); >+ >+ auto marginLeft = displayBox.marginLeft(); >+ auto marginRight = displayBox.marginRight(); >+ >+ auto paddingLeft = displayBox.paddingLeft(); >+ auto paddingRight = displayBox.paddingRight(); >+ >+ auto borderLeft = displayBox.borderLeft(); >+ auto borderRight = displayBox.borderRight(); >+ >+ computedWidthValue = containingBlockWidth - (left.value() + marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight + right.value()); >+ } else { >+ // #2 #4 #6 have width != auto >+ ASSERT_NOT_REACHED(); >+ } >+ >+ return computedWidthValue; >+} >+ >+LayoutUnit FormattingContext::Geometry::outOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced()); >+ // 10.6.5 Absolutely positioned, replaced elements >+ // >+ // The used value of 'height' is determined as for inline replaced elements. >+ return replacedHeight(layoutContext, layoutBox); >+} >+ >+LayoutUnit FormattingContext::Geometry::outOfFlowReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced()); >+ // 10.3.8 Absolutely positioned, replaced elements >+ // >+ // The used value of 'width' is determined as for inline replaced elements. >+ return replacedWidth(layoutContext, layoutBox); >+} >+ >+LayoutUnit FormattingContext::Geometry::floatingNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced()); >+ // 10.6.6 Complicated cases >+ // >+ // Floating, non-replaced elements. >+ // >+ // If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. >+ auto height = layoutBox.style().logicalHeight(); >+ return height.isAuto() ? contentHeightForFormattingContextRoot(layoutContext, layoutBox) : LayoutUnit(height.value()); >+} >+ >+LayoutUnit FormattingContext::Geometry::floatingNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced()); >+ // 10.3.5 Floating, non-replaced elements >+ >+ // If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width. >+ auto width = layoutBox.style().logicalWidth(); >+ return width.isAuto() ? shrinkToFitWidth(layoutContext, layoutBox) : LayoutUnit(width.value()); >+} >+ >+LayoutUnit FormattingContext::Geometry::floatingReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isFloatingPositioned() && layoutBox.replaced()); >+ // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' >+ // replaced elements in normal flow and floating replaced elements >+ return replacedHeight(layoutContext, layoutBox); >+} >+ >+LayoutUnit FormattingContext::Geometry::floatingReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isFloatingPositioned() && layoutBox.replaced()); >+ // 10.3.6 Floating, replaced elements >+ // >+ // The used value of 'width' is determined as for inline replaced elements. >+ return replacedWidth(layoutContext, layoutBox); >+} >+ >+LayoutPoint FormattingContext::Geometry::outOfFlowNonReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ // 10.3.7 Absolutely positioned, non-replaced elements (left/right) >+ // 10.6.4 Absolutely positioned, non-replaced elements (top/bottom) >+ >+ // At this point we've the size computed. >+ auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); >+ auto size = displayBox.size(); >+ auto& style = layoutBox.style(); >+ >+ // 10.6.4 Absolutely positioned, non-replaced elements >+ auto top = style.logicalTop(); >+ auto bottom = style.logicalBottom(); >+ auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height(); >+ >+ // 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' >+ // = height of containing block >+ // >+ // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7, >+ // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >+ // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for >+ // 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >+ // 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content per 10.6.7, set 'auto' >+ // values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' >+ // 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' >+ // 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', then 'auto' values for 'margin-top' and 'margin-bottom' are set to 0 and solve for 'height' >+ // 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0 and solve for 'bottom' >+ LayoutUnit computedTopValue; >+ if (top.isAuto() && !bottom.isAuto()) { >+ // #1 #4 >+ auto marginTop = displayBox.marginTop(); >+ auto marginBottom = displayBox.marginBottom(); >+ >+ auto paddingTop = displayBox.paddingTop(); >+ auto paddingBottom = displayBox.paddingBottom(); >+ >+ auto borderTop = displayBox.borderTop(); >+ auto borderBottom = displayBox.borderBottom(); >+ >+ computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value()); >+ } else if (top.isAuto() && bottom.isAuto()) { >+ // #2 >+ // Already computed as part of the computeStaticPosition(); >+ computedTopValue = displayBox.top(); >+ } else { >+ // #3 #5 #6 have top != auto >+ computedTopValue = valueForLength(top, containingBlockHeight); >+ } >+ >+ >+ // 10.3.7 Absolutely positioned, non-replaced elements >+ auto left = style.logicalLeft(); >+ auto right = style.logicalRight(); >+ auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >+ >+ // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' >+ // = width of containing block >+ // >+ // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. >+ // Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static >+ // position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below. >+ >+ // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left' >+ // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position >+ // containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. >+ // Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr'). >+ // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right' >+ // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left' >+ // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width' >+ // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right' >+ LayoutUnit computedLeftValue; >+ if (left.isAuto() && !right.isAuto()) { >+ // #1 #4 >+ auto marginLeft = displayBox.marginLeft(); >+ auto marginRight = displayBox.marginRight(); >+ >+ auto paddingLeft = displayBox.paddingLeft(); >+ auto paddingRight = displayBox.paddingRight(); >+ >+ auto borderLeft = displayBox.borderLeft(); >+ auto borderRight = displayBox.borderRight(); >+ >+ computedLeftValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + size.width() + paddingRight + borderRight + marginRight + right.value()); >+ } else if (left.isAuto() && right.isAuto()) { >+ // #2 >+ // FIXME: rtl >+ computedLeftValue = displayBox.left(); >+ } else { >+ // #3 #5 #6 have left != auto >+ computedLeftValue = valueForLength(left, containingBlockWidth); >+ } >+ >+ return { computedLeftValue, computedTopValue }; >+} >+ >+LayoutPoint FormattingContext::Geometry::outOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ // 10.6.5 Absolutely positioned, replaced elements (top/bottom) >+ // 10.3.8 Absolutely positioned, replaced elements (left/right) >+ >+ // At this point we've the size computed. >+ auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); >+ auto size = displayBox.size(); >+ auto& style = layoutBox.style(); >+ >+ // 10.6.5 Absolutely positioned, replaced elements >+ // >+ // This situation is similar to the previous one, except that the element has an intrinsic height. The sequence of substitutions is now: >+ // The used value of 'height' is determined as for inline replaced elements. If 'margin-top' or 'margin-bottom' is specified as 'auto' >+ // its used value is determined by the rules below. >+ // >+ // 1. If both 'top' and 'bottom' have the value 'auto', replace 'top' with the element's static position. >+ // 2. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or 'margin-bottom' with '0'. >+ // 3. If at this point both 'margin-top' and 'margin-bottom' are still 'auto', solve the equation under the extra constraint that the two margins must get equal values. >+ // 4. If at this point there is only one 'auto' left, solve the equation for that value. >+ // 5. If at this point the values are over-constrained, ignore the value for 'bottom' and solve for that value. >+ auto top = style.logicalTop(); >+ auto bottom = style.logicalBottom(); >+ auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height(); >+ LayoutUnit computedTopValue; >+ >+ if (!top.isAuto()) >+ computedTopValue = valueForLength(top, containingBlockHeight); >+ else if (bottom.isAuto()) { >+ // #1 >+ computedTopValue = displayBox.top(); >+ } else { >+ // #4 >+ auto marginTop = displayBox.marginTop(); >+ auto marginBottom = displayBox.marginBottom(); >+ >+ auto paddingTop = displayBox.paddingTop(); >+ auto paddingBottom = displayBox.paddingBottom(); >+ >+ auto borderTop = displayBox.borderTop(); >+ auto borderBottom = displayBox.borderBottom(); >+ >+ computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value()); >+ } >+ >+ >+ // 10.3.8 Absolutely positioned, replaced elements >+ // >+ // In this case, section 10.3.7 applies up through and including the constraint equation, but the rest of section 10.3.7 is replaced by the following rules: >+ // >+ // The used value of 'width' is determined as for inline replaced elements. >+ // >+ // 1. If 'margin-left' or 'margin-right' is specified as 'auto' its used value is determined by the rules below. >+ // 2. If both 'left' and 'right' have the value 'auto', then if the 'direction' property of the element establishing the >+ // static-position containing block is 'ltr', set 'left' to the static position; else if 'direction' is 'rtl', set 'right' to the static position. >+ // 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' or 'margin-right' with '0'. >+ // 4. If at this point both 'margin-left' and 'margin-right' are still 'auto', solve the equation under the extra constraint >+ // that the two margins must get equal values, unless this would make them negative, in which case when the direction of >+ // the containing block is 'ltr' ('rtl'), set 'margin-left' ('margin-right') to zero and solve for 'margin-right' ('margin-left'). >+ // 5. If at this point there is an 'auto' left, solve the equation for that value. >+ // 6. If at this point the values are over-constrained, ignore the value for either 'left' (in case the 'direction' >+ // property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value. >+ auto left = style.logicalLeft(); >+ auto right = style.logicalRight(); >+ auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >+ LayoutUnit computedLeftValue; >+ >+ if (!left.isAuto()) >+ computedLeftValue = valueForLength(left, containingBlockWidth); >+ else if (right.isAuto()) { >+ // FIXME: take direction into account >+ computedLeftValue = displayBox.left(); >+ } else { >+ // #5 >+ auto marginLeft = displayBox.marginLeft(); >+ auto marginRight = displayBox.marginRight(); >+ >+ auto paddingLeft = displayBox.paddingLeft(); >+ auto paddingRight = displayBox.paddingRight(); >+ >+ auto borderLeft = displayBox.borderLeft(); >+ auto borderRight = displayBox.borderRight(); >+ >+ computedLeftValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + size.width() + paddingRight + borderRight + marginRight + right.value()); >+ } >+ >+ return { computedLeftValue, computedTopValue }; >+} >+ >+LayoutUnit FormattingContext::Geometry::replacedHeight(LayoutContext&, const Box& layoutBox) >+{ >+ ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced()); >+ // 10.6.5 Absolutely positioned, replaced elements. The used value of 'height' is determined as for inline replaced elements. >+ >+ // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements >+ // >+ // 1. If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'. >+ // >+ // 2. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is: >+ // (used width) / (intrinsic ratio) >+ // >+ // 3. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'. >+ // >+ // 4. Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to >+ // the height of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width. >+ auto& style = layoutBox.style(); >+ auto width = style.logicalWidth(); >+ auto height = style.logicalHeight(); >+ >+ LayoutUnit computedHeightValue; >+ auto replaced = layoutBox.replaced(); >+ ASSERT(replaced); >+ >+ if (height.isAuto()) { >+ if (width.isAuto() && replaced->hasIntrinsicHeight()) { >+ // #1 >+ computedHeightValue = replaced->intrinsicHeight(); >+ } else if (replaced->hasIntrinsicRatio()) { >+ // #2 >+ computedHeightValue = width.value() / replaced->intrinsicRatio(); >+ } else if (replaced->hasIntrinsicHeight()) { >+ // #3 >+ computedHeightValue = replaced->intrinsicHeight(); >+ } else { >+ // #4 >+ computedHeightValue = 150; >+ } >+ } else >+ computedHeightValue = height.value(); >+ >+ return computedHeightValue; >+} >+ >+LayoutUnit FormattingContext::Geometry::replacedWidth(LayoutContext&, const Box& layoutBox) >+{ >+ ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced()); >+ >+ // 10.3.4 Block-level, replaced elements in normal flow: The used value of 'width' is determined as for inline replaced elements. >+ // 10.3.6 Floating, replaced elements: The used value of 'width' is determined as for inline replaced elements. >+ // 10.3.8 Absolutely positioned, replaced elements: The used value of 'width' is determined as for inline replaced elements. >+ >+ // 10.3.2 Inline, replaced elements >+ // >+ // 1. 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'. >+ // >+ // 2. If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio; >+ // 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) >+ // >+ // 3. 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 'width' is undefined in CSS 2.2. However, it is suggested that, if the containing block's width does not itself depend on the replaced >+ // element's width, then the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow. >+ // >+ // 4. 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'. >+ // >+ // 5. 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. >+ auto& style = layoutBox.style(); >+ auto width = style.logicalWidth(); >+ auto height = style.logicalHeight(); >+ >+ LayoutUnit computedWidthValue; >+ auto replaced = layoutBox.replaced(); >+ ASSERT(replaced); >+ >+ if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicWidth()) { >+ // #1 >+ computedWidthValue = replaced->intrinsicWidth(); >+ } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) { >+ // #2 >+ auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight(); >+ computedWidthValue = usedHeight * replaced->intrinsicRatio(); >+ } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) { >+ // #3 >+ // FIXME: undefined but surely doable. >+ ASSERT_NOT_IMPLEMENTED_YET(); >+ } else if (width.isAuto() && replaced->hasIntrinsicWidth()) { >+ // #4 >+ computedWidthValue = replaced->intrinsicWidth(); >+ } else { >+ // #5 >+ computedWidthValue = 300; >+ } >+ >+ return computedWidthValue; >+} >+ >+} >+} >+#endif >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >index cd048fbb3ab0f9f723a0fc6ce5eab3e004459440..bdec43d580d9ac1023be894f72cab1bec4714619 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp >@@ -130,69 +130,36 @@ Ref<FloatingState> BlockFormattingContext::createOrFindFloatingState(LayoutConte > > void BlockFormattingContext::computeStaticPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- // https://www.w3.org/TR/CSS22/visuren.html#block-formatting >- // In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. >- // The vertical distance between two sibling boxes is determined by the 'margin' properties. >- // Vertical margins between adjacent block-level boxes in a block formatting context collapse. >- // In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). >- auto containingBlockContentBox = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->contentBox(); >- // Start from the top of the container's content box. >- auto top = containingBlockContentBox.y(); >- auto left = containingBlockContentBox.x(); >- if (auto* previousInFlowSibling = layoutBox.previousInFlowSibling()) >- top = layoutContext.displayBoxForLayoutBox(*previousInFlowSibling)->bottom() + marginBottom(*previousInFlowSibling); >- LayoutPoint topLeft = { top, left }; >- topLeft.moveBy({ marginLeft(layoutBox), marginTop(layoutBox) }); >+ auto topLeft = Geometry::staticPosition(layoutContext, layoutBox); > displayBox.setTopLeft(topLeft); > } > >-void BlockFormattingContext::computeInFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- if (!layoutBox.replaced()) { >- computeInFlowNonReplacedWidth(layoutContext, layoutBox, displayBox); >- return; >- } >- computeReplacedWidth(layoutContext, layoutBox, displayBox); >-} >- >-void BlockFormattingContext::computeInFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >+void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- ASSERT(layoutBox.isInFlow() && !layoutBox.replaced()); >- >- // 10.3.3 Block-level, non-replaced elements in normal flow >- // The following constraints must hold among the used values of the other properties: >- // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block >+ LayoutUnit computedHeight; > >- // If 'width' is set to 'auto', any other 'auto' values become '0' and 'width' follows from the resulting equality. >- auto& style = layoutBox.style(); >- auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >- >- LayoutUnit computedWidthValue; >- auto width = style.logicalWidth(); >- if (width.isAuto()) { >- auto marginLeft = displayBox.marginLeft(); >- auto marginRight = displayBox.marginRight(); >- >- auto paddingLeft = displayBox.paddingLeft(); >- auto paddingRight = displayBox.paddingRight(); >- >- auto borderLeft = displayBox.borderLeft(); >- auto borderRight = displayBox.borderRight(); >- >- computedWidthValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight); >+ if (layoutBox.replaced()) { >+ // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' >+ // replaced elements in normal flow and floating replaced elements >+ computedHeight = FormattingContext::Geometry::replacedHeight(layoutContext, layoutBox); > } else >- computedWidthValue = valueForLength(width, containingBlockWidth); >+ computedHeight = Geometry::inFlowNonReplacedHeight(layoutContext, layoutBox); > >- displayBox.setWidth(computedWidthValue); >+ displayBox.setHeight(computedHeight); > } > >-void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >+void BlockFormattingContext::computeInFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const > { >- if (!layoutBox.replaced()) { >- computeInFlowNonReplacedHeight(layoutContext, layoutBox, displayBox); >- return; >- } >- computeReplacedHeight(layoutContext, layoutBox, displayBox); >+ LayoutUnit computedWidth; >+ >+ if (layoutBox.replaced()) { >+ // 10.3.4 Block-level, replaced elements in normal flow >+ // The used value of 'width' is determined as for inline replaced elements >+ computedWidth = FormattingContext::Geometry::replacedWidth(layoutContext, layoutBox); >+ } else >+ computedWidth = Geometry::inFlowNonReplacedWidth(layoutContext, layoutBox); >+ >+ displayBox.setWidth(computedWidth); > } > > LayoutUnit BlockFormattingContext::marginTop(const Box& layoutBox) const >@@ -205,63 +172,6 @@ LayoutUnit BlockFormattingContext::marginBottom(const Box& layoutBox) const > return BlockMarginCollapse::marginBottom(layoutBox); > } > >-void BlockFormattingContext::computeInFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const >-{ >- ASSERT(layoutBox.isInFlow() && !layoutBox.replaced()); >- >- // https://www.w3.org/TR/CSS22/visudet.html >- // If 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders: >- // The element's height is the distance from its top content edge to the first applicable of the following: >- // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines >- // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin >- // does not collapse with the element's bottom margin >- // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin >- // 4. zero, otherwise >- // Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, >- // and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box. >- if (!layoutBox.style().logicalHeight().isAuto()) { >- // FIXME: Only fixed values yet. >- displayBox.setHeight(layoutBox.style().logicalHeight().value()); >- return; >- } >- >- if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) { >- displayBox.setHeight(0); >- return; >- } >- >- // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines >- if (layoutBox.establishesInlineFormattingContext()) { >- // height = lastLineBox().bottom(); >- displayBox.setHeight(0); >- return; >- } >- >- // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin... >- auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild(); >- ASSERT(lastInFlowChild); >- if (!BlockMarginCollapse::isMarginBottomCollapsedWithParent(*lastInFlowChild)) { >- auto* lastInFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*lastInFlowChild); >- ASSERT(lastInFlowDisplayBox); >- displayBox.setHeight(lastInFlowDisplayBox->bottom() + lastInFlowDisplayBox->marginBottom()); >- return; >- } >- >- // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin >- auto* inFlowChild = lastInFlowChild; >- while (inFlowChild && BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom(*inFlowChild)) >- inFlowChild = inFlowChild->previousInFlowSibling(); >- if (inFlowChild) { >- auto* inFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*inFlowChild); >- ASSERT(inFlowDisplayBox); >- displayBox.setHeight(inFlowDisplayBox->top() + inFlowDisplayBox->borderBox().height()); >- return; >- } >- >- // 4. zero, otherwise >- displayBox.setHeight(0); >-} >- > } > } > >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContext.h b/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >index 0419f6b394fea92f58c718dce5fe818ed856178c..fed1a601a9befc95a9c282202c27b95acb5677c7 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContext.h >@@ -28,11 +28,12 @@ > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > > #include "FormattingContext.h" >-#include "LayoutUnit.h" > #include <wtf/IsoMalloc.h> > > namespace WebCore { > >+class LayoutUnit; >+ > namespace Layout { > > class BlockFormattingState; >@@ -51,18 +52,22 @@ public: > > private: > void computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const override; >- > void computeInFlowWidth(LayoutContext&, const Box&, Display::Box&) const override; >- void computeInFlowNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const; >- > void computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const override; >- void computeInFlowNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const; > > LayoutUnit marginTop(const Box&) const override; > LayoutUnit marginBottom(const Box&) const override; >+ >+ // This class implements positioning and sizing for boxes participating in a block formatting context. >+ class Geometry { >+ public: >+ static LayoutUnit inFlowNonReplacedHeight(LayoutContext&, const Box&); >+ static LayoutUnit inFlowNonReplacedWidth(LayoutContext&, const Box&); >+ >+ static LayoutPoint staticPosition(LayoutContext&, const Box&); >+ }; > }; > > } > } > #endif >- >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..6f4cfd1d94fc57504fb3bbe94a977c24ae9634b2 >--- /dev/null >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >@@ -0,0 +1,143 @@ >+/* >+ * Copyright (C) 2018 Apple 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. 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 INC. 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 "BlockFormattingContext.h" >+ >+#if ENABLE(LAYOUT_FORMATTING_CONTEXT) >+ >+#include "FormattingContext.h" >+ >+namespace WebCore { >+namespace Layout { >+ >+LayoutUnit BlockFormattingContext::Geometry::inFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isInFlow() && !layoutBox.replaced()); >+ >+ // https://www.w3.org/TR/CSS22/visudet.html >+ // If 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders: >+ // The element's height is the distance from its top content edge to the first applicable of the following: >+ // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines >+ // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin >+ // does not collapse with the element's bottom margin >+ // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin >+ // 4. zero, otherwise >+ // Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, >+ // and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box. >+ if (!layoutBox.style().logicalHeight().isAuto()) { >+ // FIXME: Only fixed values yet. >+ return layoutBox.style().logicalHeight().value(); >+ } >+ >+ if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) >+ return 0; >+ >+ // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines >+ if (layoutBox.establishesInlineFormattingContext()) { >+ // height = lastLineBox().bottom(); >+ return 0; >+ } >+ >+ // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin... >+ auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild(); >+ ASSERT(lastInFlowChild); >+ if (!BlockMarginCollapse::isMarginBottomCollapsedWithParent(*lastInFlowChild)) { >+ auto* lastInFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*lastInFlowChild); >+ ASSERT(lastInFlowDisplayBox); >+ return lastInFlowDisplayBox->bottom() + lastInFlowDisplayBox->marginBottom(); >+ } >+ >+ // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin >+ auto* inFlowChild = lastInFlowChild; >+ while (inFlowChild && BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom(*inFlowChild)) >+ inFlowChild = inFlowChild->previousInFlowSibling(); >+ if (inFlowChild) { >+ auto* inFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*inFlowChild); >+ ASSERT(inFlowDisplayBox); >+ return inFlowDisplayBox->top() + inFlowDisplayBox->borderBox().height(); >+ } >+ >+ // 4. zero, otherwise >+ return 0; >+} >+ >+LayoutUnit BlockFormattingContext::Geometry::inFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ ASSERT(layoutBox.isInFlow() && !layoutBox.replaced()); >+ >+ // 10.3.3 Block-level, non-replaced elements in normal flow >+ // The following constraints must hold among the used values of the other properties: >+ // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block >+ >+ // If 'width' is set to 'auto', any other 'auto' values become '0' and 'width' follows from the resulting equality. >+ auto& style = layoutBox.style(); >+ auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width(); >+ >+ LayoutUnit computedWidthValue; >+ auto width = style.logicalWidth(); >+ if (width.isAuto()) { >+ auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); >+ auto marginLeft = displayBox.marginLeft(); >+ auto marginRight = displayBox.marginRight(); >+ >+ auto paddingLeft = displayBox.paddingLeft(); >+ auto paddingRight = displayBox.paddingRight(); >+ >+ auto borderLeft = displayBox.borderLeft(); >+ auto borderRight = displayBox.borderRight(); >+ >+ computedWidthValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight); >+ } else >+ computedWidthValue = valueForLength(width, containingBlockWidth); >+ >+ return computedWidthValue; >+} >+ >+LayoutPoint BlockFormattingContext::Geometry::staticPosition(LayoutContext& layoutContext, const Box& layoutBox) >+{ >+ // https://www.w3.org/TR/CSS22/visuren.html#block-formatting >+ // In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. >+ // The vertical distance between two sibling boxes is determined by the 'margin' properties. >+ // Vertical margins between adjacent block-level boxes in a block formatting context collapse. >+ // In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). >+ auto containingBlockContentBox = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->contentBox(); >+ // Start from the top of the container's content box. >+ auto top = containingBlockContentBox.y(); >+ auto left = containingBlockContentBox.x(); >+ if (auto* previousInFlowSibling = layoutBox.previousInFlowSibling()) { >+ auto& previousInFlowDisplayBox = *layoutContext.displayBoxForLayoutBox(*previousInFlowSibling); >+ top = previousInFlowDisplayBox.bottom() + previousInFlowDisplayBox.marginBottom(); >+ } >+ auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); >+ LayoutPoint topLeft = { top, left }; >+ topLeft.moveBy({ displayBox.marginLeft(), displayBox.marginTop() }); >+ return topLeft; >+} >+ >+} >+} >+ >+#endif >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.h b/Source/WebCore/layout/displaytree/DisplayBox.h >index b178bd4818b3b06c5c96dfc66125ad46a8381367..afedfb5271303ef870ce5bcb8938fc6a7d580f6d 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.h >+++ b/Source/WebCore/layout/displaytree/DisplayBox.h >@@ -48,9 +48,9 @@ namespace Display { > class Box { > WTF_MAKE_ISO_ALLOCATED(Box); > public: >- friend class Layout::LayoutContext; >- friend class Layout::FormattingContext; > friend class Layout::BlockFormattingContext; >+ friend class Layout::FormattingContext; >+ friend class Layout::LayoutContext; > > ~Box(); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 185898
:
341064
| 341096