blob: 21879f3c1117d166e87d29559656567eed558b5c [file] [log] [blame]
zalan@apple.com903aad72018-03-09 19:10:37 +00001/*
2 * Copyright (C) 2018 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
zalan@apple.comc2fa0692018-04-14 04:48:35 +000026/*
27class FormattingContext {
28public:
29 Layout::Container& formattingRoot();
30 FormattingState& formattingState();
31 LayoutState& layoutState();
32 FloatingContext& floatingContext();
33
34 virtual void layout();
35
36 virtual void computeWidth(const Layout::Box&);
37 virtual void computeHeight(const Layout::Box&);
38
39 virtual LayoutUnit marginTop(const Layout::Box&);
40 virtual LayoutUnit marginLeft(const Layout::Box&);
41 virtual LayoutUnit marginBottom(const Layout::Box&);
42 virtual LayoutUnit marginRight(const Layout::Box&);
43
44private:
45 void computeFloatingWidth(const Layout::Box&);
46 void computeFloatingHeight(const Layout::Box&);
47
48 void placeInFlowPositionedChildren(const Layout::Box&);
49 void computeInFlowPositionedPosition(const Layout::Box&);
50 void computeInFlowWidth(const Layout::Box&);
51
52 void layoutOutOfFlowDescendants();
53
54 void computeOutOfFlowWidth(const Layout::Box&);
55 void computeOutOfFlowHeight(const Layout::Box&);
56 void computeOutOfFlowPosition(const Layout::Box&);
57
58 LayoutUnit shrinkToFitWidth(Layout::Box&);
59};
60*/
zalan@apple.com903aad72018-03-09 19:10:37 +000061class FormattingContext {
zalan@apple.comf5e498a2018-03-21 04:42:32 +000062 constructor(formattingState) {
63 this.m_formattingState = formattingState;
zalan@apple.com94319d42018-04-01 02:44:49 +000064 this.m_floatingContext = new FloatingContext(formattingState.floatingState());
zalan@apple.com4d9437e2018-03-17 04:34:02 +000065 this.m_layoutStack = new Array();
zalan@apple.com903aad72018-03-09 19:10:37 +000066 }
67
zalan@apple.comf5e498a2018-03-21 04:42:32 +000068 formattingRoot() {
69 return this.m_formattingState.formattingRoot();
70 }
71
72 formattingState() {
73 return this.m_formattingState;
zalan@apple.com903aad72018-03-09 19:10:37 +000074 }
75
zalan@apple.com67022232018-03-20 15:12:33 +000076 layoutState() {
zalan@apple.comf5e498a2018-03-21 04:42:32 +000077 return this.formattingState().layoutState();
zalan@apple.comae809a72018-03-20 05:02:41 +000078 }
79
zalan@apple.com903aad72018-03-09 19:10:37 +000080 floatingContext() {
81 return this.m_floatingContext;
82 }
83
zalan@apple.com67022232018-03-20 15:12:33 +000084 layout() {
85 ASSERT_NOT_REACHED();
zalan@apple.com903aad72018-03-09 19:10:37 +000086 }
87
zalan@apple.com5fd41f82018-03-15 15:59:46 +000088 computeWidth(layoutBox) {
zalan@apple.com903aad72018-03-09 19:10:37 +000089 }
90
zalan@apple.com5fd41f82018-03-15 15:59:46 +000091 computeHeight(layoutBox) {
zalan@apple.com903aad72018-03-09 19:10:37 +000092 }
93
zalan@apple.com5fd41f82018-03-15 15:59:46 +000094 marginTop(layoutBox) {
zalan@apple.come1fa8e82018-03-16 14:52:42 +000095 return Utils.computedMarginTop(layoutBox.node());
zalan@apple.com903aad72018-03-09 19:10:37 +000096 }
97
zalan@apple.com5fd41f82018-03-15 15:59:46 +000098 marginLeft(layoutBox) {
zalan@apple.come1fa8e82018-03-16 14:52:42 +000099 return Utils.computedMarginLeft(layoutBox.node());
zalan@apple.com903aad72018-03-09 19:10:37 +0000100 }
101
zalan@apple.com5fd41f82018-03-15 15:59:46 +0000102 marginBottom(layoutBox) {
zalan@apple.come1fa8e82018-03-16 14:52:42 +0000103 return Utils.computedMarginBottom(layoutBox.node());
zalan@apple.com903aad72018-03-09 19:10:37 +0000104 }
105
zalan@apple.com5fd41f82018-03-15 15:59:46 +0000106 marginRight(layoutBox) {
zalan@apple.come1fa8e82018-03-16 14:52:42 +0000107 return Utils.computedMarginRight(layoutBox.node());
zalan@apple.com903aad72018-03-09 19:10:37 +0000108 }
109
zalan@apple.com53972bd2018-04-12 17:26:55 +0000110 static isInFormattingContext(layoutBox, formattingContextRoot) {
111 ASSERT(formattingContextRoot.establishesFormattingContext());
112 // If we hit the "this" while climbing up on the containing block chain and we don't pass a formatting context root -> box is part of this box's formatting context.
113 for (let containingBlock = layoutBox.containingBlock(); containingBlock; containingBlock = containingBlock.containingBlock()) {
114 if (containingBlock == formattingContextRoot)
115 return true;
116 if (containingBlock.establishesFormattingContext())
117 return false;
118 }
119 return false;
120 }
121
zalan@apple.com4d9437e2018-03-17 04:34:02 +0000122 _descendantNeedsLayout() {
123 return this.m_layoutStack.length;
124 }
125
126 _addToLayoutQueue(layoutBox) {
zalan@apple.com91a50c22018-04-08 05:27:36 +0000127 if (!layoutBox)
128 return;
zalan@apple.com4d9437e2018-03-17 04:34:02 +0000129 // Initialize the corresponding display box.
zalan@apple.com1e490172018-04-01 00:50:13 +0000130 let displayBox = this.formattingState().createDisplayBox(layoutBox, this);
131 if (layoutBox.node()) {
132 displayBox.setMarginTop(this.marginTop(layoutBox));
133 displayBox.setMarginLeft(this.marginLeft(layoutBox));
134 displayBox.setMarginBottom(this.marginBottom(layoutBox));
135 displayBox.setMarginRight(this.marginRight(layoutBox));
136 }
137
zalan@apple.com4d9437e2018-03-17 04:34:02 +0000138 this.m_layoutStack.push(layoutBox);
139 }
140
141 _nextInLayoutQueue() {
142 ASSERT(this.m_layoutStack.length);
143 return this.m_layoutStack[this.m_layoutStack.length - 1];
144 }
145
146 _removeFromLayoutQueue(layoutBox) {
147 // With the current layout logic, the layoutBox should be at the top (this.m_layoutStack.pop() should do).
148 ASSERT(this.m_layoutStack.length);
149 ASSERT(this.m_layoutStack[this.m_layoutStack.length - 1] == layoutBox);
150 this.m_layoutStack.splice(this.m_layoutStack.indexOf(layoutBox), 1);
151 }
152
zalan@apple.comedb14302018-03-20 16:14:28 +0000153 displayBox(layoutBox) {
zalan@apple.comf5e498a2018-03-21 04:42:32 +0000154 return this.formattingState().displayBox(layoutBox);
zalan@apple.com4d9437e2018-03-17 04:34:02 +0000155 }
zalan@apple.comadf66182018-03-18 16:41:46 +0000156
zalan@apple.com589be6c2018-04-04 04:36:36 +0000157 _computeFloatingWidth(layoutBox) {
158 // FIXME: missing cases
159 this.displayBox(layoutBox).setWidth(Utils.width(layoutBox) + Utils.computedHorizontalBorderAndPadding(layoutBox.node()));
160 }
161
162 _computeFloatingHeight(layoutBox) {
163 // FIXME: missing cases
164 this.displayBox(layoutBox).setHeight(Utils.height(layoutBox) + Utils.computedVerticalBorderAndPadding(layoutBox.node()));
165 }
166
zalan@apple.comfc7c26d2018-04-10 17:21:50 +0000167 _placeInFlowPositionedChildren(container) {
168 if (!container.isContainer())
169 return;
170 // If this layoutBox also establishes a formatting context, then positioning already has happend at the formatting context.
171 if (container.establishesFormattingContext() && container != this.formattingRoot())
172 return;
173 ASSERT(container.isContainer());
174 for (let inFlowChild = container.firstInFlowChild(); inFlowChild; inFlowChild = inFlowChild.nextInFlowSibling()) {
175 if (!inFlowChild.isInFlowPositioned())
176 continue;
177 this._computeInFlowPositionedPosition(inFlowChild);
178 }
179 }
180
zalan@apple.com49fae342018-04-10 05:06:37 +0000181 _computeInFlowPositionedPosition(layoutBox) {
182 // Start with the original, static position.
183 let displayBox = this.displayBox(layoutBox);
184 let relativePosition = displayBox.topLeft();
185 // Top/bottom
186 if (!Utils.isTopAuto(layoutBox))
187 relativePosition.shiftTop(Utils.top(layoutBox));
188 else if (!Utils.isBottomAuto(layoutBox))
189 relativePosition.shiftTop(-Utils.bottom(layoutBox));
190 // Left/right
191 if (!Utils.isLeftAuto(layoutBox))
192 relativePosition.shiftLeft(Utils.left(layoutBox));
193 else if (!Utils.isRightAuto(layoutBox))
194 relativePosition.shiftLeft(-Utils.right(layoutBox));
195 displayBox.setTopLeft(relativePosition);
196 }
197
zalan@apple.comfc7c26d2018-04-10 17:21:50 +0000198 _computeInFlowWidth(layoutBox) {
199 if (Utils.isWidthAuto(layoutBox))
200 return this.displayBox(layoutBox).setWidth(this._horizontalConstraint(layoutBox));
201 return this.displayBox(layoutBox).setWidth(Utils.width(layoutBox) + Utils.computedHorizontalBorderAndPadding(layoutBox.node()));
202 }
203
204 _layoutOutOfFlowDescendants() {
205 // This lays out all the out-of-flow boxes that belong to this formatting context even if
206 // the root container is not the containing block.
207 let outOfFlowDescendants = this._outOfFlowDescendants();
208 for (let outOfFlowBox of outOfFlowDescendants) {
209 this._addToLayoutQueue(outOfFlowBox);
210 this._computeOutOfFlowWidth(outOfFlowBox);
zalan@apple.com5a5aa912018-04-13 03:09:03 +0000211 this.layoutState().formattingContext(outOfFlowBox).layout();
zalan@apple.comfc7c26d2018-04-10 17:21:50 +0000212 this._computeOutOfFlowHeight(outOfFlowBox);
213 this._computeOutOfFlowPosition(outOfFlowBox);
214 this._removeFromLayoutQueue(outOfFlowBox);
zalan@apple.com0d2ec3b2018-04-12 04:19:30 +0000215 this.formattingState().clearNeedsLayout(outOfFlowBox);
zalan@apple.com49fae342018-04-10 05:06:37 +0000216 }
217 }
218
zalan@apple.comfc7c26d2018-04-10 17:21:50 +0000219 _computeOutOfFlowWidth(layoutBox) {
220 // 10.3.7 Absolutely positioned, non-replaced elements
221
222 // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
223 // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing
224 // the static-position containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position.
225 // Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
226 // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
227 // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
228 // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
229 // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right'
230 let width = Number.NaN;
231 if (Utils.isWidthAuto(layoutBox) && Utils.isLeftAuto(layoutBox) && Utils.isRightAuto(layoutBox))
232 width = this._shrinkToFitWidth(layoutBox);
233 else if (Utils.isLeftAuto(layoutBox) && Utils.isWidthAuto(layoutBox) && !Utils.isRightAuto(layoutBox))
234 width = this._shrinkToFitWidth(layoutBox); // 1
235 else if (Utils.isLeftAuto(layoutBox) && Utils.isRightAuto(layoutBox) && !Utils.isWidthAuto(layoutBox))
236 width = Utils.width(layoutBox); // 2
237 else if (Utils.isWidthAuto(layoutBox) && Utils.isRightAuto(layoutBox) && !Utils.isLeftAuto(layoutBox))
238 width = this._shrinkToFitWidth(layoutBox); // 3
239 else if (Utils.isLeftAuto(layoutBox) && !Utils.isWidthAuto(layoutBox) && !Utils.isRightAuto(layoutBox))
240 width = Utils.width(layoutBox); // 4
241 else if (Utils.isWidthAuto(layoutBox) && !Utils.isLeftAuto(layoutBox) && !Utils.isRightAuto(layoutBox))
242 width = Math.max(0, this.displayBox(layoutBox.containingBlock()).contentBox().width() - Utils.right(layoutBox) - Utils.left(layoutBox)); // 5
243 else if (Utils.isRightAuto(layoutBox) && !Utils.isLeftAuto(layoutBox) && !Utils.isWidthAuto(layoutBox))
244 width = Utils.width(layoutBox); // 6
245 else
246 ASSERT_NOT_REACHED();
247 width += Utils.computedHorizontalBorderAndPadding(layoutBox.node());
248 this.displayBox(layoutBox).setWidth(width);
249 }
250
251 _computeOutOfFlowHeight(layoutBox) {
252 // 1. If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and apply rule number three below.
253 // 2. If none of the three are 'auto': If both 'margin-top' and 'margin-bottom' are 'auto', solve the equation under
254 // the extra constraint that the two margins get equal values. If one of 'margin-top' or 'margin-bottom' is 'auto',
255 // solve the equation for that value. If the values are over-constrained, ignore the value for 'bottom' and solve for that value.
256 // Otherwise, pick the one of the following six rules that applies.
257
258 // 3. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content per 10.6.7,
259 // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top'
260 // 4. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values
261 // for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'
262 // 5. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content per 10.6.7,
263 // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'
264 // 6. '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'
265 // 7. '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'
266 // 8. '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'
267 let height = Number.NaN;
268 if (Utils.isHeightAuto(layoutBox) && Utils.isBottomAuto(layoutBox) && Utils.isTopAuto(layoutBox))
269 height = this._contentHeight(layoutBox); // 1
270 else if (Utils.isTopAuto((layoutBox)) && Utils.isHeightAuto((layoutBox)) && !Utils.isBottomAuto((layoutBox)))
271 height = this._contentHeight(layoutBox); // 3
272 else if (Utils.isTopAuto((layoutBox)) && Utils.isBottomAuto((layoutBox)) && !Utils.isHeightAuto((layoutBox)))
273 height = Utils.height(layoutBox); // 4
274 else if (Utils.isHeightAuto((layoutBox)) && Utils.isBottomAuto((layoutBox)) && !Utils.isTopAuto((layoutBox)))
275 height = this._contentHeight(layoutBox); // 5
276 else if (Utils.isTopAuto((layoutBox)) && !Utils.isHeightAuto((layoutBox)) && !Utils.isBottomAuto((layoutBox)))
277 height = Utils.height(layoutBox); // 6
278 else if (Utils.isHeightAuto((layoutBox)) && !Utils.isTopAuto((layoutBox)) && !Utils.isBottomAuto((layoutBox)))
279 height = Math.max(0, this.displayBox(layoutBox.containingBlock()).contentBox().height() - Utils.bottom(layoutBox) - Utils.top(layoutBox)); // 7
280 else if (Utils.isBottomAuto((layoutBox)) && !Utils.isTopAuto((layoutBox)) && !Utils.isHeightAuto((layoutBox)))
281 height = Utils.height(layoutBox); // 8
282 else
283 ASSERT_NOT_REACHED();
284 height += Utils.computedVerticalBorderAndPadding(layoutBox.node());
285 this.displayBox(layoutBox).setHeight(height);
286 }
287
288 _computeOutOfFlowPosition(layoutBox) {
289 let displayBox = this.displayBox(layoutBox);
290 let top = Number.NaN;
291 let containerSize = this.displayBox(layoutBox.containingBlock()).contentBox().size();
292 // Top/bottom
293 if (Utils.isTopAuto(layoutBox) && Utils.isBottomAuto(layoutBox)) {
294 ASSERT(Utils.isStaticallyPositioned(layoutBox));
295 // Vertically statically positioned.
296 // FIXME: Figure out if it is actually valid that we use the parent box as the container (which is not even in this formatting context).
297 let parent = layoutBox.parent();
298 let parentDisplayBox = this.displayBox(parent);
299 let previousInFlowSibling = layoutBox.previousInFlowSibling();
300 let contentBottom = previousInFlowSibling ? this.displayBox(previousInFlowSibling).bottom() : parentDisplayBox.contentBox().top();
301 top = contentBottom + this.marginTop(layoutBox);
302 // Convert static position (in parent coordinate system) to absolute (in containing block coordindate system).
303 if (parent != layoutBox.containingBlock()) {
304 ASSERT(displayBox.parent() == this.displayBox(layoutBox.containingBlock()));
305 top += Utils.mapPosition(parentDisplayBox.topLeft(), parentDisplayBox, displayBox.parent()).top();
306 }
307 } else if (!Utils.isTopAuto(layoutBox))
308 top = Utils.top(layoutBox) + this.marginTop(layoutBox);
309 else if (!Utils.isBottomAuto(layoutBox))
310 top = containerSize.height() - Utils.bottom(layoutBox) - displayBox.height() - this.marginBottom(layoutBox);
311 else
312 ASSERT_NOT_REACHED();
313 // Left/right
314 let left = Number.NaN;
315 if (Utils.isLeftAuto(layoutBox) && Utils.isRightAuto(layoutBox)) {
316 ASSERT(Utils.isStaticallyPositioned(layoutBox));
317 // Horizontally statically positioned.
318 // FIXME: Figure out if it is actually valid that we use the parent box as the container (which is not even in this formatting context).
319 let parent = layoutBox.parent();
320 let parentDisplayBox = this.displayBox(parent);
321 left = parentDisplayBox.contentBox().left() + this.marginLeft(layoutBox);
322 // Convert static position (in parent coordinate system) to absolute (in containing block coordindate system).
323 if (parent != layoutBox.containingBlock()) {
324 ASSERT(displayBox.parent() == this.displayBox(layoutBox.containingBlock()));
325 left += Utils.mapPosition(parentDisplayBox.topLeft(), parentDisplayBox, displayBox.parent()).left();
326 }
327 } else if (!Utils.isLeftAuto(layoutBox))
328 left = Utils.left(layoutBox) + this.marginLeft(layoutBox);
329 else if (!Utils.isRightAuto(layoutBox))
330 left = containerSize.width() - Utils.right(layoutBox) - displayBox.width() - this.marginRight(layoutBox);
331 else
332 ASSERT_NOT_REACHED();
333 displayBox.setTopLeft(new LayoutPoint(top, left));
334 }
335
336 _shrinkToFitWidth(layoutBox) {
337 // FIXME: this is naive and missing the actual preferred width computation.
338 ASSERT(Utils.isWidthAuto(layoutBox));
339 if (!layoutBox.isContainer() || !layoutBox.hasChild())
340 return 0;
341 let width = 0;
342 for (let inFlowChild = layoutBox.firstInFlowChild(); inFlowChild; inFlowChild = inFlowChild.nextInFlowSibling()) {
343 let widthCandidate = Utils.isWidthAuto(inFlowChild) ? this._shrinkToFitWidth(inFlowChild) : Utils.width(inFlowChild);
344 width = Math.max(width, widthCandidate + Utils.computedHorizontalBorderAndPadding(inFlowChild.node()));
345 }
346 return width;
347 }
348
zalan@apple.comadf66182018-03-18 16:41:46 +0000349 _outOfFlowDescendants() {
350 // FIXME: This is highly inefficient but will do for now.
351 // 1. Collect all the out-of-flow descendants first.
352 // 2. Check if they are all belong to this formatting context.
353 // - either the root container is the containing block.
354 // - or a descendant of the root container is the containing block
355 // and there is not other formatting context inbetween.
356 let allOutOfFlowBoxes = new Array();
357 let descendants = new Array();
zalan@apple.comf5e498a2018-03-21 04:42:32 +0000358 for (let child = this.formattingRoot().firstChild(); child; child = child.nextSibling())
zalan@apple.comadf66182018-03-18 16:41:46 +0000359 descendants.push(child);
360 while (descendants.length) {
361 let descendant = descendants.pop();
362 if (descendant.isOutOfFlowPositioned())
363 allOutOfFlowBoxes.push(descendant);
364 if (!descendant.isContainer())
365 continue;
366 for (let child = descendant.lastChild(); child; child = child.previousSibling())
367 descendants.push(child);
368 }
369 let outOfFlowBoxes = new Array();
370 for (let outOfFlowBox of allOutOfFlowBoxes) {
371 let containingBlock = outOfFlowBox.containingBlock();
372 // Collect the out-of-flow descendant that belong to this formatting context.
zalan@apple.comf5e498a2018-03-21 04:42:32 +0000373 if (containingBlock == this.formattingRoot())
zalan@apple.comadf66182018-03-18 16:41:46 +0000374 outOfFlowBoxes.push(outOfFlowBox);
zalan@apple.comf5e498a2018-03-21 04:42:32 +0000375 else if (containingBlock.isDescendantOf(this.formattingRoot())) {
zalan@apple.comae809a72018-03-20 05:02:41 +0000376 if (!containingBlock.establishesFormattingContext() || !containingBlock.isPositioned())
zalan@apple.comadf66182018-03-18 16:41:46 +0000377 outOfFlowBoxes.push(outOfFlowBox);
378 }
379 }
380 return outOfFlowBoxes;
381 }
zalan@apple.comc6553172018-04-12 14:51:35 +0000382
383 _firstInFlowChildWithNeedsLayout(layoutBox) {
384 if (!layoutBox.isContainer())
385 return null;
386 for (let child = layoutBox.firstInFlowOrFloatChild(); child; child = child.nextInFlowOrFloatSibling()) {
387 if (this.formattingState().needsLayout(child))
388 return child;
389 }
390 return null;
391 }
392
393 _nextInFlowSiblingWithNeedsLayout(layoutBox) {
394 for (let sibling = layoutBox.nextInFlowOrFloatSibling(); sibling; sibling = sibling.nextInFlowOrFloatSibling()) {
395 if (this.formattingState().needsLayout(sibling))
396 return sibling;
397 }
398 return null;
399 }
zalan@apple.com903aad72018-03-09 19:10:37 +0000400}