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