Changeset 232114 in webkit
- Timestamp:
- May 23, 2018 9:56:12 AM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 1 added
- 8 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r232113 r232114 1 2018-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 1 67 2018-05-23 Antti Koivisto <antti@apple.com> 2 68 -
trunk/Source/WebCore/Sources.txt
r231895 r232114 1217 1217 layout/FloatingState.cpp 1218 1218 layout/FormattingContext.cpp 1219 layout/FormattingContextGeometry.cpp 1219 1220 layout/FormattingState.cpp 1220 1221 layout/LayoutContext.cpp 1221 1222 layout/blockformatting/BlockFormattingContext.cpp 1223 layout/blockformatting/BlockFormattingContextGeometry.cpp 1222 1224 layout/blockformatting/BlockFormattingState.cpp 1223 1225 layout/blockformatting/BlockMarginCollapse.cpp -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r232042 r232114 8887 8887 6EE8A77010F803F3005A4A24 /* JSWebGLContextAttributes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLContextAttributes.cpp; sourceTree = "<group>"; }; 8888 8888 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>"; }; 8889 8890 6F222B741AB52D640094651A /* WebGLVertexArrayObjectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGLVertexArrayObjectBase.h; sourceTree = "<group>"; }; 8890 8891 6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebGLVertexArrayObjectBase.cpp; sourceTree = "<group>"; }; … … 8918 8919 6F995A2F1A70833700A735F4 /* JSWebGLVertexArrayObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLVertexArrayObject.cpp; sourceTree = "<group>"; }; 8919 8920 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>"; }; 8920 8922 709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleFetchFailureKind.h; sourceTree = "<group>"; }; 8921 8923 71004B9D1DC1398800A52A38 /* playback-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "playback-support.js"; sourceTree = "<group>"; }; … … 15679 15681 115CFA69208AF7D0001E6991 /* FormattingContext.cpp */, 15680 15682 115CFA68208AF7D0001E6991 /* FormattingContext.h */, 15683 6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */, 15681 15684 115CFA75208AFE30001E6991 /* FormattingState.cpp */, 15682 15685 115CFA74208AFE30001E6991 /* FormattingState.h */, … … 15718 15721 115CFA6D208AFAB6001E6991 /* BlockFormattingContext.cpp */, 15719 15722 115CFA6C208AFAB6001E6991 /* BlockFormattingContext.h */, 15723 6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */, 15720 15724 115CFA79208B8D9D001E6991 /* BlockFormattingState.cpp */, 15721 15725 115CFA78208B8D9D001E6991 /* BlockFormattingState.h */, -
trunk/Source/WebCore/layout/FormattingContext.cpp
r232109 r232114 60 60 void FormattingContext::computeOutOfFlowPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 61 61 { 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); 67 70 } 68 71 … … 87 90 void FormattingContext::computeOutOfFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 88 91 { 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); 94 100 } 95 101 96 102 void FormattingContext::computeFloatingWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 97 103 { 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); 103 112 } 104 113 105 114 void FormattingContext::computeOutOfFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 106 115 { 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); 112 124 } 113 125 114 126 void FormattingContext::computeFloatingHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 115 127 { 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); 121 136 } 122 137 … … 167 182 computeOutOfFlowPosition(layoutContext, layoutBox, displayBox); 168 183 } 169 }170 171 void FormattingContext::computeOutOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const172 {173 ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced());174 175 // 10.6.4 Absolutely positioned, non-replaced elements176 //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 block180 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 extra184 // 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 for192 // '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 #3210 computedHeightValue = contentHeightForFormattingContextRoot(layoutContext, layoutBox);211 } else if (!top.isAuto() && height.isAuto() && !bottom.isAuto()) {212 // #5213 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 else226 ASSERT_NOT_REACHED();227 228 displayBox.setHeight(computedHeightValue);229 }230 231 void FormattingContext::computeFloatingNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const232 {233 ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());234 // 10.6.6 Complicated cases235 //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) const244 {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 elements249 //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 to258 // 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 // #1270 computedHeightValue = replaced->intrinsicHeight();271 } else if (replaced->hasIntrinsicRatio()) {272 // #2273 computedHeightValue = width.value() / replaced->intrinsicRatio();274 } else if (replaced->hasIntrinsicHeight()) {275 // #3276 computedHeightValue = replaced->intrinsicHeight();277 } else {278 // #4279 computedHeightValue = 150;280 }281 } else282 computedHeightValue = height.value();283 284 displayBox.setHeight(computedHeightValue);285 }286 287 void FormattingContext::computeReplacedWidth(LayoutContext&, const Box& layoutBox, Display::Box& displayBox) const288 {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 elements296 //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 replaced305 // 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 // #1321 computedWidthValue = replaced->intrinsicWidth();322 } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) {323 // #2324 auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight();325 computedWidthValue = usedHeight * replaced->intrinsicRatio();326 } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) {327 // #3328 // FIXME: undefined but surely doable.329 ASSERT_NOT_IMPLEMENTED_YET();330 } else if (width.isAuto() && replaced->hasIntrinsicWidth()) {331 // #4332 computedWidthValue = replaced->intrinsicWidth();333 } else {334 // #5335 computedWidthValue = 300;336 }337 338 displayBox.setWidth(computedWidthValue);339 }340 341 LayoutUnit FormattingContext::contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox) const342 {343 ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext());344 // 10.6.7 'Auto' heights for block formatting context roots345 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-level348 // 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 taken352 // 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) const370 {371 ASSERT(layoutBox.isFloatingPositioned() && !layoutBox.replaced());372 // 10.3.5 Floating, non-replaced elements373 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) const380 {381 ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced());382 383 // 10.3.7 Absolutely positioned, non-replaced elements384 //385 // 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right'386 // = width of containing block387 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 static390 // 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-position394 // 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 #3412 computedWidthValue = shrinkToFitWidth(layoutContext, layoutBox);413 } else if (!left.isAuto() && width.isAuto() && !right.isAuto()) {414 // #5415 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 else428 ASSERT_NOT_REACHED();429 430 displayBox.setWidth(computedWidthValue);431 }432 433 void FormattingContext::computeOutOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const434 {435 ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());436 // 10.6.5 Absolutely positioned, replaced elements437 //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) const443 {444 ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());445 // 10.3.8 Absolutely positioned, replaced elements446 //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) const452 {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 elements461 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 block467 //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 for471 // '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 #4480 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 // #2492 // Already computed as part of the computeStaticPosition();493 computedTopValue = displayBox.top();494 } else {495 // #3 #5 #6 have top != auto496 computedTopValue = valueForLength(top, containingBlockHeight);497 }498 499 displayBox.setTop(computedTopValue);500 501 // 10.3.7 Absolutely positioned, non-replaced elements502 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 block508 //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 static511 // 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-position515 // 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 #4524 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 // #2536 // FIXME: rtl537 computedLeftValue = displayBox.left();538 } else {539 // #3 #5 #6 have left != auto540 computedLeftValue = valueForLength(left, containingBlockWidth);541 }542 543 displayBox.setLeft(computedLeftValue);544 }545 546 void FormattingContext::computeOutOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const547 {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 elements556 //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 // #1575 computedTopValue = displayBox.top();576 } else {577 // #4578 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 elements594 //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 the601 // 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 constraint604 // that the two margins must get equal values, unless this would make them negative, in which case when the direction of605 // 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 account618 computedLeftValue = displayBox.left();619 } else {620 // #5621 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&) const637 {638 return 0;639 184 } 640 185 -
trunk/Source/WebCore/layout/FormattingContext.h
r232065 r232114 29 29 30 30 #include "FloatingState.h" 31 #include "LayoutUnit.h"32 31 #include <wtf/IsoMalloc.h> 33 32 #include <wtf/WeakPtr.h> 34 33 35 34 namespace WebCore { 35 36 class LayoutPoint; 37 class LayoutUnit; 36 38 37 39 namespace Display { … … 88 90 void layoutOutOfFlowDescendants(LayoutContext&s) const; 89 91 90 void computeReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;91 void computeReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;92 93 92 #ifndef NDEBUG 94 93 virtual void validateGeometryConstraintsAfterLayout(const LayoutContext&) const; 95 94 #endif 96 95 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 97 118 private: 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 112 119 WeakPtr<Box> m_root; 113 120 }; -
trunk/Source/WebCore/layout/FormattingContextGeometry.cpp
r232113 r232114 29 29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT) 30 30 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 38 31 namespace WebCore { 39 32 namespace Layout { 40 33 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 34 static 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 62 static LayoutUnit shrinkToFitWidth(LayoutContext&, const Box&) 63 { 64 return { }; 65 } 66 67 LayoutUnit FormattingContext::Geometry::outOfFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) 172 68 { 173 69 ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()); … … 204 100 LayoutUnit computedHeightValue; 205 101 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())) { 209 107 // All auto (#3), #1 and #3 210 108 computedHeightValue = contentHeightForFormattingContextRoot(layoutContext, layoutBox); 211 } else if (!top.isAuto() && height.isAuto() &&!bottom.isAuto()) {109 } else if (!top.isAuto() && !bottom.isAuto()) { 212 110 // #5 111 auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); 112 213 113 auto marginTop = displayBox.marginTop(); 214 114 auto marginBottom = displayBox.marginBottom(); … … 221 121 222 122 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 226 125 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 131 LayoutUnit FormattingContext::Geometry::outOfFlowNonReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) 380 132 { 381 133 ASSERT(layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()); … … 406 158 LayoutUnit computedWidthValue; 407 159 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())) { 411 165 // All auto (#1), #1 and #3 412 166 computedWidthValue = shrinkToFitWidth(layoutContext, layoutBox); 413 } else if (!left.isAuto() && width.isAuto() &&!right.isAuto()) {167 } else if (!left.isAuto() && !right.isAuto()) { 414 168 // #5 169 auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); 170 415 171 auto marginLeft = displayBox.marginLeft(); 416 172 auto marginRight = displayBox.marginRight(); … … 423 179 424 180 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 428 183 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 189 LayoutUnit FormattingContext::Geometry::outOfFlowReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox) 434 190 { 435 191 ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced()); … … 437 193 // 438 194 // 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 198 LayoutUnit FormattingContext::Geometry::outOfFlowReplacedWidth(LayoutContext& layoutContext, const Box& layoutBox) 443 199 { 444 200 ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced()); … … 446 202 // 447 203 // 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 207 LayoutUnit 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 219 LayoutUnit 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 229 LayoutUnit 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 237 LayoutUnit 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 246 LayoutPoint FormattingContext::Geometry::outOfFlowNonReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox) 452 247 { 453 248 // 10.3.7 Absolutely positioned, non-replaced elements (left/right) … … 455 250 456 251 // At this point we've the size computed. 252 auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); 457 253 auto size = displayBox.size(); 458 254 auto& style = layoutBox.style(); … … 497 293 } 498 294 499 displayBox.setTop(computedTopValue);500 295 501 296 // 10.3.7 Absolutely positioned, non-replaced elements … … 541 336 } 542 337 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 341 LayoutPoint FormattingContext::Geometry::outOfFlowReplacedPosition(LayoutContext& layoutContext, const Box& layoutBox) 547 342 { 548 343 // 10.6.5 Absolutely positioned, replaced elements (top/bottom) … … 550 345 551 346 // At this point we've the size computed. 347 auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox); 552 348 auto size = displayBox.size(); 553 349 auto& style = layoutBox.style(); … … 587 383 computedTopValue = containingBlockHeight - (marginTop + borderTop + paddingTop + size.height() + paddingBottom + borderBottom + marginBottom + bottom.value()); 588 384 } 589 590 displayBox.setTop(computedTopValue);591 385 592 386 … … 631 425 } 632 426 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 430 LayoutUnit 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; 663 467 } 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 474 LayoutUnit 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 } 672 529 } 673 530 #endif 674 675 }676 }677 #endif -
trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp
r232042 r232114 131 131 void BlockFormattingContext::computeStaticPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 132 132 { 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); 146 134 displayBox.setTopLeft(topLeft); 135 } 136 137 void 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); 147 149 } 148 150 149 151 void BlockFormattingContext::computeInFlowWidth(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const 150 152 { 151 if (!layoutBox.replaced()) { 152 computeInFlowNonReplacedWidth(layoutContext, layoutBox, displayBox); 153 return; 154 } 155 computeReplacedWidth(layoutContext, layoutBox, displayBox); 156 } 153 LayoutUnit computedWidth; 157 154 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); 161 161 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); 196 163 } 197 164 … … 206 173 } 207 174 208 void BlockFormattingContext::computeInFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const209 {210 ASSERT(layoutBox.isInFlow() && !layoutBox.replaced());211 212 // https://www.w3.org/TR/CSS22/visudet.html213 // 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 lines216 // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin217 // does not collapse with the element's bottom margin218 // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin219 // 4. zero, otherwise220 // 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 lines234 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 margin251 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, otherwise262 displayBox.setHeight(0);263 }264 265 175 } 266 176 } -
trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h
r231786 r232114 29 29 30 30 #include "FormattingContext.h" 31 #include "LayoutUnit.h"32 31 #include <wtf/IsoMalloc.h> 33 32 34 33 namespace WebCore { 34 35 class LayoutUnit; 35 36 36 37 namespace Layout { … … 52 53 private: 53 54 void computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const override; 54 55 55 void computeInFlowWidth(LayoutContext&, const Box&, Display::Box&) const override; 56 void computeInFlowNonReplacedWidth(LayoutContext&, const Box&, Display::Box&) const;57 58 56 void computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const override; 59 void computeInFlowNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;60 57 61 58 LayoutUnit marginTop(const Box&) const override; 62 59 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 }; 63 69 }; 64 70 … … 66 72 } 67 73 #endif 68 -
trunk/Source/WebCore/layout/displaytree/DisplayBox.h
r232018 r232114 49 49 WTF_MAKE_ISO_ALLOCATED(Box); 50 50 public: 51 friend class Layout::BlockFormattingContext; 52 friend class Layout::FormattingContext; 51 53 friend class Layout::LayoutContext; 52 friend class Layout::FormattingContext;53 friend class Layout::BlockFormattingContext;54 54 55 55 ~Box();
Note: See TracChangeset
for help on using the changeset viewer.