[CSSRegions] Use auto keyword to clean-up for loops
[WebKit-https.git] / Source / WebCore / rendering / FlowThreadController.cpp
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. 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  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "config.h"
31
32 #include "FlowThreadController.h"
33
34 #include "NamedFlowCollection.h"
35 #include "RenderFlowThread.h"
36 #include "RenderLayer.h"
37 #include "RenderNamedFlowThread.h"
38 #include "StyleInheritedData.h"
39 #include "WebKitNamedFlow.h"
40 #include <wtf/text/AtomicString.h>
41
42 namespace WebCore {
43
44 PassOwnPtr<FlowThreadController> FlowThreadController::create(RenderView* view)
45 {
46     return adoptPtr(new FlowThreadController(view));
47 }
48
49 FlowThreadController::FlowThreadController(RenderView* view)
50     : m_view(view)
51     , m_currentRenderFlowThread(0)
52     , m_isRenderNamedFlowThreadOrderDirty(false)
53     , m_flowThreadsWithAutoLogicalHeightRegions(0)
54 {
55 }
56
57 FlowThreadController::~FlowThreadController()
58 {
59 }
60
61 RenderNamedFlowThread& FlowThreadController::ensureRenderFlowThreadWithName(const AtomicString& name)
62 {
63     if (!m_renderNamedFlowThreadList)
64         m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList());
65     else {
66         for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
67             RenderNamedFlowThread* flowRenderer = *iter;
68             if (flowRenderer->flowThreadName() == name)
69                 return *flowRenderer;
70         }
71     }
72
73     NamedFlowCollection* namedFlows = m_view->document().namedFlows();
74
75     // Sanity check for the absence of a named flow in the "CREATED" state with the same name.
76     ASSERT(!namedFlows->flowByName(name));
77
78     auto flowRenderer = new RenderNamedFlowThread(m_view->document(), RenderFlowThread::createFlowThreadStyle(&m_view->style()), namedFlows->ensureFlowWithName(name));
79     flowRenderer->initializeStyle();
80     m_renderNamedFlowThreadList->add(flowRenderer);
81
82     // Keep the flow renderer as a child of RenderView.
83     m_view->addChild(flowRenderer);
84
85     setIsRenderNamedFlowThreadOrderDirty(true);
86
87     return *flowRenderer;
88 }
89
90 void FlowThreadController::styleDidChange()
91 {
92     RenderStyle& viewStyle = m_view->style();
93     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
94         RenderNamedFlowThread* flowRenderer = *iter;
95         flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(&viewStyle));
96     }
97 }
98
99 void FlowThreadController::layoutRenderNamedFlowThreads()
100 {
101     updateFlowThreadsChainIfNecessary();
102
103     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
104         RenderNamedFlowThread* flowRenderer = *iter;
105         flowRenderer->layoutIfNeeded();
106     }
107 }
108
109 void FlowThreadController::registerNamedFlowContentElement(Element& contentElement, RenderNamedFlowThread& namedFlow)
110 {
111     ASSERT(!m_mapNamedFlowContentElement.contains(&contentElement));
112     ASSERT(!namedFlow.hasContentElement(contentElement));
113     m_mapNamedFlowContentElement.add(&contentElement, &namedFlow);
114     namedFlow.registerNamedFlowContentElement(contentElement);
115 }
116
117 void FlowThreadController::unregisterNamedFlowContentElement(Element& contentElement)
118 {
119     auto it = m_mapNamedFlowContentElement.find(&contentElement);
120     ASSERT(it != m_mapNamedFlowContentElement.end());
121     ASSERT(it->value);
122     ASSERT(it->value->hasContentElement(contentElement));
123     it->value->unregisterNamedFlowContentElement(contentElement);
124     m_mapNamedFlowContentElement.remove(&contentElement);
125 }
126
127 void FlowThreadController::updateFlowThreadsChainIfNecessary()
128 {
129     ASSERT(m_renderNamedFlowThreadList);
130     ASSERT(isAutoLogicalHeightRegionsCountConsistent());
131
132     // Remove the left-over flow threads.
133     RenderNamedFlowThreadList toRemoveList;
134     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
135         RenderNamedFlowThread* flowRenderer = *iter;
136         if (flowRenderer->isMarkedForDestruction())
137             toRemoveList.add(flowRenderer);
138     }
139
140     if (toRemoveList.size() > 0)
141         setIsRenderNamedFlowThreadOrderDirty(true);
142
143     for (auto iter = toRemoveList.begin(), end = toRemoveList.end(); iter != end; ++iter) {
144         RenderNamedFlowThread* flowRenderer = *iter;
145         m_renderNamedFlowThreadList->remove(flowRenderer);
146         flowRenderer->destroy();
147     }
148
149     if (isRenderNamedFlowThreadOrderDirty()) {
150         // Arrange the thread list according to dependencies.
151         RenderNamedFlowThreadList sortedList;
152         for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
153             RenderNamedFlowThread* flowRenderer = *iter;
154             if (sortedList.contains(flowRenderer))
155                 continue;
156             flowRenderer->pushDependencies(sortedList);
157             sortedList.add(flowRenderer);
158         }
159         m_renderNamedFlowThreadList->swap(sortedList);
160         setIsRenderNamedFlowThreadOrderDirty(false);
161     }
162 }
163
164 bool FlowThreadController::updateFlowThreadsNeedingLayout()
165 {
166     bool needsTwoPassLayout = false;
167
168     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
169         RenderNamedFlowThread* flowRenderer = *iter;
170         ASSERT(!flowRenderer->needsTwoPhasesLayout());
171         ASSERT(flowRenderer->inMeasureContentLayoutPhase());
172         if (flowRenderer->needsLayout() && flowRenderer->hasAutoLogicalHeightRegions())
173             needsTwoPassLayout = true;
174     }
175
176     if (needsTwoPassLayout)
177         resetFlowThreadsWithAutoHeightRegions();
178
179     return needsTwoPassLayout;
180 }
181
182 bool FlowThreadController::updateFlowThreadsNeedingTwoStepLayout()
183 {
184     bool needsTwoPassLayout = false;
185
186     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
187         RenderNamedFlowThread* flowRenderer = *iter;
188         if (flowRenderer->needsTwoPhasesLayout()) {
189             needsTwoPassLayout = true;
190             break;
191         }
192     }
193
194     if (needsTwoPassLayout)
195         resetFlowThreadsWithAutoHeightRegions();
196
197     return needsTwoPassLayout;
198 }
199
200 void FlowThreadController::resetFlowThreadsWithAutoHeightRegions()
201 {
202     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
203         RenderNamedFlowThread* flowRenderer = *iter;
204         if (flowRenderer->hasAutoLogicalHeightRegions()) {
205             flowRenderer->markAutoLogicalHeightRegionsForLayout();
206             flowRenderer->invalidateRegions();
207         }
208     }
209 }
210
211 void FlowThreadController::updateFlowThreadsIntoConstrainedPhase()
212 {
213     // Walk the flow chain in reverse order to update the auto-height regions and compute correct sizes for the containing regions. Only after this we can
214     // set the flow in the constrained layout phase.
215     for (auto iter = m_renderNamedFlowThreadList->rbegin(), end = m_renderNamedFlowThreadList->rend(); iter != end; ++iter) {
216         RenderNamedFlowThread* flowRenderer = *iter;
217         ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo());
218         flowRenderer->layoutIfNeeded();
219         if (flowRenderer->hasAutoLogicalHeightRegions()) {
220             ASSERT(flowRenderer->needsTwoPhasesLayout());
221             flowRenderer->markAutoLogicalHeightRegionsForLayout();
222         }
223         flowRenderer->setLayoutPhase(RenderFlowThread::LayoutPhaseConstrained);
224         flowRenderer->clearNeedsTwoPhasesLayout();
225     }
226 }
227
228 void FlowThreadController::updateFlowThreadsIntoOverflowPhase()
229 {
230     for (auto iter = m_renderNamedFlowThreadList->rbegin(), end = m_renderNamedFlowThreadList->rend(); iter != end; ++iter) {
231         RenderNamedFlowThread* flowRenderer = *iter;
232         ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo());
233         ASSERT(!flowRenderer->needsTwoPhasesLayout());
234
235         // In the overflow computation phase the flow threads start in the constrained phase even though optimizations didn't set the state before.
236         flowRenderer->setLayoutPhase(RenderFlowThread::LayoutPhaseConstrained);
237
238         flowRenderer->layoutIfNeeded();
239         flowRenderer->markRegionsForOverflowLayoutIfNeeded();
240         flowRenderer->setLayoutPhase(RenderFlowThread::LayoutPhaseOverflow);
241     }
242 }
243
244 void FlowThreadController::updateFlowThreadsIntoMeasureContentPhase()
245 {
246     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
247         RenderNamedFlowThread* flowRenderer = *iter;
248         ASSERT(flowRenderer->inFinalLayoutPhase());
249
250         flowRenderer->setLayoutPhase(RenderFlowThread::LayoutPhaseMeasureContent);
251     }
252 }
253
254 void FlowThreadController::updateFlowThreadsIntoFinalPhase()
255 {
256     for (auto iter = m_renderNamedFlowThreadList->rbegin(), end = m_renderNamedFlowThreadList->rend(); iter != end; ++iter) {
257         RenderNamedFlowThread* flowRenderer = *iter;
258         flowRenderer->layoutIfNeeded();
259         if (flowRenderer->needsTwoPhasesLayout()) {
260             flowRenderer->markRegionsForOverflowLayoutIfNeeded();
261             flowRenderer->clearNeedsTwoPhasesLayout();
262         }
263         flowRenderer->setLayoutPhase(RenderFlowThread::LayoutPhaseFinal);
264     }
265 }
266
267 #if USE(ACCELERATED_COMPOSITING)
268 void FlowThreadController::updateRenderFlowThreadLayersIfNeeded()
269 {
270     // Walk the flow chain in reverse order because RenderRegions might become RenderLayers for the following flow threads.
271     for (auto iter = m_renderNamedFlowThreadList->rbegin(), end = m_renderNamedFlowThreadList->rend(); iter != end; ++iter) {
272         RenderNamedFlowThread* flowRenderer = *iter;
273         flowRenderer->updateAllLayerToRegionMappingsIfNeeded();
274     }
275 }
276 #endif
277
278 bool FlowThreadController::isContentElementRegisteredWithAnyNamedFlow(const Element& contentElement) const
279 {
280     return m_mapNamedFlowContentElement.contains(&contentElement);
281 }
282
283 // Collect the fixed positioned layers that have the named flows as containing block
284 // These layers are painted and hit-tested starting from RenderView not from regions.
285 void FlowThreadController::collectFixedPositionedLayers(Vector<RenderLayer*>& fixedPosLayers) const
286 {
287     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
288         RenderNamedFlowThread* flowRenderer = *iter;
289
290         // If the named flow does not have any regions attached, a fixed element should not be
291         // displayed even if the fixed element is positioned/sized by the viewport.
292         if (!flowRenderer->hasRegions())
293             continue;
294
295         // Iterate over the fixed positioned elements in the flow thread
296         TrackedRendererListHashSet* positionedDescendants = flowRenderer->positionedObjects();
297         if (positionedDescendants) {
298             for (auto it = positionedDescendants->begin(), end = positionedDescendants->end(); it != end; ++it) {
299                 RenderBox* box = *it;
300                 if (!box->fixedPositionedWithNamedFlowContainingBlock())
301                     continue;
302                 fixedPosLayers.append(box->layer());
303             }
304         }
305     }
306 }
307
308 #ifndef NDEBUG
309 bool FlowThreadController::isAutoLogicalHeightRegionsCountConsistent() const
310 {
311     if (!hasRenderNamedFlowThreads())
312         return !hasFlowThreadsWithAutoLogicalHeightRegions();
313
314     for (auto iter = m_renderNamedFlowThreadList->begin(), end = m_renderNamedFlowThreadList->end(); iter != end; ++iter) {
315         if (!(*iter)->isAutoLogicalHeightRegionsCountConsistent())
316             return false;
317     }
318
319     return true;
320 }
321 #endif
322
323 } // namespace WebCore