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