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.
28 Layout.Box = class Box {
29 constructor(node, id) {
31 this.m_rendererName = 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;
45 setRendererName(name) {
46 this.m_rendererName = name;
50 return this.m_rendererName;
62 return this.m_nextSibling;
66 let nextInFlowSibling = this.nextSibling();
67 while (nextInFlowSibling) {
68 if (nextInFlowSibling.isInFlow())
69 return nextInFlowSibling;
70 nextInFlowSibling = nextInFlowSibling.nextSibling();
75 nextInFlowOrFloatSibling() {
76 let nextInFlowSibling = this.nextSibling();
77 while (nextInFlowSibling) {
78 if (nextInFlowSibling.isInFlow() || nextInFlowSibling.isFloatingPositioned())
79 return nextInFlowSibling;
80 nextInFlowSibling = nextInFlowSibling.nextSibling();
86 return this.m_previousSibling;
89 previousInFlowSibling() {
90 let previousInFlowSibling = this.previousSibling();
91 while (previousInFlowSibling) {
92 if (previousInFlowSibling.isInFlow())
93 return previousInFlowSibling;
94 previousInFlowSibling = previousInFlowSibling.previousSibling();
100 this.m_parent = parent;
103 setNextSibling(nextSibling) {
104 this.m_nextSibling = nextSibling;
107 setPreviousSibling(previousSibling) {
108 this.m_previousSibling = previousSibling;
111 setDisplayBox(displayBox) {
112 ASSERT(!this.m_displayBox);
113 this.m_displayBox = displayBox;
117 ASSERT(this.m_displayBox);
118 return this.m_displayBox;
122 return this.displayBox().rect();
126 return this.rect().topLeft();
130 return this.rect().bottomRight();
133 setTopLeft(topLeft) {
134 this.displayBox().setTopLeft(topLeft);
138 this.displayBox().setSize(size);
142 this.displayBox().setWidth(width);
146 this.displayBox().setHeight(height);
154 return Utils.isBlockLevelElement(this.node());
157 isBlockContainerBox() {
158 return Utils.isBlockContainerElement(this.node());
162 return Utils.isInlineLevelElement(this.node());
166 this.m_isAnonymous = true;
170 return this.m_isAnonymous;
173 establishesFormattingContext() {
174 if (this.isAnonymous())
176 return this.establishesBlockFormattingContext() || this.establishesInlineFormattingContext();
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;
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));
194 establishesInlineFormattingContext() {
199 return this.isOutOfFlowPositioned() || this.isRelativelyPositioned();
202 isRelativelyPositioned() {
203 return Utils.isRelativelyPositioned(this);
206 isAbsolutelyPositioned() {
207 return Utils.isAbsolutelyPositioned(this) || this.isFixedPositioned();
210 isFixedPositioned() {
211 return Utils.isFixedPositioned(this);
215 if (this.isAnonymous())
217 return !this.isFloatingOrOutOfFlowPositioned();
220 isOutOfFlowPositioned() {
221 return this.isAbsolutelyPositioned() || this.isFixedPositioned();
224 isInFlowPositioned() {
225 return this.isPositioned() && !this.isOutOfFlowPositioned();
228 isFloatingPositioned() {
229 return Utils.isFloatingPositioned(this);
232 isFloatingOrOutOfFlowPositioned() {
233 return this.isFloatingPositioned() || this.isOutOfFlowPositioned();
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();
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();
253 if (this.isFixedPositioned()) {
254 let ascendant = this.parent();
255 while (ascendant.parent())
256 ascendant = ascendant.parent();
259 ASSERT_NOT_REACHED();
263 isDescendantOf(container) {
265 let ascendant = this.parent();
266 while (ascendant && ascendant != container)
267 ascendant = ascendant.parent();
272 return this.displayBox().borderBox();
276 return this.displayBox().paddingBox();
280 return this.displayBox().contentBox();