OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. | 2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above | 8 * 1. Redistributions of source code must retain the above |
9 * copyright notice, this list of conditions and the following | 9 * copyright notice, this list of conditions and the following |
10 * disclaimer. | 10 * disclaimer. |
(...skipping 16 matching lines...) Expand all Loading... |
27 * SUCH DAMAGE. | 27 * SUCH DAMAGE. |
28 */ | 28 */ |
29 | 29 |
30 #include "config.h" | 30 #include "config.h" |
31 #include "core/rendering/RenderRegion.h" | 31 #include "core/rendering/RenderRegion.h" |
32 | 32 |
33 #include "core/css/resolver/StyleResolver.h" | 33 #include "core/css/resolver/StyleResolver.h" |
34 #include "core/rendering/FlowThreadController.h" | 34 #include "core/rendering/FlowThreadController.h" |
35 #include "core/rendering/HitTestLocation.h" | 35 #include "core/rendering/HitTestLocation.h" |
36 #include "core/rendering/PaintInfo.h" | 36 #include "core/rendering/PaintInfo.h" |
37 #include "core/rendering/RenderBoxRegionInfo.h" | 37 #include "core/rendering/RenderFlowThread.h" |
38 #include "core/rendering/RenderNamedFlowThread.h" | |
39 #include "core/rendering/RenderView.h" | 38 #include "core/rendering/RenderView.h" |
40 | 39 |
41 using namespace std; | 40 using namespace std; |
42 | 41 |
43 namespace WebCore { | 42 namespace WebCore { |
44 | 43 |
45 RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread) | 44 RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread) |
46 : RenderBlockFlow(element) | 45 : RenderBlockFlow(element) |
47 , m_flowThread(flowThread) | 46 , m_flowThread(flowThread) |
48 , m_parentNamedFlowThread(0) | |
49 , m_computedAutoHeight(-1) | |
50 , m_isValid(false) | 47 , m_isValid(false) |
51 , m_hasCustomRegionStyle(false) | |
52 , m_hasAutoLogicalHeight(false) | |
53 { | 48 { |
54 } | 49 } |
55 | 50 |
56 LayoutUnit RenderRegion::pageLogicalWidth() const | 51 LayoutUnit RenderRegion::pageLogicalWidth() const |
57 { | 52 { |
58 ASSERT(m_flowThread); | 53 ASSERT(m_flowThread); |
59 return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHei
ght(); | 54 return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHei
ght(); |
60 } | 55 } |
61 | 56 |
62 LayoutUnit RenderRegion::pageLogicalHeight() const | 57 LayoutUnit RenderRegion::pageLogicalHeight() const |
63 { | 58 { |
64 ASSERT(m_flowThread); | 59 ASSERT(m_flowThread); |
65 if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) { | |
66 ASSERT(hasAutoLogicalHeight()); | |
67 return computedAutoHeight(); | |
68 } | |
69 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); | 60 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); |
70 } | 61 } |
71 | 62 |
72 // This method returns the maximum page size of a region with auto-height. This
is the initial | |
73 // height value for auto-height regions in the first layout phase of the parent
named flow. | |
74 LayoutUnit RenderRegion::maxPageLogicalHeight() const | |
75 { | |
76 ASSERT(m_flowThread); | |
77 ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()); | |
78 return style()->logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogi
calHeight() : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight()); | |
79 } | |
80 | |
81 LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const | 63 LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const |
82 { | 64 { |
83 ASSERT(m_flowThread); | 65 ASSERT(m_flowThread); |
84 if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) { | |
85 ASSERT(hasAutoLogicalHeight()); | |
86 return computedAutoHeight(); | |
87 } | |
88 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); | 66 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); |
89 } | 67 } |
90 | 68 |
91 LayoutRect RenderRegion::flowThreadPortionOverflowRect() const | 69 LayoutRect RenderRegion::flowThreadPortionOverflowRect() const |
92 { | 70 { |
93 return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegi
on(), isLastRegion()); | 71 return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegi
on(), isLastRegion()); |
94 } | 72 } |
95 | 73 |
96 LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flow
ThreadPortionRect, bool isFirstPortion, bool isLastPortion) const | 74 LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flow
ThreadPortionRect, bool isFirstPortion, bool isLastPortion) const |
97 { | 75 { |
98 ASSERT(isValid()); | 76 ASSERT(isValid()); |
99 | 77 |
100 bool isLastRegionWithRegionFragmentBreak = (isLastPortion && (style()->regio
nFragment() == BreakRegionFragment)); | 78 if (hasOverflowClip()) |
101 if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak) | |
102 return flowThreadPortionRect; | 79 return flowThreadPortionRect; |
103 | 80 |
104 LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); | 81 LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); |
105 | 82 |
106 // Only clip along the flow thread axis. | 83 // Only clip along the flow thread axis. |
107 LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline); | 84 LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline); |
108 LayoutRect clipRect; | 85 LayoutRect clipRect; |
109 bool shouldApplyClip = !style()->isOverflowVisible(); | 86 bool shouldApplyClip = !style()->isOverflowVisible(); |
110 if (m_flowThread->isHorizontalWritingMode()) { | 87 if (m_flowThread->isHorizontalWritingMode()) { |
111 LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize
) : flowThreadPortionRect.y(); | 88 LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize
) : flowThreadPortionRect.y(); |
112 LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flow
ThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); | 89 LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flow
ThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); |
113 LayoutUnit minX = shouldApplyClip ? flowThreadPortionRect.x() : min(flow
ThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); | 90 LayoutUnit minX = shouldApplyClip ? flowThreadPortionRect.x() : min(flow
ThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); |
114 LayoutUnit maxX = shouldApplyClip ? flowThreadPortionRect.maxX() : max(f
lowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize)); | 91 LayoutUnit maxX = shouldApplyClip ? flowThreadPortionRect.maxX() : max(f
lowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize)); |
115 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); | 92 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); |
116 } else { | 93 } else { |
117 LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize
) : flowThreadPortionRect.x(); | 94 LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize
) : flowThreadPortionRect.x(); |
118 LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flow
ThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); | 95 LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flow
ThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); |
119 LayoutUnit minY = shouldApplyClip ? flowThreadPortionRect.y() : min(flow
ThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); | 96 LayoutUnit minY = shouldApplyClip ? flowThreadPortionRect.y() : min(flow
ThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); |
120 LayoutUnit maxY = shouldApplyClip ? flowThreadPortionRect.maxY() : max(f
lowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); | 97 LayoutUnit maxY = shouldApplyClip ? flowThreadPortionRect.maxY() : max(f
lowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); |
121 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); | 98 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); |
122 } | 99 } |
123 | 100 |
124 return clipRect; | 101 return clipRect; |
125 } | 102 } |
126 | 103 |
127 RegionOversetState RenderRegion::regionOversetState() const | |
128 { | |
129 if (isValid() && element()) | |
130 return element()->regionOversetState(); | |
131 | |
132 return RegionUndefined; | |
133 } | |
134 | |
135 void RenderRegion::setRegionOversetState(RegionOversetState state) | |
136 { | |
137 if (element()) | |
138 element()->setRegionOversetState(state); | |
139 } | |
140 | |
141 Element* RenderRegion::element() const | |
142 { | |
143 ASSERT(nodeForRegion() && nodeForRegion()->isElementNode()); | |
144 return toElement(nodeForRegion()); | |
145 } | |
146 | |
147 LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const | 104 LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const |
148 { | 105 { |
149 return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y()
: flowThreadPortionRect().x(); | 106 return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y()
: flowThreadPortionRect().x(); |
150 } | 107 } |
151 | 108 |
152 bool RenderRegion::isFirstRegion() const | 109 bool RenderRegion::isFirstRegion() const |
153 { | 110 { |
154 ASSERT(isValid()); | 111 ASSERT(isValid()); |
155 | 112 |
156 return m_flowThread->firstRegion() == this; | 113 return m_flowThread->firstRegion() == this; |
157 } | 114 } |
158 | 115 |
159 bool RenderRegion::isLastRegion() const | 116 bool RenderRegion::isLastRegion() const |
160 { | 117 { |
161 ASSERT(isValid()); | 118 ASSERT(isValid()); |
162 | 119 |
163 return m_flowThread->lastRegion() == this; | 120 return m_flowThread->lastRegion() == this; |
164 } | 121 } |
165 | 122 |
166 static bool shouldPaintRegionContentsInPhase(PaintPhase phase) | |
167 { | |
168 return phase == PaintPhaseForeground | |
169 || phase == PaintPhaseSelection | |
170 || phase == PaintPhaseTextClip; | |
171 } | |
172 | |
173 void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOff
set) | |
174 { | |
175 if (style()->visibility() != VISIBLE) | |
176 return; | |
177 | |
178 RenderBlock::paintObject(paintInfo, paintOffset); | |
179 | |
180 if (!isValid()) | |
181 return; | |
182 | |
183 // Delegate painting of content in region to RenderFlowThread. | |
184 // RenderFlowThread is a self painting layer (being a positioned object) who
is painting its children, the collected objects. | |
185 // Since we do not want to paint the flow thread content multiple times (for
each painting phase of the region object), | |
186 // we allow the flow thread painting only in certain phases. | |
187 if (!shouldPaintRegionContentsInPhase(paintInfo.phase)) | |
188 return; | |
189 | |
190 setRegionObjectsRegionStyle(); | |
191 m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPort
ionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + border
Left() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); | |
192 restoreRegionObjectsOriginalStyle(); | |
193 } | |
194 | |
195 // Hit Testing | |
196 bool RenderRegion::hitTestFlowThreadContents(const HitTestRequest& request, HitT
estResult& result, const HitTestLocation& locationInContainer, const LayoutPoint
& accumulatedOffset, HitTestAction action) | |
197 { | |
198 if (!isValid() || action != HitTestForeground) | |
199 return false; | |
200 | |
201 LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); | |
202 boundsRect.moveBy(accumulatedOffset); | |
203 if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) { | |
204 if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPorti
onRect(), flowThreadPortionOverflowRect(), request, result, | |
205 locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft(
) + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop()))) | |
206 return true; | |
207 } | |
208 | |
209 return false; | |
210 } | |
211 | |
212 void RenderRegion::checkRegionStyle() | |
213 { | |
214 ASSERT(m_flowThread); | |
215 bool customRegionStyle = false; | |
216 | |
217 // FIXME: Region styling doesn't work for pseudo elements. | |
218 if (isElementBasedRegion()) | |
219 customRegionStyle = view()->document().ensureStyleResolver().checkRegion
Style(this->element()); | |
220 | |
221 setHasCustomRegionStyle(customRegionStyle); | |
222 m_flowThread->checkRegionsWithStyling(); | |
223 } | |
224 | |
225 void RenderRegion::incrementAutoLogicalHeightCount() | |
226 { | |
227 ASSERT(isValid()); | |
228 ASSERT(m_hasAutoLogicalHeight); | |
229 | |
230 m_flowThread->incrementAutoLogicalHeightRegions(); | |
231 } | |
232 | |
233 void RenderRegion::decrementAutoLogicalHeightCount() | |
234 { | |
235 ASSERT(isValid()); | |
236 | |
237 m_flowThread->decrementAutoLogicalHeightRegions(); | |
238 } | |
239 | |
240 void RenderRegion::updateRegionHasAutoLogicalHeightFlag() | |
241 { | |
242 ASSERT(m_flowThread); | |
243 | |
244 if (!isValid()) | |
245 return; | |
246 | |
247 bool didHaveAutoLogicalHeight = m_hasAutoLogicalHeight; | |
248 m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); | |
249 if (m_hasAutoLogicalHeight != didHaveAutoLogicalHeight) { | |
250 if (m_hasAutoLogicalHeight) { | |
251 incrementAutoLogicalHeightCount(); | |
252 } else { | |
253 clearComputedAutoHeight(); | |
254 decrementAutoLogicalHeightCount(); | |
255 } | |
256 } | |
257 } | |
258 | |
259 bool RenderRegion::shouldHaveAutoLogicalHeight() const | |
260 { | |
261 bool hasSpecifiedEndpointsForHeight = style()->logicalTop().isSpecified() &&
style()->logicalBottom().isSpecified(); | |
262 bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecified
EndpointsForHeight; | |
263 bool hasAutoHeightStyle = style()->logicalHeight().isAuto() || style()->logi
calHeight().isFitContent() | |
264 || style()->logicalHeight().isMaxContent() || style()->logicalHeight().i
sMinContent(); | |
265 return hasAutoHeightStyle && !hasAnchoredEndpointsForHeight; | |
266 } | |
267 | |
268 void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
yle) | |
269 { | |
270 RenderBlock::styleDidChange(diff, oldStyle); | |
271 | |
272 // If the region is not attached to any thread, there is no need to check | |
273 // whether the region has region styling since no content will be displayed | |
274 // into the region. | |
275 if (!m_flowThread) { | |
276 setHasCustomRegionStyle(false); | |
277 return; | |
278 } | |
279 | |
280 checkRegionStyle(); | |
281 updateRegionHasAutoLogicalHeightFlag(); | |
282 | |
283 if (oldStyle && oldStyle->writingMode() != style()->writingMode()) | |
284 m_flowThread->regionChangedWritingMode(this); | |
285 } | |
286 | |
287 void RenderRegion::layoutBlock(bool relayoutChildren) | 123 void RenderRegion::layoutBlock(bool relayoutChildren) |
288 { | 124 { |
289 RenderBlockFlow::layoutBlock(relayoutChildren); | 125 RenderBlockFlow::layoutBlock(relayoutChildren); |
290 | 126 |
291 if (isValid()) { | |
292 LayoutRect oldRegionRect(flowThreadPortionRect()); | |
293 if (!isHorizontalWritingMode()) | |
294 oldRegionRect = oldRegionRect.transposedRect(); | |
295 | |
296 if (hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase())
{ | |
297 m_flowThread->invalidateRegions(); | |
298 clearComputedAutoHeight(); | |
299 return; | |
300 } | |
301 | |
302 if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth()
|| oldRegionRect.height() != pageLogicalHeight())) { | |
303 // This can happen even if we are in the inConstrainedLayoutPhase an
d it will trigger a pathological layout of the flow thread. | |
304 m_flowThread->invalidateRegions(); | |
305 } | |
306 } | |
307 | |
308 // FIXME: We need to find a way to set up overflow properly. Our flow thread
hasn't gotten a layout | 127 // FIXME: We need to find a way to set up overflow properly. Our flow thread
hasn't gotten a layout |
309 // yet, so we can't look to it for correct information. It's possible we cou
ld wait until after the RenderFlowThread | 128 // yet, so we can't look to it for correct information. It's possible we cou
ld wait until after the RenderFlowThread |
310 // gets a layout, and then try to propagate overflow information back to the
region, and then mark for a second layout. | 129 // gets a layout, and then try to propagate overflow information back to the
region, and then mark for a second layout. |
311 // That second layout would then be able to use the information from the Ren
derFlowThread to set up overflow. | 130 // That second layout would then be able to use the information from the Ren
derFlowThread to set up overflow. |
312 // | 131 // |
313 // The big problem though is that overflow needs to be region-specific. We c
an't simply use the RenderFlowThread's global | 132 // The big problem though is that overflow needs to be region-specific. We c
an't simply use the RenderFlowThread's global |
314 // overflow values, since then we'd always think any narrow region had huge
overflow (all the way to the width of the | 133 // overflow values, since then we'd always think any narrow region had huge
overflow (all the way to the width of the |
315 // RenderFlowThread itself). | 134 // RenderFlowThread itself). |
316 // | |
317 // We'll need to expand RenderBoxRegionInfo to also hold left and right over
flow values. | |
318 } | 135 } |
319 | 136 |
320 void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const | 137 void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const |
321 { | 138 { |
322 repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flow
ThreadPortionOverflowRect(), contentBoxRect().location()); | 139 repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flow
ThreadPortionOverflowRect(), contentBoxRect().location()); |
323 } | 140 } |
324 | 141 |
325 void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRe
ct, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortion
OverflowRect, const LayoutPoint& regionLocation) const | 142 void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRe
ct, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortion
OverflowRect, const LayoutPoint& regionLocation) const |
326 { | 143 { |
327 ASSERT(isValid()); | 144 ASSERT(isValid()); |
(...skipping 12 matching lines...) Expand all Loading... |
340 // Put the region rect into the region's physical coordinate space. | 157 // Put the region rect into the region's physical coordinate space. |
341 clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFl
owThreadPortionRect.location())); | 158 clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFl
owThreadPortionRect.location())); |
342 | 159 |
343 // Now switch to the region's writing mode coordinate space and let it repai
nt itself. | 160 // Now switch to the region's writing mode coordinate space and let it repai
nt itself. |
344 flipForWritingMode(clippedRect); | 161 flipForWritingMode(clippedRect); |
345 | 162 |
346 // Issue the repaint. | 163 // Issue the repaint. |
347 repaintRectangle(clippedRect); | 164 repaintRectangle(clippedRect); |
348 } | 165 } |
349 | 166 |
350 void RenderRegion::installFlowThread() | |
351 { | |
352 ASSERT(view()); | |
353 | |
354 m_flowThread = view()->flowThreadController()->ensureRenderFlowThreadWithNam
e(style()->regionThread()); | |
355 | |
356 // By now the flow thread should already be added to the rendering tree, | |
357 // so we go up the rendering parents and check that this region is not part
of the same | |
358 // flow that it actually needs to display. It would create a circular refere
nce. | |
359 RenderObject* parentObject = parent(); | |
360 m_parentNamedFlowThread = 0; | |
361 for ( ; parentObject; parentObject = parentObject->parent()) { | |
362 if (parentObject->isRenderNamedFlowThread()) { | |
363 m_parentNamedFlowThread = toRenderNamedFlowThread(parentObject); | |
364 // Do not take into account a region that links a flow with itself.
The dependency | |
365 // cannot change, so it is not worth adding it to the list. | |
366 if (m_flowThread == m_parentNamedFlowThread) | |
367 m_flowThread = 0; | |
368 break; | |
369 } | |
370 } | |
371 } | |
372 | |
373 void RenderRegion::attachRegion() | 167 void RenderRegion::attachRegion() |
374 { | 168 { |
375 if (documentBeingDestroyed()) | 169 if (documentBeingDestroyed()) |
376 return; | 170 return; |
377 | 171 |
378 // A region starts off invalid. | 172 // A region starts off invalid. |
379 setIsValid(false); | 173 setIsValid(false); |
380 | 174 |
381 // Initialize the flow thread reference and create the flow thread object if
needed. | |
382 // The flow thread lifetime is influenced by the number of regions attached
to it, | |
383 // and we are attaching the region to the flow thread. | |
384 installFlowThread(); | |
385 | |
386 if (!m_flowThread) | 175 if (!m_flowThread) |
387 return; | 176 return; |
388 | 177 |
389 // Only after adding the region to the thread, the region is marked to be va
lid. | 178 // Only after adding the region to the thread, the region is marked to be va
lid. |
390 m_flowThread->addRegionToThread(this); | 179 m_flowThread->addRegionToThread(this); |
391 | |
392 // The region just got attached to the flow thread, lets check whether | |
393 // it has region styling rules associated. | |
394 checkRegionStyle(); | |
395 | |
396 if (!isValid()) | |
397 return; | |
398 | |
399 m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); | |
400 if (hasAutoLogicalHeight()) | |
401 incrementAutoLogicalHeightCount(); | |
402 } | 180 } |
403 | 181 |
404 void RenderRegion::detachRegion() | 182 void RenderRegion::detachRegion() |
405 { | 183 { |
406 if (m_flowThread) { | 184 if (m_flowThread) { |
407 m_flowThread->removeRegionFromThread(this); | 185 m_flowThread->removeRegionFromThread(this); |
408 if (hasAutoLogicalHeight()) | 186 m_flowThread = 0; |
409 decrementAutoLogicalHeightCount(); | |
410 } | 187 } |
411 m_flowThread = 0; | |
412 } | |
413 | |
414 RenderBoxRegionInfo* RenderRegion::renderBoxRegionInfo(const RenderBox* box) con
st | |
415 { | |
416 ASSERT(isValid()); | |
417 return m_renderBoxRegionInfo.get(box); | |
418 } | |
419 | |
420 RenderBoxRegionInfo* RenderRegion::setRenderBoxRegionInfo(const RenderBox* box,
LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset, | |
421 bool containingBlockChainIsInset) | |
422 { | |
423 ASSERT(isValid()); | |
424 | |
425 OwnPtr<RenderBoxRegionInfo>& boxInfo = m_renderBoxRegionInfo.add(box, nullpt
r).iterator->value; | |
426 if (boxInfo) | |
427 *boxInfo = RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, cont
ainingBlockChainIsInset); | |
428 else | |
429 boxInfo = adoptPtr(new RenderBoxRegionInfo(logicalLeftInset, logicalRigh
tInset, containingBlockChainIsInset)); | |
430 | |
431 return boxInfo.get(); | |
432 } | |
433 | |
434 PassOwnPtr<RenderBoxRegionInfo> RenderRegion::takeRenderBoxRegionInfo(const Rend
erBox* box) | |
435 { | |
436 return m_renderBoxRegionInfo.take(box); | |
437 } | |
438 | |
439 void RenderRegion::removeRenderBoxRegionInfo(const RenderBox* box) | |
440 { | |
441 m_renderBoxRegionInfo.remove(box); | |
442 } | |
443 | |
444 void RenderRegion::deleteAllRenderBoxRegionInfo() | |
445 { | |
446 m_renderBoxRegionInfo.clear(); | |
447 } | 188 } |
448 | 189 |
449 LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rec
t) const | 190 LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rec
t) const |
450 { | 191 { |
451 ASSERT(isValid()); | 192 ASSERT(isValid()); |
452 return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x(); | 193 return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x(); |
453 } | 194 } |
454 | 195 |
455 LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect&
rect) const | 196 LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect&
rect) const |
456 { | 197 { |
457 ASSERT(isValid()); | 198 ASSERT(isValid()); |
458 return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX(); | 199 return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX(); |
459 } | 200 } |
460 | 201 |
461 void RenderRegion::setRegionObjectsRegionStyle() | |
462 { | |
463 if (!hasCustomRegionStyle()) | |
464 return; | |
465 | |
466 // Start from content nodes and recursively compute the style in region for
the render objects below. | |
467 // If the style in region was already computed, used that style instead of c
omputing a new one. | |
468 RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRen
derFlowThreadWithName(style()->regionThread()); | |
469 const NamedFlowContentNodes& contentNodes = namedFlow->contentNodes(); | |
470 | |
471 for (NamedFlowContentNodes::const_iterator iter = contentNodes.begin(), end
= contentNodes.end(); iter != end; ++iter) { | |
472 const Node* node = *iter; | |
473 // The list of content nodes contains also the nodes with display:none. | |
474 if (!node->renderer()) | |
475 continue; | |
476 | |
477 RenderObject* object = node->renderer(); | |
478 // If the content node does not flow any of its children in this region, | |
479 // we do not compute any style for them in this region. | |
480 if (!flowThread()->objectInFlowRegion(object, this)) | |
481 continue; | |
482 | |
483 // If the object has style in region, use that instead of computing a ne
w one. | |
484 RenderObjectRegionStyleMap::iterator it = m_renderObjectRegionStyle.find
(object); | |
485 RefPtr<RenderStyle> objectStyleInRegion; | |
486 bool objectRegionStyleCached = false; | |
487 if (it != m_renderObjectRegionStyle.end()) { | |
488 objectStyleInRegion = it->value.style; | |
489 ASSERT(it->value.cached); | |
490 objectRegionStyleCached = true; | |
491 } else { | |
492 objectStyleInRegion = computeStyleInRegion(object); | |
493 } | |
494 | |
495 setObjectStyleInRegion(object, objectStyleInRegion, objectRegionStyleCac
hed); | |
496 | |
497 computeChildrenStyleInRegion(object); | |
498 } | |
499 } | |
500 | |
501 void RenderRegion::restoreRegionObjectsOriginalStyle() | |
502 { | |
503 if (!hasCustomRegionStyle()) | |
504 return; | |
505 | |
506 RenderObjectRegionStyleMap temp; | |
507 for (RenderObjectRegionStyleMap::iterator iter = m_renderObjectRegionStyle.b
egin(), end = m_renderObjectRegionStyle.end(); iter != end; ++iter) { | |
508 RenderObject* object = const_cast<RenderObject*>(iter->key); | |
509 RefPtr<RenderStyle> objectRegionStyle = object->style(); | |
510 RefPtr<RenderStyle> objectOriginalStyle = iter->value.style; | |
511 object->setStyleInternal(objectOriginalStyle); | |
512 | |
513 bool shouldCacheRegionStyle = iter->value.cached; | |
514 if (!shouldCacheRegionStyle) { | |
515 // Check whether we should cache the computed style in region. | |
516 unsigned changedContextSensitiveProperties = ContextSensitivePropert
yNone; | |
517 StyleDifference styleDiff = objectOriginalStyle->diff(objectRegionSt
yle.get(), changedContextSensitiveProperties); | |
518 if (styleDiff < StyleDifferenceLayoutPositionedMovementOnly) | |
519 shouldCacheRegionStyle = true; | |
520 } | |
521 if (shouldCacheRegionStyle) { | |
522 ObjectRegionStyleInfo styleInfo; | |
523 styleInfo.style = objectRegionStyle; | |
524 styleInfo.cached = true; | |
525 temp.set(object, styleInfo); | |
526 } | |
527 } | |
528 | |
529 m_renderObjectRegionStyle.swap(temp); | |
530 } | |
531 | |
532 void RenderRegion::insertedIntoTree() | 202 void RenderRegion::insertedIntoTree() |
533 { | 203 { |
534 RenderBlock::insertedIntoTree(); | 204 RenderBlock::insertedIntoTree(); |
535 | 205 |
536 attachRegion(); | 206 attachRegion(); |
537 } | 207 } |
538 | 208 |
539 void RenderRegion::willBeRemovedFromTree() | 209 void RenderRegion::willBeRemovedFromTree() |
540 { | 210 { |
541 RenderBlock::willBeRemovedFromTree(); | 211 RenderBlock::willBeRemovedFromTree(); |
542 | 212 |
543 detachRegion(); | 213 detachRegion(); |
544 } | 214 } |
545 | 215 |
546 PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* o
bject) | |
547 { | |
548 ASSERT(object); | |
549 ASSERT(object->view()); | |
550 ASSERT(!object->isAnonymous()); | |
551 ASSERT(object->node() && object->node()->isElementNode()); | |
552 | |
553 // FIXME: Region styling fails for pseudo-elements because the renderers don
't have a node. | |
554 Element* element = toElement(object->node()); | |
555 RefPtr<RenderStyle> renderObjectRegionStyle = object->view()->document().ens
ureStyleResolver().styleForElement(element, 0, DisallowStyleSharing, MatchAllRul
es, this); | |
556 | |
557 return renderObjectRegionStyle.release(); | |
558 } | |
559 | |
560 void RenderRegion::computeChildrenStyleInRegion(const RenderObject* object) | |
561 { | |
562 for (RenderObject* child = object->lastChild(); child; child = child->previo
usSibling()) { | |
563 | |
564 RenderObjectRegionStyleMap::iterator it = m_renderObjectRegionStyle.find
(child); | |
565 | |
566 RefPtr<RenderStyle> childStyleInRegion; | |
567 bool objectRegionStyleCached = false; | |
568 if (it != m_renderObjectRegionStyle.end()) { | |
569 childStyleInRegion = it->value.style; | |
570 objectRegionStyleCached = true; | |
571 } else { | |
572 if (child->isAnonymous() || child->isInFlowRenderFlowThread()) | |
573 childStyleInRegion = RenderStyle::createAnonymousStyleWithDispla
y(object->style(), child->style()->display()); | |
574 else if (child->isText()) | |
575 childStyleInRegion = RenderStyle::clone(object->style()); | |
576 else | |
577 childStyleInRegion = computeStyleInRegion(child); | |
578 } | |
579 | |
580 setObjectStyleInRegion(child, childStyleInRegion, objectRegionStyleCache
d); | |
581 | |
582 computeChildrenStyleInRegion(child); | |
583 } | |
584 } | |
585 | |
586 void RenderRegion::setObjectStyleInRegion(RenderObject* object, PassRefPtr<Rende
rStyle> styleInRegion, bool objectRegionStyleCached) | |
587 { | |
588 ASSERT(object->flowThreadContainingBlock()); | |
589 | |
590 RefPtr<RenderStyle> objectOriginalStyle = object->style(); | |
591 object->setStyleInternal(styleInRegion); | |
592 | |
593 if (object->isBoxModelObject() && !object->hasBoxDecorations()) { | |
594 bool hasBoxDecorations = object->isTableCell() | |
595 || object->style()->hasBackground() | |
596 || object->style()->hasBorder() | |
597 || object->style()->hasAppearance() | |
598 || object->style()->boxShadow(); | |
599 object->setHasBoxDecorations(hasBoxDecorations); | |
600 } | |
601 | |
602 ObjectRegionStyleInfo styleInfo; | |
603 styleInfo.style = objectOriginalStyle; | |
604 styleInfo.cached = objectRegionStyleCached; | |
605 m_renderObjectRegionStyle.set(object, styleInfo); | |
606 } | |
607 | |
608 void RenderRegion::clearObjectStyleInRegion(const RenderObject* object) | |
609 { | |
610 ASSERT(object); | |
611 m_renderObjectRegionStyle.remove(object); | |
612 | |
613 // Clear the style for the children of this object. | |
614 for (RenderObject* child = object->lastChild(); child; child = child->previo
usSibling()) | |
615 clearObjectStyleInRegion(child); | |
616 } | |
617 | |
618 void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, La
youtUnit& maxLogicalWidth) const | 216 void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, La
youtUnit& maxLogicalWidth) const |
619 { | 217 { |
620 if (!isValid()) { | 218 if (!isValid()) { |
621 RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWi
dth); | 219 RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWi
dth); |
622 return; | 220 return; |
623 } | 221 } |
624 | 222 |
625 minLogicalWidth = m_flowThread->minPreferredLogicalWidth(); | 223 minLogicalWidth = m_flowThread->minPreferredLogicalWidth(); |
626 maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth(); | 224 maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth(); |
627 } | 225 } |
628 | 226 |
629 void RenderRegion::getRanges(Vector<RefPtr<Range> >& rangeObjects) const | |
630 { | |
631 RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRen
derFlowThreadWithName(style()->regionThread()); | |
632 namedFlow->getRanges(rangeObjects, this); | |
633 } | |
634 | |
635 void RenderRegion::updateLogicalHeight() | |
636 { | |
637 RenderBlock::updateLogicalHeight(); | |
638 | |
639 if (!hasAutoLogicalHeight()) | |
640 return; | |
641 | |
642 // We want to update the logical height based on the computed auto-height | |
643 // only if the view is in the layout phase in which all the | |
644 // auto logical height regions have a computed auto-height. | |
645 if (!m_flowThread->inConstrainedLayoutPhase()) | |
646 return; | |
647 | |
648 // There may be regions with auto logical height that during the prerequisit
e layout phase | |
649 // did not have the chance to layout flow thread content. Because of that, t
hese regions do not | |
650 // have a computedAutoHeight and they will not be able to fragment any flow | |
651 // thread content. | |
652 if (!hasComputedAutoHeight()) | |
653 return; | |
654 | |
655 LayoutUnit autoHeight = hasOverrideHeight() ? overrideLogicalContentHeight()
: computedAutoHeight(); | |
656 | |
657 LayoutUnit newLogicalHeight = autoHeight + borderAndPaddingLogicalHeight(); | |
658 ASSERT(newLogicalHeight < RenderFlowThread::maxLogicalHeight()); | |
659 if (newLogicalHeight > logicalHeight()) { | |
660 setLogicalHeight(newLogicalHeight); | |
661 // Recalculate position of the render block after new logical height is
set. | |
662 // (needed in absolute positioning case with bottom alignment for exampl
e) | |
663 RenderBlock::updateLogicalHeight(); | |
664 } | |
665 } | |
666 | |
667 Node* RenderRegion::nodeForRegion() const | |
668 { | |
669 if (parent() && isRenderNamedFlowFragment()) | |
670 return parent()->node(); | |
671 return node(); | |
672 } | |
673 | |
674 Node* RenderRegion::generatingNodeForRegion() const | |
675 { | |
676 if (parent() && isRenderNamedFlowFragment()) | |
677 return parent()->generatingNode(); | |
678 return generatingNode(); | |
679 } | |
680 | |
681 bool RenderRegion::isElementBasedRegion() const | |
682 { | |
683 Node* node = nodeForRegion(); | |
684 return node && node->isElementNode() && !node->isPseudoElement(); | |
685 } | |
686 | |
687 } // namespace WebCore | 227 } // namespace WebCore |
OLD | NEW |