2 * Copyright (C) 2018 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 class FormattingContext {
27 constructor(formattingState) {
28 this.m_formattingState = formattingState;
29 this.m_floatingContext = new FloatingContext(formattingState.floatingState(), this);
30 this.m_layoutStack = new Array();
34 return this.m_formattingState.formattingRoot();
38 return this.m_formattingState;
42 return this.formattingState().layoutState();
46 return this.m_floatingContext;
53 computeWidth(layoutBox) {
56 computeHeight(layoutBox) {
59 marginTop(layoutBox) {
60 return Utils.computedMarginTop(layoutBox.node());
63 marginLeft(layoutBox) {
64 return Utils.computedMarginLeft(layoutBox.node());
67 marginBottom(layoutBox) {
68 return Utils.computedMarginBottom(layoutBox.node());
71 marginRight(layoutBox) {
72 return Utils.computedMarginRight(layoutBox.node());
75 _descendantNeedsLayout() {
76 return this.m_layoutStack.length;
79 _addToLayoutQueue(layoutBox) {
80 // Initialize the corresponding display box.
81 let displayBox = this.formattingState().createDisplayBox(layoutBox, this);
82 if (layoutBox.node()) {
83 displayBox.setMarginTop(this.marginTop(layoutBox));
84 displayBox.setMarginLeft(this.marginLeft(layoutBox));
85 displayBox.setMarginBottom(this.marginBottom(layoutBox));
86 displayBox.setMarginRight(this.marginRight(layoutBox));
89 this.m_layoutStack.push(layoutBox);
92 _nextInLayoutQueue() {
93 ASSERT(this.m_layoutStack.length);
94 return this.m_layoutStack[this.m_layoutStack.length - 1];
97 _removeFromLayoutQueue(layoutBox) {
98 // With the current layout logic, the layoutBox should be at the top (this.m_layoutStack.pop() should do).
99 ASSERT(this.m_layoutStack.length);
100 ASSERT(this.m_layoutStack[this.m_layoutStack.length - 1] == layoutBox);
101 this.m_layoutStack.splice(this.m_layoutStack.indexOf(layoutBox), 1);
104 displayBox(layoutBox) {
105 return this.formattingState().displayBox(layoutBox);
108 _outOfFlowDescendants() {
109 // FIXME: This is highly inefficient but will do for now.
110 // 1. Collect all the out-of-flow descendants first.
111 // 2. Check if they are all belong to this formatting context.
112 // - either the root container is the containing block.
113 // - or a descendant of the root container is the containing block
114 // and there is not other formatting context inbetween.
115 let allOutOfFlowBoxes = new Array();
116 let descendants = new Array();
117 for (let child = this.formattingRoot().firstChild(); child; child = child.nextSibling())
118 descendants.push(child);
119 while (descendants.length) {
120 let descendant = descendants.pop();
121 if (descendant.isOutOfFlowPositioned())
122 allOutOfFlowBoxes.push(descendant);
123 if (!descendant.isContainer())
125 for (let child = descendant.lastChild(); child; child = child.previousSibling())
126 descendants.push(child);
128 let outOfFlowBoxes = new Array();
129 for (let outOfFlowBox of allOutOfFlowBoxes) {
130 let containingBlock = outOfFlowBox.containingBlock();
131 // Collect the out-of-flow descendant that belong to this formatting context.
132 if (containingBlock == this.formattingRoot())
133 outOfFlowBoxes.push(outOfFlowBox);
134 else if (containingBlock.isDescendantOf(this.formattingRoot())) {
135 if (!containingBlock.establishesFormattingContext() || !containingBlock.isPositioned())
136 outOfFlowBoxes.push(outOfFlowBox);
139 return outOfFlowBoxes;