[LayoutReloaded] Move Display.Box handling from FormattingContext to FormattingState
[WebKit-https.git] / Tools / LayoutReloaded / FormattingContext / FormattingContext.js
1 /*
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
26 class FormattingContext {
27     constructor(rootContainer, layoutState) {
28         this.m_rootContainer = rootContainer;
29         this.m_layoutState = layoutState;
30         this.m_floatingContext = null;
31         this.m_layoutStack = new Array();
32     }
33
34     rootContainer() {
35         return this.m_rootContainer;
36     }
37
38     layoutState() {
39         return this.m_layoutState;
40     }
41
42     layoutContext() {
43         return this.layoutState().layoutContext();
44     }
45
46     floatingContext() {
47         return this.m_floatingContext;
48     }
49
50     layout() {
51         ASSERT_NOT_REACHED();
52     }
53
54     computeWidth(layoutBox) {
55     }
56
57     computeHeight(layoutBox) {
58     }
59
60     marginTop(layoutBox) {
61         return Utils.computedMarginTop(layoutBox.node());
62     }
63     
64     marginLeft(layoutBox) {
65         return Utils.computedMarginLeft(layoutBox.node());
66     }
67     
68     marginBottom(layoutBox) {
69         return Utils.computedMarginBottom(layoutBox.node());
70     }
71     
72     marginRight(layoutBox) {
73         return Utils.computedMarginRight(layoutBox.node());
74     }
75
76     absoluteMarginBox(layoutBox) {
77         let displayBox = this.displayBox(layoutBox);
78         let absoluteContentBox = new LayoutRect(this._toRootAbsolutePosition(layoutBox), displayBox.size());
79         absoluteContentBox.moveBy(new LayoutSize(-this.marginLeft(layoutBox), -this.marginTop(layoutBox)));
80         absoluteContentBox.growBy(new LayoutSize(this.marginLeft(layoutBox) + this.marginRight(layoutBox), this.marginTop(layoutBox) + this.marginBottom(layoutBox)));
81         return absoluteContentBox;
82     }
83
84     absoluteBorderBox(layoutBox) {
85         let borderBox = this.displayBox(layoutBox).borderBox();
86         let absoluteRect = new LayoutRect(this._toRootAbsolutePosition(layoutBox), borderBox.size());
87         absoluteRect.moveBy(borderBox.topLeft());
88         return absoluteRect;
89     }
90
91     absolutePaddingBox(layoutBox) {
92         let paddingBox = this.displayBox(layoutBox).paddingBox();
93         let absoluteRect = new LayoutRect(this._toRootAbsolutePosition(layoutBox), paddingBox.size());
94         absoluteRect.moveBy(paddingBox.topLeft());
95         return absoluteRect;
96     }
97
98     absoluteContentBox(layoutBox) {
99         let contentBox = this.displayBox(layoutBox).contentBox();
100         let absoluteRect = new LayoutRect(this._toRootAbsolutePosition(layoutBox), contentBox.size());
101         absoluteRect.moveBy(contentBox.topLeft());
102         return absoluteRect;
103     }
104
105     _toAbsolutePosition(position, layoutBox, container) {
106         // We should never need to go beyond the root container.
107         ASSERT(container == this.rootContainer() || container.isDescendantOf(this.rootContainer()));
108         let absolutePosition = position;
109         let ascendant = layoutBox.containingBlock();
110         while (ascendant && ascendant != container) {
111             ASSERT(ascendant.isDescendantOf(this.rootContainer()));
112             absolutePosition.moveBy(this.displayBox(ascendant).topLeft());
113             ascendant = ascendant.containingBlock();
114         }
115         return absolutePosition;
116     }
117
118     _toRootAbsolutePosition(layoutBox) {
119         return this._toAbsolutePosition(this.displayBox(layoutBox).topLeft(), layoutBox, this.rootContainer());
120     }
121
122     _descendantNeedsLayout() {
123         return this.m_layoutStack.length;
124     }
125
126     _addToLayoutQueue(layoutBox) {
127         // Initialize the corresponding display box.
128         this.layoutState().createDisplayBox(layoutBox);
129         this.m_layoutStack.push(layoutBox);
130     }
131
132     _nextInLayoutQueue() {
133         ASSERT(this.m_layoutStack.length);
134         return this.m_layoutStack[this.m_layoutStack.length - 1];
135     }
136
137     _removeFromLayoutQueue(layoutBox) {
138         // With the current layout logic, the layoutBox should be at the top (this.m_layoutStack.pop() should do).
139         ASSERT(this.m_layoutStack.length);
140         ASSERT(this.m_layoutStack[this.m_layoutStack.length - 1] == layoutBox);
141         this.m_layoutStack.splice(this.m_layoutStack.indexOf(layoutBox), 1);
142     }
143
144     displayBox(layoutBox) {
145         return this.layoutState().displayBox(layoutBox);
146     }
147
148     _outOfFlowDescendants() {
149         // FIXME: This is highly inefficient but will do for now.
150         // 1. Collect all the out-of-flow descendants first.
151         // 2. Check if they are all belong to this formatting context.
152         //    - either the root container is the containing block.
153         //    - or a descendant of the root container is the containing block
154         //      and there is not other formatting context inbetween.
155         let allOutOfFlowBoxes = new Array();
156         let descendants = new Array();
157         for (let child = this.rootContainer().firstChild(); child; child = child.nextSibling())
158             descendants.push(child);
159         while (descendants.length) {
160             let descendant = descendants.pop();
161             if (descendant.isOutOfFlowPositioned())
162                 allOutOfFlowBoxes.push(descendant);
163             if (!descendant.isContainer())
164                 continue;
165             for (let child = descendant.lastChild(); child; child = child.previousSibling())
166                 descendants.push(child);
167         }
168         let outOfFlowBoxes = new Array();
169         for (let outOfFlowBox of allOutOfFlowBoxes) {
170             let containingBlock = outOfFlowBox.containingBlock();
171             // Collect the out-of-flow descendant that belong to this formatting context.
172             if (containingBlock == this.rootContainer())
173                 outOfFlowBoxes.push(outOfFlowBox);
174             else if (containingBlock.isDescendantOf(this.rootContainer())) {
175                 if (!containingBlock.establishesFormattingContext() || !containingBlock.isPositioned())
176                     outOfFlowBoxes.push(outOfFlowBox);
177             }
178         }
179         return outOfFlowBoxes;
180     }
181
182 }