Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/rendering/FlowThreadController.h"
33
34 #include "core/dom/NamedFlowCollection.h"
35 #include "core/rendering/RenderFlowThread.h"
36 #include "core/rendering/RenderNamedFlowThread.h"
37 #include "wtf/text/AtomicString.h"
38
39 namespace WebCore {
40
41 PassOwnPtr<FlowThreadController> FlowThreadController::create(RenderView* view)
42 {
43     return adoptPtr(new FlowThreadController(view));
44 }
45
46 FlowThreadController::FlowThreadController(RenderView* view)
47     : m_view(view)
48     , m_currentRenderFlowThread(0)
49     , m_isRenderNamedFlowThreadOrderDirty(false)
50     , m_flowThreadsWithAutoLogicalHeightRegions(0)
51 {
52 }
53
54 FlowThreadController::~FlowThreadController()
55 {
56 }
57
58 RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(const AtomicString& name)
59 {
60     if (!m_renderNamedFlowThreadList)
61         m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList());
62     else {
63         for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
64             RenderNamedFlowThread* flowRenderer = *iter;
65             if (flowRenderer->flowThreadName() == name)
66                 return flowRenderer;
67         }
68     }
69
70     NamedFlowCollection* namedFlows = m_view->document().namedFlows();
71
72     // Sanity check for the absence of a named flow in the "CREATED" state with the same name.
73     ASSERT(!namedFlows->flowByName(name));
74
75     RenderNamedFlowThread* flowRenderer = RenderNamedFlowThread::createAnonymous(&m_view->document(), namedFlows->ensureFlowWithName(name));
76     flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style()));
77     m_renderNamedFlowThreadList->add(flowRenderer);
78
79     // Keep the flow renderer as a child of RenderView.
80     m_view->addChild(flowRenderer);
81
82     setIsRenderNamedFlowThreadOrderDirty(true);
83
84     return flowRenderer;
85 }
86
87 void FlowThreadController::styleDidChange()
88 {
89     RenderStyle* viewStyle = m_view->style();
90     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
91         RenderNamedFlowThread* flowRenderer = *iter;
92         flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(viewStyle));
93     }
94 }
95
96 void FlowThreadController::layoutRenderNamedFlowThreads()
97 {
98     updateFlowThreadsChainIfNecessary();
99
100     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
101         RenderNamedFlowThread* flowRenderer = *iter;
102         flowRenderer->layoutIfNeeded();
103     }
104 }
105
106 void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow)
107 {
108     ASSERT(contentNode && contentNode->isElementNode());
109     ASSERT(namedFlow);
110     ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode));
111     ASSERT(!namedFlow->hasContentNode(contentNode));
112     m_mapNamedFlowContentNodes.add(contentNode, namedFlow);
113     namedFlow->registerNamedFlowContentNode(contentNode);
114 }
115
116 void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode)
117 {
118     ASSERT(contentNode && contentNode->isElementNode());
119     HashMap<const Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode);
120     ASSERT_WITH_SECURITY_IMPLICATION(it != m_mapNamedFlowContentNodes.end());
121     ASSERT(it->value);
122     ASSERT(it->value->hasContentNode(contentNode));
123     it->value->unregisterNamedFlowContentNode(contentNode);
124     m_mapNamedFlowContentNodes.remove(contentNode);
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 (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->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 (RenderNamedFlowThreadList::iterator iter = toRemoveList.begin(); iter != toRemoveList.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 (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->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 (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
169         RenderNamedFlowThread* flowRenderer = *iter;
170         ASSERT(!flowRenderer->needsTwoPhasesLayout());
171         flowRenderer->setInConstrainedLayoutPhase(false);
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 (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->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 (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->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 (RenderNamedFlowThreadList::reverse_iterator iter = m_renderNamedFlowThreadList->rbegin(); iter != m_renderNamedFlowThreadList->rend(); ++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->setInConstrainedLayoutPhase(true);
224         flowRenderer->clearNeedsTwoPhasesLayout();
225     }
226 }
227
228 bool FlowThreadController::isContentNodeRegisteredWithAnyNamedFlow(const Node* contentNode) const
229 {
230     return m_mapNamedFlowContentNodes.contains(contentNode);
231 }
232
233 #ifndef NDEBUG
234 bool FlowThreadController::isAutoLogicalHeightRegionsCountConsistent() const
235 {
236     if (!hasRenderNamedFlowThreads())
237         return !hasFlowThreadsWithAutoLogicalHeightRegions();
238
239     for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) {
240         if (!(*iter)->isAutoLogicalHeightRegionsCountConsistent())
241             return false;
242     }
243
244     return true;
245 }
246 #endif
247
248 } // namespace WebCore