54c530214f505635d1bb4374832493ec3f909926
[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_establishedFormattingContext = null;
38         this.m_displayBox = 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     nextInFlowOrFloatSibling() {
76         let nextInFlowSibling = this.nextSibling();
77         while (nextInFlowSibling) {
78             if (nextInFlowSibling.isInFlow() || nextInFlowSibling.isFloatingPositioned())
79                 return nextInFlowSibling;
80             nextInFlowSibling = nextInFlowSibling.nextSibling();
81         }
82         return null;
83     }
84
85     previousSibling() {
86         return this.m_previousSibling;
87     }
88
89     previousInFlowSibling() {
90         let previousInFlowSibling = this.previousSibling();
91         while (previousInFlowSibling) {
92             if (previousInFlowSibling.isInFlow())
93                 return previousInFlowSibling;
94             previousInFlowSibling = previousInFlowSibling.previousSibling();
95         }
96         return null;
97     }
98
99     setParent(parent) {
100         this.m_parent = parent;
101     }
102
103     setNextSibling(nextSibling) {
104         this.m_nextSibling = nextSibling;
105     }
106     
107     setPreviousSibling(previousSibling) {
108         this.m_previousSibling = previousSibling;
109     }
110
111     setDisplayBox(displayBox) {
112         ASSERT(!this.m_displayBox);
113         this.m_displayBox = displayBox;
114     }
115
116     displayBox() {
117         ASSERT(this.m_displayBox);
118         return this.m_displayBox;
119     }
120
121     rect() {
122         return this.displayBox().rect();
123     }
124
125     topLeft() {
126         return this.rect().topLeft();
127     }
128
129     bottomRight() {
130         return this.rect().bottomRight();
131     }
132
133     setTopLeft(topLeft) {
134         this.displayBox().setTopLeft(topLeft);
135     }
136
137     setSize(size) {
138         this.displayBox().setSize(size);
139     }
140
141     setWidth(width) {
142         this.displayBox().setWidth(width);
143     }
144
145     setHeight(height) {
146         this.displayBox().setHeight(height);
147     }
148
149     isContainer() {
150         return false;
151     }
152
153     isBlockLevelBox() {
154         return Utils.isBlockLevelElement(this.node());
155     }
156
157     isBlockContainerBox() {
158         return Utils.isBlockContainerElement(this.node());
159     }
160
161     isInlineLevelBox() {
162         return Utils.isInlineLevelElement(this.node());
163     }
164
165     setIsAnonymous() {
166         this.m_isAnonymous = true;
167     }
168
169     isAnonymous() {
170         return this.m_isAnonymous;
171     }
172
173     establishesFormattingContext() {
174         if (this.isAnonymous())
175             return false;
176         return this.establishesBlockFormattingContext() || this.establishesInlineFormattingContext();
177     }
178
179     establishedFormattingContext() {
180         if (this.establishesFormattingContext() && !this.m_establishedFormattingContext)
181             this.m_establishedFormattingContext = this.establishesBlockFormattingContext() ? new BlockFormattingContext(this) : new InlineFormattingContext(this);
182         return this.m_establishedFormattingContext;
183     }
184
185     establishesBlockFormattingContext() {
186         // 9.4.1 Block formatting contexts
187         // Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions)
188         // that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport)
189         // establish new block formatting contexts for their contents.
190         return this.isFloatingPositioned() || this.isAbsolutelyPositioned() || (this.isBlockContainerBox() && !this.isBlockLevelBox())
191             || (this.isBlockLevelBox() && !Utils.isOverflowVisible(this));
192     }
193
194     establishesInlineFormattingContext() {
195         return false;
196     }
197
198     isPositioned() {
199         return this.isOutOfFlowPositioned() || this.isRelativelyPositioned();
200     }
201
202     isRelativelyPositioned() {
203         return Utils.isRelativelyPositioned(this);
204     }
205
206     isAbsolutelyPositioned() {
207         return Utils.isAbsolutelyPositioned(this) || this.isFixedPositioned();
208     }
209
210     isFixedPositioned() {
211         return Utils.isFixedPositioned(this);
212     }
213
214     isInFlow() {
215         if (this.isAnonymous())
216             return true;
217         return !this.isFloatingOrOutOfFlowPositioned();
218     }
219
220     isOutOfFlowPositioned() {
221         return this.isAbsolutelyPositioned() || this.isFixedPositioned();
222     }
223
224     isInFlowPositioned() {
225         return this.isPositioned() && !this.isOutOfFlowPositioned();
226     }
227
228     isFloatingPositioned() {
229         return Utils.isFloatingPositioned(this);
230     }
231
232     isFloatingOrOutOfFlowPositioned() {
233         return this.isFloatingPositioned() || this.isOutOfFlowPositioned();
234     }
235
236     isRootBox() {
237         // FIXME: This should just be a simple instanceof check, but we are in the mainframe while the test document is in an iframe
238         // Let's just return root for both the RenderView and the <html> element.
239         return !this.parent() || !this.parent().parent();
240     }
241
242     containingBlock() {
243         if (!this.parent())
244             return null;
245         if (!this.isPositioned() || this.isInFlowPositioned())
246             return this.parent();
247         if (this.isAbsolutelyPositioned() && !this.isFixedPositioned()) {
248             let ascendant = this.parent();
249             while (ascendant.parent() && !ascendant.isPositioned())
250                 ascendant = ascendant.parent();
251             return ascendant;
252         }
253         if (this.isFixedPositioned()) {
254             let ascendant = this.parent();
255             while (ascendant.parent())
256                 ascendant = ascendant.parent();
257             return ascendant;
258         }
259         ASSERT_NOT_REACHED();
260         return null;
261     }
262
263     isDescendantOf(container) {
264         ASSERT(container);
265         let ascendant = this.parent();
266         while (ascendant && ascendant != container)
267             ascendant = ascendant.parent();
268         return !!ascendant;
269     }
270
271     borderBox() {
272         return this.displayBox().borderBox();
273     }
274
275     paddingBox() {
276         return this.displayBox().paddingBox();
277     }
278
279     contentBox() {
280         return this.displayBox().contentBox();
281     }
282 }