62bb35e8166e3988c443036b723bed6ff3f41495
[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 "RenderNamedFlowThread.h"
37 #include "StyleInheritedData.h"
38 #include "WebKitNamedFlow.h"
39 #include <wtf/text/AtomicString.h>
40
41 namespace WebCore {
42
43 PassOwnPtr<FlowThreadController> FlowThreadController::create(RenderView* view)
44 {
45     return adoptPtr(new FlowThreadController(view));
46 }
47
48 FlowThreadController::FlowThreadController(RenderView* view)
49     : m_view(view)
50     , m_currentRenderFlowThread(0)
51     , m_isRenderNamedFlowThreadOrderDirty(false)
52     , m_flowThreadsWithAutoLogicalHeightRegions(0)
53 {
54 }
55
56 FlowThreadController::~FlowThreadController()
57 {
58 }
59
60 RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(const AtomicString& name)
61 {
62     if (!m_renderNamedFlowThreadList)
63         m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList());
64     else {
65         for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
66             RenderNamedFlowThread* flowRenderer = *iter;
67             if (flowRenderer->flowThreadName() == name)
68                 return flowRenderer;
69         }
70     }
71
72     NamedFlowCollection* namedFlows = m_view->document()->namedFlows();
73
74     // Sanity check for the absence of a named flow in the "CREATED" state with the same name.
75     ASSERT(!namedFlows->flowByName(name));
76
77     RenderNamedFlowThread* flowRenderer = RenderNamedFlowThread::createAnonymous(m_view->document(), namedFlows->ensureFlowWithName(name));
78     flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style()));
79     m_renderNamedFlowThreadList->add(flowRenderer);
80
81     // Keep the flow renderer as a child of RenderView.
82     m_view->addChild(flowRenderer);
83
84     setIsRenderNamedFlowThreadOrderDirty(true);
85
86     return flowRenderer;
87 }
88
89 void FlowThreadController::styleDidChange()
90 {
91     RenderStyle* viewStyle = m_view->style();
92     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
93         RenderNamedFlowThread* flowRenderer = *iter;
94         flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(viewStyle));
95     }
96 }
97
98 void FlowThreadController::layoutRenderNamedFlowThreads()
99 {
100     updateFlowThreadsChainIfNecessary();
101
102     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
103         RenderNamedFlowThread* flowRenderer = *iter;
104         flowRenderer->layoutIfNeeded();
105     }
106 }
107
108 void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow)
109 {
110     ASSERT(contentNode && contentNode->isElementNode());
111     ASSERT(namedFlow);
112     ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode));
113     ASSERT(!namedFlow->hasContentNode(contentNode));
114     m_mapNamedFlowContentNodes.add(contentNode, namedFlow);
115     namedFlow->registerNamedFlowContentNode(contentNode);
116 }
117
118 void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode)
119 {
120     ASSERT(contentNode && contentNode->isElementNode());
121     HashMap<Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode);
122     ASSERT(it != m_mapNamedFlowContentNodes.end());
123     ASSERT(it->value);
124     ASSERT(it->value->hasContentNode(contentNode));
125     it->value->unregisterNamedFlowContentNode(contentNode);
126     m_mapNamedFlowContentNodes.remove(contentNode);
127 }
128
129 void FlowThreadController::updateFlowThreadsChainIfNecessary()
130 {
131     ASSERT(m_renderNamedFlowThreadList);
132     ASSERT(isAutoLogicalHeightRegionsCountConsistent());
133
134     // Remove the left-over flow threads.
135     RenderNamedFlowThreadList toRemoveList;
136     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
137         RenderNamedFlowThread* flowRenderer = *iter;
138         if (flowRenderer->isMarkedForDestruction())
139             toRemoveList.add(flowRenderer);
140     }
141
142     if (toRemoveList.size() > 0)
143         setIsRenderNamedFlowThreadOrderDirty(true);
144
145     for (RenderNamedFlowThreadList::iterator iter = toRemoveList.begin(); iter != toRemoveList.end(); ++iter) {
146         RenderNamedFlowThread* flowRenderer = *iter;
147         m_renderNamedFlowThreadList->remove(flowRenderer);
148         flowRenderer->destroy();
149     }
150
151     if (isRenderNamedFlowThreadOrderDirty()) {
152         // Arrange the thread list according to dependencies.
153         RenderNamedFlowThreadList sortedList;
154         for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
155             RenderNamedFlowThread* flowRenderer = *iter;
156             if (sortedList.contains(flowRenderer))
157                 continue;
158             flowRenderer->pushDependencies(sortedList);
159             sortedList.add(flowRenderer);
160         }
161         m_renderNamedFlowThreadList->swap(sortedList);
162         setIsRenderNamedFlowThreadOrderDirty(false);
163     }
164 }
165
166 bool FlowThreadController::updateFlowThreadsNeedingLayout()
167 {
168     bool needsTwoPassLayout = false;
169
170     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
171         RenderNamedFlowThread* flowRenderer = *iter;
172         ASSERT(!flowRenderer->needsTwoPhasesLayout());
173         flowRenderer->setInConstrainedLayoutPhase(false);
174         if (flowRenderer->needsLayout() && flowRenderer->hasAutoLogicalHeightRegions())
175             needsTwoPassLayout = true;
176     }
177
178     if (needsTwoPassLayout)
179         resetFlowThreadsWithAutoHeightRegions();
180
181     return needsTwoPassLayout;
182 }
183
184 bool FlowThreadController::updateFlowThreadsNeedingTwoStepLayout()
185 {
186     bool needsTwoPassLayout = false;
187
188     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
189         RenderNamedFlowThread* flowRenderer = *iter;
190         if (flowRenderer->needsTwoPhasesLayout()) {
191             needsTwoPassLayout = true;
192             break;
193         }
194     }
195
196     if (needsTwoPassLayout)
197         resetFlowThreadsWithAutoHeightRegions();
198
199     return needsTwoPassLayout;
200 }
201
202 void FlowThreadController::resetFlowThreadsWithAutoHeightRegions()
203 {
204     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
205         RenderNamedFlowThread* flowRenderer = *iter;
206         if (flowRenderer->hasAutoLogicalHeightRegions()) {
207             flowRenderer->markAutoLogicalHeightRegionsForLayout();
208             flowRenderer->invalidateRegions();
209         }
210     }
211 }
212
213 void FlowThreadController::updateFlowThreadsIntoConstrainedPhase()
214 {
215     // 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
216     // set the flow in the constrained layout phase.
217     for (RenderNamedFlowThreadList::reverse_iterator iter = m_renderNamedFlowThreadList->rbegin(); iter != m_renderNamedFlowThreadList->rend(); ++iter) {
218         RenderNamedFlowThread* flowRenderer = *iter;
219         ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo());
220         flowRenderer->layoutIfNeeded();
221         if (flowRenderer->hasAutoLogicalHeightRegions()) {
222             ASSERT(flowRenderer->needsTwoPhasesLayout());
223             flowRenderer->markAutoLogicalHeightRegionsForLayout();
224         }
225         flowRenderer->setInConstrainedLayoutPhase(true);
226         flowRenderer->clearNeedsTwoPhasesLayout();
227     }
228 }
229
230 #ifndef NDEBUG
231 bool FlowThreadController::isAutoLogicalHeightRegionsCountConsistent() const
232 {
233     if (!hasRenderNamedFlowThreads())
234         return !hasFlowThreadsWithAutoLogicalHeightRegions();
235
236     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
237         if (!(*iter)->isAutoLogicalHeightRegionsCountConsistent())
238             return false;
239     }
240
241     return true;
242 }
243 #endif
244
245 } // namespace WebCore