OLD | NEW |
| (Empty) |
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(cons
t AtomicString& name) | |
59 { | |
60 if (!m_renderNamedFlowThreadList) | |
61 m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList()); | |
62 else { | |
63 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadL
ist->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, Rende
rNamedFlowThread* 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_mapNamedFlowCo
ntentNodes.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_renderNamedFlowThreadL
ist->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->hasAutoLogicalHeightReg
ions()) | |
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 an
d 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_renderNamedFlowThr
eadList->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* c
ontentNode) 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 | |
OLD | NEW |