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