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