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 41using namespace std; 42 43namespace WebCore { 44 45RenderRegion::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 56LayoutUnit RenderRegion::pageLogicalWidth() const 57{ 58 ASSERT(m_flowThread); 59 return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHeight(); 60} 61 62LayoutUnit 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() : contentWidth(); 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. 74LayoutUnit RenderRegion::maxPageLogicalHeight() const 75{ 76 ASSERT(m_flowThread); 77 ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()); 78 return style()->logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight()); 79} 80 81LayoutUnit 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() : contentWidth(); 89} 90 91LayoutRect RenderRegion::flowThreadPortionOverflowRect() const 92{ 93 return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion()); 94} 95 96LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const 97{ 98 ASSERT(isValid()); 99 100 bool isLastRegionWithRegionFragmentBreak = (isLastPortion && (style()->regionFragment() == 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(), flowThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); 112 bool clipX = style()->overflowX() != OVISIBLE; 113 LayoutUnit minX = clipX ? flowThreadPortionRect.x() : min(flowThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); 114 LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : max(flowThreadPortionRect.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(), flowThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); 119 bool clipY = style()->overflowY() != OVISIBLE; 120 LayoutUnit minY = clipY ? flowThreadPortionRect.y() : min(flowThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); 121 LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); 122 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); 123 } 124 125 return clipRect; 126} 127 128RegionOversetState RenderRegion::regionOversetState() const 129{ 130 if (isValid() && element()) 131 return element()->regionOversetState(); 132 133 return RegionUndefined; 134} 135 136void RenderRegion::setRegionOversetState(RegionOversetState state) 137{ 138 if (element()) 139 element()->setRegionOversetState(state); 140} 141 142Element* RenderRegion::element() const 143{ 144 ASSERT(nodeForRegion() && nodeForRegion()->isElementNode()); 145 return toElement(nodeForRegion()); 146} 147 148LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const 149{ 150 return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x(); 151} 152 153bool RenderRegion::isFirstRegion() const 154{ 155 ASSERT(isValid()); 156 157 return m_flowThread->firstRegion() == this; 158} 159 160bool RenderRegion::isLastRegion() const 161{ 162 ASSERT(isValid()); 163 164 return m_flowThread->lastRegion() == this; 165} 166 167static bool shouldPaintRegionContentsInPhase(PaintPhase phase) 168{ 169 return phase == PaintPhaseForeground 170 || phase == PaintPhaseSelection 171 || phase == PaintPhaseTextClip; 172} 173 174void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 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, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); 193 restoreRegionObjectsOriginalStyle(); 194} 195 196// Hit Testing 197bool RenderRegion::hitTestFlowThreadContents(const HitTestRequest& request, HitTestResult& 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, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, 206 locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft() + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop()))) 207 return true; 208 } 209 210 return false; 211} 212 213void 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().checkRegionStyle(this->element()); 221 222 setHasCustomRegionStyle(customRegionStyle); 223 m_flowThread->checkRegionsWithStyling(); 224} 225 226void RenderRegion::incrementAutoLogicalHeightCount() 227{ 228 ASSERT(isValid()); 229 ASSERT(m_hasAutoLogicalHeight); 230 231 m_flowThread->incrementAutoLogicalHeightRegions(); 232} 233 234void RenderRegion::decrementAutoLogicalHeightCount() 235{ 236 ASSERT(isValid()); 237 238 m_flowThread->decrementAutoLogicalHeightRegions(); 239} 240 241void 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 260bool RenderRegion::shouldHaveAutoLogicalHeight() const 261{ 262 bool hasSpecifiedEndpointsForHeight = style()->logicalTop().isSpecified() && style()->logicalBottom().isSpecified(); 263 bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecifiedEndpointsForHeight; 264 bool hasAutoHeightStyle = style()->logicalHeight().isAuto() || style()->logicalHeight().isFitContent() 265 || style()->logicalHeight().isMaxContent() || style()->logicalHeight().isMinContent(); 266 return hasAutoHeightStyle && !hasAnchoredEndpointsForHeight; 267} 268 269void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 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 288void RenderRegion::layoutBlock(bool relayoutChildren, LayoutUnit) 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 and 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 could 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 RenderFlowThread to set up overflow. 313 // 314 // The big problem though is that overflow needs to be region-specific. We can'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 overflow values. 319} 320 321void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const 322{ 323 repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flowThreadPortionOverflowRect(), contentBoxRect().location()); 324} 325 326void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const 327{ 328 ASSERT(isValid()); 329 330 // We only have to issue a repaint in this region if the region rect intersects the repaint rect. 331 LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); 332 LayoutRect flippedFlowThreadPortionOverflowRect(flowThreadPortionOverflowRect); 333 flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); // Put the region 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() - flippedFlowThreadPortionRect.location())); 343 344 // Now switch to the region's writing mode coordinate space and let it repaint itself. 345 flipForWritingMode(clippedRect); 346 347 // Issue the repaint. 348 repaintRectangle(clippedRect); 349} 350 351void RenderRegion::installFlowThread() 352{ 353 ASSERT(view()); 354 355 m_flowThread = view()->flowThreadController()->ensureRenderFlowThreadWithName(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 reference. 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 374void 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 valid. 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 405void RenderRegion::detachRegion() 406{ 407 if (m_flowThread) { 408 m_flowThread->removeRegionFromThread(this); 409 if (hasAutoLogicalHeight()) 410 decrementAutoLogicalHeightCount(); 411 } 412 m_flowThread = 0; 413} 414 415RenderBoxRegionInfo* RenderRegion::renderBoxRegionInfo(const RenderBox* box) const 416{ 417 ASSERT(isValid()); 418 return m_renderBoxRegionInfo.get(box); 419} 420 421RenderBoxRegionInfo* 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, nullptr).iterator->value; 427 if (boxInfo) 428 *boxInfo = RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, containingBlockChainIsInset); 429 else 430 boxInfo = adoptPtr(new RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, containingBlockChainIsInset)); 431 432 return boxInfo.get(); 433} 434 435PassOwnPtr<RenderBoxRegionInfo> RenderRegion::takeRenderBoxRegionInfo(const RenderBox* box) 436{ 437 return m_renderBoxRegionInfo.take(box); 438} 439 440void RenderRegion::removeRenderBoxRegionInfo(const RenderBox* box) 441{ 442 m_renderBoxRegionInfo.remove(box); 443} 444 445void RenderRegion::deleteAllRenderBoxRegionInfo() 446{ 447 m_renderBoxRegionInfo.clear(); 448} 449 450LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rect) const 451{ 452 ASSERT(isValid()); 453 return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x(); 454} 455 456LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect& rect) const 457{ 458 ASSERT(isValid()); 459 return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX(); 460} 461 462void 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 computing a new one. 469 RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRenderFlowThreadWithName(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 new 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, objectRegionStyleCached); 497 498 computeChildrenStyleInRegion(object); 499 } 500} 501 502void RenderRegion::restoreRegionObjectsOriginalStyle() 503{ 504 if (!hasCustomRegionStyle()) 505 return; 506 507 RenderObjectRegionStyleMap temp; 508 for (RenderObjectRegionStyleMap::iterator iter = m_renderObjectRegionStyle.begin(), 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 = ContextSensitivePropertyNone; 518 StyleDifference styleDiff = objectOriginalStyle->diff(objectRegionStyle.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 533void RenderRegion::insertedIntoTree() 534{ 535 RenderBlock::insertedIntoTree(); 536 537 attachRegion(); 538} 539 540void RenderRegion::willBeRemovedFromTree() 541{ 542 RenderBlock::willBeRemovedFromTree(); 543 544 detachRegion(); 545} 546 547PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* object) 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().ensureStyleResolver().styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this); 557 558 return renderObjectRegionStyle.release(); 559} 560 561void RenderRegion::computeChildrenStyleInRegion(const RenderObject* object) 562{ 563 for (RenderObject* child = object->lastChild(); child; child = child->previousSibling()) { 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::createAnonymousStyleWithDisplay(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, objectRegionStyleCached); 582 583 computeChildrenStyleInRegion(child); 584 } 585} 586 587void RenderRegion::setObjectStyleInRegion(RenderObject* object, PassRefPtr<RenderStyle> 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 609void 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->previousSibling()) 616 clearObjectStyleInRegion(child); 617} 618 619void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const 620{ 621 if (!isValid()) { 622 RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth); 623 return; 624 } 625 626 minLogicalWidth = m_flowThread->minPreferredLogicalWidth(); 627 maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth(); 628} 629 630void RenderRegion::getRanges(Vector<RefPtr<Range> >& rangeObjects) const 631{ 632 RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRenderFlowThreadWithName(style()->regionThread()); 633 namedFlow->getRanges(rangeObjects, this); 634} 635 636void 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 prerequisite layout phase 650 // did not have the chance to layout flow thread content. Because of that, these 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 example) 664 RenderBlock::updateLogicalHeight(); 665 } 666} 667 668Node* RenderRegion::nodeForRegion() const 669{ 670 if (parent() && isRenderNamedFlowFragment()) 671 return parent()->node(); 672 return node(); 673} 674 675Node* RenderRegion::generatingNodeForRegion() const 676{ 677 if (parent() && isRenderNamedFlowFragment()) 678 return parent()->generatingNode(); 679 return generatingNode(); 680} 681 682bool RenderRegion::isElementBasedRegion() const 683{ 684 Node* node = nodeForRegion(); 685 return node && node->isElementNode() && !node->isPseudoElement(); 686} 687 688} // namespace WebCore 689