[LayoutReloaded] Introduce Layout namespace
[WebKit-https.git] / Tools / LayoutReloaded / LayoutTree / Box.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 var Layout = { }
27
28 Layout.Box = class Box {
29     constructor(node, id) {
30         this.m_id = id;
31         this.m_rendererName = null;
32         this.m_node = node;
33         this.m_parent = null;
34         this.m_nextSibling = null;
35         this.m_previousSibling = null;
36         this.m_isAnonymous = false;
37         this.m_rect = new LayoutRect(new LayoutPoint(0, 0), new LayoutSize(0, 0));
38         this.m_establishedFormattingContext = null;
39     }
40
41     id() {
42         return this.m_id;
43     }
44
45     setRendererName(name) {
46         this.m_rendererName = name;
47     }
48
49     name() {
50         return this.m_rendererName;
51     }
52
53     node() {
54         return this.m_node;
55     }
56
57     parent() {
58         return this.m_parent;
59     }
60
61     nextSibling() {
62         return this.m_nextSibling;
63     }
64
65     nextInFlowSibling() {
66         let nextInFlowSibling = this.nextSibling();
67         while (nextInFlowSibling) {
68             if (nextInFlowSibling.isInFlow())
69                 return nextInFlowSibling;
70             nextInFlowSibling = nextInFlowSibling.nextSibling();
71         }
72         return null;
73     }
74
75     previousSibling() {
76         return this.m_previousSibling;
77     }
78
79     previousInFlowSibling() {
80         let previousInFlowSibling = this.previousSibling();
81         while (previousInFlowSibling) {
82             if (previousInFlowSibling.isInFlow())
83                 return previousInFlowSibling;
84             previousInFlowSibling = previousInFlowSibling.previousSibling();
85         }
86         return null;
87     }
88
89     setParent(parent) {
90         this.m_parent = parent;
91     }
92
93     setNextSibling(nextSibling) {
94         this.m_nextSibling = nextSibling;
95     }
96     
97     setPreviousSibling(previousSibling) {
98         this.m_previousSibling = previousSibling;
99     }
100
101     rect() {
102         return this.m_rect.clone();
103     }
104
105     topLeft() {
106         return this.rect().topLeft();
107     }
108
109     bottomRight() {
110         return this.rect().bottomRight();
111     }
112
113     setTopLeft(topLeft) {
114         this.m_rect.setTopLeft(topLeft);
115     }
116
117     setSize(size) {
118         this.m_rect.setSize(size);
119     }
120
121     setWidth(width) {
122         this.m_rect.setWidth(width);
123     }
124
125     setHeight(height) {
126         this.m_rect.setHeight(height);
127     }
128
129     isContainer() {
130         return false;
131     }
132
133     isBlockLevelBox() {
134         return Utils.isBlockLevelElement(this.node());
135     }
136
137     isBlockContainerBox() {
138         return Utils.isBlockContainerElement(this.node());
139     }
140
141     isInlineLevelBox() {
142         return Utils.isInlineLevelElement(this.node());
143     }
144
145     setIsAnonymous() {
146         this.m_isAnonymous = true;
147     }
148
149     isAnonymous() {
150         return this.m_isAnonymous;
151     }
152
153     establishesFormattingContext() {
154         if (this.isAnonymous())
155             return false;
156         return this.establishesBlockFormattingContext() || this.establishesInlineFormattingContext();
157     }
158
159     establishedFormattingContext() {
160         if (this.establishesFormattingContext() && !this.m_establishedFormattingContext)
161             this.m_establishedFormattingContext = this.establishesBlockFormattingContext() ? new BlockFormattingContext(this) : new InlineFormattingContext(this);
162         return this.m_establishedFormattingContext;
163     }
164
165     establishesBlockFormattingContext() {
166         // 9.4.1 Block formatting contexts
167         // Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions)
168         // that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport)
169         // establish new block formatting contexts for their contents.
170         return this.isFloatingPositioned() || this.isAbsolutePositioned() || (this.isBlockContainerBox() && !this.isBlockLevelBox())
171             || (this.isBlockLevelBox() && !Utils.isOverflowVisible(this));
172     }
173
174     establishesInlineFormattingContext() {
175         return false;
176     }
177
178     isPositioned() {
179         return this.isOutOfFlowPositioned() || this.isRelativePositioned();
180     }
181
182     isRelativePositioned() {
183         return Utils.isRelativePositioned(this);
184     }
185
186     isAbsolutePositioned() {
187         return Utils.isAbsolutePositioned(this);
188     }
189
190     isFixedPositioned() {
191         return Utils.isFixedPositioned(this);
192     }
193
194     isInFlow() {
195         if (this.isAnonymous())
196             return true;
197         return !this.isFloatingOrOutOfFlowPositioned();
198     }
199
200     isOutOfFlowPositioned() {
201         return this.isAbsolutePositioned() || this.isFixedPositioned();
202     }
203
204     isInFlowPositioned() {
205         return this.isPositioned() && !this.isOutOfFlowPositioned();
206     }
207
208     isFloatingPositioned() {
209         return Utils.isFloatingPositioned(this);
210     }
211
212     isFloatingOrOutOfFlowPositioned() {
213         return this.isFloatingPositioned() || this.isOutOfFlowPositioned();
214     }
215
216     isRootElement() {
217         // FIXME: This should just be a simple instanceof check, but we are in the mainframe while the test document is in an iframe
218         // Let's just return root for both the RenderView and the <html> element.
219         return !this.parent() || !this.parent().parent();
220     }
221
222     containingBlock() {
223         if (!this.parent())
224             return null;
225         if (!this.isPositioned() || this.isInFlowPositioned())
226             return this.parent();
227         let parent = this.parent();
228         while (parent.parent()) {
229             if (this.isAbsolutePositioned() && parent.isPositioned())
230                 return parent;
231             parent = parent.parent();
232         }
233         return parent;
234     }
235
236     borderBox() {
237         return new LayoutRect(new LayoutPoint(0, 0), this.rect().size());
238     }
239
240     paddingBox() {
241         let paddingBox = this.borderBox();
242         let borderSize = Utils.computedBorderTopLeft(this);
243         paddingBox.moveBy(borderSize);
244         paddingBox.shrinkBy(borderSize);
245         paddingBox.shrinkBy(Utils.computedBorderBottomRight(this));
246         return paddingBox;
247     }
248
249     contentBox() {
250         let contentBox = this.paddingBox();
251         let paddingSize = Utils.computedPaddingTopLeft(this);
252         contentBox.moveBy(paddingSize);
253         contentBox.shrinkBy(paddingSize);
254         contentBox.shrinkBy(Utils.computedPaddingBottomRight(this));
255         return contentBox;
256     }
257 }