[LFC][IFC] Add generic inline line breaker
[WebKit-https.git] / Source / WebCore / layout / LayoutContext.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 "LayoutContext.h"
28
29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31 #include "BlockFormattingContext.h"
32 #include "BlockFormattingState.h"
33 #include "BlockInvalidation.h"
34 #include "DisplayBox.h"
35 #include "InlineFormattingContext.h"
36 #include "InlineFormattingState.h"
37 #include "InlineInvalidation.h"
38 #include "Invalidation.h"
39 #include "LayoutBox.h"
40 #include "LayoutContainer.h"
41 #include <wtf/IsoMallocInlines.h>
42
43 namespace WebCore {
44 namespace Layout {
45
46 WTF_MAKE_ISO_ALLOCATED_IMPL(LayoutContext);
47
48 LayoutContext::LayoutContext()
49 {
50 }
51
52 void LayoutContext::initializeRoot(const Container& root, const LayoutSize& containerSize)
53 {
54     ASSERT(root.establishesFormattingContext());
55
56     m_root = makeWeakPtr(root);
57     auto& displayBox = displayBoxForLayoutBox(root);
58
59     // FIXME: m_root could very well be a formatting context root with ancestors and resolvable border and padding (as opposed to the topmost root)
60     displayBox.setHorizontalMargin({ });
61     displayBox.setHorizontalNonComputedMargin({ });
62     displayBox.setVerticalMargin({ });
63     displayBox.setVerticalNonCollapsedMargin({ });
64     displayBox.setBorder({ });
65     displayBox.setPadding({ });
66     displayBox.setContentBoxHeight(containerSize.height());
67     displayBox.setContentBoxWidth(containerSize.width());
68     displayBox.setTopLeft({ });
69
70     m_formattingContextRootListForLayout.add(&root);
71 }
72
73 void LayoutContext::updateLayout()
74 {
75     ASSERT(!m_formattingContextRootListForLayout.isEmpty());
76     for (auto* layoutRoot : m_formattingContextRootListForLayout)
77         layoutFormattingContextSubtree(*layoutRoot);
78     m_formattingContextRootListForLayout.clear();
79 }
80
81 void LayoutContext::layoutFormattingContextSubtree(const Box& layoutRoot)
82 {
83     RELEASE_ASSERT(layoutRoot.establishesFormattingContext());
84     auto formattingContext = this->formattingContext(layoutRoot);
85     auto& formattingState = createFormattingStateForFormattingRootIfNeeded(layoutRoot);
86     formattingContext->layout(*this, formattingState);
87     formattingContext->layoutOutOfFlowDescendants(*this, layoutRoot);
88 }
89
90 Display::Box& LayoutContext::displayBoxForLayoutBox(const Box& layoutBox) const
91 {
92     return *m_layoutToDisplayBox.ensure(&layoutBox, [&layoutBox] {
93         return std::make_unique<Display::Box>(layoutBox.style());
94     }).iterator->value;
95 }
96
97 void LayoutContext::styleChanged(const Box& layoutBox, StyleDiff styleDiff)
98 {
99     auto& formattingState = formattingStateForBox(layoutBox);
100     const Container* invalidationRoot = nullptr;
101     if (is<BlockFormattingState>(formattingState))
102         invalidationRoot = BlockInvalidation::invalidate(layoutBox, styleDiff, *this, downcast<BlockFormattingState>(formattingState)).root;
103     else if (is<InlineFormattingState>(formattingState))
104         invalidationRoot = InlineInvalidation::invalidate(layoutBox, styleDiff, *this, downcast<InlineFormattingState>(formattingState)).root;
105     else
106         ASSERT_NOT_IMPLEMENTED_YET();
107     ASSERT(invalidationRoot);
108     m_formattingContextRootListForLayout.addVoid(invalidationRoot);
109 }
110
111 void LayoutContext::markNeedsUpdate(const Box&, OptionSet<UpdateType>)
112 {
113 }
114
115 FormattingState& LayoutContext::formattingStateForBox(const Box& layoutBox) const
116 {
117     auto& root = layoutBox.formattingContextRoot();
118     RELEASE_ASSERT(m_formattingStates.contains(&root));
119     return *m_formattingStates.get(&root);
120 }
121
122 FormattingState& LayoutContext::establishedFormattingState(const Box& formattingRoot) const
123 {
124     ASSERT(formattingRoot.establishesFormattingContext());
125     RELEASE_ASSERT(m_formattingStates.contains(&formattingRoot));
126     return *m_formattingStates.get(&formattingRoot);
127 }
128
129 FormattingState& LayoutContext::createFormattingStateForFormattingRootIfNeeded(const Box& formattingRoot)
130 {
131     ASSERT(formattingRoot.establishesFormattingContext());
132
133     if (formattingRoot.establishesInlineFormattingContext()) {
134         return *m_formattingStates.ensure(&formattingRoot, [&] {
135
136             // If the block container box that initiates this inline formatting context also establishes a block context, the floats outside of the formatting root
137             // should not interfere with the content inside.
138             // <div style="float: left"></div><div style="overflow: hidden"> <- is a non-intrusive float, because overflow: hidden triggers new block formatting context.</div>
139             if (formattingRoot.establishesBlockFormattingContext())
140                 return std::make_unique<InlineFormattingState>(FloatingState::create(*this, formattingRoot), *this);
141
142             // Otherwise, the formatting context inherits the floats from the parent formatting context.
143             // Find the formatting state in which this formatting root lives, not the one it creates and use its floating state.
144             return std::make_unique<InlineFormattingState>(formattingStateForBox(formattingRoot).floatingState(), *this);
145         }).iterator->value;
146     }
147
148     if (formattingRoot.establishesBlockFormattingContext()) {
149         return *m_formattingStates.ensure(&formattingRoot, [&] {
150
151             // Block formatting context always establishes a new floating state.
152             return std::make_unique<BlockFormattingState>(FloatingState::create(*this, formattingRoot), *this);
153         }).iterator->value;
154     }
155
156     CRASH();
157 }
158
159 std::unique_ptr<FormattingContext> LayoutContext::formattingContext(const Box& formattingContextRoot) const
160 {
161     if (formattingContextRoot.establishesBlockFormattingContext())
162         return std::make_unique<BlockFormattingContext>(formattingContextRoot);
163
164     if (formattingContextRoot.establishesInlineFormattingContext())
165         return std::make_unique<InlineFormattingContext>(formattingContextRoot);
166
167     ASSERT_NOT_IMPLEMENTED_YET();
168     return nullptr;
169 }
170
171 }
172 }
173
174 #endif