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