Changeset 232114 in webkit


Ignore:
Timestamp:
May 23, 2018 9:56:12 AM (6 years ago)
Author:
Alan Bujtas
Message:

[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:
Location:
trunk/Source/WebCore
Files:
1 added
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r232113 r232114  
     12018-05-23  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC] Move sizing/positioning logic to helper classes
     4        https://bugs.webkit.org/show_bug.cgi?id=185898
     5
     6        Reviewed by Antti Koivisto.
     7
     8        The idea here is to move all the sizing and positioning logic to helper classes so that
     9        the formatting context code stays lean.
     10        This is similar to the dedicated BlockMarginCollapse class for the collapsing logic.
     11        The helper classes have only static functions. These static functions do not mutate the associated DisplayBoxes,
     12        but instead they simply retun the computed values.
     13
     14        * Sources.txt:
     15        * WebCore.xcodeproj/project.pbxproj:
     16        * layout/FormattingContext.cpp:
     17        (WebCore::Layout::FormattingContext::computeOutOfFlowPosition const):
     18        (WebCore::Layout::FormattingContext::computeOutOfFlowWidth const):
     19        (WebCore::Layout::FormattingContext::computeFloatingWidth const):
     20        (WebCore::Layout::FormattingContext::computeOutOfFlowHeight const):
     21        (WebCore::Layout::FormattingContext::computeFloatingHeight const):
     22        (WebCore::Layout::FormattingContext::computeOutOfFlowNonReplacedHeight const): Deleted.
     23        (WebCore::Layout::FormattingContext::computeFloatingNonReplacedHeight const): Deleted.
     24        (WebCore::Layout::FormattingContext::computeReplacedHeight const): Deleted.
     25        (WebCore::Layout::FormattingContext::computeReplacedWidth const): Deleted.
     26        (WebCore::Layout::FormattingContext::contentHeightForFormattingContextRoot const): Deleted.
     27        (WebCore::Layout::FormattingContext::computeFloatingNonReplacedWidth const): Deleted.
     28        (WebCore::Layout::FormattingContext::computeOutOfFlowNonReplacedWidth const): Deleted.
     29        (WebCore::Layout::FormattingContext::computeOutOfFlowReplacedHeight const): Deleted.
     30        (WebCore::Layout::FormattingContext::computeOutOfFlowReplacedWidth const): Deleted.
     31        (WebCore::Layout::FormattingContext::computeOutOfFlowNonReplacedPosition const): Deleted.
     32        (WebCore::Layout::FormattingContext::computeOutOfFlowReplacedPosition const): Deleted.
     33        (WebCore::Layout::FormattingContext::shrinkToFitWidth const): Deleted.
     34        * layout/FormattingContext.h:
     35        * layout/FormattingContextGeometry.cpp: Copied from Source/WebCore/layout/FormattingContext.cpp.
     36        (WebCore::Layout::contentHeightForFormattingContextRoot):
     37        (WebCore::Layout::shrinkToFitWidth):
     38        (WebCore::Layout::FormattingContextGeometry::outOfFlowNonReplacedHeight):
     39        (WebCore::Layout::FormattingContextGeometry::outOfFlowNonReplacedWidth):
     40        (WebCore::Layout::FormattingContextGeometry::outOfFlowReplacedHeight):
     41        (WebCore::Layout::FormattingContextGeometry::outOfFlowReplacedWidth):
     42        (WebCore::Layout::FormattingContextGeometry::floatingNonReplacedHeight):
     43        (WebCore::Layout::FormattingContextGeometry::floatingNonReplacedWidth):
     44        (WebCore::Layout::FormattingContextGeometry::floatingReplacedHeight):
     45        (WebCore::Layout::FormattingContextGeometry::floatingReplacedWidth):
     46        (WebCore::Layout::FormattingContextGeometry::outOfFlowNonReplacedPosition):
     47        (WebCore::Layout::FormattingContextGeometry::outOfFlowReplacedPosition):
     48        (WebCore::Layout::FormattingContextGeometry::replacedHeight):
     49        (WebCore::Layout::FormattingContextGeometry::replacedWidth):
     50        * layout/FormattingContextGeometry.h: Copied from Source/WebCore/layout/blockformatting/BlockFormattingContext.h.
     51        * layout/blockformatting/BlockFormattingContext.cpp:
     52        (WebCore::Layout::BlockFormattingContext::computeStaticPosition const):
     53        (WebCore::Layout::BlockFormattingContext::computeInFlowHeight const):
     54        (WebCore::Layout::BlockFormattingContext::computeInFlowWidth const):
     55        (WebCore::Layout::BlockFormattingContext::computeInFlowNonReplacedWidth const): Deleted.
     56        (WebCore::Layout::BlockFormattingContext::computeInFlowNonReplacedHeight const): Deleted.
     57        * layout/blockformatting/BlockFormattingContext.h:
     58        * layout/blockformatting/BlockFormattingContextGeometry.cpp: Added.
     59        (WebCore::Layout::BlockFormattingContextGeometry::inFlowNonReplacedHeight):
     60        (WebCore::Layout::BlockFormattingContextGeometry::inFlowNonReplacedWidth):
     61        (WebCore::Layout::BlockFormattingContextGeometry::inFlowReplacedHeight):
     62        (WebCore::Layout::BlockFormattingContextGeometry::inFlowReplacedWidth):
     63        (WebCore::Layout::BlockFormattingContextGeometry::staticPosition):
     64        * layout/blockformatting/BlockFormattingContextGeometry.h: Copied from Source/WebCore/layout/blockformatting/BlockFormattingContext.h.
     65        * layout/displaytree/DisplayBox.h:
     66
    1672018-05-23  Antti Koivisto  <antti@apple.com>
    268
  • trunk/Source/WebCore/Sources.txt

    r231895 r232114  
    12171217layout/FloatingState.cpp
    12181218layout/FormattingContext.cpp
     1219layout/FormattingContextGeometry.cpp
    12191220layout/FormattingState.cpp
    12201221layout/LayoutContext.cpp
    12211222layout/blockformatting/BlockFormattingContext.cpp
     1223layout/blockformatting/BlockFormattingContextGeometry.cpp
    12221224layout/blockformatting/BlockFormattingState.cpp
    12231225layout/blockformatting/BlockMarginCollapse.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r232042 r232114  
    88878887                6EE8A77010F803F3005A4A24 /* JSWebGLContextAttributes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLContextAttributes.cpp; sourceTree = "<group>"; };
    88888888                6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLContextAttributes.h; sourceTree = "<group>"; };
     8889                6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlockFormattingContextGeometry.cpp; sourceTree = "<group>"; };
    88898890                6F222B741AB52D640094651A /* WebGLVertexArrayObjectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGLVertexArrayObjectBase.h; sourceTree = "<group>"; };
    88908891                6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebGLVertexArrayObjectBase.cpp; sourceTree = "<group>"; };
     
    89188919                6F995A2F1A70833700A735F4 /* JSWebGLVertexArrayObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLVertexArrayObject.cpp; sourceTree = "<group>"; };
    89198920                6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLVertexArrayObject.h; sourceTree = "<group>"; };
     8921                6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormattingContextGeometry.cpp; sourceTree = "<group>"; };
    89208922                709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleFetchFailureKind.h; sourceTree = "<group>"; };
    89218923                71004B9D1DC1398800A52A38 /* playback-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "playback-support.js"; sourceTree = "<group>"; };
     
    1567915681                                115CFA69208AF7D0001E6991 /* FormattingContext.cpp */,
    1568015682                                115CFA68208AF7D0001E6991 /* FormattingContext.h */,
     15683                                6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */,
    1568115684                                115CFA75208AFE30001E6991 /* FormattingState.cpp */,
    1568215685                                115CFA74208AFE30001E6991 /* FormattingState.h */,
     
    1571815721                                115CFA6D208AFAB6001E6991 /* BlockFormattingContext.cpp */,
    1571915722                                115CFA6C208AFAB6001E6991 /* BlockFormattingContext.h */,
     15723                                6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */,
    1572015724                                115CFA79208B8D9D001E6991 /* BlockFormattingState.cpp */,
    1572115725                                115CFA78208B8D9D001E6991 /* BlockFormattingState.h */,
  • trunk/Source/WebCore/layout/FormattingContext.cpp

    r232109 r232114  
    6060void FormattingContext::computeOutOfFlowPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    6161{
    62     if (!layoutBox.replaced()) {
    63         computeOutOfFlowNonReplacedPosition(layoutContext, layoutBox, displayBox);
    64         return;
    65     }
    66     computeOutOfFlowReplacedPosition(layoutContext, layoutBox, displayBox);
     62    LayoutPoint computedTopLeft;
     63
     64    if (layoutBox.replaced())
     65        computedTopLeft = Geometry::outOfFlowReplacedPosition(layoutContext, layoutBox);
     66    else
     67        computedTopLeft = Geometry::outOfFlowNonReplacedPosition(layoutContext, layoutBox);
     68
     69    displayBox.setTopLeft(computedTopLeft);
    6770}
    6871
     
    8790void FormattingContext::computeOutOfFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    8891{
    89     if (!layoutBox.replaced()) {
    90         computeOutOfFlowNonReplacedWidth(layoutContext, layoutBox, displayBox);
    91         return;
    92     }
    93     computeOutOfFlowReplacedWidth(layoutContext, layoutBox, displayBox);
     92    LayoutUnit computedWidth;
     93
     94    if (layoutBox.replaced())
     95        computedWidth = Geometry::outOfFlowReplacedWidth(layoutContext, layoutBox);
     96    else
     97        computedWidth = Geometry::outOfFlowNonReplacedWidth(layoutContext, layoutBox);
     98
     99    displayBox.setWidth(computedWidth);
    94100}
    95101
    96102void FormattingContext::computeFloatingWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    97103{
    98     if (!layoutBox.replaced()) {
    99         computeFloatingNonReplacedWidth(layoutContext, layoutBox, displayBox);
    100         return;
    101     }
    102     computeReplacedWidth(layoutContext, layoutBox, displayBox);
     104    LayoutUnit computedWidth;
     105
     106    if (layoutBox.replaced())
     107        computedWidth = Geometry::floatingReplacedWidth(layoutContext, layoutBox);
     108    else
     109        computedWidth = Geometry::floatingNonReplacedWidth(layoutContext, layoutBox);
     110
     111    displayBox.setWidth(computedWidth);
    103112}
    104113
    105114void FormattingContext::computeOutOfFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    106115{
    107     if (!layoutBox.replaced()) {
    108         computeOutOfFlowNonReplacedHeight(layoutContext, layoutBox, displayBox);
    109         return;
    110     }
    111     computeOutOfFlowReplacedHeight(layoutContext, layoutBox, displayBox);
     116    LayoutUnit computedHeight;
     117
     118    if (layoutBox.replaced())
     119        computedHeight = Geometry::outOfFlowReplacedHeight(layoutContext, layoutBox);
     120    else
     121        computedHeight = Geometry::outOfFlowNonReplacedHeight(layoutContext, layoutBox);
     122
     123    displayBox.setHeight(computedHeight);
    112124}
    113125
    114126void FormattingContext::computeFloatingHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    115127{
    116     if (!layoutBox.replaced()) {
    117         computeFloatingNonReplacedHeight(layoutContext, layoutBox, displayBox);
    118         return;
    119     }
    120     computeReplacedHeight(layoutContext, layoutBox, displayBox);
     128    LayoutUnit computedHeight;
     129
     130    if (layoutBox.replaced())
     131        computedHeight = Geometry::floatingReplacedHeight(layoutContext, layoutBox);
     132    else
     133        computedHeight = Geometry::floatingNonReplacedHeight(layoutContext, layoutBox);
     134
     135    displayBox.setHeight(computedHeight);
    121136}
    122137
     
    167182        computeOutOfFlowPosition(layoutContext, layoutBox, displayBox);
    168183    }
    169 }
    170 
    171 void FormattingContext::computeOutOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    172 {
    173     ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced());
    174 
    175     // 10.6.4 Absolutely positioned, non-replaced elements
    176     //
    177     // For absolutely positioned elements, the used values of the vertical dimensions must satisfy this constraint:
    178     // 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom'
    179     // = height of containing block
    180 
    181     // If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and apply rule number three below.
    182 
    183     // If none of the three are 'auto': If both 'margin-top' and 'margin-bottom' are 'auto', solve the equation under the extra
    184     // constraint that the two margins get equal values. If one of 'margin-top' or 'margin-bottom' is 'auto', solve the equation for that value.
    185     // If the values are over-constrained, ignore the value for 'bottom' and solve for that value.
    186 
    187     // Otherwise, pick the one of the following six rules that applies.
    188 
    189     // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7,
    190     //     set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top'
    191     // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for
    192     //    'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'
    193     // 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'
    194     //     values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'
    195     // 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'
    196     // 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'
    197     // 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'
    198     auto& style = layoutBox.style();
    199     auto top = style.logicalTop();
    200     auto bottom = style.logicalBottom();
    201     auto height = style.logicalHeight();
    202 
    203     auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height();
    204     LayoutUnit computedHeightValue;
    205 
    206     if ((top.isAuto() && height.isAuto() && bottom.isAuto())
    207         || (top.isAuto() && height.isAuto() && !bottom.isAuto())
    208         || (!top.isAuto() && height.isAuto() && bottom.isAuto())) {
    209         // All auto (#3), #1 and #3
    210         computedHeightValue = contentHeightForFormattingContextRoot(layoutContext, layoutBox);
    211     } else if (!top.isAuto() && height.isAuto() && !bottom.isAuto()) {
    212         // #5
    213         auto marginTop = displayBox.marginTop();
    214         auto marginBottom = displayBox.marginBottom();
    215    
    216         auto paddingTop = displayBox.paddingTop();
    217         auto paddingBottom = displayBox.paddingBottom();
    218 
    219         auto borderTop = displayBox.borderTop();
    220         auto borderBottom = displayBox.borderBottom();
    221 
    222         computedHeightValue = containingBlockHeight - (top.value() + marginTop + borderTop + paddingTop + paddingBottom + borderBottom + marginBottom + bottom.value());
    223     } else if (!height.isAuto())
    224         computedHeightValue = valueForLength(height, containingBlockHeight);
    225     else
    226         ASSERT_NOT_REACHED();
    227 
    228     displayBox.setHeight(computedHeightValue);
    229 }
    230 
    231 void FormattingContext::computeFloatingNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    232 {
    233     ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());
    234     // 10.6.6 Complicated cases
    235     //
    236     // Floating, non-replaced elements.
    237     //
    238     // If 'height' is 'auto', the height depends on the element's descendants per 10.6.7.
    239     auto height = layoutBox.style().logicalHeight();
    240     displayBox.setHeight(height.isAuto() ? contentHeightForFormattingContextRoot(layoutContext, layoutBox) : LayoutUnit(height.value()));
    241 }
    242 
    243 void FormattingContext::computeReplacedHeight(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const
    244 {
    245     ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
    246     // 10.6.5 Absolutely positioned, replaced elements. The used value of 'height' is determined as for inline replaced elements.
    247 
    248     // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
    249     //
    250     // 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'.
    251     //
    252     // 2. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
    253     //    (used width) / (intrinsic ratio)
    254     //
    255     // 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'.
    256     //
    257     // 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
    258     //    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.
    259     auto& style = layoutBox.style();
    260     auto width = style.logicalWidth();
    261     auto height = style.logicalHeight();
    262 
    263     LayoutUnit computedHeightValue;
    264     auto replaced = layoutBox.replaced();
    265     ASSERT(replaced);
    266 
    267     if (height.isAuto()) {
    268         if (width.isAuto() && replaced->hasIntrinsicHeight()) {
    269             // #1
    270             computedHeightValue = replaced->intrinsicHeight();
    271         } else if (replaced->hasIntrinsicRatio()) {
    272             // #2
    273             computedHeightValue = width.value() / replaced->intrinsicRatio();
    274         } else if (replaced->hasIntrinsicHeight()) {
    275             // #3
    276             computedHeightValue = replaced->intrinsicHeight();
    277         } else {
    278             // #4
    279             computedHeightValue = 150;
    280         }
    281     } else
    282         computedHeightValue = height.value();
    283 
    284     displayBox.setHeight(computedHeightValue);
    285 }
    286 
    287 void FormattingContext::computeReplacedWidth(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const
    288 {
    289     ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
    290 
    291     // 10.3.4 Block-level, replaced elements in normal flow: The used value of 'width' is determined as for inline replaced elements.
    292     // 10.3.6 Floating, replaced elements: The used value of 'width' is determined as for inline replaced elements.
    293     // 10.3.8 Absolutely positioned, replaced elements: The used value of 'width' is determined as for inline replaced elements.
    294 
    295     // 10.3.2 Inline, replaced elements
    296     //
    297     // 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'.
    298     //
    299     // 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;
    300     //    or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio;
    301     //    then the used value of 'width' is: (used height) * (intrinsic ratio)
    302     //
    303     // 3. If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width,
    304     //    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
    305     //    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.
    306     //
    307     // 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'.
    308     //
    309     // 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.
    310     //    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.
    311     auto& style = layoutBox.style();
    312     auto width = style.logicalWidth();
    313     auto height = style.logicalHeight();
    314 
    315     LayoutUnit computedWidthValue;
    316     auto replaced = layoutBox.replaced();
    317     ASSERT(replaced);
    318 
    319     if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicWidth()) {
    320         // #1
    321         computedWidthValue = replaced->intrinsicWidth();
    322     } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) {
    323         // #2
    324         auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight();   
    325         computedWidthValue = usedHeight * replaced->intrinsicRatio();
    326     } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) {
    327         // #3
    328         // FIXME: undefined but surely doable.
    329         ASSERT_NOT_IMPLEMENTED_YET();
    330     } else if (width.isAuto() && replaced->hasIntrinsicWidth()) {
    331         // #4
    332         computedWidthValue = replaced->intrinsicWidth();
    333     } else {
    334         // #5
    335         computedWidthValue = 300;
    336     }
    337 
    338     displayBox.setWidth(computedWidthValue);
    339 }
    340 
    341 LayoutUnit FormattingContext::contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox) const
    342 {
    343     ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext());
    344     // 10.6.7 'Auto' heights for block formatting context roots
    345 
    346     // 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.
    347     // If it has block-level children, the height is the distance between the top margin-edge of the topmost block-level
    348     // child box and the bottom margin-edge of the bottommost block-level child box.
    349 
    350     // In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge,
    351     // then the height is increased to include those edges. Only floats that participate in this block formatting context are taken
    352     // into account, e.g., floats inside absolutely positioned descendants or other floats are not.
    353     if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
    354         return 0;
    355 
    356     auto& formattingRootContainer = downcast<Container>(layoutBox);
    357     if (formattingRootContainer.establishesInlineFormattingContext())
    358         return 0;
    359 
    360     auto* firstDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild());
    361     auto* lastDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.lastInFlowChild());
    362 
    363     auto top = firstDisplayBox->marginBox().y();
    364     auto bottom = lastDisplayBox->marginBox().maxY();
    365     // FIXME: add floating support.
    366     return bottom - top;
    367 }
    368 
    369 void FormattingContext::computeFloatingNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    370 {
    371     ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());
    372     // 10.3.5 Floating, non-replaced elements
    373 
    374     // If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
    375     auto width = layoutBox.style().logicalWidth();
    376     displayBox.setWidth(width.isAuto() ? shrinkToFitWidth(layoutContext, layoutBox) : LayoutUnit(width.value()));
    377 }
    378 
    379 void FormattingContext::computeOutOfFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    380 {
    381     ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced());
    382    
    383     // 10.3.7 Absolutely positioned, non-replaced elements
    384     //
    385     // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right'
    386     // = width of containing block
    387 
    388     // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0.
    389     // Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static
    390     // position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
    391 
    392     // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
    393     // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position
    394     //    containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position.
    395     //    Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
    396     // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
    397     // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
    398     // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
    399     // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right'
    400     auto& style = layoutBox.style();
    401     auto left = style.logicalLeft();
    402     auto right = style.logicalRight();
    403     auto width = style.logicalWidth();
    404 
    405     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
    406     LayoutUnit computedWidthValue;
    407 
    408     if ((left.isAuto() && width.isAuto() && right.isAuto())
    409         || (left.isAuto() && width.isAuto() && !right.isAuto())
    410         || (!left.isAuto() && width.isAuto() && right.isAuto())) {
    411         // All auto (#1), #1 and #3
    412         computedWidthValue = shrinkToFitWidth(layoutContext, layoutBox);
    413     } else if (!left.isAuto() && width.isAuto() && !right.isAuto()) {
    414         // #5
    415         auto marginLeft = displayBox.marginLeft();
    416         auto marginRight = displayBox.marginRight();
    417    
    418         auto paddingLeft = displayBox.paddingLeft();
    419         auto paddingRight = displayBox.paddingRight();
    420 
    421         auto borderLeft = displayBox.borderLeft();
    422         auto borderRight = displayBox.borderRight();
    423 
    424         computedWidthValue = containingBlockWidth - (left.value() + marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight + right.value());
    425     } else if (!width.isAuto())
    426         computedWidthValue = valueForLength(width, containingBlockWidth);
    427     else
    428         ASSERT_NOT_REACHED();
    429 
    430     displayBox.setWidth(computedWidthValue);
    431 }
    432 
    433 void FormattingContext::computeOutOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    434 {
    435     ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());
    436     // 10.6.5 Absolutely positioned, replaced elements
    437     //
    438     // The used value of 'height' is determined as for inline replaced elements.
    439     computeReplacedHeight(layoutContext, layoutBox, displayBox);
    440 }
    441 
    442 void FormattingContext::computeOutOfFlowReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    443 {
    444     ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());
    445     // 10.3.8 Absolutely positioned, replaced elements
    446     //
    447     // The used value of 'width' is determined as for inline replaced elements.
    448     computeReplacedWidth(layoutContext, layoutBox, displayBox);
    449 }
    450 
    451 void FormattingContext::computeOutOfFlowNonReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    452 {
    453     // 10.3.7 Absolutely positioned, non-replaced elements (left/right)
    454     // 10.6.4 Absolutely positioned, non-replaced elements (top/bottom)
    455 
    456     // At this point we've the size computed.
    457     auto size = displayBox.size();
    458     auto& style = layoutBox.style();
    459 
    460     // 10.6.4 Absolutely positioned, non-replaced elements
    461     auto top = style.logicalTop();
    462     auto bottom = style.logicalBottom();
    463     auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height();
    464 
    465     // 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom'
    466     // = height of containing block
    467     //
    468     // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7,
    469     //     set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top'
    470     // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for
    471     //    'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'
    472     // 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'
    473     //     values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'
    474     // 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'
    475     // 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'
    476     // 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'
    477     LayoutUnit computedTopValue;
    478     if (top.isAuto() && !bottom.isAuto()) {
    479         // #1 #4
    480         auto marginTop = displayBox.marginTop();
    481         auto marginBottom = displayBox.marginBottom();
    482    
    483         auto paddingTop = displayBox.paddingTop();
    484         auto paddingBottom = displayBox.paddingBottom();
    485 
    486         auto borderTop = displayBox.borderTop();
    487         auto borderBottom = displayBox.borderBottom();
    488 
    489         computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value());
    490     } else if (top.isAuto() && bottom.isAuto()) {
    491         // #2
    492         // Already computed as part of the computeStaticPosition();
    493         computedTopValue = displayBox.top();
    494     } else {
    495         // #3 #5 #6 have top != auto
    496         computedTopValue = valueForLength(top, containingBlockHeight);
    497     }
    498 
    499     displayBox.setTop(computedTopValue);
    500 
    501     // 10.3.7 Absolutely positioned, non-replaced elements
    502     auto left = style.logicalLeft();
    503     auto right = style.logicalRight();
    504     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
    505 
    506     // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right'
    507     // = width of containing block
    508     //
    509     // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0.
    510     // Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static
    511     // position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
    512 
    513     // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
    514     // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position
    515     //    containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position.
    516     //    Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
    517     // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
    518     // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
    519     // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
    520     // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right'
    521     LayoutUnit computedLeftValue;
    522     if (left.isAuto() && !right.isAuto()) {
    523         // #1 #4
    524         auto marginLeft = displayBox.marginLeft();
    525         auto marginRight = displayBox.marginRight();
    526    
    527         auto paddingLeft = displayBox.paddingLeft();
    528         auto paddingRight = displayBox.paddingRight();
    529 
    530         auto borderLeft = displayBox.borderLeft();
    531         auto borderRight = displayBox.borderRight();
    532 
    533         computedLeftValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + size.width() + paddingRight + borderRight + marginRight + right.value());
    534     } else if (left.isAuto() && right.isAuto()) {
    535         // #2
    536         // FIXME: rtl
    537         computedLeftValue = displayBox.left();
    538     } else {
    539         // #3 #5 #6 have left != auto
    540         computedLeftValue = valueForLength(left, containingBlockWidth);
    541     }
    542 
    543     displayBox.setLeft(computedLeftValue);
    544 }
    545 
    546 void FormattingContext::computeOutOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    547 {
    548     // 10.6.5 Absolutely positioned, replaced elements (top/bottom)
    549     // 10.3.8 Absolutely positioned, replaced elements (left/right)
    550 
    551     // At this point we've the size computed.
    552     auto size = displayBox.size();
    553     auto& style = layoutBox.style();
    554 
    555     // 10.6.5 Absolutely positioned, replaced elements
    556     //
    557     // This situation is similar to the previous one, except that the element has an intrinsic height. The sequence of substitutions is now:
    558     // The used value of 'height' is determined as for inline replaced elements. If 'margin-top' or 'margin-bottom' is specified as 'auto'
    559     // its used value is determined by the rules below.
    560     //
    561     // 1. If both 'top' and 'bottom' have the value 'auto', replace 'top' with the element's static position.
    562     // 2. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or 'margin-bottom' with '0'.
    563     // 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.
    564     // 4. If at this point there is only one 'auto' left, solve the equation for that value.
    565     // 5. If at this point the values are over-constrained, ignore the value for 'bottom' and solve for that value.
    566     auto top = style.logicalTop();
    567     auto bottom = style.logicalBottom();
    568     auto containingBlockHeight = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->height();
    569     LayoutUnit computedTopValue;
    570 
    571     if (!top.isAuto())
    572         computedTopValue = valueForLength(top, containingBlockHeight);
    573     else if (bottom.isAuto()) {
    574         // #1
    575         computedTopValue = displayBox.top();
    576     } else {
    577         // #4
    578         auto marginTop = displayBox.marginTop();
    579         auto marginBottom = displayBox.marginBottom();
    580 
    581         auto paddingTop = displayBox.paddingTop();
    582         auto paddingBottom = displayBox.paddingBottom();
    583 
    584         auto borderTop = displayBox.borderTop();
    585         auto borderBottom = displayBox.borderBottom();
    586 
    587         computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value());
    588     }
    589 
    590     displayBox.setTop(computedTopValue);
    591 
    592 
    593     // 10.3.8 Absolutely positioned, replaced elements
    594     //
    595     // 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:
    596     //
    597     // The used value of 'width' is determined as for inline replaced elements.
    598     //
    599     // 1. If 'margin-left' or 'margin-right' is specified as 'auto' its used value is determined by the rules below.
    600     // 2. If both 'left' and 'right' have the value 'auto', then if the 'direction' property of the element establishing the
    601     //    static-position containing block is 'ltr', set 'left' to the static position; else if 'direction' is 'rtl', set 'right' to the static position.
    602     // 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' or 'margin-right' with '0'.
    603     // 4. If at this point both 'margin-left' and 'margin-right' are still 'auto', solve the equation under the extra constraint
    604     //    that the two margins must get equal values, unless this would make them negative, in which case when the direction of
    605     //    the containing block is 'ltr' ('rtl'), set 'margin-left' ('margin-right') to zero and solve for 'margin-right' ('margin-left').
    606     // 5. If at this point there is an 'auto' left, solve the equation for that value.
    607     // 6. If at this point the values are over-constrained, ignore the value for either 'left' (in case the 'direction'
    608     //    property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value.
    609     auto left = style.logicalLeft();
    610     auto right = style.logicalRight();
    611     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
    612     LayoutUnit computedLeftValue;
    613 
    614     if (!left.isAuto())   
    615         computedLeftValue = valueForLength(left, containingBlockWidth);
    616     else if (right.isAuto()) {
    617         // FIXME: take direction into account
    618         computedLeftValue = displayBox.left();
    619     } else {
    620         // #5
    621         auto marginLeft = displayBox.marginLeft();
    622         auto marginRight = displayBox.marginRight();
    623    
    624         auto paddingLeft = displayBox.paddingLeft();
    625         auto paddingRight = displayBox.paddingRight();
    626 
    627         auto borderLeft = displayBox.borderLeft();
    628         auto borderRight = displayBox.borderRight();
    629 
    630         computedLeftValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + size.width() + paddingRight + borderRight + marginRight + right.value());
    631     }
    632 
    633     displayBox.setLeft(computedLeftValue);
    634 }
    635 
    636 LayoutUnit FormattingContext::shrinkToFitWidth(LayoutContext&, const Box&) const
    637 {
    638     return 0;
    639184}
    640185
  • trunk/Source/WebCore/layout/FormattingContext.h

    r232065 r232114  
    2929
    3030#include "FloatingState.h"
    31 #include "LayoutUnit.h"
    3231#include <wtf/IsoMalloc.h>
    3332#include <wtf/WeakPtr.h>
    3433
    3534namespace WebCore {
     35
     36class LayoutPoint;
     37class LayoutUnit;
    3638
    3739namespace Display {
     
    8890    void layoutOutOfFlowDescendants(LayoutContext&s) const;
    8991
    90     void computeReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
    91     void computeReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;
    92 
    9392#ifndef NDEBUG
    9493    virtual void validateGeometryConstraintsAfterLayout(const LayoutContext&) const;
    9594#endif
    9695
     96    // This class implements generic positioning and sizing.
     97    class Geometry {
     98    public:
     99        static LayoutUnit outOfFlowNonReplacedHeight(LayoutContext&, const Box&);
     100        static LayoutUnit outOfFlowNonReplacedWidth(LayoutContext&, const Box&);
     101
     102        static LayoutUnit outOfFlowReplacedHeight(LayoutContext&, const Box&);
     103        static LayoutUnit outOfFlowReplacedWidth(LayoutContext&, const Box&);
     104
     105        static LayoutUnit floatingNonReplacedHeight(LayoutContext&, const Box&);
     106        static LayoutUnit floatingNonReplacedWidth(LayoutContext&, const Box&);
     107
     108        static LayoutUnit floatingReplacedHeight(LayoutContext&, const Box&);
     109        static LayoutUnit floatingReplacedWidth(LayoutContext&, const Box&);
     110
     111        static LayoutPoint outOfFlowNonReplacedPosition(LayoutContext&, const Box&);
     112        static LayoutPoint outOfFlowReplacedPosition(LayoutContext&, const Box&);
     113
     114        static LayoutUnit replacedHeight(LayoutContext&, const Box&);
     115        static LayoutUnit replacedWidth(LayoutContext&, const Box&);
     116    };
     117
    97118private:
    98     void computeOutOfFlowNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
    99     void computeOutOfFlowNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;
    100     void computeOutOfFlowReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
    101     void computeOutOfFlowReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;
    102 
    103     void computeOutOfFlowNonReplacedPosition(LayoutContext&, const Box&, Display::Box&) const;
    104     void computeOutOfFlowReplacedPosition(LayoutContext&, const Box&, Display::Box&) const;
    105 
    106     void computeFloatingNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
    107     void computeFloatingNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;
    108 
    109     LayoutUnit contentHeightForFormattingContextRoot(LayoutContext&, const Box&) const;
    110     LayoutUnit shrinkToFitWidth(LayoutContext&, const Box&) const;
    111 
    112119    WeakPtr<Box> m_root;
    113120};
  • trunk/Source/WebCore/layout/FormattingContextGeometry.cpp

    r232113 r232114  
    2929#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
    3030
    31 #include "DisplayBox.h"
    32 #include "LayoutBox.h"
    33 #include "LayoutContainer.h"
    34 #include "LayoutContext.h"
    35 #include "LayoutDescendantIterator.h"
    36 #include <wtf/IsoMallocInlines.h>
    37 
    3831namespace WebCore {
    3932namespace Layout {
    4033
    41 WTF_MAKE_ISO_ALLOCATED_IMPL(FormattingContext);
    42 
    43 FormattingContext::FormattingContext(const Box& formattingContextRoot)
    44     : m_root(makeWeakPtr(const_cast<Box&>(formattingContextRoot)))
    45 {
    46 }
    47 
    48 FormattingContext::~FormattingContext()
    49 {
    50 }
    51 
    52 void FormattingContext::computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const
    53 {
    54 }
    55 
    56 void FormattingContext::computeInFlowPositionedPosition(const Box&, Display::Box&) const
    57 {
    58 }
    59 
    60 void FormattingContext::computeOutOfFlowPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    61 {
    62     if (!layoutBox.replaced()) {
    63         computeOutOfFlowNonReplacedPosition(layoutContext, layoutBox, displayBox);
    64         return;
    65     }
    66     computeOutOfFlowReplacedPosition(layoutContext, layoutBox, displayBox);
    67 }
    68 
    69 void FormattingContext::computeWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    70 {
    71     if (layoutBox.isOutOfFlowPositioned())
    72         return computeOutOfFlowWidth(layoutContext, layoutBox, displayBox);
    73     if (layoutBox.isFloatingPositioned())
    74         return computeFloatingWidth(layoutContext, layoutBox, displayBox);
    75     return computeInFlowWidth(layoutContext, layoutBox, displayBox);
    76 }
    77 
    78 void FormattingContext::computeHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    79 {
    80     if (layoutBox.isOutOfFlowPositioned())
    81         return computeOutOfFlowHeight(layoutContext, layoutBox, displayBox);
    82     if (layoutBox.isFloatingPositioned())
    83         return computeFloatingHeight(layoutContext, layoutBox, displayBox);
    84     return computeInFlowHeight(layoutContext, layoutBox, displayBox);
    85 }
    86 
    87 void FormattingContext::computeOutOfFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    88 {
    89     if (!layoutBox.replaced()) {
    90         computeOutOfFlowNonReplacedWidth(layoutContext, layoutBox, displayBox);
    91         return;
    92     }
    93     computeOutOfFlowReplacedWidth(layoutContext, layoutBox, displayBox);
    94 }
    95 
    96 void FormattingContext::computeFloatingWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    97 {
    98     if (!layoutBox.replaced()) {
    99         computeFloatingNonReplacedWidth(layoutContext, layoutBox, displayBox);
    100         return;
    101     }
    102     computeReplacedWidth(layoutContext, layoutBox, displayBox);
    103 }
    104 
    105 void FormattingContext::computeOutOfFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    106 {
    107     if (!layoutBox.replaced()) {
    108         computeOutOfFlowNonReplacedHeight(layoutContext, layoutBox, displayBox);
    109         return;
    110     }
    111     computeOutOfFlowReplacedHeight(layoutContext, layoutBox, displayBox);
    112 }
    113 
    114 void FormattingContext::computeFloatingHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    115 {
    116     if (!layoutBox.replaced()) {
    117         computeFloatingNonReplacedHeight(layoutContext, layoutBox, displayBox);
    118         return;
    119     }
    120     computeReplacedHeight(layoutContext, layoutBox, displayBox);
    121 }
    122 
    123 LayoutUnit FormattingContext::marginTop(const Box&) const
    124 {
    125     return 0;
    126 }
    127 
    128 LayoutUnit FormattingContext::marginLeft(const Box&) const
    129 {
    130     return 0;
    131 }
    132 
    133 LayoutUnit FormattingContext::marginBottom(const Box&) const
    134 {
    135     return 0;
    136 }
    137 
    138 LayoutUnit FormattingContext::marginRight(const Box&) const
    139 {
    140     return 0;
    141 }
    142 
    143 void FormattingContext::placeInFlowPositionedChildren(const Container&) const
    144 {
    145 }
    146 
    147 void FormattingContext::layoutOutOfFlowDescendants(LayoutContext& layoutContext) const
    148 {
    149     if (!is<Container>(m_root.get()))
    150         return;
    151     for (auto& outOfFlowBox : downcast<Container>(*m_root).outOfFlowDescendants()) {
    152         auto& layoutBox = *outOfFlowBox;
    153         auto& displayBox = layoutContext.createDisplayBox(layoutBox);
    154 
    155         // The term "static position" (of an element) refers, roughly, to the position an element would have had in the normal flow.
    156         // More precisely, the static position for 'top' is the distance from the top edge of the containing block to the top margin edge
    157         // of a hypothetical box that would have been the first box of the element if its specified 'position' value had been 'static' and
    158         // its specified 'float' had been 'none' and its specified 'clear' had been 'none'.
    159         computeStaticPosition(layoutContext, layoutBox, displayBox);
    160         computeOutOfFlowWidth(layoutContext, layoutBox, displayBox);
    161 
    162         ASSERT(layoutBox.establishesFormattingContext());
    163         auto formattingContext = layoutContext.formattingContext(layoutBox);
    164         formattingContext->layout(layoutContext, layoutContext.establishedFormattingState(layoutBox, *formattingContext));
    165 
    166         computeOutOfFlowHeight(layoutContext, layoutBox, displayBox);
    167         computeOutOfFlowPosition(layoutContext, layoutBox, displayBox);
    168     }
    169 }
    170 
    171 void FormattingContext::computeOutOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     34static LayoutUnit contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox)
     35{
     36    ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext());
     37    // 10.6.7 'Auto' heights for block formatting context roots
     38
     39    // 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.
     40    // If it has block-level children, the height is the distance between the top margin-edge of the topmost block-level
     41    // child box and the bottom margin-edge of the bottommost block-level child box.
     42
     43    // In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge,
     44    // then the height is increased to include those edges. Only floats that participate in this block formatting context are taken
     45    // into account, e.g., floats inside absolutely positioned descendants or other floats are not.
     46    if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
     47        return 0;
     48
     49    auto& formattingRootContainer = downcast<Container>(layoutBox);
     50    if (formattingRootContainer.establishesInlineFormattingContext())
     51        return 0;
     52
     53    auto* firstDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild());
     54    auto* lastDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.lastInFlowChild());
     55
     56    auto top = firstDisplayBox->marginBox().y();
     57    auto bottom = lastDisplayBox->marginBox().maxY();
     58    // FIXME: add floating support.
     59    return bottom - top;
     60}
     61
     62static LayoutUnit shrinkToFitWidth(LayoutContext&, const Box&)
     63{
     64    return { };
     65}
     66
     67LayoutUnit FormattingContext::Geometry::outOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox)
    17268{
    17369    ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced());
     
    204100    LayoutUnit computedHeightValue;
    205101
    206     if ((top.isAuto() && height.isAuto() && bottom.isAuto())
    207         || (top.isAuto() && height.isAuto() && !bottom.isAuto())
    208         || (!top.isAuto() && height.isAuto() && bottom.isAuto())) {
     102    if (!height.isAuto())
     103        computedHeightValue = valueForLength(height, containingBlockHeight);
     104    else if ((top.isAuto() && bottom.isAuto())
     105        || (top.isAuto() && !bottom.isAuto())
     106        || (!top.isAuto() && bottom.isAuto())) {
    209107        // All auto (#3), #1 and #3
    210108        computedHeightValue = contentHeightForFormattingContextRoot(layoutContext, layoutBox);
    211     } else if (!top.isAuto() && height.isAuto() && !bottom.isAuto()) {
     109    } else if (!top.isAuto() && !bottom.isAuto()) {
    212110        // #5
     111        auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
     112
    213113        auto marginTop = displayBox.marginTop();
    214114        auto marginBottom = displayBox.marginBottom();
     
    221121
    222122        computedHeightValue = containingBlockHeight - (top.value() + marginTop + borderTop + paddingTop + paddingBottom + borderBottom + marginBottom + bottom.value());
    223     } else if (!height.isAuto())
    224         computedHeightValue = valueForLength(height, containingBlockHeight);
    225     else
     123    } else {
     124        // #2 #4 #6 have height != auto
    226125        ASSERT_NOT_REACHED();
    227 
    228     displayBox.setHeight(computedHeightValue);
    229 }
    230 
    231 void FormattingContext::computeFloatingNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    232 {
    233     ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());
    234     // 10.6.6 Complicated cases
    235     //
    236     // Floating, non-replaced elements.
    237     //
    238     // If 'height' is 'auto', the height depends on the element's descendants per 10.6.7.
    239     auto height = layoutBox.style().logicalHeight();
    240     displayBox.setHeight(height.isAuto() ? contentHeightForFormattingContextRoot(layoutContext, layoutBox) : LayoutUnit(height.value()));
    241 }
    242 
    243 void FormattingContext::computeReplacedHeight(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const
    244 {
    245     ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
    246     // 10.6.5 Absolutely positioned, replaced elements. The used value of 'height' is determined as for inline replaced elements.
    247 
    248     // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
    249     //
    250     // 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'.
    251     //
    252     // 2. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
    253     //    (used width) / (intrinsic ratio)
    254     //
    255     // 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'.
    256     //
    257     // 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
    258     //    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.
    259     auto& style = layoutBox.style();
    260     auto width = style.logicalWidth();
    261     auto height = style.logicalHeight();
    262 
    263     LayoutUnit computedHeightValue;
    264     auto replaced = layoutBox.replaced();
    265     ASSERT(replaced);
    266 
    267     if (height.isAuto()) {
    268         if (width.isAuto() && replaced->hasIntrinsicHeight()) {
    269             // #1
    270             computedHeightValue = replaced->intrinsicHeight();
    271         } else if (replaced->hasIntrinsicRatio()) {
    272             // #2
    273             computedHeightValue = width.value() / replaced->intrinsicRatio();
    274         } else if (replaced->hasIntrinsicHeight()) {
    275             // #3
    276             computedHeightValue = replaced->intrinsicHeight();
    277         } else {
    278             // #4
    279             computedHeightValue = 150;
    280         }
    281     } else
    282         computedHeightValue = height.value();
    283 
    284     displayBox.setHeight(computedHeightValue);
    285 }
    286 
    287 void FormattingContext::computeReplacedWidth(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const
    288 {
    289     ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
    290 
    291     // 10.3.4 Block-level, replaced elements in normal flow: The used value of 'width' is determined as for inline replaced elements.
    292     // 10.3.6 Floating, replaced elements: The used value of 'width' is determined as for inline replaced elements.
    293     // 10.3.8 Absolutely positioned, replaced elements: The used value of 'width' is determined as for inline replaced elements.
    294 
    295     // 10.3.2 Inline, replaced elements
    296     //
    297     // 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'.
    298     //
    299     // 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;
    300     //    or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio;
    301     //    then the used value of 'width' is: (used height) * (intrinsic ratio)
    302     //
    303     // 3. If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width,
    304     //    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
    305     //    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.
    306     //
    307     // 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'.
    308     //
    309     // 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.
    310     //    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.
    311     auto& style = layoutBox.style();
    312     auto width = style.logicalWidth();
    313     auto height = style.logicalHeight();
    314 
    315     LayoutUnit computedWidthValue;
    316     auto replaced = layoutBox.replaced();
    317     ASSERT(replaced);
    318 
    319     if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicWidth()) {
    320         // #1
    321         computedWidthValue = replaced->intrinsicWidth();
    322     } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) {
    323         // #2
    324         auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight();   
    325         computedWidthValue = usedHeight * replaced->intrinsicRatio();
    326     } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) {
    327         // #3
    328         // FIXME: undefined but surely doable.
    329         ASSERT_NOT_IMPLEMENTED_YET();
    330     } else if (width.isAuto() && replaced->hasIntrinsicWidth()) {
    331         // #4
    332         computedWidthValue = replaced->intrinsicWidth();
    333     } else {
    334         // #5
    335         computedWidthValue = 300;
    336     }
    337 
    338     displayBox.setWidth(computedWidthValue);
    339 }
    340 
    341 LayoutUnit FormattingContext::contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox) const
    342 {
    343     ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext());
    344     // 10.6.7 'Auto' heights for block formatting context roots
    345 
    346     // 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.
    347     // If it has block-level children, the height is the distance between the top margin-edge of the topmost block-level
    348     // child box and the bottom margin-edge of the bottommost block-level child box.
    349 
    350     // In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge,
    351     // then the height is increased to include those edges. Only floats that participate in this block formatting context are taken
    352     // into account, e.g., floats inside absolutely positioned descendants or other floats are not.
    353     if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
    354         return 0;
    355 
    356     auto& formattingRootContainer = downcast<Container>(layoutBox);
    357     if (formattingRootContainer.establishesInlineFormattingContext())
    358         return 0;
    359 
    360     auto* firstDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild());
    361     auto* lastDisplayBox = layoutContext.displayBoxForLayoutBox(*formattingRootContainer.lastInFlowChild());
    362 
    363     auto top = firstDisplayBox->marginBox().y();
    364     auto bottom = lastDisplayBox->marginBox().maxY();
    365     // FIXME: add floating support.
    366     return bottom - top;
    367 }
    368 
    369 void FormattingContext::computeFloatingNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    370 {
    371     ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());
    372     // 10.3.5 Floating, non-replaced elements
    373 
    374     // If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
    375     auto width = layoutBox.style().logicalWidth();
    376     displayBox.setWidth(width.isAuto() ? shrinkToFitWidth(layoutContext, layoutBox) : LayoutUnit(width.value()));
    377 }
    378 
    379 void FormattingContext::computeOutOfFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     126    }
     127
     128    return computedHeightValue;
     129}
     130
     131LayoutUnit FormattingContext::Geometry::outOfFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox)
    380132{
    381133    ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced());
     
    406158    LayoutUnit computedWidthValue;
    407159
    408     if ((left.isAuto() && width.isAuto() && right.isAuto())
    409         || (left.isAuto() && width.isAuto() && !right.isAuto())
    410         || (!left.isAuto() && width.isAuto() && right.isAuto())) {
     160    if (!width.isAuto())
     161        computedWidthValue = valueForLength(width, containingBlockWidth);
     162    else if ((left.isAuto() && right.isAuto())
     163        || (left.isAuto() && !right.isAuto())
     164        || (!left.isAuto() && right.isAuto())) {
    411165        // All auto (#1), #1 and #3
    412166        computedWidthValue = shrinkToFitWidth(layoutContext, layoutBox);
    413     } else if (!left.isAuto() && width.isAuto() && !right.isAuto()) {
     167    } else if (!left.isAuto() && !right.isAuto()) {
    414168        // #5
     169        auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
     170
    415171        auto marginLeft = displayBox.marginLeft();
    416172        auto marginRight = displayBox.marginRight();
     
    423179
    424180        computedWidthValue = containingBlockWidth - (left.value() + marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight + right.value());
    425     } else if (!width.isAuto())
    426         computedWidthValue = valueForLength(width, containingBlockWidth);
    427     else
     181    } else {
     182        // #2 #4 #6 have width != auto
    428183        ASSERT_NOT_REACHED();
    429 
    430     displayBox.setWidth(computedWidthValue);
    431 }
    432 
    433 void FormattingContext::computeOutOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     184    }
     185
     186    return computedWidthValue;
     187}
     188
     189LayoutUnit FormattingContext::Geometry::outOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox)
    434190{
    435191    ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());
     
    437193    //
    438194    // The used value of 'height' is determined as for inline replaced elements.
    439     computeReplacedHeight(layoutContext, layoutBox, displayBox);
    440 }
    441 
    442 void FormattingContext::computeOutOfFlowReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     195    return replacedHeight(layoutContext, layoutBox);
     196}
     197
     198LayoutUnit FormattingContext::Geometry::outOfFlowReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox)
    443199{
    444200    ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());
     
    446202    //
    447203    // The used value of 'width' is determined as for inline replaced elements.
    448     computeReplacedWidth(layoutContext, layoutBox, displayBox);
    449 }
    450 
    451 void FormattingContext::computeOutOfFlowNonReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     204    return replacedWidth(layoutContext, layoutBox);
     205}
     206
     207LayoutUnit FormattingContext::Geometry::floatingNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox)
     208{
     209    ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());
     210    // 10.6.6 Complicated cases
     211    //
     212    // Floating, non-replaced elements.
     213    //
     214    // If 'height' is 'auto', the height depends on the element's descendants per 10.6.7.
     215    auto height = layoutBox.style().logicalHeight();
     216    return height.isAuto() ? contentHeightForFormattingContextRoot(layoutContext, layoutBox) : LayoutUnit(height.value());
     217}
     218
     219LayoutUnit FormattingContext::Geometry::floatingNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox)
     220{
     221    ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());
     222    // 10.3.5 Floating, non-replaced elements
     223
     224    // If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
     225    auto width = layoutBox.style().logicalWidth();
     226    return width.isAuto() ? shrinkToFitWidth(layoutContext, layoutBox) : LayoutUnit(width.value());
     227}
     228
     229LayoutUnit FormattingContext::Geometry::floatingReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox)
     230{
     231    ASSERT(layoutBox.isFloatingPositioned() && layoutBox.replaced());
     232    // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block'
     233    // replaced elements in normal flow and floating replaced elements
     234    return replacedHeight(layoutContext, layoutBox);
     235}
     236
     237LayoutUnit FormattingContext::Geometry::floatingReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox)
     238{
     239    ASSERT(layoutBox.isFloatingPositioned() && layoutBox.replaced());
     240    // 10.3.6 Floating, replaced elements
     241    //
     242    // The used value of 'width' is determined as for inline replaced elements.
     243    return replacedWidth(layoutContext, layoutBox);
     244}
     245
     246LayoutPoint FormattingContext::Geometry::outOfFlowNonReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox)
    452247{
    453248    // 10.3.7 Absolutely positioned, non-replaced elements (left/right)
     
    455250
    456251    // At this point we've the size computed.
     252    auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
    457253    auto size = displayBox.size();
    458254    auto& style = layoutBox.style();
     
    497293    }
    498294
    499     displayBox.setTop(computedTopValue);
    500295
    501296    // 10.3.7 Absolutely positioned, non-replaced elements
     
    541336    }
    542337
    543     displayBox.setLeft(computedLeftValue);
    544 }
    545 
    546 void FormattingContext::computeOutOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     338    return { computedLeftValue, computedTopValue };
     339}
     340
     341LayoutPoint FormattingContext::Geometry::outOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox)
    547342{
    548343    // 10.6.5 Absolutely positioned, replaced elements (top/bottom)
     
    550345
    551346    // At this point we've the size computed.
     347    auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
    552348    auto size = displayBox.size();
    553349    auto& style = layoutBox.style();
     
    587383        computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value());
    588384    }
    589 
    590     displayBox.setTop(computedTopValue);
    591385
    592386
     
    631425    }
    632426
    633     displayBox.setLeft(computedLeftValue);
    634 }
    635 
    636 LayoutUnit FormattingContext::shrinkToFitWidth(LayoutContext&, const Box&) const
    637 {
    638     return 0;
    639 }
    640 
    641 #ifndef NDEBUG
    642 void FormattingContext::validateGeometryConstraintsAfterLayout(const LayoutContext& layoutContext) const
    643 {
    644     if (!is<Container>(root()))
    645         return;
    646     auto& formattingContextRoot = downcast<Container>(root());
    647     // FIXME: add a descendantsOfType<> flavor that stops at nested formatting contexts
    648     for (auto& layoutBox : descendantsOfType<Box>(formattingContextRoot)) {
    649         if (&layoutBox.formattingContextRoot() != &formattingContextRoot)
    650             continue;
    651         auto* containingBlock = layoutBox.containingBlock();
    652         ASSERT(containingBlock);
    653         auto containingBlockSize = layoutContext.displayBoxForLayoutBox(*containingBlock)->size();
    654         auto* displayBox = layoutContext.displayBoxForLayoutBox(layoutBox);
    655         ASSERT(displayBox);
    656 
    657         // 10.3.3 Block-level, non-replaced elements in normal flow
    658         // 10.3.7 Absolutely positioned, non-replaced elements
    659         if ((layoutBox.isBlockLevelBox() || layoutBox.isOutOfFlowPositioned()) && !layoutBox.replaced()) {
    660             // margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right = width of containing block
    661             ASSERT(displayBox->marginLeft() + displayBox->borderLeft() + displayBox->paddingLeft() + displayBox->width()
    662                 + displayBox->paddingRight() + displayBox->borderRight() + displayBox->marginRight() == containingBlockSize.width());
     427    return { computedLeftValue, computedTopValue };
     428}
     429
     430LayoutUnit FormattingContext::Geometry::replacedHeight(LayoutContext&, const Box& layoutBox)
     431{
     432    ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
     433    // 10.6.5 Absolutely positioned, replaced elements. The used value of 'height' is determined as for inline replaced elements.
     434
     435    // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
     436    //
     437    // 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'.
     438    //
     439    // 2. Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
     440    //    (used width) / (intrinsic ratio)
     441    //
     442    // 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'.
     443    //
     444    // 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
     445    //    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.
     446    auto& style = layoutBox.style();
     447    auto width = style.logicalWidth();
     448    auto height = style.logicalHeight();
     449
     450    LayoutUnit computedHeightValue;
     451    auto replaced = layoutBox.replaced();
     452    ASSERT(replaced);
     453
     454    if (height.isAuto()) {
     455        if (width.isAuto() && replaced->hasIntrinsicHeight()) {
     456            // #1
     457            computedHeightValue = replaced->intrinsicHeight();
     458        } else if (replaced->hasIntrinsicRatio()) {
     459            // #2
     460            computedHeightValue = width.value() / replaced->intrinsicRatio();
     461        } else if (replaced->hasIntrinsicHeight()) {
     462            // #3
     463            computedHeightValue = replaced->intrinsicHeight();
     464        } else {
     465            // #4
     466            computedHeightValue = 150;
    663467        }
    664 
    665         // 10.6.4 Absolutely positioned, non-replaced elements
    666         if (layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()) {
    667             // top + margin-top + border-top-width + padding-top + height + padding-bottom + border-bottom-width + margin-bottom + bottom = height of containing block
    668             ASSERT(displayBox->top() + displayBox->marginTop() + displayBox->borderTop() + displayBox->paddingTop()
    669                 + displayBox->paddingBottom() + displayBox->borderBottom() + displayBox->marginBottom() == containingBlockSize.height());
    670         }
    671     }
     468    } else
     469        computedHeightValue = height.value();
     470
     471    return computedHeightValue;
     472}
     473
     474LayoutUnit FormattingContext::Geometry::replacedWidth(LayoutContext&, const Box& layoutBox)
     475{
     476    ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
     477
     478    // 10.3.4 Block-level, replaced elements in normal flow: The used value of 'width' is determined as for inline replaced elements.
     479    // 10.3.6 Floating, replaced elements: The used value of 'width' is determined as for inline replaced elements.
     480    // 10.3.8 Absolutely positioned, replaced elements: The used value of 'width' is determined as for inline replaced elements.
     481
     482    // 10.3.2 Inline, replaced elements
     483    //
     484    // 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'.
     485    //
     486    // 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;
     487    //    or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio;
     488    //    then the used value of 'width' is: (used height) * (intrinsic ratio)
     489    //
     490    // 3. If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width,
     491    //    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
     492    //    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.
     493    //
     494    // 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'.
     495    //
     496    // 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.
     497    //    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.
     498    auto& style = layoutBox.style();
     499    auto width = style.logicalWidth();
     500    auto height = style.logicalHeight();
     501
     502    LayoutUnit computedWidthValue;
     503    auto replaced = layoutBox.replaced();
     504    ASSERT(replaced);
     505
     506    if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicWidth()) {
     507        // #1
     508        computedWidthValue = replaced->intrinsicWidth();
     509    } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) {
     510        // #2
     511        auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight();
     512        computedWidthValue = usedHeight * replaced->intrinsicRatio();
     513    } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) {
     514        // #3
     515        // FIXME: undefined but surely doable.
     516        ASSERT_NOT_IMPLEMENTED_YET();
     517    } else if (width.isAuto() && replaced->hasIntrinsicWidth()) {
     518        // #4
     519        computedWidthValue = replaced->intrinsicWidth();
     520    } else {
     521        // #5
     522        computedWidthValue = 300;
     523    }
     524
     525    return computedWidthValue;
     526}
     527
     528}
    672529}
    673530#endif
    674 
    675 }
    676 }
    677 #endif
  • trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp

    r232042 r232114  
    131131void BlockFormattingContext::computeStaticPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    132132{
    133     // https://www.w3.org/TR/CSS22/visuren.html#block-formatting
    134     // In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block.
    135     // The vertical distance between two sibling boxes is determined by the 'margin' properties.
    136     // Vertical margins between adjacent block-level boxes in a block formatting context collapse.
    137     // 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).
    138     auto containingBlockContentBox = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->contentBox();
    139     // Start from the top of the container's content box.
    140     auto top = containingBlockContentBox.y();
    141     auto left = containingBlockContentBox.x();
    142     if (auto* previousInFlowSibling = layoutBox.previousInFlowSibling())
    143         top = layoutContext.displayBoxForLayoutBox(*previousInFlowSibling)->bottom() + marginBottom(*previousInFlowSibling);
    144     LayoutPoint topLeft = { top, left };
    145     topLeft.moveBy({ marginLeft(layoutBox), marginTop(layoutBox) });
     133    auto topLeft = Geometry::staticPosition(layoutContext, layoutBox);
    146134    displayBox.setTopLeft(topLeft);
     135}
     136
     137void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
     138{
     139    LayoutUnit computedHeight;
     140
     141    if (layoutBox.replaced()) {
     142        // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block'
     143        // replaced elements in normal flow and floating replaced elements
     144        computedHeight = FormattingContext::Geometry::replacedHeight(layoutContext, layoutBox);
     145    } else
     146        computedHeight = Geometry::inFlowNonReplacedHeight(layoutContext, layoutBox);
     147
     148    displayBox.setHeight(computedHeight);
    147149}
    148150
    149151void BlockFormattingContext::computeInFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    150152{
    151     if (!layoutBox.replaced()) {
    152         computeInFlowNonReplacedWidth(layoutContext, layoutBox, displayBox);
    153         return;
    154     }
    155     computeReplacedWidth(layoutContext, layoutBox, displayBox);
    156 }
     153    LayoutUnit computedWidth;
    157154
    158 void BlockFormattingContext::computeInFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    159 {
    160     ASSERT(layoutBox.isInFlow() && !layoutBox.replaced());
     155    if (layoutBox.replaced()) {
     156        // 10.3.4 Block-level, replaced elements in normal flow
     157        // The used value of 'width' is determined as for inline replaced elements
     158        computedWidth = FormattingContext::Geometry::replacedWidth(layoutContext, layoutBox);
     159    } else
     160        computedWidth = Geometry::inFlowNonReplacedWidth(layoutContext, layoutBox);
    161161
    162     // 10.3.3 Block-level, non-replaced elements in normal flow
    163     // The following constraints must hold among the used values of the other properties:
    164     // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
    165 
    166     // If 'width' is set to 'auto', any other 'auto' values become '0' and 'width' follows from the resulting equality.
    167     auto& style = layoutBox.style();
    168     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
    169 
    170     LayoutUnit computedWidthValue;
    171     auto width = style.logicalWidth();
    172     if (width.isAuto()) {
    173         auto marginLeft = displayBox.marginLeft();
    174         auto marginRight = displayBox.marginRight();
    175 
    176         auto paddingLeft = displayBox.paddingLeft();
    177         auto paddingRight = displayBox.paddingRight();
    178 
    179         auto borderLeft = displayBox.borderLeft();
    180         auto borderRight = displayBox.borderRight();
    181 
    182         computedWidthValue = containingBlockWidth - (marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + marginRight);
    183     } else
    184         computedWidthValue = valueForLength(width, containingBlockWidth);
    185 
    186     displayBox.setWidth(computedWidthValue);
    187 }
    188 
    189 void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    190 {
    191     if (!layoutBox.replaced()) {
    192         computeInFlowNonReplacedHeight(layoutContext, layoutBox, displayBox);
    193         return;
    194     }
    195     computeReplacedHeight(layoutContext, layoutBox, displayBox);
     162    displayBox.setWidth(computedWidth);
    196163}
    197164
     
    206173}
    207174
    208 void BlockFormattingContext::computeInFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
    209 {
    210     ASSERT(layoutBox.isInFlow() && !layoutBox.replaced());
    211 
    212     // https://www.w3.org/TR/CSS22/visudet.html
    213     // If 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders:
    214     // The element's height is the distance from its top content edge to the first applicable of the following:
    215     // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
    216     // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin
    217     //    does not collapse with the element's bottom margin
    218     // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
    219     // 4. zero, otherwise
    220     // Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored,
    221     // and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box.
    222     if (!layoutBox.style().logicalHeight().isAuto()) {
    223         // FIXME: Only fixed values yet.
    224         displayBox.setHeight(layoutBox.style().logicalHeight().value());
    225         return;
    226     }
    227 
    228     if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) {
    229         displayBox.setHeight(0);
    230         return;
    231     }
    232 
    233     // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
    234     if (layoutBox.establishesInlineFormattingContext()) {
    235         // height = lastLineBox().bottom();
    236         displayBox.setHeight(0);
    237         return;
    238     }
    239 
    240     // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin...
    241     auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild();
    242     ASSERT(lastInFlowChild);
    243     if (!BlockMarginCollapse::isMarginBottomCollapsedWithParent(*lastInFlowChild)) {
    244         auto* lastInFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*lastInFlowChild);
    245         ASSERT(lastInFlowDisplayBox);
    246         displayBox.setHeight(lastInFlowDisplayBox->bottom() + lastInFlowDisplayBox->marginBottom());
    247         return;
    248     }
    249 
    250     // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
    251     auto* inFlowChild = lastInFlowChild;
    252     while (inFlowChild && BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom(*inFlowChild))
    253         inFlowChild = inFlowChild->previousInFlowSibling();
    254     if (inFlowChild) {
    255         auto* inFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*inFlowChild);
    256         ASSERT(inFlowDisplayBox);
    257         displayBox.setHeight(inFlowDisplayBox->top() + inFlowDisplayBox->borderBox().height());
    258         return;
    259     }
    260 
    261     // 4. zero, otherwise
    262     displayBox.setHeight(0);
    263 }
    264 
    265175}
    266176}
  • trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h

    r231786 r232114  
    2929
    3030#include "FormattingContext.h"
    31 #include "LayoutUnit.h"
    3231#include <wtf/IsoMalloc.h>
    3332
    3433namespace WebCore {
     34
     35class LayoutUnit;
    3536
    3637namespace Layout {
     
    5253private:
    5354    void computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const override;
    54 
    5555    void computeInFlowWidth(LayoutContext&, const Box&, Display::Box&) const override;
    56     void computeInFlowNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;
    57 
    5856    void computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const override;
    59     void computeInFlowNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
    6057
    6158    LayoutUnit marginTop(const Box&) const override;
    6259    LayoutUnit marginBottom(const Box&) const override;
     60   
     61    // This class implements positioning and sizing for boxes participating in a block formatting context.
     62    class Geometry {
     63    public:
     64        static LayoutUnit inFlowNonReplacedHeight(LayoutContext&, const Box&);
     65        static LayoutUnit inFlowNonReplacedWidth(LayoutContext&, const Box&);
     66
     67        static LayoutPoint staticPosition(LayoutContext&, const Box&);
     68    };
    6369};
    6470
     
    6672}
    6773#endif
    68 
  • trunk/Source/WebCore/layout/displaytree/DisplayBox.h

    r232018 r232114  
    4949    WTF_MAKE_ISO_ALLOCATED(Box);
    5050public:
     51    friend class Layout::BlockFormattingContext;
     52    friend class Layout::FormattingContext;
    5153    friend class Layout::LayoutContext;
    52     friend class Layout::FormattingContext;
    53     friend class Layout::BlockFormattingContext;
    5454
    5555    ~Box();
Note: See TracChangeset for help on using the changeset viewer.