Diff
Modified: trunk/Source/WebCore/ChangeLog (232113 => 232114)
--- trunk/Source/WebCore/ChangeLog 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/ChangeLog 2018-05-23 16:56:12 UTC (rev 232114)
@@ -1,3 +1,69 @@
+2018-05-23 Zalan Bujtas <[email protected]>
+
+ [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 Antti Koivisto <[email protected]>
Page keeps reloading when viewing photos in google drive (due to too high canvas memory limits)
Modified: trunk/Source/WebCore/Sources.txt (232113 => 232114)
--- trunk/Source/WebCore/Sources.txt 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/Sources.txt 2018-05-23 16:56:12 UTC (rev 232114)
@@ -1216,9 +1216,11 @@
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
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (232113 => 232114)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2018-05-23 16:56:12 UTC (rev 232114)
@@ -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 */,
Modified: trunk/Source/WebCore/layout/FormattingContext.cpp (232113 => 232114)
--- trunk/Source/WebCore/layout/FormattingContext.cpp 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/layout/FormattingContext.cpp 2018-05-23 16:56:12 UTC (rev 232114)
@@ -59,11 +59,14 @@
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::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::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
{
Modified: trunk/Source/WebCore/layout/FormattingContext.h (232113 => 232114)
--- trunk/Source/WebCore/layout/FormattingContext.h 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/layout/FormattingContext.h 2018-05-23 16:56:12 UTC (rev 232114)
@@ -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 @@
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&);
- void computeOutOfFlowNonReplacedPosition(LayoutContext&, const Box&, Display::Box&) const;
- void computeOutOfFlowReplacedPosition(LayoutContext&, const Box&, Display::Box&) const;
+ static LayoutUnit outOfFlowReplacedHeight(LayoutContext&, const Box&);
+ static LayoutUnit outOfFlowReplacedWidth(LayoutContext&, const Box&);
- void computeFloatingNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
- void computeFloatingNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;
+ static LayoutUnit floatingNonReplacedHeight(LayoutContext&, const Box&);
+ static LayoutUnit floatingNonReplacedWidth(LayoutContext&, const Box&);
- LayoutUnit contentHeightForFormattingContextRoot(LayoutContext&, const Box&) const;
- LayoutUnit shrinkToFitWidth(LayoutContext&, const Box&) const;
+ static LayoutUnit floatingReplacedHeight(LayoutContext&, const Box&);
+ static LayoutUnit floatingReplacedWidth(LayoutContext&, const Box&);
+ 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;
};
Copied: trunk/Source/WebCore/layout/FormattingContextGeometry.cpp (from rev 232113, trunk/Source/WebCore/layout/FormattingContext.cpp) (0 => 232114)
--- trunk/Source/WebCore/layout/FormattingContextGeometry.cpp (rev 0)
+++ trunk/Source/WebCore/layout/FormattingContextGeometry.cpp 2018-05-23 16:56:12 UTC (rev 232114)
@@ -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
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp (232113 => 232114)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp 2018-05-23 16:56:12 UTC (rev 232114)
@@ -130,71 +130,38 @@
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
+void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
- if (!layoutBox.replaced()) {
- computeInFlowNonReplacedWidth(layoutContext, layoutBox, displayBox);
- return;
- }
- computeReplacedWidth(layoutContext, layoutBox, displayBox);
+ LayoutUnit computedHeight;
+
+ 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
+ computedHeight = Geometry::inFlowNonReplacedHeight(layoutContext, layoutBox);
+
+ displayBox.setHeight(computedHeight);
}
-void BlockFormattingContext::computeInFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
+void BlockFormattingContext::computeInFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
- ASSERT(layoutBox.isInFlow() && !layoutBox.replaced());
+ LayoutUnit computedWidth;
- // 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 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.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
- computedWidthValue = valueForLength(width, containingBlockWidth);
+ computedWidth = Geometry::inFlowNonReplacedWidth(layoutContext, layoutBox);
- displayBox.setWidth(computedWidthValue);
+ displayBox.setWidth(computedWidth);
}
-void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
-{
- if (!layoutBox.replaced()) {
- computeInFlowNonReplacedHeight(layoutContext, layoutBox, displayBox);
- return;
- }
- computeReplacedHeight(layoutContext, layoutBox, displayBox);
-}
-
LayoutUnit BlockFormattingContext::marginTop(const Box& layoutBox) const
{
return BlockMarginCollapse::marginTop(layoutBox);
@@ -205,64 +172,7 @@
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);
}
-
}
-}
#endif
Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h (232113 => 232114)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h 2018-05-23 16:56:12 UTC (rev 232114)
@@ -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 @@
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
-
Added: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp (0 => 232114)
--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp (rev 0)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp 2018-05-23 16:56:12 UTC (rev 232114)
@@ -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
Modified: trunk/Source/WebCore/layout/displaytree/DisplayBox.h (232113 => 232114)
--- trunk/Source/WebCore/layout/displaytree/DisplayBox.h 2018-05-23 16:09:54 UTC (rev 232113)
+++ trunk/Source/WebCore/layout/displaytree/DisplayBox.h 2018-05-23 16:56:12 UTC (rev 232114)
@@ -48,9 +48,9 @@
class Box {
WTF_MAKE_ISO_ALLOCATED(Box);
public:
+ friend class Layout::BlockFormattingContext;
+ friend class Layout::FormattingContext;
friend class Layout::LayoutContext;
- friend class Layout::FormattingContext;
- friend class Layout::BlockFormattingContext;
~Box();