44797af8ec71a028e68baee13d31282f54f0f65a
[WebKit-https.git] / Source / WebCore / layout / layouttree / LayoutBox.cpp
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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "LayoutBox.h"
28
29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31 #include "RenderStyle.h"
32 #include <wtf/IsoMallocInlines.h>
33
34 namespace WebCore {
35 namespace Layout {
36
37 WTF_MAKE_ISO_ALLOCATED_IMPL(Box);
38
39 Box::Box(RenderStyle&& style, BaseTypeFlags baseTypeFlags)
40     : m_style(WTFMove(style))
41     , m_baseTypeFlags(baseTypeFlags)
42     , m_isAnonymous(false)
43 {
44 }
45
46 Box::~Box()
47 {
48 }
49
50 bool Box::establishesFormattingContext() const
51 {
52     return establishesBlockFormattingContext() || establishesInlineFormattingContext();
53 }
54
55 bool Box::establishesBlockFormattingContext() const
56 {
57     // Initial Containing Block always creates a new (inital) block formatting context.
58     if (!parent())
59         return true;
60     // 9.4.1 Block formatting contexts
61     // Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions)
62     // that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport)
63     // establish new block formatting contexts for their contents.
64     if (isFloatingPositioned() || isAbsolutelyPositioned())
65         return true;
66     if (isBlockContainerBox() && !isBlockLevelBox())
67         return true;
68     if (isBlockLevelBox() && !isOverflowVisible())
69         return true;
70     return false;
71 }
72
73 bool Box::isRelativelyPositioned() const
74 {
75     return m_style.position() == RelativePosition;
76 }
77
78 bool Box::isStickyPositioned() const
79 {
80     return m_style.position() == StickyPosition;
81 }
82
83 bool Box::isAbsolutelyPositioned() const
84 {
85     return m_style.position() == AbsolutePosition;
86 }
87
88 bool Box::isFixedPositioned() const
89 {
90     return m_style.position() == FixedPosition;
91 }
92
93 bool Box::isFloatingPositioned() const
94 {
95     return m_style.floating() != NoFloat;
96 }
97
98 const Container* Box::containingBlock() const
99 {
100     // The containing block in which the root element lives is a rectangle called the initial containing block.
101     // For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the
102     // content edge of the nearest block container ancestor box.
103     // If the element has 'position: fixed', the containing block is established by the viewport
104     // If the element has 'position: absolute', the containing block is established by the nearest ancestor with a
105     // 'position' of 'absolute', 'relative' or 'fixed'.
106     if (!parent())
107         return nullptr;
108
109     if (!isPositioned() || isInFlowPositioned()) {
110         auto* nearestBlockContainer = parent();
111         for (; nearestBlockContainer->parent() && !nearestBlockContainer->isBlockContainerBox(); nearestBlockContainer = nearestBlockContainer->parent()) { }
112         return nearestBlockContainer;
113     }
114
115     if (isFixedPositioned()) {
116         auto* initialContainingBlock = parent();
117         for (; initialContainingBlock->parent(); initialContainingBlock = initialContainingBlock->parent()) { }
118         return initialContainingBlock;
119     }
120
121     if (isOutOfFlowPositioned()) {
122         auto* positionedAncestor = parent();
123         for (; positionedAncestor->parent() && !positionedAncestor->isPositioned(); positionedAncestor = positionedAncestor->parent()) { }
124         return positionedAncestor;
125     }
126
127     ASSERT_NOT_REACHED();
128     return nullptr;
129 }
130
131 const Container& Box::formattingContextRoot() const
132 {
133     for (auto* ancestor = containingBlock(); ancestor; ancestor = ancestor->containingBlock()) {
134         if (ancestor->establishesFormattingContext())
135             return *ancestor;
136     }
137
138     // Initial containing block always establishes a formatting context.
139     if (isInitialContainingBlock())
140         return downcast<Container>(*this);
141     RELEASE_ASSERT_NOT_REACHED();
142 }
143
144 bool Box::isDescendantOf(Container& container) const
145 {
146     auto* ancestor = parent();
147     for (; ancestor && ancestor != &container; ancestor = ancestor->parent()) { }
148     return ancestor;
149 }
150
151 bool Box::isInlineBlockBox() const
152 {
153     return m_style.display() == INLINE_BLOCK;
154 }
155
156 bool Box::isBlockLevelBox() const
157 {
158     // Block level elements generate block level boxes.
159     auto display = m_style.display();
160     return display == BLOCK || display == LIST_ITEM || display == TABLE;
161 }
162
163 bool Box::isInlineLevelBox() const
164 {
165     // Inline level elements generate inline level boxes.
166     auto display = m_style.display();
167     return display == INLINE || display == INLINE_BLOCK || display == INLINE_TABLE;
168 }
169
170 bool Box::isBlockContainerBox() const
171 {
172     // Inline level elements generate inline level boxes.
173     auto display = m_style.display();
174     return display == BLOCK || display == LIST_ITEM || display == INLINE_BLOCK || display == TABLE_CELL || display == TABLE_CAPTION; // TODO && !replaced element
175 }
176
177 bool Box::isInitialContainingBlock() const
178 {
179     return !parent();
180 }
181
182 const Box* Box::nextInFlowSibling() const
183 {
184     if (auto* nextSibling = this->nextSibling()) {
185         if (nextSibling->isInFlow())
186             return nextSibling;
187         return nextSibling->nextInFlowSibling();
188     }
189     return nullptr;
190 }
191
192 const Box* Box::nextInFlowOrFloatingSibling() const
193 {
194     if (auto* nextSibling = this->nextSibling()) {
195         if (nextSibling->isInFlow() || nextSibling->isFloatingPositioned())
196             return nextSibling;
197         return nextSibling->nextInFlowSibling();
198     }
199     return nullptr;
200 }
201
202 const Box* Box::previousInFlowSibling() const
203 {
204     if (auto* previousSibling = this->previousSibling()) {
205         if (previousSibling->isInFlow())
206             return previousSibling;
207         return previousSibling->previousInFlowSibling();
208     }
209     return nullptr;
210 }
211
212 const Box* Box::previousInFlowOrFloatingSibling() const
213 {
214     if (auto* previousSibling = this->previousSibling()) {
215         if (previousSibling->isInFlow() || previousSibling->isFloatingPositioned())
216             return previousSibling;
217         return previousSibling->previousInFlowOrFloatingSibling();
218     }
219     return nullptr;
220 }
221
222 bool Box::isOverflowVisible() const
223 {
224     return m_style.overflowX() == OVISIBLE || m_style.overflowY() == OVISIBLE;
225 }
226
227 }
228 }
229
230 #endif