1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 3 * 4 * Portions are Copyright (C) 1998 Netscape Communications Corporation. 5 * 6 * Other contributors: 7 * Robert O'Callahan <roc+@cs.cmu.edu> 8 * David Baron <dbaron (at) fas.harvard.edu> 9 * Christian Biesinger <cbiesinger (at) web.de> 10 * Randall Jesup <rjesup (at) wgate.com> 11 * Roland Mainz <roland.mainz (at) informatik.med.uni-giessen.de> 12 * Josh Soref <timeless (at) mac.com> 13 * Boris Zbarsky <bzbarsky (at) mit.edu> 14 * 15 * This library is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU Lesser General Public 17 * License as published by the Free Software Foundation; either 18 * version 2.1 of the License, or (at your option) any later version. 19 * 20 * This library is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 * Lesser General Public License for more details. 24 * 25 * You should have received a copy of the GNU Lesser General Public 26 * License along with this library; if not, write to the Free Software 27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 28 * 29 * Alternatively, the contents of this file may be used under the terms 30 * of either the Mozilla Public License Version 1.1, found at 31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public 32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html 33 * (the "GPL"), in which case the provisions of the MPL or the GPL are 34 * applicable instead of those above. If you wish to allow use of your 35 * version of this file only under the terms of one of those two 36 * licenses (the MPL or the GPL) and not to allow others to use your 37 * version of this file under the LGPL, indicate your decision by 38 * deletingthe provisions above and replace them with the notice and 39 * other provisions required by the MPL or the GPL, as the case may be. 40 * If you do not delete the provisions above, a recipient may use your 41 * version of this file under any of the LGPL, the MPL or the GPL. 42 */ 43 44 #include "config.h" 45 #include "core/rendering/RenderLayer.h" 46 47 #include "CSSPropertyNames.h" 48 #include "HTMLNames.h" 49 #include "RuntimeEnabledFeatures.h" 50 #include "SVGNames.h" 51 #include "core/css/PseudoStyleRequest.h" 52 #include "core/dom/Document.h" 53 #include "core/dom/DocumentEventQueue.h" 54 #include "core/dom/shadow/ShadowRoot.h" 55 #include "core/editing/FrameSelection.h" 56 #include "core/html/HTMLFrameElement.h" 57 #include "core/html/HTMLFrameOwnerElement.h" 58 #include "core/inspector/InspectorInstrumentation.h" 59 #include "core/page/EventHandler.h" 60 #include "core/page/FocusController.h" 61 #include "core/page/Frame.h" 62 #include "core/page/FrameView.h" 63 #include "core/page/Page.h" 64 #include "core/page/Settings.h" 65 #include "core/page/UseCounter.h" 66 #include "core/page/animation/AnimationController.h" 67 #include "core/page/scrolling/ScrollingCoordinator.h" 68 #include "core/platform/HistogramSupport.h" 69 #include "core/platform/Partitions.h" 70 #include "core/platform/PlatformGestureEvent.h" 71 #include "core/platform/PlatformMouseEvent.h" 72 #include "core/platform/ScrollAnimator.h" 73 #include "core/platform/Scrollbar.h" 74 #include "core/platform/ScrollbarTheme.h" 75 #include "core/platform/chromium/TraceEvent.h" 76 #include "core/platform/graphics/FloatPoint3D.h" 77 #include "core/platform/graphics/FloatRect.h" 78 #include "core/platform/graphics/GraphicsContextStateSaver.h" 79 #include "core/platform/graphics/filters/ReferenceFilter.h" 80 #include "core/platform/graphics/filters/SourceGraphic.h" 81 #include "core/platform/graphics/filters/custom/CustomFilterGlobalContext.h" 82 #include "core/platform/graphics/filters/custom/CustomFilterOperation.h" 83 #include "core/platform/graphics/filters/custom/CustomFilterValidatedProgram.h" 84 #include "core/platform/graphics/filters/custom/ValidatedCustomFilterOperation.h" 85 #include "core/platform/graphics/transforms/ScaleTransformOperation.h" 86 #include "core/platform/graphics/transforms/TransformationMatrix.h" 87 #include "core/platform/graphics/transforms/TranslateTransformOperation.h" 88 #include "core/rendering/ColumnInfo.h" 89 #include "core/rendering/FilterEffectRenderer.h" 90 #include "core/rendering/HitTestRequest.h" 91 #include "core/rendering/HitTestResult.h" 92 #include "core/rendering/HitTestingTransformState.h" 93 #include "core/rendering/RenderFlowThread.h" 94 #include "core/rendering/RenderGeometryMap.h" 95 #include "core/rendering/RenderInline.h" 96 #include "core/rendering/RenderLayerBacking.h" 97 #include "core/rendering/RenderLayerCompositor.h" 98 #include "core/rendering/RenderReplica.h" 99 #include "core/rendering/RenderScrollbar.h" 100 #include "core/rendering/RenderScrollbarPart.h" 101 #include "core/rendering/RenderTreeAsText.h" 102 #include "core/rendering/RenderView.h" 103 #include "core/rendering/svg/ReferenceFilterBuilder.h" 104 #include "core/rendering/svg/RenderSVGResourceClipper.h" 105 #include "wtf/StdLibExtras.h" 106 #include "wtf/UnusedParam.h" 107 #include "wtf/text/CString.h" 108 109 #define MIN_INTERSECT_FOR_REVEAL 32 110 111 using namespace std; 112 113 namespace WebCore { 114 115 using namespace HTMLNames; 116 117 const int MinimumWidthWhileResizing = 100; 118 const int MinimumHeightWhileResizing = 40; 119 const int ResizerControlExpandRatioForTouch = 2; 120 121 bool ClipRect::intersects(const HitTestLocation& hitTestLocation) const 122 { 123 return hitTestLocation.intersects(m_rect); 124 } 125 126 RenderLayer::RenderLayer(RenderLayerModelObject* renderer) 127 : m_inResizeMode(false) 128 , m_scrollDimensionsDirty(true) 129 , m_normalFlowListDirty(true) 130 , m_hasSelfPaintingLayerDescendant(false) 131 , m_hasSelfPaintingLayerDescendantDirty(false) 132 , m_hasOutOfFlowPositionedDescendant(false) 133 , m_hasOutOfFlowPositionedDescendantDirty(true) 134 , m_hasUnclippedDescendant(false) 135 , m_needsCompositedScrolling(false) 136 , m_canBePromotedToStackingContainer(false) 137 , m_canBePromotedToStackingContainerDirty(true) 138 , m_isRootLayer(renderer->isRenderView()) 139 , m_usedTransparency(false) 140 , m_paintingInsideReflection(false) 141 , m_inOverflowRelayout(false) 142 , m_repaintStatus(NeedsNormalRepaint) 143 , m_visibleContentStatusDirty(true) 144 , m_hasVisibleContent(false) 145 , m_visibleDescendantStatusDirty(false) 146 , m_hasVisibleDescendant(false) 147 , m_isPaginated(false) 148 , m_3DTransformedDescendantStatusDirty(true) 149 , m_has3DTransformedDescendant(false) 150 , m_containsDirtyOverlayScrollbars(false) 151 #if !ASSERT_DISABLED 152 , m_layerListMutationAllowed(true) 153 #endif 154 , m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell()) 155 , m_hasFilterInfo(false) 156 , m_blendMode(BlendModeNormal) 157 , m_renderer(renderer) 158 , m_parent(0) 159 , m_previous(0) 160 , m_next(0) 161 , m_first(0) 162 , m_last(0) 163 , m_staticInlinePosition(0) 164 , m_staticBlockPosition(0) 165 , m_reflection(0) 166 , m_scrollCorner(0) 167 , m_resizer(0) 168 , m_enclosingPaginationLayer(0) 169 , m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling) 170 { 171 m_isNormalFlowOnly = shouldBeNormalFlowOnly(); 172 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer(); 173 174 // Non-stacking containers should have empty z-order lists. As this is already the case, 175 // there is no need to dirty / recompute these lists. 176 m_zOrderListsDirty = isStackingContainer(); 177 178 ScrollableArea::setConstrainsScrollingToContentEdge(false); 179 180 if (!renderer->firstChild() && renderer->style()) { 181 m_visibleContentStatusDirty = false; 182 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; 183 } 184 185 Node* node = renderer->node(); 186 if (node && node->isElementNode()) { 187 // We save and restore only the scrollOffset as the other scroll values are recalculated. 188 Element* element = toElement(node); 189 m_scrollOffset = element->savedLayerScrollOffset(); 190 if (!m_scrollOffset.isZero()) 191 scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height())); 192 element->setSavedLayerScrollOffset(IntSize()); 193 } 194 195 updateResizerAreaSet(); 196 } 197 198 RenderLayer::~RenderLayer() 199 { 200 if (inResizeMode() && !renderer()->documentBeingDestroyed()) { 201 if (Frame* frame = renderer()->frame()) 202 frame->eventHandler()->resizeLayerDestroyed(); 203 } 204 205 if (Frame* frame = renderer()->frame()) { 206 if (FrameView* frameView = frame->view()) { 207 frameView->removeScrollableArea(this); 208 frameView->removeResizerArea(this); 209 } 210 } 211 212 if (!m_renderer->documentBeingDestroyed()) { 213 Node* node = m_renderer->node(); 214 if (node && node->isElementNode()) 215 toElement(node)->setSavedLayerScrollOffset(m_scrollOffset); 216 } 217 218 if (!m_renderer->documentBeingDestroyed()) 219 compositor()->removeOutOfFlowPositionedLayer(this); 220 221 destroyScrollbar(HorizontalScrollbar); 222 destroyScrollbar(VerticalScrollbar); 223 224 if (renderer()->frame() && renderer()->frame()->page()) { 225 if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->page()->scrollingCoordinator()) 226 scrollingCoordinator->willDestroyScrollableArea(this); 227 } 228 229 if (m_reflection) 230 removeReflection(); 231 232 removeFilterInfoIfNeeded(); 233 234 // Child layers will be deleted by their corresponding render objects, so 235 // we don't need to delete them ourselves. 236 237 clearBacking(true); 238 239 if (m_scrollCorner) 240 m_scrollCorner->destroy(); 241 if (m_resizer) 242 m_resizer->destroy(); 243 } 244 245 #ifndef NDEBUG 246 String RenderLayer::debugName() const 247 { 248 String name = renderer()->debugName(); 249 if (!isReflection()) 250 return name; 251 return name + " (reflection)"; 252 } 253 #endif 254 255 RenderLayerCompositor* RenderLayer::compositor() const 256 { 257 if (!renderer()->view()) 258 return 0; 259 return renderer()->view()->compositor(); 260 } 261 262 void RenderLayer::contentChanged(ContentChangeType changeType) 263 { 264 // This can get called when video becomes accelerated, so the layers may change. 265 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this)) 266 compositor()->setCompositingLayersNeedRebuild(); 267 268 if (m_backing) 269 m_backing->contentChanged(changeType); 270 } 271 272 bool RenderLayer::canRender3DTransforms() const 273 { 274 return compositor()->canRender3DTransforms(); 275 } 276 277 bool RenderLayer::paintsWithFilters() const 278 { 279 // FIXME: Eventually there will be more factors than isComposited() to decide whether or not to render the filter 280 if (!renderer()->hasFilter()) 281 return false; 282 283 if (!isComposited()) 284 return true; 285 286 if (!m_backing || !m_backing->canCompositeFilters()) 287 return true; 288 289 return false; 290 } 291 292 bool RenderLayer::requiresFullLayerImageForFilters() const 293 { 294 if (!paintsWithFilters()) 295 return false; 296 FilterEffectRenderer* filter = filterRenderer(); 297 return filter ? filter->hasFilterThatMovesPixels() : false; 298 } 299 300 LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const 301 { 302 hasLayerOffset = true; 303 304 if (!parent()) 305 return LayoutPoint(); 306 307 // This is similar to root() but we check if an ancestor layer would 308 // prevent the optimization from working. 309 const RenderLayer* rootLayer = 0; 310 for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) { 311 hasLayerOffset = parentLayer->canUseConvertToLayerCoords(); 312 if (!hasLayerOffset) 313 return LayoutPoint(); 314 } 315 ASSERT(rootLayer == root()); 316 317 LayoutPoint offset; 318 parent()->convertToLayerCoords(rootLayer, offset); 319 return offset; 320 } 321 322 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags) 323 { 324 RenderGeometryMap geometryMap(UseTransforms); 325 if (this != rootLayer) 326 geometryMap.pushMappingsToAncestor(parent(), 0); 327 updateLayerPositions(&geometryMap, flags); 328 } 329 330 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags) 331 { 332 updateLayerPosition(); // For relpositioned layers or non-positioned layers, 333 // we need to keep in sync, since we may have shifted relative 334 // to our parent layer. 335 if (geometryMap) 336 geometryMap->pushMappingsToAncestor(this, parent()); 337 338 // Clear our cached clip rect information. 339 clearClipRects(); 340 341 if (hasOverflowControls()) { 342 LayoutPoint offsetFromRoot; 343 if (geometryMap) 344 offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint())); 345 else { 346 // FIXME: It looks suspicious to call convertToLayerCoords here 347 // as canUseConvertToLayerCoords may be true for an ancestor layer. 348 convertToLayerCoords(root(), offsetFromRoot); 349 } 350 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot))); 351 } 352 353 updateDescendantDependentFlags(); 354 355 if (flags & UpdatePagination) 356 updatePagination(); 357 else { 358 m_isPaginated = false; 359 m_enclosingPaginationLayer = 0; 360 } 361 362 if (m_hasVisibleContent) { 363 RenderView* view = renderer()->view(); 364 ASSERT(view); 365 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1 366 // mapping between them and the RenderObjects. It would be neat to enable 367 // LayoutState outside the layout() phase and use it here. 368 ASSERT(!view->layoutStateEnabled()); 369 370 RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint(); 371 LayoutRect oldRepaintRect = m_repaintRect; 372 LayoutRect oldOutlineBox = m_outlineBox; 373 computeRepaintRects(repaintContainer, geometryMap); 374 375 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same 376 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048 377 if (flags & CheckForRepaint) { 378 if (view && !view->printing()) { 379 if (m_repaintStatus & NeedsFullRepaint) { 380 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect)); 381 if (m_repaintRect != oldRepaintRect) 382 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect)); 383 } else if (shouldRepaintAfterLayout()) 384 renderer()->repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox); 385 } 386 } 387 } else 388 clearRepaintRects(); 389 390 m_repaintStatus = NeedsNormalRepaint; 391 392 // Go ahead and update the reflection's position and size. 393 if (m_reflection) 394 m_reflection->layout(); 395 396 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update. 397 bool isUpdateRoot = (flags & IsCompositingUpdateRoot); 398 if (isComposited()) 399 flags &= ~IsCompositingUpdateRoot; 400 401 if (useRegionBasedColumns() && renderer()->isInFlowRenderFlowThread()) { 402 updatePagination(); 403 flags |= UpdatePagination; 404 } 405 406 if (renderer()->hasColumns()) 407 flags |= UpdatePagination; 408 409 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 410 child->updateLayerPositions(geometryMap, flags); 411 412 if ((flags & UpdateCompositingLayers) && isComposited()) { 413 RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly; 414 if (flags & NeedsFullRepaintInBacking) 415 updateFlags |= RenderLayerBacking::NeedsFullRepaint; 416 if (isUpdateRoot) 417 updateFlags |= RenderLayerBacking::IsUpdateRoot; 418 backing()->updateAfterLayout(updateFlags); 419 } 420 421 if (geometryMap) 422 geometryMap->popMappingsToAncestor(parent()); 423 } 424 425 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const 426 { 427 LayoutRect repaintRect = m_repaintRect; 428 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 429 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin. 430 if (child->isComposited()) 431 continue; 432 433 repaintRect.unite(child->repaintRectIncludingNonCompositingDescendants()); 434 } 435 return repaintRect; 436 } 437 438 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant() 439 { 440 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 441 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant()) 442 break; 443 444 layer->m_hasSelfPaintingLayerDescendantDirty = false; 445 layer->m_hasSelfPaintingLayerDescendant = true; 446 } 447 } 448 449 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus() 450 { 451 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 452 layer->m_hasSelfPaintingLayerDescendantDirty = true; 453 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant 454 // in this case, there is no need to dirty our ancestors further. 455 if (layer->isSelfPaintingLayer()) { 456 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant()); 457 break; 458 } 459 } 460 } 461 462 void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant() 463 { 464 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 465 if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant()) 466 break; 467 468 layer->setHasOutOfFlowPositionedDescendantDirty(false); 469 layer->setHasOutOfFlowPositionedDescendant(true); 470 } 471 } 472 473 void RenderLayer::dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus() 474 { 475 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 476 layer->setHasOutOfFlowPositionedDescendantDirty(true); 477 478 // We may or may not have an unclipped descendant. If we do, we'll reset 479 // this to true the next time composited scrolling state is updated. 480 layer->setHasUnclippedDescendant(false); 481 482 // If we have reached an out of flow positioned layer, we know our parent should have an out-of-flow positioned descendant. 483 // In this case, there is no need to dirty our ancestors further. 484 if (layer->renderer()->isOutOfFlowPositioned()) { 485 ASSERT(!parent() || parent()->m_hasOutOfFlowPositionedDescendantDirty || parent()->hasOutOfFlowPositionedDescendant()); 486 break; 487 } 488 } 489 } 490 491 bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const 492 { 493 const Settings* settings = renderer()->document()->settings(); 494 return settings && settings->acceleratedCompositingForOverflowScrollEnabled(); 495 } 496 497 // FIXME: This is a temporary flag and should be removed once accelerated 498 // overflow scroll is ready (crbug.com/254111). 499 bool RenderLayer::compositorDrivenAcceleratedScrollingEnabled() const 500 { 501 const Settings* settings = renderer()->document()->settings(); 502 return settings && settings->isCompositorDrivenAcceleratedScrollingEnabled(); 503 } 504 505 // Determine whether the current layer can be promoted to a stacking container. 506 // We do this by computing what positive and negative z-order lists would look 507 // like before and after promotion, and ensuring that proper stacking order is 508 // preserved between the two sets of lists. 509 void RenderLayer::updateCanBeStackingContainer() 510 { 511 TRACE_EVENT0("blink_rendering", "RenderLayer::updateCanBeStackingContainer"); 512 513 if (isStackingContext() || !m_canBePromotedToStackingContainerDirty || !acceleratedCompositingForOverflowScrollEnabled()) 514 return; 515 516 FrameView* frameView = renderer()->view()->frameView(); 517 if (!frameView || !frameView->containsScrollableArea(this)) 518 return; 519 520 RenderLayer* ancestorStackingContext = this->ancestorStackingContext(); 521 if (!ancestorStackingContext) 522 return; 523 524 OwnPtr<Vector<RenderLayer*> > posZOrderListBeforePromote = adoptPtr(new Vector<RenderLayer*>); 525 OwnPtr<Vector<RenderLayer*> > negZOrderListBeforePromote = adoptPtr(new Vector<RenderLayer*>); 526 OwnPtr<Vector<RenderLayer*> > posZOrderListAfterPromote = adoptPtr(new Vector<RenderLayer*>); 527 OwnPtr<Vector<RenderLayer*> > negZOrderListAfterPromote = adoptPtr(new Vector<RenderLayer*>); 528 529 collectBeforePromotionZOrderList(ancestorStackingContext, posZOrderListBeforePromote, negZOrderListBeforePromote); 530 collectAfterPromotionZOrderList(ancestorStackingContext, posZOrderListAfterPromote, negZOrderListAfterPromote); 531 532 size_t maxIndex = std::min(posZOrderListAfterPromote->size() + negZOrderListAfterPromote->size(), posZOrderListBeforePromote->size() + negZOrderListBeforePromote->size()); 533 534 m_canBePromotedToStackingContainerDirty = false; 535 m_canBePromotedToStackingContainer = false; 536 537 const RenderLayer* layerAfterPromote = 0; 538 for (size_t i = 0; i < maxIndex && layerAfterPromote != this; ++i) { 539 const RenderLayer* layerBeforePromote = i < negZOrderListBeforePromote->size() 540 ? negZOrderListBeforePromote->at(i) 541 : posZOrderListBeforePromote->at(i - negZOrderListBeforePromote->size()); 542 layerAfterPromote = i < negZOrderListAfterPromote->size() 543 ? negZOrderListAfterPromote->at(i) 544 : posZOrderListAfterPromote->at(i - negZOrderListAfterPromote->size()); 545 546 if (layerBeforePromote != layerAfterPromote && (layerAfterPromote != this || renderer()->hasBackground())) 547 return; 548 } 549 550 layerAfterPromote = 0; 551 for (size_t i = 0; i < maxIndex && layerAfterPromote != this; ++i) { 552 const RenderLayer* layerBeforePromote = i < posZOrderListBeforePromote->size() 553 ? posZOrderListBeforePromote->at(posZOrderListBeforePromote->size() - i - 1) 554 : negZOrderListBeforePromote->at(negZOrderListBeforePromote->size() + posZOrderListBeforePromote->size() - i - 1); 555 layerAfterPromote = i < posZOrderListAfterPromote->size() 556 ? posZOrderListAfterPromote->at(posZOrderListAfterPromote->size() - i - 1) 557 : negZOrderListAfterPromote->at(negZOrderListAfterPromote->size() + posZOrderListAfterPromote->size() - i - 1); 558 559 if (layerBeforePromote != layerAfterPromote && layerAfterPromote != this) 560 return; 561 } 562 563 m_canBePromotedToStackingContainer = true; 564 } 565 566 static inline bool isPositionedContainer(const RenderLayer* layer) 567 { 568 // FIXME: This is not in sync with containingBlock. 569 // RenderObject::canContainFixedPositionedObject() should probably be used 570 // instead. 571 RenderLayerModelObject* layerRenderer = layer->renderer(); 572 return layer->isRootLayer() || layerRenderer->isPositioned() || layer->hasTransform(); 573 } 574 575 void RenderLayer::collectBeforePromotionZOrderList(RenderLayer* ancestorStackingContext, OwnPtr<Vector<RenderLayer*> >& posZOrderListBeforePromote, OwnPtr<Vector<RenderLayer*> >& negZOrderListBeforePromote) 576 { 577 ancestorStackingContext->rebuildZOrderLists(posZOrderListBeforePromote, negZOrderListBeforePromote, this, OnlyStackingContextsCanBeStackingContainers); 578 579 const RenderLayer* positionedAncestor = parent(); 580 while (positionedAncestor && !isPositionedContainer(positionedAncestor) && !positionedAncestor->isStackingContext()) 581 positionedAncestor = positionedAncestor->parent(); 582 if (positionedAncestor && (!isPositionedContainer(positionedAncestor) || positionedAncestor->isStackingContext())) 583 positionedAncestor = 0; 584 585 if (!posZOrderListBeforePromote) 586 posZOrderListBeforePromote = adoptPtr(new Vector<RenderLayer*>()); 587 else if (posZOrderListBeforePromote->find(this) != notFound) 588 return; 589 590 // The current layer will appear in the z-order lists after promotion, so 591 // for a meaningful comparison, we must insert it in the z-order lists 592 // before promotion if it does not appear there already. 593 if (!positionedAncestor) { 594 posZOrderListBeforePromote->prepend(this); 595 return; 596 } 597 598 for (size_t index = 0; index < posZOrderListBeforePromote->size(); index++) { 599 if (posZOrderListBeforePromote->at(index) == positionedAncestor) { 600 posZOrderListBeforePromote->insert(index + 1, this); 601 return; 602 } 603 } 604 } 605 606 void RenderLayer::collectAfterPromotionZOrderList(RenderLayer* ancestorStackingContext, OwnPtr<Vector<RenderLayer*> >& posZOrderListAfterPromote, OwnPtr<Vector<RenderLayer*> >& negZOrderListAfterPromote) 607 { 608 ancestorStackingContext->rebuildZOrderLists(posZOrderListAfterPromote, negZOrderListAfterPromote, this, ForceLayerToStackingContainer); 609 } 610 611 // Compute what positive and negative z-order lists would look like before and 612 // after promotion, so we can later ensure that proper stacking order is 613 // preserved between the two sets of lists. 614 // 615 // A few examples: 616 // c = currentLayer 617 // - = negative z-order child of currentLayer 618 // + = positive z-order child of currentLayer 619 // a = positioned ancestor of currentLayer 620 // x = any other RenderLayer in the list 621 // 622 // (a) xxxxx-----++a+++x 623 // (b) xxx-----c++++++xx 624 // 625 // Normally the current layer would be painted in the normal flow list if it 626 // doesn't already appear in the positive z-order list. However, in the case 627 // that the layer has a positioned ancestor, it will paint directly after the 628 // positioned ancestor. In example (a), the current layer would be painted in 629 // the middle of its own positive z-order children, so promoting would cause a 630 // change in paint order (since a promoted layer will paint all of its positive 631 // z-order children strictly after it paints itself). 632 // 633 // In example (b), it is ok to promote the current layer only if it does not 634 // have a background. If it has a background, the background gets painted before 635 // the layer's negative z-order children, so again, a promotion would cause a 636 // change in paint order (causing the background to get painted after the 637 // negative z-order children instead of before). 638 // 639 void RenderLayer::computePaintOrderList(PaintOrderListType type, Vector<RefPtr<Node> >& list) 640 { 641 OwnPtr<Vector<RenderLayer*> > posZOrderList; 642 OwnPtr<Vector<RenderLayer*> > negZOrderList; 643 644 RenderLayer* stackingContext = ancestorStackingContext(); 645 646 if (!stackingContext) 647 return; 648 649 switch (type) { 650 case BeforePromote: 651 collectBeforePromotionZOrderList(stackingContext, posZOrderList, negZOrderList); 652 break; 653 case AfterPromote: 654 collectAfterPromotionZOrderList(stackingContext, posZOrderList, negZOrderList); 655 break; 656 } 657 658 if (negZOrderList) { 659 for (size_t index = 0; index < negZOrderList->size(); ++index) 660 list.append(negZOrderList->at(index)->renderer()->node()); 661 } 662 663 if (posZOrderList) { 664 for (size_t index = 0; index < posZOrderList->size(); ++index) 665 list.append(posZOrderList->at(index)->renderer()->node()); 666 } 667 } 668 669 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) 670 { 671 ASSERT(!m_visibleContentStatusDirty); 672 673 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); 674 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, geometryMap); 675 } 676 677 678 void RenderLayer::computeRepaintRectsIncludingDescendants() 679 { 680 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects. 681 // We should make this more efficient. 682 // FIXME: it's wrong to call this when layout is not up-to-date, which we do. 683 computeRepaintRects(renderer()->containerForRepaint()); 684 685 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling()) 686 layer->computeRepaintRectsIncludingDescendants(); 687 } 688 689 void RenderLayer::clearRepaintRects() 690 { 691 ASSERT(!m_hasVisibleContent); 692 ASSERT(!m_visibleContentStatusDirty); 693 694 m_repaintRect = IntRect(); 695 m_outlineBox = IntRect(); 696 } 697 698 void RenderLayer::updateLayerPositionsAfterDocumentScroll() 699 { 700 ASSERT(this == renderer()->view()->layer()); 701 702 RenderGeometryMap geometryMap(UseTransforms); 703 updateLayerPositionsAfterScroll(&geometryMap); 704 } 705 706 void RenderLayer::updateLayerPositionsAfterOverflowScroll() 707 { 708 RenderGeometryMap geometryMap(UseTransforms); 709 RenderView* view = renderer()->view(); 710 if (this != view->layer()) 711 geometryMap.pushMappingsToAncestor(parent(), 0); 712 713 // FIXME: why is it OK to not check the ancestors of this layer in order to 714 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags? 715 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll); 716 } 717 718 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags) 719 { 720 // FIXME: This shouldn't be needed, but there are some corner cases where 721 // these flags are still dirty. Update so that the check below is valid. 722 updateDescendantDependentFlags(); 723 724 // If we have no visible content and no visible descendants, there is no point recomputing 725 // our rectangles as they will be empty. If our visibility changes, we are expected to 726 // recompute all our positions anyway. 727 if (!m_hasVisibleDescendant && !m_hasVisibleContent) 728 return; 729 730 bool positionChanged = updateLayerPosition(); 731 if (positionChanged) 732 flags |= HasChangedAncestor; 733 734 if (geometryMap) 735 geometryMap->pushMappingsToAncestor(this, parent()); 736 737 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll) 738 clearClipRects(); 739 740 if (renderer()->style()->hasViewportConstrainedPosition()) 741 flags |= HasSeenViewportConstrainedAncestor; 742 743 if (renderer()->hasOverflowClip()) 744 flags |= HasSeenAncestorWithOverflowClip; 745 746 if (flags & HasSeenViewportConstrainedAncestor 747 || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip && !m_canSkipRepaintRectsUpdateOnScroll)) { 748 // FIXME: We could track the repaint container as we walk down the tree. 749 computeRepaintRects(renderer()->containerForRepaint(), geometryMap); 750 } else { 751 // Check that our cached rects are correct. 752 // FIXME: re-enable these assertions when the issue with table cells is resolved: https://bugs.webkit.org/show_bug.cgi?id=103432 753 // ASSERT(m_repaintRect == renderer()->clippedOverflowRectForRepaint(renderer()->containerForRepaint())); 754 // ASSERT(m_outlineBox == renderer()->outlineBoundsForRepaint(renderer()->containerForRepaint(), geometryMap)); 755 } 756 757 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 758 child->updateLayerPositionsAfterScroll(geometryMap, flags); 759 760 // We don't update our reflection as scrolling is a translation which does not change the size() 761 // of an object, thus RenderReplica will still repaint itself properly as the layer position was 762 // updated above. 763 764 if (geometryMap) 765 geometryMap->popMappingsToAncestor(parent()); 766 } 767 768 void RenderLayer::positionNewlyCreatedOverflowControls() 769 { 770 if (!backing()->hasUnpositionedOverflowControlsLayers()) 771 return; 772 773 RenderGeometryMap geometryMap(UseTransforms); 774 RenderView* view = renderer()->view(); 775 if (this != view->layer() && parent()) 776 geometryMap.pushMappingsToAncestor(parent(), 0); 777 778 LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint())); 779 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot))); 780 } 781 782 bool RenderLayer::hasBlendMode() const 783 { 784 return RuntimeEnabledFeatures::cssCompositingEnabled() && renderer()->hasBlendMode(); 785 } 786 787 void RenderLayer::updateBlendMode() 788 { 789 if (!RuntimeEnabledFeatures::cssCompositingEnabled()) 790 return; 791 792 BlendMode newBlendMode = renderer()->style()->blendMode(); 793 if (newBlendMode != m_blendMode) { 794 m_blendMode = newBlendMode; 795 if (backing()) 796 backing()->setBlendMode(newBlendMode); 797 } 798 } 799 800 void RenderLayer::updateTransform() 801 { 802 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, 803 // so check style too. 804 bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform(); 805 bool had3DTransform = has3DTransform(); 806 807 bool hadTransform = m_transform; 808 if (hasTransform != hadTransform) { 809 if (hasTransform) 810 m_transform = adoptPtr(new TransformationMatrix); 811 else 812 m_transform.clear(); 813 814 // Layers with transforms act as clip rects roots, so clear the cached clip rects here. 815 clearClipRectsIncludingDescendants(); 816 } 817 818 if (hasTransform) { 819 RenderBox* box = renderBox(); 820 ASSERT(box); 821 m_transform->makeIdentity(); 822 box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin); 823 makeMatrixRenderable(*m_transform, canRender3DTransforms()); 824 } 825 826 if (had3DTransform != has3DTransform()) 827 dirty3DTransformedDescendantStatus(); 828 } 829 830 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const 831 { 832 if (!m_transform) 833 return TransformationMatrix(); 834 835 if (renderer()->style()->isRunningAcceleratedAnimation()) { 836 TransformationMatrix currTransform; 837 RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer()); 838 style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), applyOrigin); 839 makeMatrixRenderable(currTransform, canRender3DTransforms()); 840 return currTransform; 841 } 842 843 // m_transform includes transform-origin, so we need to recompute the transform here. 844 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) { 845 RenderBox* box = renderBox(); 846 TransformationMatrix currTransform; 847 box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); 848 makeMatrixRenderable(currTransform, canRender3DTransforms()); 849 return currTransform; 850 } 851 852 return *m_transform; 853 } 854 855 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const 856 { 857 if (!m_transform) 858 return TransformationMatrix(); 859 860 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) { 861 TransformationMatrix matrix = *m_transform; 862 makeMatrixRenderable(matrix, false /* flatten 3d */); 863 return matrix; 864 } 865 866 return *m_transform; 867 } 868 869 static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer) 870 { 871 RenderView* view = renderer->view(); 872 RenderLayerModelObject* prevBlock = renderer; 873 RenderBlock* containingBlock; 874 for (containingBlock = renderer->containingBlock(); 875 containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer; 876 containingBlock = containingBlock->containingBlock()) 877 prevBlock = containingBlock; 878 879 // If the columns block wasn't in our containing block chain, then we aren't paginated by it. 880 if (containingBlock != ancestorColumnsRenderer) 881 return false; 882 883 // If the previous block is absolutely positioned, then we can't be paginated by the columns block. 884 if (prevBlock->isOutOfFlowPositioned()) 885 return false; 886 887 // Otherwise we are paginated by the columns block. 888 return true; 889 } 890 891 bool RenderLayer::useRegionBasedColumns() const 892 { 893 const Settings* settings = renderer()->document()->settings(); 894 return settings && settings->regionBasedColumnsEnabled(); 895 } 896 897 void RenderLayer::updatePagination() 898 { 899 m_isPaginated = false; 900 m_enclosingPaginationLayer = 0; 901 902 if (isComposited() || !parent()) 903 return; // FIXME: We will have to deal with paginated compositing layers someday. 904 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though. 905 906 // The main difference between the paginated booleans for the old column code and the new column code 907 // is that each paginated layer has to paint on its own with the new code. There is no 908 // recurring into child layers. This means that the m_isPaginated bits for the new column code can't just be set on 909 // "roots" that get split and paint all their descendants. Instead each layer has to be checked individually and 910 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant 911 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back 912 // to that layer easily. 913 bool regionBasedColumnsUsed = useRegionBasedColumns(); 914 if (regionBasedColumnsUsed && renderer()->isInFlowRenderFlowThread()) { 915 m_enclosingPaginationLayer = this; 916 return; 917 } 918 919 if (isNormalFlowOnly()) { 920 if (regionBasedColumnsUsed) { 921 // Content inside a transform is not considered to be paginated, since we simply 922 // paint the transform multiple times in each column, so we don't have to use 923 // fragments for the transformed content. 924 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(); 925 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform()) 926 m_enclosingPaginationLayer = 0; 927 } else 928 m_isPaginated = parent()->renderer()->hasColumns(); 929 return; 930 } 931 932 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once 933 // we find one, then we just check its pagination status. 934 if (regionBasedColumnsUsed) { 935 RenderView* view = renderer()->view(); 936 RenderBlock* containingBlock; 937 for (containingBlock = renderer()->containingBlock(); 938 containingBlock && containingBlock != view; 939 containingBlock = containingBlock->containingBlock()) { 940 if (containingBlock->hasLayer()) { 941 // Content inside a transform is not considered to be paginated, since we simply 942 // paint the transform multiple times in each column, so we don't have to use 943 // fragments for the transformed content. 944 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(); 945 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform()) 946 m_enclosingPaginationLayer = 0; 947 return; 948 } 949 } 950 return; 951 } 952 953 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container. 954 RenderLayer* ancestorStackingContainer = this->ancestorStackingContainer(); 955 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { 956 if (curr->renderer()->hasColumns()) { 957 m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox()); 958 return; 959 } 960 if (curr == ancestorStackingContainer) 961 return; 962 } 963 } 964 965 bool RenderLayer::canBeStackingContainer() const 966 { 967 if (isStackingContext() || !ancestorStackingContainer()) 968 return true; 969 970 ASSERT(!m_canBePromotedToStackingContainerDirty); 971 return m_canBePromotedToStackingContainer; 972 } 973 974 void RenderLayer::setHasVisibleContent() 975 { 976 if (m_hasVisibleContent && !m_visibleContentStatusDirty) { 977 ASSERT(!parent() || parent()->hasVisibleDescendant()); 978 return; 979 } 980 981 m_visibleContentStatusDirty = false; 982 m_hasVisibleContent = true; 983 computeRepaintRects(renderer()->containerForRepaint()); 984 if (!isNormalFlowOnly()) { 985 // We don't collect invisible layers in z-order lists if we are not in compositing mode. 986 // As we became visible, we need to dirty our stacking containers ancestors to be properly 987 // collected. FIXME: When compositing, we could skip this dirtying phase. 988 for (RenderLayer* sc = ancestorStackingContainer(); sc; sc = sc->ancestorStackingContainer()) { 989 sc->dirtyZOrderLists(); 990 if (sc->hasVisibleContent()) 991 break; 992 } 993 } 994 995 if (parent()) 996 parent()->setAncestorChainHasVisibleDescendant(); 997 } 998 999 void RenderLayer::dirtyVisibleContentStatus() 1000 { 1001 m_visibleContentStatusDirty = true; 1002 if (parent()) 1003 parent()->dirtyAncestorChainVisibleDescendantStatus(); 1004 } 1005 1006 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus() 1007 { 1008 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 1009 if (layer->m_visibleDescendantStatusDirty) 1010 break; 1011 1012 layer->m_visibleDescendantStatusDirty = true; 1013 } 1014 } 1015 1016 void RenderLayer::setAncestorChainHasVisibleDescendant() 1017 { 1018 for (RenderLayer* layer = this; layer; layer = layer->parent()) { 1019 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant()) 1020 break; 1021 1022 layer->m_hasVisibleDescendant = true; 1023 layer->m_visibleDescendantStatusDirty = false; 1024 } 1025 } 1026 1027 void RenderLayer::updateHasUnclippedDescendant() 1028 { 1029 TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasUnclippedDescendant"); 1030 ASSERT(renderer()->isOutOfFlowPositioned()); 1031 if (!m_hasVisibleContent && !m_hasVisibleDescendant) 1032 return; 1033 1034 const RenderObject* containingBlock = renderer()->containingBlock(); 1035 for (RenderLayer* ancestor = parent(); ancestor && ancestor->renderer() != containingBlock; ancestor = ancestor->parent()) 1036 ancestor->setHasUnclippedDescendant(true); 1037 } 1038 1039 static bool subtreeContainsOutOfFlowPositionedLayer(const RenderLayer* subtreeRoot) 1040 { 1041 return (subtreeRoot->renderer() && subtreeRoot->renderer()->isOutOfFlowPositioned()) || subtreeRoot->hasOutOfFlowPositionedDescendant(); 1042 } 1043 1044 void RenderLayer::updateDescendantDependentFlags() 1045 { 1046 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) { 1047 m_hasVisibleDescendant = false; 1048 m_hasSelfPaintingLayerDescendant = false; 1049 m_hasOutOfFlowPositionedDescendant = false; 1050 1051 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 1052 child->updateDescendantDependentFlags(); 1053 1054 bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant; 1055 bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant(); 1056 bool hasOutOfFlowPositionedDescendant = subtreeContainsOutOfFlowPositionedLayer(child); 1057 1058 m_hasVisibleDescendant |= hasVisibleDescendant; 1059 m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant; 1060 m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant; 1061 1062 if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant) 1063 break; 1064 } 1065 1066 m_visibleDescendantStatusDirty = false; 1067 m_hasSelfPaintingLayerDescendantDirty = false; 1068 m_hasOutOfFlowPositionedDescendantDirty = false; 1069 } 1070 1071 if (m_visibleContentStatusDirty) { 1072 if (renderer()->style()->visibility() == VISIBLE) 1073 m_hasVisibleContent = true; 1074 else { 1075 // layer may be hidden but still have some visible content, check for this 1076 m_hasVisibleContent = false; 1077 RenderObject* r = renderer()->firstChild(); 1078 while (r) { 1079 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { 1080 m_hasVisibleContent = true; 1081 break; 1082 } 1083 if (r->firstChild() && !r->hasLayer()) 1084 r = r->firstChild(); 1085 else if (r->nextSibling()) 1086 r = r->nextSibling(); 1087 else { 1088 do { 1089 r = r->parent(); 1090 if (r == renderer()) 1091 r = 0; 1092 } while (r && !r->nextSibling()); 1093 if (r) 1094 r = r->nextSibling(); 1095 } 1096 } 1097 } 1098 m_visibleContentStatusDirty = false; 1099 } 1100 } 1101 1102 void RenderLayer::dirty3DTransformedDescendantStatus() 1103 { 1104 RenderLayer* curr = ancestorStackingContainer(); 1105 if (curr) 1106 curr->m_3DTransformedDescendantStatusDirty = true; 1107 1108 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer. 1109 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers. 1110 while (curr && curr->preserves3D()) { 1111 curr->m_3DTransformedDescendantStatusDirty = true; 1112 curr = curr->ancestorStackingContainer(); 1113 } 1114 } 1115 1116 // Return true if this layer or any preserve-3d descendants have 3d. 1117 bool RenderLayer::update3DTransformedDescendantStatus() 1118 { 1119 if (m_3DTransformedDescendantStatusDirty) { 1120 m_has3DTransformedDescendant = false; 1121 1122 updateZOrderLists(); 1123 1124 // Transformed or preserve-3d descendants can only be in the z-order lists, not 1125 // in the normal flow list, so we only need to check those. 1126 if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) { 1127 for (unsigned i = 0; i < positiveZOrderList->size(); ++i) 1128 m_has3DTransformedDescendant |= positiveZOrderList->at(i)->update3DTransformedDescendantStatus(); 1129 } 1130 1131 // Now check our negative z-index children. 1132 if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) { 1133 for (unsigned i = 0; i < negativeZOrderList->size(); ++i) 1134 m_has3DTransformedDescendant |= negativeZOrderList->at(i)->update3DTransformedDescendantStatus(); 1135 } 1136 1137 m_3DTransformedDescendantStatusDirty = false; 1138 } 1139 1140 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs 1141 // the m_has3DTransformedDescendant set. 1142 if (preserves3D()) 1143 return has3DTransform() || m_has3DTransformedDescendant; 1144 1145 return has3DTransform(); 1146 } 1147 1148 bool RenderLayer::updateLayerPosition() 1149 { 1150 LayoutPoint localPoint; 1151 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done. 1152 if (renderer()->isInline() && renderer()->isRenderInline()) { 1153 RenderInline* inlineFlow = toRenderInline(renderer()); 1154 IntRect lineBox = inlineFlow->linesBoundingBox(); 1155 setSize(lineBox.size()); 1156 inlineBoundingBoxOffset = toSize(lineBox.location()); 1157 localPoint += inlineBoundingBoxOffset; 1158 } else if (RenderBox* box = renderBox()) { 1159 // FIXME: Is snapping the size really needed here for the RenderBox case? 1160 setSize(pixelSnappedIntSize(box->size(), box->location())); 1161 localPoint += box->topLeftLocationOffset(); 1162 } 1163 1164 if (!renderer()->isOutOfFlowPositioned() && renderer()->parent()) { 1165 // We must adjust our position by walking up the render tree looking for the 1166 // nearest enclosing object with a layer. 1167 RenderObject* curr = renderer()->parent(); 1168 while (curr && !curr->hasLayer()) { 1169 if (curr->isBox() && !curr->isTableRow()) { 1170 // Rows and cells share the same coordinate space (that of the section). 1171 // Omit them when computing our xpos/ypos. 1172 localPoint += toRenderBox(curr)->topLeftLocationOffset(); 1173 } 1174 curr = curr->parent(); 1175 } 1176 if (curr->isBox() && curr->isTableRow()) { 1177 // Put ourselves into the row coordinate space. 1178 localPoint -= toRenderBox(curr)->topLeftLocationOffset(); 1179 } 1180 } 1181 1182 // Subtract our parent's scroll offset. 1183 if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) { 1184 RenderLayer* positionedParent = enclosingPositionedAncestor(); 1185 1186 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. 1187 if (positionedParent->renderer()->hasOverflowClip()) { 1188 LayoutSize offset = positionedParent->scrolledContentOffset(); 1189 localPoint -= offset; 1190 } 1191 1192 if (renderer()->isOutOfFlowPositioned() && positionedParent->renderer()->isInFlowPositioned() && positionedParent->renderer()->isRenderInline()) { 1193 LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(toRenderBox(renderer())); 1194 localPoint += offset; 1195 } 1196 } else if (parent()) { 1197 if (isComposited()) { 1198 // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column. 1199 // They won't split across columns properly. 1200 LayoutSize columnOffset; 1201 if (!parent()->renderer()->hasColumns() && parent()->renderer()->isRoot() && renderer()->view()->hasColumns()) 1202 renderer()->view()->adjustForColumns(columnOffset, localPoint); 1203 else 1204 parent()->renderer()->adjustForColumns(columnOffset, localPoint); 1205 1206 localPoint += columnOffset; 1207 } 1208 1209 if (parent()->renderer()->hasOverflowClip()) { 1210 IntSize scrollOffset = parent()->scrolledContentOffset(); 1211 localPoint -= scrollOffset; 1212 } 1213 } 1214 1215 bool positionOrOffsetChanged = false; 1216 if (renderer()->isInFlowPositioned()) { 1217 LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFlowPosition(); 1218 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition; 1219 m_offsetForInFlowPosition = newOffset; 1220 localPoint.move(m_offsetForInFlowPosition); 1221 } else { 1222 m_offsetForInFlowPosition = LayoutSize(); 1223 } 1224 1225 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. 1226 localPoint -= inlineBoundingBoxOffset; 1227 1228 positionOrOffsetChanged |= location() != localPoint; 1229 setLocation(localPoint); 1230 return positionOrOffsetChanged; 1231 } 1232 1233 TransformationMatrix RenderLayer::perspectiveTransform() const 1234 { 1235 if (!renderer()->hasTransform()) 1236 return TransformationMatrix(); 1237 1238 RenderStyle* style = renderer()->style(); 1239 if (!style->hasPerspective()) 1240 return TransformationMatrix(); 1241 1242 // Maybe fetch the perspective from the backing? 1243 const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect(); 1244 const float boxWidth = borderBox.width(); 1245 const float boxHeight = borderBox.height(); 1246 1247 float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(), boxWidth); 1248 float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(), boxHeight); 1249 1250 // A perspective origin of 0,0 makes the vanishing point in the center of the element. 1251 // We want it to be in the top-left, so subtract half the height and width. 1252 perspectiveOriginX -= boxWidth / 2.0f; 1253 perspectiveOriginY -= boxHeight / 2.0f; 1254 1255 TransformationMatrix t; 1256 t.translate(perspectiveOriginX, perspectiveOriginY); 1257 t.applyPerspective(style->perspective()); 1258 t.translate(-perspectiveOriginX, -perspectiveOriginY); 1259 1260 return t; 1261 } 1262 1263 FloatPoint RenderLayer::perspectiveOrigin() const 1264 { 1265 if (!renderer()->hasTransform()) 1266 return FloatPoint(); 1267 1268 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect(); 1269 RenderStyle* style = renderer()->style(); 1270 1271 return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width()), 1272 floatValueForLength(style->perspectiveOriginY(), borderBox.height())); 1273 } 1274 1275 RenderLayer* RenderLayer::ancestorStackingContainer() const 1276 { 1277 RenderLayer* ancestor = parent(); 1278 while (ancestor && !ancestor->isStackingContainer()) 1279 ancestor = ancestor->parent(); 1280 return ancestor; 1281 } 1282 1283 RenderLayer* RenderLayer::ancestorStackingContext() const 1284 { 1285 RenderLayer* ancestor = parent(); 1286 while (ancestor && !ancestor->isStackingContext()) 1287 ancestor = ancestor->parent(); 1288 return ancestor; 1289 } 1290 1291 static inline bool isFixedPositionedContainer(RenderLayer* layer) 1292 { 1293 return layer->isRootLayer() || layer->hasTransform(); 1294 } 1295 1296 RenderLayer* RenderLayer::enclosingPositionedAncestor() const 1297 { 1298 RenderLayer* curr = parent(); 1299 while (curr && !isPositionedContainer(curr)) 1300 curr = curr->parent(); 1301 1302 return curr; 1303 } 1304 1305 RenderLayer* RenderLayer::enclosingScrollableLayer() const 1306 { 1307 for (RenderObject* nextRenderer = renderer()->parent(); nextRenderer; nextRenderer = nextRenderer->parent()) { 1308 if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea()) 1309 return nextRenderer->enclosingLayer(); 1310 } 1311 1312 return 0; 1313 } 1314 1315 IntRect RenderLayer::scrollableAreaBoundingBox() const 1316 { 1317 return renderer()->absoluteBoundingBoxRect(); 1318 } 1319 1320 bool RenderLayer::userInputScrollable(ScrollbarOrientation orientation) const 1321 { 1322 RenderBox* box = renderBox(); 1323 ASSERT(box); 1324 1325 EOverflow overflowStyle = (orientation == HorizontalScrollbar) ? 1326 renderer()->style()->overflowX() : renderer()->style()->overflowY(); 1327 return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle == OOVERLAY); 1328 } 1329 1330 int RenderLayer::pageStep(ScrollbarOrientation orientation) const 1331 { 1332 RenderBox* box = renderBox(); 1333 ASSERT(box); 1334 1335 int length = (orientation == HorizontalScrollbar) ? 1336 box->pixelSnappedClientWidth() : box->pixelSnappedClientHeight(); 1337 int minPageStep = static_cast<float>(length) * ScrollableArea::minFractionToStepWhenPaging(); 1338 int pageStep = max(minPageStep, length - ScrollableArea::maxOverlapBetweenPages()); 1339 1340 return max(pageStep, 1); 1341 } 1342 1343 RenderLayer* RenderLayer::enclosingTransformedAncestor() const 1344 { 1345 RenderLayer* curr = parent(); 1346 while (curr && !curr->isRootLayer() && !curr->transform()) 1347 curr = curr->parent(); 1348 1349 return curr; 1350 } 1351 1352 static inline const RenderLayer* compositingContainer(const RenderLayer* layer) 1353 { 1354 return layer->isNormalFlowOnly() ? layer->parent() : layer->ancestorStackingContainer(); 1355 } 1356 1357 inline bool RenderLayer::shouldRepaintAfterLayout() const 1358 { 1359 if (m_repaintStatus == NeedsNormalRepaint) 1360 return true; 1361 1362 // Composited layers that were moved during a positioned movement only 1363 // layout, don't need to be repainted. They just need to be recomposited. 1364 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout); 1365 return !isComposited(); 1366 } 1367 1368 RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const 1369 { 1370 if (includeSelf && isComposited()) 1371 return const_cast<RenderLayer*>(this); 1372 1373 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) { 1374 if (curr->isComposited()) 1375 return const_cast<RenderLayer*>(curr); 1376 } 1377 1378 return 0; 1379 } 1380 1381 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const 1382 { 1383 if (includeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor()) 1384 return const_cast<RenderLayer*>(this); 1385 1386 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) { 1387 if (curr->isComposited() && !curr->backing()->paintsIntoCompositedAncestor()) 1388 return const_cast<RenderLayer*>(curr); 1389 } 1390 1391 return 0; 1392 } 1393 1394 RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const 1395 { 1396 const RenderLayer* curr = includeSelf ? this : parent(); 1397 for (; curr; curr = curr->parent()) { 1398 if (curr->requiresFullLayerImageForFilters()) 1399 return const_cast<RenderLayer*>(curr); 1400 } 1401 1402 return 0; 1403 } 1404 1405 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const 1406 { 1407 for (const RenderLayer* curr = this; curr; curr = curr->parent()) { 1408 if ((curr != this && curr->requiresFullLayerImageForFilters()) || curr->isComposited() || curr->isRootLayer()) 1409 return const_cast<RenderLayer*>(curr); 1410 } 1411 return 0; 1412 } 1413 1414 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect) 1415 { 1416 if (rect.isEmpty()) 1417 return; 1418 1419 LayoutRect rectForRepaint = rect; 1420 renderer()->style()->filterOutsets().expandRect(rectForRepaint); 1421 1422 RenderLayerFilterInfo* filterInfo = this->filterInfo(); 1423 ASSERT(filterInfo); 1424 filterInfo->expandDirtySourceRect(rectForRepaint); 1425 1426 ASSERT(filterInfo->renderer()); 1427 if (filterInfo->renderer()->hasCustomShaderFilter()) { 1428 // If we have at least one custom shader, we need to update the whole bounding box of the layer, because the 1429 // shader can address any ouput pixel. 1430 // Note: This is only for output rect, so there's no need to expand the dirty source rect. 1431 rectForRepaint.unite(calculateLayerBounds(this)); 1432 } 1433 1434 RenderLayer* parentLayer = enclosingFilterRepaintLayer(); 1435 ASSERT(parentLayer); 1436 FloatQuad repaintQuad(rectForRepaint); 1437 LayoutRect parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox(); 1438 1439 if (parentLayer->isComposited()) { 1440 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect); 1441 return; 1442 } 1443 1444 if (parentLayer->paintsWithFilters()) { 1445 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect); 1446 return; 1447 } 1448 1449 if (parentLayer->isRootLayer()) { 1450 RenderView* view = toRenderView(parentLayer->renderer()); 1451 view->repaintViewRectangle(parentLayerRect); 1452 return; 1453 } 1454 1455 ASSERT_NOT_REACHED(); 1456 } 1457 1458 bool RenderLayer::hasAncestorWithFilterOutsets() const 1459 { 1460 for (const RenderLayer* curr = this; curr; curr = curr->parent()) { 1461 RenderLayerModelObject* renderer = curr->renderer(); 1462 if (renderer->style()->hasFilterOutsets()) 1463 return true; 1464 } 1465 return false; 1466 } 1467 1468 RenderLayer* RenderLayer::clippingRootForPainting() const 1469 { 1470 if (isComposited()) 1471 return const_cast<RenderLayer*>(this); 1472 1473 const RenderLayer* current = this; 1474 while (current) { 1475 if (current->isRootLayer()) 1476 return const_cast<RenderLayer*>(current); 1477 1478 current = compositingContainer(current); 1479 ASSERT(current); 1480 if (current->transform() 1481 || (current->isComposited() && !current->backing()->paintsIntoCompositedAncestor()) 1482 ) 1483 return const_cast<RenderLayer*>(current); 1484 } 1485 1486 ASSERT_NOT_REACHED(); 1487 return 0; 1488 } 1489 1490 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const 1491 { 1492 // We don't use convertToLayerCoords because it doesn't know about transforms 1493 return roundedLayoutPoint(renderer()->absoluteToLocal(absolutePoint, UseTransforms)); 1494 } 1495 1496 bool RenderLayer::cannotBlitToWindow() const 1497 { 1498 if (isTransparent() || hasReflection() || hasTransform()) 1499 return true; 1500 if (!parent()) 1501 return false; 1502 return parent()->cannotBlitToWindow(); 1503 } 1504 1505 bool RenderLayer::isTransparent() const 1506 { 1507 // FIXME: This seems incorrect; why would SVG layers be opaque? 1508 if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI) 1509 return false; 1510 1511 return renderer()->isTransparent() || renderer()->hasMask(); 1512 } 1513 1514 RenderLayer* RenderLayer::transparentPaintingAncestor() 1515 { 1516 if (isComposited()) 1517 return 0; 1518 1519 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { 1520 if (curr->isComposited()) 1521 return 0; 1522 if (curr->isTransparent()) 1523 return curr; 1524 } 1525 return 0; 1526 } 1527 1528 enum TransparencyClipBoxBehavior { 1529 PaintingTransparencyClipBox, 1530 HitTestingTransparencyClipBox 1531 }; 1532 1533 enum TransparencyClipBoxMode { 1534 DescendantsOfTransparencyClipBox, 1535 RootOfTransparencyClipBox 1536 }; 1537 1538 static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0); 1539 1540 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, 1541 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior) 1542 { 1543 // If we have a mask, then the clip is limited to the border box area (and there is 1544 // no need to examine child layers). 1545 if (!layer->renderer()->hasMask()) { 1546 // Note: we don't have to walk z-order lists since transparent elements always establish 1547 // a stacking container. This means we can just walk the layer tree directly. 1548 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) { 1549 if (!layer->reflection() || layer->reflectionLayer() != curr) 1550 clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior)); 1551 } 1552 } 1553 1554 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire 1555 // current transparencyClipBox to catch all child layers. 1556 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this 1557 // size into the parent layer. 1558 if (layer->renderer()->hasReflection()) { 1559 LayoutPoint delta; 1560 layer->convertToLayerCoords(rootLayer, delta); 1561 clipRect.move(-delta.x(), -delta.y()); 1562 clipRect.unite(layer->renderBox()->reflectedRect(clipRect)); 1563 clipRect.moveBy(delta); 1564 } 1565 } 1566 1567 static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior, 1568 TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior) 1569 { 1570 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the 1571 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it 1572 // would be better to respect clips. 1573 1574 if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior)) 1575 || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) { 1576 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass 1577 // the transformed layer and all of its children. 1578 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0; 1579 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer; 1580 LayoutPoint delta; 1581 layer->convertToLayerCoords(rootLayerForTransform, delta); 1582 1583 TransformationMatrix transform; 1584 transform.translate(delta.x(), delta.y()); 1585 transform = transform * *layer->transform(); 1586 1587 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always 1588 // paints unfragmented. 1589 LayoutRect clipRect = layer->boundingBox(layer); 1590 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior); 1591 layer->renderer()->style()->filterOutsets().expandRect(clipRect); 1592 LayoutRect result = transform.mapRect(clipRect); 1593 if (!paginationLayer) 1594 return result; 1595 1596 // We have to break up the transformed extent across our columns. 1597 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to 1598 // get our true bounding box. 1599 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer()); 1600 result = enclosingFlowThread->fragmentsBoundingBox(result); 1601 1602 LayoutPoint rootLayerDelta; 1603 paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta); 1604 result.moveBy(rootLayerDelta); 1605 return result; 1606 } 1607 1608 LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes); 1609 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior); 1610 layer->renderer()->style()->filterOutsets().expandRect(clipRect); 1611 return clipRect; 1612 } 1613 1614 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior) 1615 { 1616 return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect); 1617 } 1618 1619 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior) 1620 { 1621 if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency)) 1622 return; 1623 1624 RenderLayer* ancestor = transparentPaintingAncestor(); 1625 if (ancestor) 1626 ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior); 1627 1628 if (paintsWithTransparency(paintBehavior)) { 1629 m_usedTransparency = true; 1630 context->save(); 1631 LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior); 1632 context->clip(clipRect); 1633 context->beginTransparencyLayer(renderer()->opacity()); 1634 #ifdef REVEAL_TRANSPARENCY_LAYERS 1635 context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f)); 1636 context->fillRect(clipRect); 1637 #endif 1638 } 1639 } 1640 1641 void* RenderLayer::operator new(size_t sz) 1642 { 1643 return partitionAlloc(Partitions::getRenderingPartition(), sz); 1644 } 1645 1646 void RenderLayer::operator delete(void* ptr) 1647 { 1648 partitionFree(ptr); 1649 } 1650 1651 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) 1652 { 1653 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild(); 1654 if (prevSibling) { 1655 child->setPreviousSibling(prevSibling); 1656 prevSibling->setNextSibling(child); 1657 ASSERT(prevSibling != child); 1658 } else 1659 setFirstChild(child); 1660 1661 if (beforeChild) { 1662 beforeChild->setPreviousSibling(child); 1663 child->setNextSibling(beforeChild); 1664 ASSERT(beforeChild != child); 1665 } else 1666 setLastChild(child); 1667 1668 child->setParent(this); 1669 1670 if (child->isNormalFlowOnly()) 1671 dirtyNormalFlowList(); 1672 1673 if (!child->isNormalFlowOnly() || child->firstChild()) { 1674 // Dirty the z-order list in which we are contained. The ancestorStackingContainer() can be null in the 1675 // case where we're building up generated content layers. This is ok, since the lists will start 1676 // off dirty in that case anyway. 1677 child->dirtyStackingContainerZOrderLists(); 1678 } 1679 1680 child->updateDescendantDependentFlags(); 1681 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) 1682 setAncestorChainHasVisibleDescendant(); 1683 1684 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) 1685 setAncestorChainHasSelfPaintingLayerDescendant(); 1686 1687 if (subtreeContainsOutOfFlowPositionedLayer(child)) { 1688 // Now that the out of flow positioned descendant is in the tree, we 1689 // need to tell the compositor to reevaluate the compositing 1690 // requirements since we may be able to mark more layers as having 1691 // an 'unclipped' descendant. 1692 compositor()->setNeedsUpdateCompositingRequirementsState(); 1693 setAncestorChainHasOutOfFlowPositionedDescendant(); 1694 } 1695 1696 // When we first dirty a layer, we will also dirty all the siblings in that 1697 // layer's stacking context. We need to manually do it here as well, in case 1698 // we're adding this layer after the stacking context has already been 1699 // updated. 1700 child->m_canBePromotedToStackingContainerDirty = true; 1701 compositor()->layerWasAdded(this, child); 1702 } 1703 1704 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) 1705 { 1706 if (!renderer()->documentBeingDestroyed()) 1707 compositor()->layerWillBeRemoved(this, oldChild); 1708 1709 // remove the child 1710 if (oldChild->previousSibling()) 1711 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); 1712 if (oldChild->nextSibling()) 1713 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); 1714 1715 if (m_first == oldChild) 1716 m_first = oldChild->nextSibling(); 1717 if (m_last == oldChild) 1718 m_last = oldChild->previousSibling(); 1719 1720 if (oldChild->isNormalFlowOnly()) 1721 dirtyNormalFlowList(); 1722 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) { 1723 // Dirty the z-order list in which we are contained. When called via the 1724 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected 1725 // from the main layer tree, so we need to null-check the |stackingContainer| value. 1726 oldChild->dirtyStackingContainerZOrderLists(); 1727 } 1728 1729 oldChild->setPreviousSibling(0); 1730 oldChild->setNextSibling(0); 1731 oldChild->setParent(0); 1732 1733 oldChild->updateDescendantDependentFlags(); 1734 if (subtreeContainsOutOfFlowPositionedLayer(oldChild)) { 1735 // It may now be the case that a layer no longer has an unclipped 1736 // descendant. Let the compositor know that it needs to reevaluate 1737 // its compositing requirements to check this. 1738 compositor()->setNeedsUpdateCompositingRequirementsState(); 1739 dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus(); 1740 } 1741 1742 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) 1743 dirtyAncestorChainVisibleDescendantStatus(); 1744 1745 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant()) 1746 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); 1747 1748 return oldChild; 1749 } 1750 1751 void RenderLayer::removeOnlyThisLayer() 1752 { 1753 if (!m_parent) 1754 return; 1755 1756 // Mark that we are about to lose our layer. This makes render tree 1757 // walks ignore this layer while we're removing it. 1758 m_renderer->setHasLayer(false); 1759 1760 compositor()->layerWillBeRemoved(m_parent, this); 1761 1762 // Dirty the clip rects. 1763 clearClipRectsIncludingDescendants(); 1764 1765 RenderLayer* nextSib = nextSibling(); 1766 1767 // Remove the child reflection layer before moving other child layers. 1768 // The reflection layer should not be moved to the parent. 1769 if (reflection()) 1770 removeChild(reflectionLayer()); 1771 1772 // Now walk our kids and reattach them to our parent. 1773 RenderLayer* current = m_first; 1774 while (current) { 1775 RenderLayer* next = current->nextSibling(); 1776 removeChild(current); 1777 m_parent->addChild(current, nextSib); 1778 current->setRepaintStatus(NeedsFullRepaint); 1779 // updateLayerPositions depends on hasLayer() already being false for proper layout. 1780 ASSERT(!renderer()->hasLayer()); 1781 current->updateLayerPositions(0); // FIXME: use geometry map. 1782 current = next; 1783 } 1784 1785 // Remove us from the parent. 1786 m_parent->removeChild(this); 1787 m_renderer->destroyLayer(); 1788 } 1789 1790 void RenderLayer::insertOnlyThisLayer() 1791 { 1792 if (!m_parent && renderer()->parent()) { 1793 // We need to connect ourselves when our renderer() has a parent. 1794 // Find our enclosingLayer and add ourselves. 1795 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); 1796 ASSERT(parentLayer); 1797 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0; 1798 parentLayer->addChild(this, beforeChild); 1799 } 1800 1801 // Remove all descendant layers from the hierarchy and add them to the new position. 1802 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling()) 1803 curr->moveLayers(m_parent, this); 1804 1805 // Clear out all the clip rects. 1806 clearClipRectsIncludingDescendants(); 1807 } 1808 1809 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation) const 1810 { 1811 LayoutPoint location = roundedLocation; 1812 convertToLayerCoords(ancestorLayer, location); 1813 roundedLocation = roundedIntPoint(location); 1814 } 1815 1816 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect) const 1817 { 1818 LayoutRect rect = roundedRect; 1819 convertToLayerCoords(ancestorLayer, rect); 1820 roundedRect = pixelSnappedIntRect(rect); 1821 } 1822 1823 // Returns the layer reached on the walk up towards the ancestor. 1824 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location) 1825 { 1826 ASSERT(ancestorLayer != layer); 1827 1828 const RenderLayerModelObject* renderer = layer->renderer(); 1829 EPosition position = renderer->style()->position(); 1830 1831 // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great. 1832 RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer->flowThreadContainingBlock() : 0; 1833 if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned()) 1834 fixedFlowThreadContainer = 0; 1835 1836 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread 1837 // may need to be revisited in a future patch. 1838 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute, 1839 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be 1840 // positioned in a completely different place in the viewport (RenderView). 1841 if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) { 1842 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling 1843 // localToAbsolute() on the RenderView. 1844 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed); 1845 location += LayoutSize(absPos.x(), absPos.y()); 1846 return ancestorLayer; 1847 } 1848 1849 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below 1850 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed 1851 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer. 1852 if (position == FixedPosition && !fixedFlowThreadContainer) { 1853 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container 1854 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform, 1855 // so we should always find the ancestor at or before we find the fixed position container. 1856 RenderLayer* fixedPositionContainerLayer = 0; 1857 bool foundAncestor = false; 1858 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) { 1859 if (currLayer == ancestorLayer) 1860 foundAncestor = true; 1861 1862 if (isFixedPositionedContainer(currLayer)) { 1863 fixedPositionContainerLayer = currLayer; 1864 ASSERT_UNUSED(foundAncestor, foundAncestor); 1865 break; 1866 } 1867 } 1868 1869 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least. 1870 1871 if (fixedPositionContainerLayer != ancestorLayer) { 1872 LayoutPoint fixedContainerCoords; 1873 layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords); 1874 1875 LayoutPoint ancestorCoords; 1876 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords); 1877 1878 location += (fixedContainerCoords - ancestorCoords); 1879 } else { 1880 location += toSize(layer->location()); 1881 } 1882 return ancestorLayer; 1883 } 1884 1885 RenderLayer* parentLayer; 1886 if (position == AbsolutePosition || position == FixedPosition) { 1887 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way. 1888 parentLayer = layer->parent(); 1889 bool foundAncestorFirst = false; 1890 while (parentLayer) { 1891 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0). 1892 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread, 1893 // we are bailing out before reaching root layer. 1894 if (isPositionedContainer(parentLayer)) 1895 break; 1896 1897 if (parentLayer == ancestorLayer) { 1898 foundAncestorFirst = true; 1899 break; 1900 } 1901 1902 parentLayer = parentLayer->parent(); 1903 } 1904 1905 // We should not reach RenderView layer past the RenderFlowThread layer for any 1906 // children of the RenderFlowThread. 1907 if (renderer->flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread()) 1908 ASSERT(parentLayer != renderer->view()->layer()); 1909 1910 if (foundAncestorFirst) { 1911 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative 1912 // to enclosingPositionedAncestor and subtract. 1913 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor(); 1914 1915 LayoutPoint thisCoords; 1916 layer->convertToLayerCoords(positionedAncestor, thisCoords); 1917 1918 LayoutPoint ancestorCoords; 1919 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords); 1920 1921 location += (thisCoords - ancestorCoords); 1922 return ancestorLayer; 1923 } 1924 } else 1925 parentLayer = layer->parent(); 1926 1927 if (!parentLayer) 1928 return 0; 1929 1930 location += toSize(layer->location()); 1931 return parentLayer; 1932 } 1933 1934 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const 1935 { 1936 if (ancestorLayer == this) 1937 return; 1938 1939 const RenderLayer* currLayer = this; 1940 while (currLayer && currLayer != ancestorLayer) 1941 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location); 1942 } 1943 1944 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const 1945 { 1946 LayoutPoint delta; 1947 convertToLayerCoords(ancestorLayer, delta); 1948 rect.move(-delta.x(), -delta.y()); 1949 } 1950 1951 bool RenderLayer::usesCompositedScrolling() const 1952 { 1953 return isComposited() && backing()->scrollingLayer(); 1954 } 1955 1956 bool RenderLayer::needsCompositedScrolling() const 1957 { 1958 switch (m_forceNeedsCompositedScrolling) { 1959 case DoNotForceCompositedScrolling: 1960 return m_needsCompositedScrolling; 1961 case CompositedScrollingAlwaysOn: 1962 return true; 1963 case CompositedScrollingAlwaysOff: 1964 return false; 1965 } 1966 1967 ASSERT_NOT_REACHED(); 1968 return m_needsCompositedScrolling; 1969 } 1970 1971 void RenderLayer::updateNeedsCompositedScrolling() 1972 { 1973 updateCanBeStackingContainer(); 1974 updateDescendantDependentFlags(); 1975 1976 ASSERT(renderer()->view()->frameView() && renderer()->view()->frameView()->containsScrollableArea(this)); 1977 bool needsCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled() 1978 #if 0 1979 // WEBVIEW RELEASE BRANCH HACK for http://b/10626443 1980 // Chromium M30 refrains from promoting overflow-scroll regions to layers if 1981 // it may violate CSS-standard stacking order. But this causes awful 1982 // scrolling performance. Classic WebView promotes everything to layers 1983 // without concern for standards details. Hack Chromium M30 to do the same 1984 // here. 1985 // Note that this problem should become obsolete soon when 1986 // https://codereview.chromium.org/20103002/ lands allowing Chromium to 1987 // promote everything to layers without violating web standards. 1988 && canBeStackingContainer() 1989 #endif 1990 && !hasUnclippedDescendant(); 1991 1992 // We gather a boolean value for use with Google UMA histograms to 1993 // quantify the actual effects of a set of patches attempting to 1994 // relax composited scrolling requirements, thereby increasing the 1995 // number of composited overflow divs. 1996 if (acceleratedCompositingForOverflowScrollEnabled()) 1997 HistogramSupport::histogramEnumeration("Renderer.NeedsCompositedScrolling", needsCompositedScrolling, 2); 1998 1999 setNeedsCompositedScrolling(needsCompositedScrolling); 2000 } 2001 2002 void RenderLayer::setNeedsCompositedScrolling(bool needsCompositedScrolling) 2003 { 2004 if (m_needsCompositedScrolling == needsCompositedScrolling) 2005 return; 2006 2007 m_needsCompositedScrolling = needsCompositedScrolling; 2008 2009 // Note, the z-order lists may need to be rebuilt, but our code guarantees 2010 // that we have not affected stacking, so we will not dirty 2011 // m_canBePromotedToStackingContainer for either us or our stacking context 2012 // or container. 2013 didUpdateNeedsCompositedScrolling(); 2014 } 2015 2016 void RenderLayer::setForceNeedsCompositedScrolling(RenderLayer::ForceNeedsCompositedScrollingMode mode) 2017 { 2018 if (m_forceNeedsCompositedScrolling == mode) 2019 return; 2020 2021 m_forceNeedsCompositedScrolling = mode; 2022 didUpdateNeedsCompositedScrolling(); 2023 } 2024 2025 void RenderLayer::didUpdateNeedsCompositedScrolling() 2026 { 2027 updateIsNormalFlowOnly(); 2028 updateSelfPaintingLayer(); 2029 2030 if (isStackingContainer()) 2031 dirtyZOrderLists(); 2032 else 2033 clearZOrderLists(); 2034 2035 dirtyStackingContainerZOrderLists(); 2036 2037 compositor()->setShouldReevaluateCompositingAfterLayout(); 2038 compositor()->setCompositingLayersNeedRebuild(); 2039 } 2040 2041 static inline int adjustedScrollDelta(int beginningDelta) { 2042 // This implemention matches Firefox's. 2043 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856. 2044 const int speedReducer = 12; 2045 2046 int adjustedDelta = beginningDelta / speedReducer; 2047 if (adjustedDelta > 1) 2048 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1; 2049 else if (adjustedDelta < -1) 2050 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1; 2051 2052 return adjustedDelta; 2053 } 2054 2055 static inline IntSize adjustedScrollDelta(const IntSize& delta) 2056 { 2057 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height())); 2058 } 2059 2060 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) 2061 { 2062 Frame* frame = renderer()->frame(); 2063 if (!frame) 2064 return; 2065 2066 IntPoint lastKnownMousePosition = frame->eventHandler()->lastKnownMousePosition(); 2067 2068 // We need to check if the last known mouse position is out of the window. When the mouse is out of the window, the position is incoherent 2069 static IntPoint previousMousePosition; 2070 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0) 2071 lastKnownMousePosition = previousMousePosition; 2072 else 2073 previousMousePosition = lastKnownMousePosition; 2074 2075 IntSize delta = lastKnownMousePosition - sourcePoint; 2076 2077 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon 2078 delta.setWidth(0); 2079 if (abs(delta.height()) <= ScrollView::noPanScrollRadius) 2080 delta.setHeight(0); 2081 2082 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped); 2083 } 2084 2085 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp) 2086 { 2087 if (delta.isZero()) 2088 return; 2089 2090 bool restrictedByLineClamp = false; 2091 if (renderer()->parent()) 2092 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone(); 2093 2094 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { 2095 IntSize newScrollOffset = adjustedScrollOffset() + delta; 2096 scrollToOffset(newScrollOffset, clamp); 2097 2098 // If this layer can't do the scroll we ask the next layer up that can scroll to try 2099 IntSize remainingScrollOffset = newScrollOffset - adjustedScrollOffset(); 2100 if (!remainingScrollOffset.isZero() && renderer()->parent()) { 2101 if (RenderLayer* scrollableLayer = enclosingScrollableLayer()) 2102 scrollableLayer->scrollByRecursively(remainingScrollOffset, clamp); 2103 2104 Frame* frame = renderer()->frame(); 2105 if (frame && frame->page()) 2106 frame->page()->updateAutoscrollRenderer(); 2107 } 2108 } else if (renderer()->view()->frameView()) { 2109 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't 2110 // have an overflow clip. Which means that it is a document node that can be scrolled. 2111 renderer()->view()->frameView()->scrollBy(delta); 2112 2113 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement? 2114 // https://bugs.webkit.org/show_bug.cgi?id=28237 2115 } 2116 } 2117 2118 IntSize RenderLayer::clampScrollOffset(const IntSize& scrollOffset) const 2119 { 2120 RenderBox* box = renderBox(); 2121 ASSERT(box); 2122 2123 int maxX = scrollWidth() - box->pixelSnappedClientWidth(); 2124 int maxY = scrollHeight() - box->pixelSnappedClientHeight(); 2125 2126 int x = max(min(scrollOffset.width(), maxX), 0); 2127 int y = max(min(scrollOffset.height(), maxY), 0); 2128 return IntSize(x, y); 2129 } 2130 2131 void RenderLayer::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp) 2132 { 2133 IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset; 2134 if (newScrollOffset != adjustedScrollOffset()) 2135 scrollToOffsetWithoutAnimation(-scrollOrigin() + newScrollOffset); 2136 } 2137 2138 void RenderLayer::setScrollOffset(const IntPoint& newScrollOffset) 2139 { 2140 RenderBox* box = renderBox(); 2141 if (!box) 2142 return; 2143 2144 if (!box->isMarquee()) { 2145 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks). 2146 if (m_scrollDimensionsDirty) 2147 computeScrollDimensions(); 2148 } 2149 2150 if (m_scrollOffset == toIntSize(newScrollOffset)) 2151 return; 2152 m_scrollOffset = toIntSize(newScrollOffset); 2153 2154 Frame* frame = renderer()->frame(); 2155 InspectorInstrumentation::willScrollLayer(renderer()); 2156 2157 RenderView* view = renderer()->view(); 2158 2159 // We should have a RenderView if we're trying to scroll. 2160 ASSERT(view); 2161 2162 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll). 2163 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor. 2164 bool inLayout = view ? view->frameView()->isInLayout() : false; 2165 if (!inLayout) { 2166 // If we're in the middle of layout, we'll just update layers once layout has finished. 2167 updateLayerPositionsAfterOverflowScroll(); 2168 if (view) { 2169 // Update regions, scrolling may change the clip of a particular region. 2170 view->frameView()->updateAnnotatedRegions(); 2171 2172 view->updateWidgetPositions(); 2173 2174 view->markLazyBlocksForLayout(); 2175 } 2176 2177 updateCompositingLayersAfterScroll(); 2178 } 2179 2180 RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint(); 2181 if (frame) { 2182 // The caret rect needs to be invalidated after scrolling 2183 frame->selection()->setCaretRectNeedsUpdate(); 2184 2185 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect); 2186 if (repaintContainer) 2187 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); 2188 frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); 2189 } 2190 2191 bool requiresRepaint = true; 2192 2193 if (compositor()->inCompositingMode() && usesCompositedScrolling()) 2194 requiresRepaint = false; 2195 2196 // Just schedule a full repaint of our object. 2197 if (view && requiresRepaint) 2198 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect)); 2199 2200 // Schedule the scroll DOM event. 2201 if (renderer()->node()) 2202 renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), DocumentEventQueue::ScrollEventElementTarget); 2203 2204 InspectorInstrumentation::didScrollLayer(renderer()); 2205 } 2206 2207 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView) 2208 { 2209 // If scrollbars aren't explicitly forbidden, permit scrolling. 2210 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff) 2211 return true; 2212 2213 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored. 2214 if (frameView->wasScrolledByUser()) 2215 return false; 2216 2217 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls, 2218 // like navigation to an anchor. 2219 Page* page = frameView->frame()->page(); 2220 if (!page) 2221 return false; 2222 return !page->autoscrollInProgress(); 2223 } 2224 2225 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) 2226 { 2227 RenderLayer* parentLayer = 0; 2228 LayoutRect newRect = rect; 2229 2230 // We may end up propagating a scroll event. It is important that we suspend events until 2231 // the end of the function since they could delete the layer or the layer's renderer(). 2232 FrameView* frameView = renderer()->document()->view(); 2233 if (frameView) 2234 frameView->pauseScheduledEvents(); 2235 2236 bool restrictedByLineClamp = false; 2237 if (renderer()->parent()) { 2238 parentLayer = renderer()->parent()->enclosingLayer(); 2239 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone(); 2240 } 2241 2242 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { 2243 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property. 2244 // This will prevent us from revealing text hidden by the slider in Safari RSS. 2245 RenderBox* box = renderBox(); 2246 ASSERT(box); 2247 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox()); 2248 LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight()); 2249 LayoutRect r = getRectToExpose(layerBounds, localExposeRect, alignX, alignY); 2250 2251 IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + toIntSize(roundedIntRect(r).location())); 2252 if (clampedScrollOffset != adjustedScrollOffset()) { 2253 IntSize oldScrollOffset = adjustedScrollOffset(); 2254 scrollToOffset(clampedScrollOffset); 2255 IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset; 2256 localExposeRect.move(-scrollOffsetDifference); 2257 newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); 2258 } 2259 } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled()) { 2260 if (frameView) { 2261 Element* ownerElement = 0; 2262 if (renderer()->document()) 2263 ownerElement = renderer()->document()->ownerElement(); 2264 2265 if (ownerElement && ownerElement->renderer()) { 2266 HTMLFrameElementBase* frameElementBase = 0; 2267 2268 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) 2269 frameElementBase = static_cast<HTMLFrameElementBase*>(ownerElement); 2270 2271 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) { 2272 LayoutRect viewRect = frameView->visibleContentRect(); 2273 LayoutRect exposeRect = getRectToExpose(viewRect, rect, alignX, alignY); 2274 2275 int xOffset = roundToInt(exposeRect.x()); 2276 int yOffset = roundToInt(exposeRect.y()); 2277 // Adjust offsets if they're outside of the allowable range. 2278 xOffset = max(0, min(frameView->contentsWidth(), xOffset)); 2279 yOffset = max(0, min(frameView->contentsHeight(), yOffset)); 2280 2281 frameView->setScrollPosition(IntPoint(xOffset, yOffset)); 2282 if (frameView->safeToPropagateScrollToParent()) { 2283 parentLayer = ownerElement->renderer()->enclosingLayer(); 2284 // FIXME: This doesn't correctly convert the rect to 2285 // absolute coordinates in the parent. 2286 newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); 2287 newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); 2288 } else 2289 parentLayer = 0; 2290 } 2291 } else { 2292 LayoutRect viewRect = frameView->visibleContentRect(); 2293 LayoutRect r = getRectToExpose(viewRect, rect, alignX, alignY); 2294 frameView->setScrollPosition(roundedIntPoint(r.location())); 2295 } 2296 } 2297 } 2298 2299 if (parentLayer) 2300 parentLayer->scrollRectToVisible(newRect, alignX, alignY); 2301 2302 if (frameView) 2303 frameView->resumeScheduledEvents(); 2304 } 2305 2306 void RenderLayer::updateCompositingLayersAfterScroll() 2307 { 2308 if (compositor()->inCompositingMode()) { 2309 // Our stacking container is guaranteed to contain all of our descendants that may need 2310 // repositioning, so update compositing layers from there. 2311 if (RenderLayer* compositingAncestor = ancestorStackingContainer()->enclosingCompositingLayer()) { 2312 if (usesCompositedScrolling()) 2313 compositor()->updateCompositingLayers(CompositingUpdateOnCompositedScroll, compositingAncestor); 2314 else 2315 compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor); 2316 } 2317 } 2318 } 2319 2320 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) 2321 { 2322 // Determine the appropriate X behavior. 2323 ScrollBehavior scrollX; 2324 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height()); 2325 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width(); 2326 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL) 2327 // If the rectangle is fully visible, use the specified visible behavior. 2328 // If the rectangle is partially visible, but over a certain threshold, 2329 // then treat it as fully visible to avoid unnecessary horizontal scrolling 2330 scrollX = ScrollAlignment::getVisibleBehavior(alignX); 2331 else if (intersectWidth == visibleRect.width()) { 2332 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. 2333 scrollX = ScrollAlignment::getVisibleBehavior(alignX); 2334 if (scrollX == alignCenter) 2335 scrollX = noScroll; 2336 } else if (intersectWidth > 0) 2337 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior 2338 scrollX = ScrollAlignment::getPartialBehavior(alignX); 2339 else 2340 scrollX = ScrollAlignment::getHiddenBehavior(alignX); 2341 // If we're trying to align to the closest edge, and the exposeRect is further right 2342 // than the visibleRect, and not bigger than the visible area, then align with the right. 2343 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width()) 2344 scrollX = alignRight; 2345 2346 // Given the X behavior, compute the X coordinate. 2347 LayoutUnit x; 2348 if (scrollX == noScroll) 2349 x = visibleRect.x(); 2350 else if (scrollX == alignRight) 2351 x = exposeRect.maxX() - visibleRect.width(); 2352 else if (scrollX == alignCenter) 2353 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2; 2354 else 2355 x = exposeRect.x(); 2356 2357 // Determine the appropriate Y behavior. 2358 ScrollBehavior scrollY; 2359 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height()); 2360 LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height(); 2361 if (intersectHeight == exposeRect.height()) 2362 // If the rectangle is fully visible, use the specified visible behavior. 2363 scrollY = ScrollAlignment::getVisibleBehavior(alignY); 2364 else if (intersectHeight == visibleRect.height()) { 2365 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. 2366 scrollY = ScrollAlignment::getVisibleBehavior(alignY); 2367 if (scrollY == alignCenter) 2368 scrollY = noScroll; 2369 } else if (intersectHeight > 0) 2370 // If the rectangle is partially visible, use the specified partial behavior 2371 scrollY = ScrollAlignment::getPartialBehavior(alignY); 2372 else 2373 scrollY = ScrollAlignment::getHiddenBehavior(alignY); 2374 // If we're trying to align to the closest edge, and the exposeRect is further down 2375 // than the visibleRect, and not bigger than the visible area, then align with the bottom. 2376 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height()) 2377 scrollY = alignBottom; 2378 2379 // Given the Y behavior, compute the Y coordinate. 2380 LayoutUnit y; 2381 if (scrollY == noScroll) 2382 y = visibleRect.y(); 2383 else if (scrollY == alignBottom) 2384 y = exposeRect.maxY() - visibleRect.height(); 2385 else if (scrollY == alignCenter) 2386 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2; 2387 else 2388 y = exposeRect.y(); 2389 2390 return LayoutRect(LayoutPoint(x, y), visibleRect.size()); 2391 } 2392 2393 void RenderLayer::autoscroll(const IntPoint& position) 2394 { 2395 Frame* frame = renderer()->frame(); 2396 if (!frame) 2397 return; 2398 2399 FrameView* frameView = frame->view(); 2400 if (!frameView) 2401 return; 2402 2403 IntPoint currentDocumentPosition = frameView->windowToContents(position); 2404 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); 2405 } 2406 2407 bool RenderLayer::canResize() const 2408 { 2409 if (!renderer()) 2410 return false; 2411 // We need a special case for <iframe> because they never have 2412 // hasOverflowClip(). However, they do "implicitly" clip their contents, so 2413 // we want to allow resizing them also. 2414 return (renderer()->hasOverflowClip() || renderer()->isRenderIFrame()) && renderer()->style()->resize() != RESIZE_NONE; 2415 } 2416 2417 void RenderLayer::resize(const PlatformEvent& evt, const LayoutSize& oldOffset) 2418 { 2419 // FIXME: This should be possible on generated content but is not right now. 2420 if (!inResizeMode() || !canResize() || !renderer()->node()) 2421 return; 2422 2423 ASSERT(renderer()->node()->isElementNode()); 2424 Element* element = toElement(renderer()->node()); 2425 RenderBox* renderer = toRenderBox(element->renderer()); 2426 2427 Document* document = element->document(); 2428 2429 IntPoint pos; 2430 const PlatformGestureEvent* gevt = 0; 2431 2432 switch (evt.type()) { 2433 case PlatformEvent::MouseMoved: 2434 if (!document->frame()->eventHandler()->mousePressed()) 2435 return; 2436 pos = static_cast<const PlatformMouseEvent*>(&evt)->position(); 2437 break; 2438 case PlatformEvent::GestureScrollUpdate: 2439 case PlatformEvent::GestureScrollUpdateWithoutPropagation: 2440 pos = static_cast<const PlatformGestureEvent*>(&evt)->position(); 2441 gevt = static_cast<const PlatformGestureEvent*>(&evt); 2442 pos = gevt->position(); 2443 pos.move(gevt->deltaX(), gevt->deltaY()); 2444 break; 2445 default: 2446 ASSERT_NOT_REACHED(); 2447 } 2448 2449 float zoomFactor = renderer->style()->effectiveZoom(); 2450 2451 LayoutSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(pos)); 2452 newOffset.setWidth(newOffset.width() / zoomFactor); 2453 newOffset.setHeight(newOffset.height() / zoomFactor); 2454 2455 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor); 2456 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize); 2457 element->setMinimumSizeForResizing(minimumSize); 2458 2459 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor); 2460 if (renderer->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { 2461 newOffset.setWidth(-newOffset.width()); 2462 adjustedOldOffset.setWidth(-adjustedOldOffset.width()); 2463 } 2464 2465 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize; 2466 2467 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX; 2468 2469 EResize resize = renderer->style()->resize(); 2470 if (resize != RESIZE_VERTICAL && difference.width()) { 2471 if (element->isFormControlElement()) { 2472 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). 2473 element->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX); 2474 element->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX); 2475 } 2476 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->borderAndPaddingWidth()); 2477 baseWidth = baseWidth / zoomFactor; 2478 element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX); 2479 } 2480 2481 if (resize != RESIZE_HORIZONTAL && difference.height()) { 2482 if (element->isFormControlElement()) { 2483 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). 2484 element->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX); 2485 element->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX); 2486 } 2487 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->borderAndPaddingHeight()); 2488 baseHeight = baseHeight / zoomFactor; 2489 element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX); 2490 } 2491 2492 document->updateLayout(); 2493 2494 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view. 2495 } 2496 2497 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const 2498 { 2499 IntSize scrollDimensions = maximumScrollPosition() - minimumScrollPosition(); 2500 return (orientation == HorizontalScrollbar) ? scrollDimensions.width() : scrollDimensions.height(); 2501 } 2502 2503 IntPoint RenderLayer::scrollPosition() const 2504 { 2505 return IntPoint(m_scrollOffset); 2506 } 2507 2508 IntPoint RenderLayer::minimumScrollPosition() const 2509 { 2510 return -scrollOrigin(); 2511 } 2512 2513 IntPoint RenderLayer::maximumScrollPosition() const 2514 { 2515 RenderBox* box = renderBox(); 2516 if (!box || !box->hasOverflowClip()) 2517 return -scrollOrigin(); 2518 2519 return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(box->clientBoxRect()).size(); 2520 } 2521 2522 IntRect RenderLayer::visibleContentRect(VisibleContentRectIncludesScrollbars scrollbarInclusion) const 2523 { 2524 int verticalScrollbarWidth = 0; 2525 int horizontalScrollbarHeight = 0; 2526 if (scrollbarInclusion == IncludeScrollbars) { 2527 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0; 2528 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0; 2529 } 2530 2531 return IntRect(IntPoint(scrollXOffset(), scrollYOffset()), 2532 IntSize(max(0, m_layerSize.width() - verticalScrollbarWidth), 2533 max(0, m_layerSize.height() - horizontalScrollbarHeight))); 2534 } 2535 2536 IntSize RenderLayer::overhangAmount() const 2537 { 2538 return IntSize(); 2539 } 2540 2541 bool RenderLayer::isActive() const 2542 { 2543 Page* page = renderer()->frame()->page(); 2544 return page && page->focusController().isActive(); 2545 } 2546 2547 static int cornerStart(const RenderStyle* style, int minX, int maxX, int thickness) 2548 { 2549 if (style->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 2550 return minX + style->borderLeftWidth(); 2551 return maxX - thickness - style->borderRightWidth(); 2552 } 2553 2554 static IntRect cornerRect(const RenderStyle* style, const Scrollbar* horizontalScrollbar, const Scrollbar* verticalScrollbar, const IntRect& bounds) 2555 { 2556 int horizontalThickness; 2557 int verticalThickness; 2558 if (!verticalScrollbar && !horizontalScrollbar) { 2559 // FIXME: This isn't right. We need to know the thickness of custom scrollbars 2560 // even when they don't exist in order to set the resizer square size properly. 2561 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness(); 2562 verticalThickness = horizontalThickness; 2563 } else if (verticalScrollbar && !horizontalScrollbar) { 2564 horizontalThickness = verticalScrollbar->width(); 2565 verticalThickness = horizontalThickness; 2566 } else if (horizontalScrollbar && !verticalScrollbar) { 2567 verticalThickness = horizontalScrollbar->height(); 2568 horizontalThickness = verticalThickness; 2569 } else { 2570 horizontalThickness = verticalScrollbar->width(); 2571 verticalThickness = horizontalScrollbar->height(); 2572 } 2573 return IntRect(cornerStart(style, bounds.x(), bounds.maxX(), horizontalThickness), 2574 bounds.maxY() - verticalThickness - style->borderBottomWidth(), 2575 horizontalThickness, verticalThickness); 2576 } 2577 2578 IntRect RenderLayer::scrollCornerRect() const 2579 { 2580 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box. 2581 // This happens when: 2582 // (a) A resizer is present and at least one scrollbar is present 2583 // (b) Both scrollbars are present. 2584 bool hasHorizontalBar = horizontalScrollbar(); 2585 bool hasVerticalBar = verticalScrollbar(); 2586 bool hasResizer = renderer()->style()->resize() != RESIZE_NONE; 2587 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) 2588 return cornerRect(renderer()->style(), horizontalScrollbar(), verticalScrollbar(), renderBox()->pixelSnappedBorderBoxRect()); 2589 return IntRect(); 2590 } 2591 2592 IntRect RenderLayer::resizerCornerRect(const IntRect& bounds, ResizerHitTestType resizerHitTestType) const 2593 { 2594 ASSERT(renderer()->isBox()); 2595 if (renderer()->style()->resize() == RESIZE_NONE) 2596 return IntRect(); 2597 IntRect corner = cornerRect(renderer()->style(), horizontalScrollbar(), verticalScrollbar(), bounds); 2598 2599 if (resizerHitTestType == ResizerForTouch) { 2600 // We make the resizer virtually larger for touch hit testing. With the 2601 // expanding ratio k = ResizerControlExpandRatioForTouch, we first move 2602 // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1)), 2603 // then expand the rect by new_w/h = w/h * k. 2604 int expand_ratio = ResizerControlExpandRatioForTouch - 1; 2605 corner.move(-corner.width() * expand_ratio, -corner.height() * expand_ratio); 2606 corner.expand(corner.width() * expand_ratio, corner.height() * expand_ratio); 2607 } 2608 2609 return corner; 2610 } 2611 2612 IntRect RenderLayer::scrollCornerAndResizerRect() const 2613 { 2614 RenderBox* box = renderBox(); 2615 if (!box) 2616 return IntRect(); 2617 IntRect scrollCornerAndResizer = scrollCornerRect(); 2618 if (scrollCornerAndResizer.isEmpty()) 2619 scrollCornerAndResizer = resizerCornerRect(box->pixelSnappedBorderBoxRect(), ResizerForPointer); 2620 return scrollCornerAndResizer; 2621 } 2622 2623 bool RenderLayer::isScrollCornerVisible() const 2624 { 2625 ASSERT(renderer()->isBox()); 2626 return !scrollCornerRect().isEmpty(); 2627 } 2628 2629 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const 2630 { 2631 RenderView* view = renderer()->view(); 2632 if (!view) 2633 return scrollbarRect; 2634 2635 IntRect rect = scrollbarRect; 2636 rect.move(scrollbarOffset(scrollbar)); 2637 2638 return view->frameView()->convertFromRenderer(renderer(), rect); 2639 } 2640 2641 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const 2642 { 2643 RenderView* view = renderer()->view(); 2644 if (!view) 2645 return parentRect; 2646 2647 IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect); 2648 rect.move(-scrollbarOffset(scrollbar)); 2649 return rect; 2650 } 2651 2652 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const 2653 { 2654 RenderView* view = renderer()->view(); 2655 if (!view) 2656 return scrollbarPoint; 2657 2658 IntPoint point = scrollbarPoint; 2659 point.move(scrollbarOffset(scrollbar)); 2660 return view->frameView()->convertFromRenderer(renderer(), point); 2661 } 2662 2663 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const 2664 { 2665 RenderView* view = renderer()->view(); 2666 if (!view) 2667 return parentPoint; 2668 2669 IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint); 2670 2671 point.move(-scrollbarOffset(scrollbar)); 2672 return point; 2673 } 2674 2675 IntSize RenderLayer::contentsSize() const 2676 { 2677 return IntSize(scrollWidth(), scrollHeight()); 2678 } 2679 2680 int RenderLayer::visibleHeight() const 2681 { 2682 return m_layerSize.height(); 2683 } 2684 2685 int RenderLayer::visibleWidth() const 2686 { 2687 return m_layerSize.width(); 2688 } 2689 2690 bool RenderLayer::shouldSuspendScrollAnimations() const 2691 { 2692 RenderView* view = renderer()->view(); 2693 if (!view) 2694 return true; 2695 return view->frameView()->shouldSuspendScrollAnimations(); 2696 } 2697 2698 bool RenderLayer::scrollbarsCanBeActive() const 2699 { 2700 RenderView* view = renderer()->view(); 2701 if (!view) 2702 return false; 2703 return view->frameView()->scrollbarsCanBeActive(); 2704 } 2705 2706 IntPoint RenderLayer::lastKnownMousePosition() const 2707 { 2708 return renderer()->frame() ? renderer()->frame()->eventHandler()->lastKnownMousePosition() : IntPoint(); 2709 } 2710 2711 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const 2712 { 2713 if (!m_hBar) 2714 return IntRect(); 2715 2716 const RenderBox* box = renderBox(); 2717 const IntRect& scrollCorner = scrollCornerRect(); 2718 2719 return IntRect(horizontalScrollbarStart(borderBoxRect.x()), 2720 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(), 2721 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), 2722 m_hBar->height()); 2723 } 2724 2725 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const 2726 { 2727 if (!m_vBar) 2728 return IntRect(); 2729 2730 const RenderBox* box = renderBox(); 2731 const IntRect& scrollCorner = scrollCornerRect(); 2732 2733 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()), 2734 borderBoxRect.y() + box->borderTop(), 2735 m_vBar->width(), 2736 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()); 2737 } 2738 2739 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const 2740 { 2741 const RenderBox* box = renderBox(); 2742 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 2743 return minX + box->borderLeft(); 2744 return maxX - box->borderRight() - m_vBar->width(); 2745 } 2746 2747 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const 2748 { 2749 const RenderBox* box = renderBox(); 2750 int x = minX + box->borderLeft(); 2751 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 2752 x += m_vBar ? m_vBar->width() : resizerCornerRect(box->pixelSnappedBorderBoxRect(), ResizerForPointer).width(); 2753 return x; 2754 } 2755 2756 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const 2757 { 2758 RenderBox* box = renderBox(); 2759 2760 if (scrollbar == m_vBar.get()) 2761 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop()); 2762 2763 if (scrollbar == m_hBar.get()) 2764 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height()); 2765 2766 ASSERT_NOT_REACHED(); 2767 return IntSize(); 2768 } 2769 2770 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) 2771 { 2772 if (scrollbar == m_vBar.get()) { 2773 if (GraphicsLayer* layer = layerForVerticalScrollbar()) { 2774 layer->setNeedsDisplayInRect(rect); 2775 return; 2776 } 2777 } else { 2778 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { 2779 layer->setNeedsDisplayInRect(rect); 2780 return; 2781 } 2782 } 2783 2784 IntRect scrollRect = rect; 2785 RenderBox* box = renderBox(); 2786 ASSERT(box); 2787 // If we are not yet inserted into the tree, there is no need to repaint. 2788 if (!box->parent()) 2789 return; 2790 2791 if (scrollbar == m_vBar.get()) 2792 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop()); 2793 else 2794 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height()); 2795 renderer()->repaintRectangle(scrollRect); 2796 } 2797 2798 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect) 2799 { 2800 if (GraphicsLayer* layer = layerForScrollCorner()) { 2801 layer->setNeedsDisplayInRect(rect); 2802 return; 2803 } 2804 2805 if (m_scrollCorner) 2806 m_scrollCorner->repaintRectangle(rect); 2807 if (m_resizer) 2808 m_resizer->repaintRectangle(rect); 2809 } 2810 2811 static inline RenderObject* rendererForScrollbar(RenderObject* renderer) 2812 { 2813 if (Node* node = renderer->node()) { 2814 if (ShadowRoot* shadowRoot = node->containingShadowRoot()) { 2815 if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot) 2816 return shadowRoot->host()->renderer(); 2817 } 2818 } 2819 2820 return renderer; 2821 } 2822 2823 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation) 2824 { 2825 RefPtr<Scrollbar> widget; 2826 RenderObject* actualRenderer = rendererForScrollbar(renderer()); 2827 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); 2828 if (hasCustomScrollbarStyle) 2829 widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node()); 2830 else { 2831 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); 2832 if (orientation == HorizontalScrollbar) 2833 didAddHorizontalScrollbar(widget.get()); 2834 else 2835 didAddVerticalScrollbar(widget.get()); 2836 } 2837 renderer()->document()->view()->addChild(widget.get()); 2838 return widget.release(); 2839 } 2840 2841 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation) 2842 { 2843 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar; 2844 if (!scrollbar) 2845 return; 2846 2847 if (!scrollbar->isCustomScrollbar()) { 2848 if (orientation == HorizontalScrollbar) 2849 willRemoveHorizontalScrollbar(scrollbar.get()); 2850 else 2851 willRemoveVerticalScrollbar(scrollbar.get()); 2852 } 2853 2854 scrollbar->removeFromParent(); 2855 scrollbar->disconnectFromScrollableArea(); 2856 scrollbar = 0; 2857 } 2858 2859 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) 2860 { 2861 if (hasScrollbar == hasHorizontalScrollbar()) 2862 return; 2863 2864 if (hasScrollbar) 2865 m_hBar = createScrollbar(HorizontalScrollbar); 2866 else 2867 destroyScrollbar(HorizontalScrollbar); 2868 2869 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. 2870 if (m_hBar) 2871 m_hBar->styleChanged(); 2872 if (m_vBar) 2873 m_vBar->styleChanged(); 2874 2875 // Force an update since we know the scrollbars have changed things. 2876 if (renderer()->document()->hasAnnotatedRegions()) 2877 renderer()->document()->setAnnotatedRegionsDirty(true); 2878 } 2879 2880 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) 2881 { 2882 if (hasScrollbar == hasVerticalScrollbar()) 2883 return; 2884 2885 if (hasScrollbar) 2886 m_vBar = createScrollbar(VerticalScrollbar); 2887 else 2888 destroyScrollbar(VerticalScrollbar); 2889 2890 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. 2891 if (m_hBar) 2892 m_hBar->styleChanged(); 2893 if (m_vBar) 2894 m_vBar->styleChanged(); 2895 2896 // Force an update since we know the scrollbars have changed things. 2897 if (renderer()->document()->hasAnnotatedRegions()) 2898 renderer()->document()->setAnnotatedRegionsDirty(true); 2899 } 2900 2901 ScrollableArea* RenderLayer::enclosingScrollableArea() const 2902 { 2903 if (RenderLayer* scrollableLayer = enclosingScrollableLayer()) 2904 return scrollableLayer; 2905 2906 // FIXME: We should return the frame view here (or possibly an ancestor frame view, 2907 // if the frame view isn't scrollable. 2908 return 0; 2909 } 2910 2911 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const 2912 { 2913 if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting()))) 2914 return 0; 2915 return m_vBar->width(); 2916 } 2917 2918 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const 2919 { 2920 if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting()))) 2921 return 0; 2922 return m_hBar->height(); 2923 } 2924 2925 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const 2926 { 2927 // Currently the resize corner is either the bottom right corner or the bottom left corner. 2928 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case? 2929 IntSize elementSize = size(); 2930 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 2931 elementSize.setWidth(0); 2932 IntPoint resizerPoint = IntPoint(elementSize); 2933 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint)); 2934 return localPoint - resizerPoint; 2935 } 2936 2937 bool RenderLayer::hasOverflowControls() const 2938 { 2939 return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE; 2940 } 2941 2942 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot) 2943 { 2944 if (!m_hBar && !m_vBar && !canResize()) 2945 return; 2946 2947 RenderBox* box = renderBox(); 2948 if (!box) 2949 return; 2950 2951 const IntRect borderBox = box->pixelSnappedBorderBoxRect(); 2952 const IntRect& scrollCorner = scrollCornerRect(); 2953 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size()); 2954 if (m_vBar) { 2955 IntRect vBarRect = rectForVerticalScrollbar(borderBox); 2956 vBarRect.move(offsetFromRoot); 2957 m_vBar->setFrameRect(vBarRect); 2958 } 2959 2960 if (m_hBar) { 2961 IntRect hBarRect = rectForHorizontalScrollbar(borderBox); 2962 hBarRect.move(offsetFromRoot); 2963 m_hBar->setFrameRect(hBarRect); 2964 } 2965 2966 if (m_scrollCorner) 2967 m_scrollCorner->setFrameRect(scrollCorner); 2968 if (m_resizer) 2969 m_resizer->setFrameRect(resizerCornerRect(borderBox, ResizerForPointer)); 2970 2971 if (isComposited()) 2972 backing()->positionOverflowControlsLayers(offsetFromRoot); 2973 } 2974 2975 int RenderLayer::scrollWidth() const 2976 { 2977 ASSERT(renderBox()); 2978 if (m_scrollDimensionsDirty) 2979 const_cast<RenderLayer*>(this)->computeScrollDimensions(); 2980 return snapSizeToPixel(m_overflowRect.width(), renderBox()->clientLeft() + renderBox()->x()); 2981 } 2982 2983 int RenderLayer::scrollHeight() const 2984 { 2985 ASSERT(renderBox()); 2986 if (m_scrollDimensionsDirty) 2987 const_cast<RenderLayer*>(this)->computeScrollDimensions(); 2988 return snapSizeToPixel(m_overflowRect.height(), renderBox()->clientTop() + renderBox()->y()); 2989 } 2990 2991 void RenderLayer::computeScrollDimensions() 2992 { 2993 RenderBox* box = renderBox(); 2994 ASSERT(box); 2995 2996 m_scrollDimensionsDirty = false; 2997 2998 m_overflowRect = box->layoutOverflowRect(); 2999 box->flipForWritingMode(m_overflowRect); 3000 3001 int scrollableLeftOverflow = m_overflowRect.x() - box->borderLeft(); 3002 int scrollableTopOverflow = m_overflowRect.y() - box->borderTop(); 3003 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow)); 3004 } 3005 3006 bool RenderLayer::hasScrollableHorizontalOverflow() const 3007 { 3008 return hasHorizontalOverflow() && renderBox()->scrollsOverflowX(); 3009 } 3010 3011 bool RenderLayer::hasScrollableVerticalOverflow() const 3012 { 3013 return hasVerticalOverflow() && renderBox()->scrollsOverflowY(); 3014 } 3015 3016 bool RenderLayer::hasHorizontalOverflow() const 3017 { 3018 ASSERT(!m_scrollDimensionsDirty); 3019 3020 return scrollWidth() > renderBox()->pixelSnappedClientWidth(); 3021 } 3022 3023 bool RenderLayer::hasVerticalOverflow() const 3024 { 3025 ASSERT(!m_scrollDimensionsDirty); 3026 3027 return scrollHeight() > renderBox()->pixelSnappedClientHeight(); 3028 } 3029 3030 void RenderLayer::updateScrollbarsAfterLayout() 3031 { 3032 RenderBox* box = renderBox(); 3033 ASSERT(box); 3034 3035 // List box parts handle the scrollbars by themselves so we have nothing to do. 3036 if (box->style()->appearance() == ListboxPart) 3037 return; 3038 3039 bool hasHorizontalOverflow = this->hasHorizontalOverflow(); 3040 bool hasVerticalOverflow = this->hasVerticalOverflow(); 3041 3042 // overflow:scroll should just enable/disable. 3043 if (renderer()->style()->overflowX() == OSCROLL) 3044 m_hBar->setEnabled(hasHorizontalOverflow); 3045 if (renderer()->style()->overflowY() == OSCROLL) 3046 m_vBar->setEnabled(hasVerticalOverflow); 3047 3048 // overflow:auto may need to lay out again if scrollbars got added/removed. 3049 bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); 3050 bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); 3051 3052 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { 3053 if (box->hasAutoHorizontalScrollbar()) 3054 setHasHorizontalScrollbar(hasHorizontalOverflow); 3055 if (box->hasAutoVerticalScrollbar()) 3056 setHasVerticalScrollbar(hasVerticalOverflow); 3057 3058 updateSelfPaintingLayer(); 3059 3060 // Force an update since we know the scrollbars have changed things. 3061 if (renderer()->document()->hasAnnotatedRegions()) 3062 renderer()->document()->setAnnotatedRegionsDirty(true); 3063 3064 renderer()->repaint(); 3065 3066 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) { 3067 if (!m_inOverflowRelayout) { 3068 // Our proprietary overflow: overlay value doesn't trigger a layout. 3069 m_inOverflowRelayout = true; 3070 renderer()->setNeedsLayout(MarkOnlyThis); 3071 if (renderer()->isRenderBlock()) { 3072 RenderBlock* block = toRenderBlock(renderer()); 3073 block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); 3074 block->layoutBlock(true); 3075 } else 3076 renderer()->layout(); 3077 m_inOverflowRelayout = false; 3078 } 3079 } 3080 } 3081 3082 // Set up the range (and page step/line step). 3083 if (m_hBar) { 3084 int clientWidth = box->pixelSnappedClientWidth(); 3085 m_hBar->setProportion(clientWidth, m_overflowRect.width()); 3086 } 3087 if (m_vBar) { 3088 int clientHeight = box->pixelSnappedClientHeight(); 3089 m_vBar->setProportion(clientHeight, m_overflowRect.height()); 3090 } 3091 3092 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); 3093 } 3094 3095 void RenderLayer::updateScrollInfoAfterLayout() 3096 { 3097 RenderBox* box = renderBox(); 3098 if (!box) 3099 return; 3100 3101 m_scrollDimensionsDirty = true; 3102 IntSize originalScrollOffset = adjustedScrollOffset(); 3103 3104 computeScrollDimensions(); 3105 3106 if (!box->isMarquee()) { 3107 // Layout may cause us to be at an invalid scroll position. In this case we need 3108 // to pull our scroll offsets back to the max (or push them up to the min). 3109 IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset()); 3110 if (clampedScrollOffset != adjustedScrollOffset()) 3111 scrollToOffset(clampedScrollOffset); 3112 } 3113 3114 updateScrollbarsAfterLayout(); 3115 3116 if (originalScrollOffset != adjustedScrollOffset()) 3117 scrollToOffsetWithoutAnimation(-scrollOrigin() + adjustedScrollOffset()); 3118 3119 // Composited scrolling may need to be enabled or disabled if the amount of overflow changed. 3120 if (renderer()->view() && compositor()->updateLayerCompositingState(this)) 3121 compositor()->setCompositingLayersNeedRebuild(); 3122 } 3123 3124 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const 3125 { 3126 const IntRect borderBox = renderBox()->pixelSnappedBorderBoxRect(); 3127 3128 if (rectForHorizontalScrollbar(borderBox).intersects(localRect)) 3129 return true; 3130 3131 if (rectForVerticalScrollbar(borderBox).intersects(localRect)) 3132 return true; 3133 3134 if (scrollCornerRect().intersects(localRect)) 3135 return true; 3136 3137 if (resizerCornerRect(borderBox, ResizerForPointer).intersects(localRect)) 3138 return true; 3139 3140 return false; 3141 } 3142 3143 void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) 3144 { 3145 // Don't do anything if we have no overflow. 3146 if (!renderer()->hasOverflowClip()) 3147 return; 3148 3149 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint 3150 // on top of everything else. If this is the normal painting pass, paintingOverlayControls 3151 // will be false, and we should just tell the root layer that there are overlay scrollbars 3152 // that need to be painted. That will cause the second pass through the layer tree to run, 3153 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the 3154 // second pass doesn't need to re-enter the RenderTree to get it right. 3155 if (hasOverlayScrollbars() && !paintingOverlayControls) { 3156 m_cachedOverlayScrollbarOffset = paintOffset; 3157 // It's not necessary to do the second pass if the scrollbars paint into layers. 3158 if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar())) 3159 return; 3160 IntRect localDamgeRect = damageRect; 3161 localDamgeRect.moveBy(-paintOffset); 3162 if (!overflowControlsIntersectRect(localDamgeRect)) 3163 return; 3164 3165 RenderView* renderView = renderer()->view(); 3166 3167 RenderLayer* paintingRoot = 0; 3168 paintingRoot = enclosingCompositingLayer(); 3169 if (!paintingRoot) 3170 paintingRoot = renderView->layer(); 3171 3172 paintingRoot->setContainsDirtyOverlayScrollbars(true); 3173 return; 3174 } 3175 3176 // This check is required to avoid painting custom CSS scrollbars twice. 3177 if (paintingOverlayControls && !hasOverlayScrollbars()) 3178 return; 3179 3180 IntPoint adjustedPaintOffset = paintOffset; 3181 if (paintingOverlayControls) 3182 adjustedPaintOffset = m_cachedOverlayScrollbarOffset; 3183 3184 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes 3185 // widgets can move without layout occurring (most notably when you scroll a document that 3186 // contains fixed positioned elements). 3187 positionOverflowControls(toIntSize(adjustedPaintOffset)); 3188 3189 // Now that we're sure the scrollbars are in the right place, paint them. 3190 if (m_hBar && !layerForHorizontalScrollbar()) 3191 m_hBar->paint(context, damageRect); 3192 if (m_vBar && !layerForVerticalScrollbar()) 3193 m_vBar->paint(context, damageRect); 3194 3195 if (layerForScrollCorner()) 3196 return; 3197 3198 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the 3199 // edge of the box. 3200 paintScrollCorner(context, adjustedPaintOffset, damageRect); 3201 3202 // Paint our resizer last, since it sits on top of the scroll corner. 3203 paintResizer(context, adjustedPaintOffset, damageRect); 3204 } 3205 3206 void RenderLayer::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect) 3207 { 3208 RenderBox* box = renderBox(); 3209 ASSERT(box); 3210 3211 IntRect absRect = scrollCornerRect(); 3212 absRect.moveBy(paintOffset); 3213 if (!absRect.intersects(damageRect)) 3214 return; 3215 3216 if (context->updatingControlTints()) { 3217 updateScrollCornerStyle(); 3218 return; 3219 } 3220 3221 if (m_scrollCorner) { 3222 m_scrollCorner->paintIntoRect(context, paintOffset, absRect); 3223 return; 3224 } 3225 3226 // We don't want to paint white if we have overlay scrollbars, since we need 3227 // to see what is behind it. 3228 if (!hasOverlayScrollbars()) 3229 context->fillRect(absRect, Color::white); 3230 } 3231 3232 void RenderLayer::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect) 3233 { 3234 float deviceScaleFactor = WebCore::deviceScaleFactor(renderer()->frame()); 3235 3236 RefPtr<Image> resizeCornerImage; 3237 IntSize cornerResizerSize; 3238 if (deviceScaleFactor >= 2) { 3239 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef())); 3240 resizeCornerImage = resizeCornerImageHiRes; 3241 cornerResizerSize = resizeCornerImage->size(); 3242 cornerResizerSize.scale(0.5f); 3243 } else { 3244 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner").leakRef())); 3245 resizeCornerImage = resizeCornerImageLoRes; 3246 cornerResizerSize = resizeCornerImage->size(); 3247 } 3248 3249 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { 3250 context->save(); 3251 context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height()); 3252 context->scale(FloatSize(-1.0, 1.0)); 3253 context->drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize)); 3254 context->restore(); 3255 return; 3256 } 3257 IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize); 3258 context->drawImage(resizeCornerImage.get(), imageRect); 3259 } 3260 3261 void RenderLayer::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect) 3262 { 3263 if (renderer()->style()->resize() == RESIZE_NONE) 3264 return; 3265 3266 RenderBox* box = renderBox(); 3267 ASSERT(box); 3268 3269 IntRect absRect = resizerCornerRect(box->pixelSnappedBorderBoxRect(), ResizerForPointer); 3270 absRect.moveBy(paintOffset); 3271 if (!absRect.intersects(damageRect)) 3272 return; 3273 3274 if (context->updatingControlTints()) { 3275 updateResizerStyle(); 3276 return; 3277 } 3278 3279 if (m_resizer) { 3280 m_resizer->paintIntoRect(context, paintOffset, absRect); 3281 return; 3282 } 3283 3284 drawPlatformResizerImage(context, absRect); 3285 3286 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present. 3287 // Clipping will exclude the right and bottom edges of this frame. 3288 if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) { 3289 GraphicsContextStateSaver stateSaver(*context); 3290 context->clip(absRect); 3291 IntRect largerCorner = absRect; 3292 largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1)); 3293 context->setStrokeColor(Color(217, 217, 217)); 3294 context->setStrokeThickness(1.0f); 3295 context->setFillColor(Color::transparent); 3296 context->drawRect(largerCorner); 3297 } 3298 } 3299 3300 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint, 3301 ResizerHitTestType resizerHitTestType) const 3302 { 3303 if (!canResize()) 3304 return false; 3305 3306 RenderBox* box = renderBox(); 3307 ASSERT(box); 3308 3309 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint)); 3310 IntRect localBounds (0, 0, box->pixelSnappedWidth(), box->pixelSnappedHeight()); 3311 return resizerCornerRect(localBounds, resizerHitTestType).contains(localPoint); 3312 } 3313 3314 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint) 3315 { 3316 if (!m_hBar && !m_vBar && !canResize()) 3317 return false; 3318 3319 RenderBox* box = renderBox(); 3320 ASSERT(box); 3321 3322 IntRect resizeControlRect; 3323 if (renderer()->style()->resize() != RESIZE_NONE) { 3324 resizeControlRect = resizerCornerRect(box->pixelSnappedBorderBoxRect(), ResizerForPointer); 3325 if (resizeControlRect.contains(localPoint)) 3326 return true; 3327 } 3328 3329 int resizeControlSize = max(resizeControlRect.height(), 0); 3330 3331 // FIXME: We should hit test the m_scrollCorner and pass it back through the result. 3332 3333 if (m_vBar && m_vBar->shouldParticipateInHitTesting()) { 3334 LayoutRect vBarRect(verticalScrollbarStart(0, box->width()), 3335 box->borderTop(), 3336 m_vBar->width(), 3337 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); 3338 if (vBarRect.contains(localPoint)) { 3339 result.setScrollbar(m_vBar.get()); 3340 return true; 3341 } 3342 } 3343 3344 resizeControlSize = max(resizeControlRect.width(), 0); 3345 if (m_hBar && m_hBar->shouldParticipateInHitTesting()) { 3346 LayoutRect hBarRect(horizontalScrollbarStart(0), 3347 box->height() - box->borderBottom() - m_hBar->height(), 3348 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), 3349 m_hBar->height()); 3350 if (hBarRect.contains(localPoint)) { 3351 result.setScrollbar(m_hBar.get()); 3352 return true; 3353 } 3354 } 3355 3356 return false; 3357 } 3358 3359 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) 3360 { 3361 return ScrollableArea::scroll(direction, granularity, multiplier); 3362 } 3363 3364 void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, PaintLayerFlags paintFlags) 3365 { 3366 OverlapTestRequestMap overlapTestRequests; 3367 3368 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, region, &overlapTestRequests); 3369 paintLayer(context, paintingInfo, paintFlags); 3370 3371 OverlapTestRequestMap::iterator end = overlapTestRequests.end(); 3372 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) 3373 it->key->setIsOverlapped(false); 3374 } 3375 3376 void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot) 3377 { 3378 if (!m_containsDirtyOverlayScrollbars) 3379 return; 3380 3381 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot); 3382 paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars); 3383 3384 m_containsDirtyOverlayScrollbars = false; 3385 } 3386 3387 static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer) 3388 { 3389 if (startLayer == endLayer) 3390 return true; 3391 3392 RenderView* view = startLayer->renderer()->view(); 3393 for (RenderBlock* currentBlock = startLayer->renderer()->containingBlock(); currentBlock && currentBlock != view; currentBlock = currentBlock->containingBlock()) { 3394 if (currentBlock->layer() == endLayer) 3395 return true; 3396 } 3397 3398 return false; 3399 } 3400 3401 void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect, 3402 BorderRadiusClippingRule rule) 3403 { 3404 if (clipRect.rect() == paintDirtyRect && !clipRect.hasRadius()) 3405 return; 3406 context->save(); 3407 context->clip(pixelSnappedIntRect(clipRect.rect())); 3408 3409 if (!clipRect.hasRadius()) 3410 return; 3411 3412 // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from 3413 // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our 3414 // containing block chain so we check that also. 3415 for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) { 3416 if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) { 3417 LayoutPoint delta; 3418 layer->convertToLayerCoords(rootLayer, delta); 3419 context->clipRoundedRect(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size()))); 3420 } 3421 3422 if (layer == rootLayer) 3423 break; 3424 } 3425 } 3426 3427 void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect) 3428 { 3429 if (clipRect.rect() == paintDirtyRect && !clipRect.hasRadius()) 3430 return; 3431 context->restore(); 3432 } 3433 3434 static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer) 3435 { 3436 Vector<RenderWidget*> overlappedRequestClients; 3437 OverlapTestRequestMap::iterator end = overlapTestRequests.end(); 3438 LayoutRect boundingBox = layer->boundingBox(rootLayer); 3439 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) { 3440 if (!boundingBox.intersects(it->value)) 3441 continue; 3442 3443 it->key->setIsOverlapped(true); 3444 overlappedRequestClients.append(it->key); 3445 } 3446 for (size_t i = 0; i < overlappedRequestClients.size(); ++i) 3447 overlapTestRequests.remove(overlappedRequestClients[i]); 3448 } 3449 3450 static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection) 3451 { 3452 return paintingReflection && !layer->has3DTransform(); 3453 } 3454 3455 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer) 3456 { 3457 // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC. 3458 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document 3459 // will do a full repaint(). 3460 if (layer->renderer()->document()->didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isRoot()) 3461 return true; 3462 3463 return false; 3464 } 3465 3466 static bool paintForFixedRootBackground(const RenderLayer* layer, RenderLayer::PaintLayerFlags paintFlags) 3467 { 3468 return layer->renderer()->isRoot() && (paintFlags & RenderLayer::PaintLayerPaintingRootBackgroundOnly); 3469 } 3470 3471 void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 3472 { 3473 if (isComposited()) { 3474 // The updatingControlTints() painting pass goes through compositing layers, 3475 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. 3476 if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)) { 3477 paintFlags |= PaintLayerTemporaryClipRects; 3478 } else if (!backing()->paintsIntoCompositedAncestor() 3479 && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection) 3480 && !paintForFixedRootBackground(this, paintFlags)) { 3481 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). 3482 return; 3483 } 3484 } else if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) { 3485 // Don't paint out-of-view viewport constrained layers (when doing prepainting) because they will never be visible 3486 // unless their position or viewport size is changed. 3487 return; 3488 } 3489 3490 // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself. 3491 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) 3492 return; 3493 3494 if (shouldSuppressPaintingLayer(this)) 3495 return; 3496 3497 // If this layer is totally invisible then there is nothing to paint. 3498 if (!renderer()->opacity()) 3499 return; 3500 3501 if (paintsWithTransparency(paintingInfo.paintBehavior)) 3502 paintFlags |= PaintLayerHaveTransparency; 3503 3504 // PaintLayerAppliedTransform is used in RenderReplica, to avoid applying the transform twice. 3505 if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) { 3506 TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior); 3507 // If the transform can't be inverted, then don't paint anything. 3508 if (!layerTransform.isInvertible()) 3509 return; 3510 3511 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency 3512 // layer from the parent now, assuming there is a parent 3513 if (paintFlags & PaintLayerHaveTransparency) { 3514 if (parent()) 3515 parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); 3516 else 3517 beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior); 3518 } 3519 3520 if (enclosingPaginationLayer()) { 3521 paintTransformedLayerIntoFragments(context, paintingInfo, paintFlags); 3522 return; 3523 } 3524 3525 // Make sure the parent's clip rects have been calculated. 3526 ClipRect clipRect = paintingInfo.paintDirtyRect; 3527 if (parent()) { 3528 ClipRectsContext clipRectsContext(paintingInfo.rootLayer, paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, 3529 IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip); 3530 clipRect = backgroundClipRect(clipRectsContext); 3531 clipRect.intersect(paintingInfo.paintDirtyRect); 3532 3533 // Push the parent coordinate space's clip. 3534 parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect); 3535 } 3536 3537 paintLayerByApplyingTransform(context, paintingInfo, paintFlags); 3538 3539 // Restore the clip. 3540 if (parent()) 3541 parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect); 3542 3543 return; 3544 } 3545 3546 paintLayerContentsAndReflection(context, paintingInfo, paintFlags); 3547 } 3548 3549 void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 3550 { 3551 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 3552 3553 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform); 3554 3555 // Paint the reflection first if we have one. 3556 if (m_reflection && !m_paintingInsideReflection) { 3557 // Mark that we are now inside replica painting. 3558 m_paintingInsideReflection = true; 3559 reflectionLayer()->paintLayer(context, paintingInfo, localPaintFlags | PaintLayerPaintingReflection); 3560 m_paintingInsideReflection = false; 3561 } 3562 3563 localPaintFlags |= PaintLayerPaintingCompositingAllPhases; 3564 paintLayerContents(context, paintingInfo, localPaintFlags); 3565 } 3566 3567 void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 3568 { 3569 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 3570 ASSERT(!(paintFlags & PaintLayerAppliedTransform)); 3571 3572 bool haveTransparency = paintFlags & PaintLayerHaveTransparency; 3573 bool isSelfPaintingLayer = this->isSelfPaintingLayer(); 3574 bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars; 3575 bool isPaintingScrollingContent = paintFlags & PaintLayerPaintingCompositingScrollingPhase; 3576 bool isPaintingCompositedForeground = paintFlags & PaintLayerPaintingCompositingForegroundPhase; 3577 bool isPaintingCompositedBackground = paintFlags & PaintLayerPaintingCompositingBackgroundPhase; 3578 bool isPaintingOverflowContents = paintFlags & PaintLayerPaintingOverflowContents; 3579 // Outline always needs to be painted even if we have no visible content. Also, 3580 // the outline is painted in the background phase during composited scrolling. 3581 // If it were painted in the foreground phase, it would move with the scrolled 3582 // content. When not composited scrolling, the outline is painted in the 3583 // foreground phase. Since scrolled contents are moved by repainting in this 3584 // case, the outline won't get 'dragged along'. 3585 bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars 3586 && ((isPaintingScrollingContent && isPaintingCompositedBackground) 3587 || (!isPaintingScrollingContent && isPaintingCompositedForeground)); 3588 bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars; 3589 3590 float deviceScaleFactor = WebCore::deviceScaleFactor(renderer()->frame()); 3591 context->setUseHighResMarkers(deviceScaleFactor > 1.5f); 3592 3593 GraphicsContext* transparencyLayerContext = context; 3594 3595 if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isRoot()) 3596 return; 3597 3598 // Ensure our lists are up-to-date. 3599 updateLayerListsIfNeeded(); 3600 3601 LayoutPoint offsetFromRoot; 3602 convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); 3603 3604 IntRect rootRelativeBounds; 3605 bool rootRelativeBoundsComputed = false; 3606 3607 // Apply clip-path to context. 3608 bool hasClipPath = false; 3609 RenderStyle* style = renderer()->style(); 3610 if (renderer()->hasClipPath() && !context->paintingDisabled() && style) { 3611 ASSERT(style->clipPath()); 3612 if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) { 3613 hasClipPath = true; 3614 context->save(); 3615 ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath()); 3616 3617 if (!rootRelativeBoundsComputed) { 3618 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3619 rootRelativeBoundsComputed = true; 3620 } 3621 3622 context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule()); 3623 } else if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) { 3624 ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath()); 3625 Document* document = renderer()->document(); 3626 // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405) 3627 Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0; 3628 if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) { 3629 if (!rootRelativeBoundsComputed) { 3630 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3631 rootRelativeBoundsComputed = true; 3632 } 3633 3634 // FIXME: This should use a safer cast such as toRenderSVGResourceContainer(). 3635 static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context); 3636 } 3637 } 3638 } 3639 3640 LayerPaintingInfo localPaintingInfo(paintingInfo); 3641 FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters()); 3642 if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) { 3643 RenderLayerFilterInfo* filterInfo = this->filterInfo(); 3644 ASSERT(filterInfo); 3645 LayoutRect filterRepaintRect = filterInfo->dirtySourceRect(); 3646 filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y()); 3647 3648 if (!rootRelativeBoundsComputed) { 3649 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0); 3650 rootRelativeBoundsComputed = true; 3651 } 3652 3653 if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) { 3654 // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero. 3655 filterInfo->resetDirtySourceRect(); 3656 3657 // Rewire the old context to a memory buffer, so that we can capture the contents of the layer. 3658 // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer 3659 // on the original context and avoid duplicating "beginFilterEffect" after each transparency layer call. Also, note that 3660 // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method. 3661 context = filterPainter.beginFilterEffect(context); 3662 3663 // Check that we didn't fail to allocate the graphics context for the offscreen buffer. 3664 if (filterPainter.hasStartedFilterEffect()) { 3665 localPaintingInfo.paintDirtyRect = filterPainter.repaintRect(); 3666 // If the filter needs the full source image, we need to avoid using the clip rectangles. 3667 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly. 3668 // Note that we will still apply the clipping on the final rendering of the filter. 3669 localPaintingInfo.clipToDirtyRect = !filterRenderer()->hasFilterThatMovesPixels(); 3670 } 3671 } 3672 } 3673 3674 if (filterPainter.hasStartedFilterEffect() && haveTransparency) { 3675 // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context. 3676 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior); 3677 } 3678 3679 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which 3680 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set). 3681 // Else, our renderer tree may or may not contain the painting root, so we pass that root along 3682 // so it will be tested against as we descend through the renderers. 3683 RenderObject* paintingRootForRenderer = 0; 3684 if (localPaintingInfo.paintingRoot && !renderer()->isDescendantOf(localPaintingInfo.paintingRoot)) 3685 paintingRootForRenderer = localPaintingInfo.paintingRoot; 3686 3687 if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer) 3688 performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this); 3689 3690 bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText; 3691 bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly; 3692 3693 bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly; 3694 bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground); 3695 bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent; 3696 bool shouldPaintNormalFlowAndPosZOrderLists = isPaintingCompositedForeground; 3697 bool shouldPaintOverlayScrollbars = isPaintingOverlayScrollbars; 3698 bool shouldPaintMask = (paintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly; 3699 3700 PaintBehavior paintBehavior = PaintBehaviorNormal; 3701 if (paintFlags & PaintLayerPaintingSkipRootBackground) 3702 paintBehavior |= PaintBehaviorSkipRootBackground; 3703 else if (paintFlags & PaintLayerPaintingRootBackgroundOnly) 3704 paintBehavior |= PaintBehaviorRootBackgroundOnly; 3705 3706 LayerFragments layerFragments; 3707 if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) { 3708 // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each 3709 // fragment should paint. 3710 collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.region, localPaintingInfo.paintDirtyRect, 3711 (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, 3712 (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetFromRoot); 3713 updatePaintingInfoForFragments(layerFragments, localPaintingInfo, paintFlags, shouldPaintContent, &offsetFromRoot); 3714 } 3715 3716 if (shouldPaintBackground) 3717 paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency, 3718 localPaintingInfo, paintBehavior, paintingRootForRenderer); 3719 3720 if (shouldPaintNegZOrderList) 3721 paintList(negZOrderList(), context, localPaintingInfo, paintFlags); 3722 3723 if (shouldPaintOwnContents) 3724 paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency, 3725 localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, forceBlackText); 3726 3727 if (shouldPaintOutline) 3728 paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer); 3729 3730 if (shouldPaintNormalFlowAndPosZOrderLists) 3731 paintList(m_normalFlowList.get(), context, localPaintingInfo, paintFlags); 3732 3733 if (shouldPaintNormalFlowAndPosZOrderLists) 3734 paintList(posZOrderList(), context, localPaintingInfo, paintFlags); 3735 3736 if (shouldPaintOverlayScrollbars) 3737 paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo); 3738 3739 if (filterPainter.hasStartedFilterEffect()) { 3740 // Apply the correct clipping (ie. overflow: hidden). 3741 // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved. 3742 ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect; 3743 clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect); 3744 context = filterPainter.applyFilterEffect(); 3745 restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect); 3746 } 3747 3748 // Make sure that we now use the original transparency context. 3749 ASSERT(transparencyLayerContext == context); 3750 3751 if (shouldPaintMask) 3752 paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer); 3753 3754 // End our transparency layer 3755 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) { 3756 context->endTransparencyLayer(); 3757 context->restore(); 3758 m_usedTransparency = false; 3759 } 3760 3761 if (hasClipPath) 3762 context->restore(); 3763 } 3764 3765 void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset) 3766 { 3767 // This involves subtracting out the position of the layer in our current coordinate space, but preserving 3768 // the accumulated error for sub-pixel layout. 3769 LayoutPoint delta; 3770 convertToLayerCoords(paintingInfo.rootLayer, delta); 3771 delta.moveBy(translationOffset); 3772 TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior)); 3773 IntPoint roundedDelta = roundedIntPoint(delta); 3774 transform.translateRight(roundedDelta.x(), roundedDelta.y()); 3775 LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta); 3776 3777 // Apply the transform. 3778 GraphicsContextStateSaver stateSaver(*context); 3779 context->concatCTM(transform.toAffineTransform()); 3780 3781 // Now do a paint with the root layer shifted to be us. 3782 LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior, 3783 adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.region, paintingInfo.overlapTestRequests); 3784 paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags); 3785 } 3786 3787 void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 3788 { 3789 if (!list) 3790 return; 3791 3792 if (!hasSelfPaintingLayerDescendant()) 3793 return; 3794 3795 #if !ASSERT_DISABLED 3796 LayerListMutationDetector mutationChecker(this); 3797 #endif 3798 3799 for (size_t i = 0; i < list->size(); ++i) { 3800 RenderLayer* childLayer = list->at(i); 3801 if (!childLayer->isPaginated()) 3802 childLayer->paintLayer(context, paintingInfo, paintFlags); 3803 else 3804 paintPaginatedChildLayer(childLayer, context, paintingInfo, paintFlags); 3805 } 3806 } 3807 3808 void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect, 3809 ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot, 3810 const LayoutRect* layerBoundingBox) 3811 { 3812 if (!enclosingPaginationLayer() || hasTransform()) { 3813 // For unpaginated layers, there is only one fragment. 3814 LayerFragment fragment; 3815 ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); 3816 calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot); 3817 fragments.append(fragment); 3818 return; 3819 } 3820 3821 // Compute our offset within the enclosing pagination layer. 3822 LayoutPoint offsetWithinPaginatedLayer; 3823 convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer); 3824 3825 // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate 3826 // layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that. 3827 ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); 3828 LayoutRect layerBoundsInFlowThread; 3829 ClipRect backgroundRectInFlowThread; 3830 ClipRect foregroundRectInFlowThread; 3831 ClipRect outlineRectInFlowThread; 3832 calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, 3833 outlineRectInFlowThread, &offsetWithinPaginatedLayer); 3834 3835 // Take our bounding box within the flow thread and clip it. 3836 LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer); 3837 layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect()); 3838 3839 // Shift the dirty rect into flow thread coordinates. 3840 LayoutPoint offsetOfPaginationLayerFromRoot; 3841 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot); 3842 LayoutRect dirtyRectInFlowThread(dirtyRect); 3843 dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot); 3844 3845 // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns 3846 // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box. 3847 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer()); 3848 enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread); 3849 3850 if (fragments.isEmpty()) 3851 return; 3852 3853 // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents. 3854 ClipRect ancestorClipRect = dirtyRect; 3855 if (enclosingPaginationLayer()->parent()) { 3856 ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); 3857 ancestorClipRect = enclosingPaginationLayer()->backgroundClipRect(clipRectsContext); 3858 ancestorClipRect.intersect(dirtyRect); 3859 } 3860 3861 for (size_t i = 0; i < fragments.size(); ++i) { 3862 LayerFragment& fragment = fragments.at(i); 3863 3864 // Set our four rects with all clipping applied that was internal to the flow thread. 3865 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread); 3866 3867 // Shift to the root-relative physical position used when painting the flow thread in this fragment. 3868 fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot); 3869 3870 // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are 3871 // properly clipped by the overflow. 3872 fragment.intersect(ancestorClipRect.rect()); 3873 3874 // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column 3875 // clip, so the column clip ends up being all we apply. 3876 fragment.intersect(fragment.paginationClip); 3877 } 3878 } 3879 3880 void RenderLayer::updatePaintingInfoForFragments(LayerFragments& fragments, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags localPaintFlags, 3881 bool shouldPaintContent, const LayoutPoint* offsetFromRoot) 3882 { 3883 ASSERT(offsetFromRoot); 3884 for (size_t i = 0; i < fragments.size(); ++i) { 3885 LayerFragment& fragment = fragments.at(i); 3886 fragment.shouldPaintContent = shouldPaintContent; 3887 if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) { 3888 LayoutPoint newOffsetFromRoot = *offsetFromRoot + fragment.paginationOffset; 3889 fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot); 3890 } 3891 } 3892 } 3893 3894 void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 3895 { 3896 LayerFragments enclosingPaginationFragments; 3897 LayoutPoint offsetOfPaginationLayerFromRoot; 3898 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior); 3899 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.region, paintingInfo.paintDirtyRect, 3900 (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, 3901 (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent); 3902 3903 for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) { 3904 const LayerFragment& fragment = enclosingPaginationFragments.at(i); 3905 3906 // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and 3907 // the enclosing pagination layer. 3908 LayoutRect clipRect = fragment.backgroundRect.rect(); 3909 3910 // Now compute the clips within a given fragment 3911 if (parent() != enclosingPaginationLayer()) { 3912 enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot); 3913 3914 ClipRectsContext clipRectsContext(enclosingPaginationLayer(), paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, 3915 IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip); 3916 LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect(); 3917 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot); 3918 clipRect.intersect(parentClipRect); 3919 } 3920 3921 parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect); 3922 paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset); 3923 parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect); 3924 } 3925 } 3926 3927 void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext, 3928 const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, 3929 RenderObject* paintingRootForRenderer) 3930 { 3931 for (size_t i = 0; i < layerFragments.size(); ++i) { 3932 const LayerFragment& fragment = layerFragments.at(i); 3933 if (!fragment.shouldPaintContent) 3934 continue; 3935 3936 // Begin transparency layers lazily now that we know we have to paint something. 3937 if (haveTransparency) 3938 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior); 3939 3940 if (localPaintingInfo.clipToDirtyRect) { 3941 // Paint our background first, before painting any child layers. 3942 // Establish the clip used to paint our background. 3943 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. 3944 } 3945 3946 // Paint the background. 3947 // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info. 3948 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); 3949 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); 3950 3951 if (localPaintingInfo.clipToDirtyRect) 3952 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); 3953 } 3954 } 3955 3956 void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext, 3957 const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, 3958 RenderObject* paintingRootForRenderer, bool selectionOnly, bool forceBlackText) 3959 { 3960 // Begin transparency if we have something to paint. 3961 if (haveTransparency) { 3962 for (size_t i = 0; i < layerFragments.size(); ++i) { 3963 const LayerFragment& fragment = layerFragments.at(i); 3964 if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) { 3965 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior); 3966 break; 3967 } 3968 } 3969 } 3970 3971 PaintBehavior localPaintBehavior = forceBlackText ? (PaintBehavior)PaintBehaviorForceBlackText : paintBehavior; 3972 3973 // Optimize clipping for the single fragment case. 3974 bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty(); 3975 if (shouldClip) 3976 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect); 3977 3978 // We have to loop through every fragment multiple times, since we have to repaint in each specific phase in order for 3979 // interleaving of the fragments to work properly. 3980 paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, layerFragments, 3981 context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); 3982 3983 if (!selectionOnly) { 3984 paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); 3985 paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); 3986 paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer); 3987 } 3988 3989 if (shouldClip) 3990 restoreClip(context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect); 3991 } 3992 3993 void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context, 3994 const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer) 3995 { 3996 bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1; 3997 3998 for (size_t i = 0; i < layerFragments.size(); ++i) { 3999 const LayerFragment& fragment = layerFragments.at(i); 4000 if (!fragment.shouldPaintContent || fragment.foregroundRect.isEmpty()) 4001 continue; 4002 4003 if (shouldClip) 4004 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect); 4005 4006 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); 4007 if (phase == PaintPhaseForeground) 4008 paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests; 4009 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); 4010 4011 if (shouldClip) 4012 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect); 4013 } 4014 } 4015 4016 void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, 4017 PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer) 4018 { 4019 for (size_t i = 0; i < layerFragments.size(); ++i) { 4020 const LayerFragment& fragment = layerFragments.at(i); 4021 if (fragment.outlineRect.isEmpty()) 4022 continue; 4023 4024 // Paint our own outline 4025 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); 4026 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.outlineRect, DoNotIncludeSelfForBorderRadius); 4027 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); 4028 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect); 4029 } 4030 } 4031 4032 void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, 4033 RenderObject* paintingRootForRenderer) 4034 { 4035 for (size_t i = 0; i < layerFragments.size(); ++i) { 4036 const LayerFragment& fragment = layerFragments.at(i); 4037 if (!fragment.shouldPaintContent) 4038 continue; 4039 4040 if (localPaintingInfo.clipToDirtyRect) 4041 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. 4042 4043 // Paint the mask. 4044 // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info. 4045 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer()); 4046 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)); 4047 4048 if (localPaintingInfo.clipToDirtyRect) 4049 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); 4050 } 4051 } 4052 4053 void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo) 4054 { 4055 for (size_t i = 0; i < layerFragments.size(); ++i) { 4056 const LayerFragment& fragment = layerFragments.at(i); 4057 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); 4058 paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)), 4059 pixelSnappedIntRect(fragment.backgroundRect.rect()), true); 4060 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect); 4061 } 4062 } 4063 4064 void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) 4065 { 4066 // We need to do multiple passes, breaking up our child layer into strips. 4067 Vector<RenderLayer*> columnLayers; 4068 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : ancestorStackingContainer(); 4069 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) { 4070 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox())) 4071 columnLayers.append(curr); 4072 if (curr == ancestorLayer) 4073 break; 4074 } 4075 4076 // It is possible for paintLayer() to be called after the child layer ceases to be paginated but before 4077 // updateLayerPositions() is called and resets the isPaginated() flag, see <rdar://problem/10098679>. 4078 // If this is the case, just bail out, since the upcoming call to updateLayerPositions() will repaint the layer. 4079 if (!columnLayers.size()) 4080 return; 4081 4082 paintChildLayerIntoColumns(childLayer, context, paintingInfo, paintFlags, columnLayers, columnLayers.size() - 1); 4083 } 4084 4085 void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, 4086 PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex) 4087 { 4088 RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer()); 4089 4090 ASSERT(columnBlock && columnBlock->hasColumns()); 4091 if (!columnBlock || !columnBlock->hasColumns()) 4092 return; 4093 4094 LayoutPoint layerOffset; 4095 // FIXME: It looks suspicious to call convertToLayerCoords here 4096 // as canUseConvertToLayerCoords is true for this layer. 4097 columnBlock->layer()->convertToLayerCoords(paintingInfo.rootLayer, layerOffset); 4098 4099 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); 4100 4101 ColumnInfo* colInfo = columnBlock->columnInfo(); 4102 unsigned colCount = columnBlock->columnCount(colInfo); 4103 LayoutUnit currLogicalTopOffset = 0; 4104 for (unsigned i = 0; i < colCount; i++) { 4105 // For each rect, we clip to the rect, and then we adjust our coords. 4106 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); 4107 columnBlock->flipForWritingMode(colRect); 4108 LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent(); 4109 LayoutSize offset; 4110 if (isHorizontal) { 4111 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 4112 offset = LayoutSize(logicalLeftOffset, currLogicalTopOffset); 4113 else 4114 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop()); 4115 } else { 4116 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 4117 offset = LayoutSize(currLogicalTopOffset, logicalLeftOffset); 4118 else 4119 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0); 4120 } 4121 4122 colRect.moveBy(layerOffset); 4123 4124 LayoutRect localDirtyRect(paintingInfo.paintDirtyRect); 4125 localDirtyRect.intersect(colRect); 4126 4127 if (!localDirtyRect.isEmpty()) { 4128 GraphicsContextStateSaver stateSaver(*context); 4129 4130 // Each strip pushes a clip, since column boxes are specified as being 4131 // like overflow:hidden. 4132 context->clip(pixelSnappedIntRect(colRect)); 4133 4134 if (!colIndex) { 4135 // Apply a translation transform to change where the layer paints. 4136 TransformationMatrix oldTransform; 4137 bool oldHasTransform = childLayer->transform(); 4138 if (oldHasTransform) 4139 oldTransform = *childLayer->transform(); 4140 TransformationMatrix newTransform(oldTransform); 4141 newTransform.translateRight(roundToInt(offset.width()), roundToInt(offset.height())); 4142 4143 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform)); 4144 4145 LayerPaintingInfo localPaintingInfo(paintingInfo); 4146 localPaintingInfo.paintDirtyRect = localDirtyRect; 4147 childLayer->paintLayer(context, localPaintingInfo, paintFlags); 4148 4149 if (oldHasTransform) 4150 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform)); 4151 else 4152 childLayer->m_transform.clear(); 4153 } else { 4154 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space. 4155 // This involves subtracting out the position of the layer in our current coordinate space. 4156 LayoutPoint childOffset; 4157 columnLayers[colIndex - 1]->convertToLayerCoords(paintingInfo.rootLayer, childOffset); 4158 TransformationMatrix transform; 4159 transform.translateRight(roundToInt(childOffset.x() + offset.width()), roundToInt(childOffset.y() + offset.height())); 4160 4161 // Apply the transform. 4162 context->concatCTM(transform.toAffineTransform()); 4163 4164 // Now do a paint with the root layer shifted to be the next multicol block. 4165 LayerPaintingInfo columnPaintingInfo(paintingInfo); 4166 columnPaintingInfo.rootLayer = columnLayers[colIndex - 1]; 4167 columnPaintingInfo.paintDirtyRect = transform.inverse().mapRect(localDirtyRect); 4168 paintChildLayerIntoColumns(childLayer, context, columnPaintingInfo, paintFlags, columnLayers, colIndex - 1); 4169 } 4170 } 4171 4172 // Move to the next position. 4173 LayoutUnit blockDelta = isHorizontal ? colRect.height() : colRect.width(); 4174 if (columnBlock->style()->isFlippedBlocksWritingMode()) 4175 currLogicalTopOffset += blockDelta; 4176 else 4177 currLogicalTopOffset -= blockDelta; 4178 } 4179 } 4180 4181 static inline LayoutRect frameVisibleRect(RenderObject* renderer) 4182 { 4183 FrameView* frameView = renderer->document()->view(); 4184 if (!frameView) 4185 return LayoutRect(); 4186 4187 return frameView->visibleContentRect(); 4188 } 4189 4190 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) 4191 { 4192 return hitTest(request, result.hitTestLocation(), result); 4193 } 4194 4195 bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result) 4196 { 4197 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 4198 4199 // RenderView should make sure to update layout before entering hit testing 4200 ASSERT(!renderer()->frame()->view()->layoutPending()); 4201 ASSERT(!renderer()->document()->renderer()->needsLayout()); 4202 4203 LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect(); 4204 if (!request.ignoreClipping()) 4205 hitTestArea.intersect(frameVisibleRect(renderer())); 4206 4207 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false); 4208 if (!insideLayer) { 4209 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, 4210 // return ourselves. We do this so mouse events continue getting delivered after a drag has 4211 // exited the WebView, and so hit testing over a scrollbar hits the content document. 4212 if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) { 4213 renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point())); 4214 insideLayer = this; 4215 } 4216 } 4217 4218 // Now determine if the result is inside an anchor - if the urlElement isn't already set. 4219 Node* node = result.innerNode(); 4220 if (node && !result.URLElement()) 4221 result.setURLElement(toElement(node->enclosingLinkEventParentOrSelf())); 4222 4223 // Now return whether we were inside this layer (this will always be true for the root 4224 // layer). 4225 return insideLayer; 4226 } 4227 4228 Node* RenderLayer::enclosingElement() const 4229 { 4230 for (RenderObject* r = renderer(); r; r = r->parent()) { 4231 if (Node* e = r->node()) 4232 return e; 4233 } 4234 ASSERT_NOT_REACHED(); 4235 return 0; 4236 } 4237 4238 bool RenderLayer::isInTopLayer() const 4239 { 4240 Node* node = renderer()->node(); 4241 return node && node->isElementNode() && toElement(node)->isInTopLayer(); 4242 } 4243 4244 bool RenderLayer::isInTopLayerSubtree() const 4245 { 4246 for (const RenderLayer* layer = this; layer; layer = layer->parent()) { 4247 if (layer->isInTopLayer()) 4248 return true; 4249 } 4250 return false; 4251 } 4252 4253 // Compute the z-offset of the point in the transformState. 4254 // This is effectively projecting a ray normal to the plane of ancestor, finding where that 4255 // ray intersects target, and computing the z delta between those two points. 4256 static double computeZOffset(const HitTestingTransformState& transformState) 4257 { 4258 // We got an affine transform, so no z-offset 4259 if (transformState.m_accumulatedTransform.isAffine()) 4260 return 0; 4261 4262 // Flatten the point into the target plane 4263 FloatPoint targetPoint = transformState.mappedPoint(); 4264 4265 // Now map the point back through the transform, which computes Z. 4266 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint)); 4267 return backmappedPoint.z(); 4268 } 4269 4270 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer, 4271 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, 4272 const HitTestingTransformState* containerTransformState, 4273 const LayoutPoint& translationOffset) const 4274 { 4275 RefPtr<HitTestingTransformState> transformState; 4276 LayoutPoint offset; 4277 if (containerTransformState) { 4278 // If we're already computing transform state, then it's relative to the container (which we know is non-null). 4279 transformState = HitTestingTransformState::create(*containerTransformState); 4280 convertToLayerCoords(containerLayer, offset); 4281 } else { 4282 // If this is the first time we need to make transform state, then base it off of hitTestLocation, 4283 // which is relative to rootLayer. 4284 transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect)); 4285 convertToLayerCoords(rootLayer, offset); 4286 } 4287 offset.moveBy(translationOffset); 4288 4289 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0; 4290 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) { 4291 TransformationMatrix containerTransform; 4292 renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform); 4293 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform); 4294 } else { 4295 transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform); 4296 } 4297 4298 return transformState; 4299 } 4300 4301 4302 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState) 4303 { 4304 if (!hitLayer) 4305 return false; 4306 4307 // The hit layer is depth-sorting with other layers, so just say that it was hit. 4308 if (canDepthSort) 4309 return true; 4310 4311 // We need to look at z-depth to decide if this layer was hit. 4312 if (zOffset) { 4313 ASSERT(transformState); 4314 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us. 4315 double childZOffset = computeZOffset(*transformState); 4316 if (childZOffset > *zOffset) { 4317 *zOffset = childZOffset; 4318 return true; 4319 } 4320 return false; 4321 } 4322 4323 return true; 4324 } 4325 4326 // hitTestLocation and hitTestRect are relative to rootLayer. 4327 // A 'flattening' layer is one preserves3D() == false. 4328 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer. 4329 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer. 4330 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer. 4331 // 4332 // If zOffset is non-null (which indicates that the caller wants z offset information), 4333 // *zOffset on return is the z offset of the hit point relative to the containing flattening layer. 4334 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, 4335 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform, 4336 const HitTestingTransformState* transformState, double* zOffset) 4337 { 4338 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) 4339 return 0; 4340 4341 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. 4342 4343 // Apply a transform if we have one. 4344 if (transform() && !appliedTransform) { 4345 if (enclosingPaginationLayer()) 4346 return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset); 4347 4348 // Make sure the parent's clip rects have been calculated. 4349 if (parent()) { 4350 ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize); 4351 ClipRect clipRect = backgroundClipRect(clipRectsContext); 4352 // Go ahead and test the enclosing clip now. 4353 if (!clipRect.intersects(hitTestLocation)) 4354 return 0; 4355 } 4356 4357 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset); 4358 } 4359 4360 // Ensure our lists and 3d status are up-to-date. 4361 updateLayerListsIfNeeded(); 4362 update3DTransformedDescendantStatus(); 4363 4364 RefPtr<HitTestingTransformState> localTransformState; 4365 if (appliedTransform) { 4366 // We computed the correct state in the caller (above code), so just reference it. 4367 ASSERT(transformState); 4368 localTransformState = const_cast<HitTestingTransformState*>(transformState); 4369 } else if (transformState || m_has3DTransformedDescendant || preserves3D()) { 4370 // We need transform state for the first time, or to offset the container state, so create it here. 4371 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState); 4372 } 4373 4374 // Check for hit test on backface if backface-visibility is 'hidden' 4375 if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) { 4376 TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse(); 4377 // If the z-vector of the matrix is negative, the back is facing towards the viewer. 4378 if (invertedMatrix.m33() < 0) 4379 return 0; 4380 } 4381 4382 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState; 4383 if (localTransformState && !preserves3D()) { 4384 // Keep a copy of the pre-flattening state, for computing z-offsets for the container 4385 unflattenedTransformState = HitTestingTransformState::create(*localTransformState); 4386 // This layer is flattening, so flatten the state passed to descendants. 4387 localTransformState->flatten(); 4388 } 4389 4390 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed 4391 // descendants. 4392 double localZOffset = -numeric_limits<double>::infinity(); 4393 double* zOffsetForDescendantsPtr = 0; 4394 double* zOffsetForContentsPtr = 0; 4395 4396 bool depthSortDescendants = false; 4397 if (preserves3D()) { 4398 depthSortDescendants = true; 4399 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down. 4400 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; 4401 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; 4402 } else if (m_has3DTransformedDescendant) { 4403 // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground. 4404 depthSortDescendants = true; 4405 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; 4406 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; 4407 } else if (zOffset) { 4408 zOffsetForDescendantsPtr = 0; 4409 // Container needs us to give back a z offset for the hit layer. 4410 zOffsetForContentsPtr = zOffset; 4411 } 4412 4413 // This variable tracks which layer the mouse ends up being inside. 4414 RenderLayer* candidateLayer = 0; 4415 4416 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. 4417 RenderLayer* hitLayer = hitTestList(posZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation, 4418 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); 4419 if (hitLayer) { 4420 if (!depthSortDescendants) 4421 return hitLayer; 4422 candidateLayer = hitLayer; 4423 } 4424 4425 // Now check our overflow objects. 4426 hitLayer = hitTestList(m_normalFlowList.get(), rootLayer, request, result, hitTestRect, hitTestLocation, 4427 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); 4428 if (hitLayer) { 4429 if (!depthSortDescendants) 4430 return hitLayer; 4431 candidateLayer = hitLayer; 4432 } 4433 4434 // Collect the fragments. This will compute the clip rectangles for each layer fragment. 4435 LayerFragments layerFragments; 4436 collectFragments(layerFragments, rootLayer, hitTestLocation.region(), hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize); 4437 4438 if (canResize() && hitTestResizerInFragments(layerFragments, hitTestLocation)) { 4439 renderer()->updateHitTestResult(result, hitTestLocation.point()); 4440 return this; 4441 } 4442 4443 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check 4444 // every fragment in reverse order. 4445 if (isSelfPaintingLayer()) { 4446 // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. 4447 HitTestResult tempResult(result.hitTestLocation()); 4448 bool insideFragmentForegroundRect = false; 4449 if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestDescendants, insideFragmentForegroundRect) 4450 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { 4451 if (result.isRectBasedTest()) 4452 result.append(tempResult); 4453 else 4454 result = tempResult; 4455 if (!depthSortDescendants) 4456 return this; 4457 // Foreground can depth-sort with descendant layers, so keep this as a candidate. 4458 candidateLayer = this; 4459 } else if (insideFragmentForegroundRect && result.isRectBasedTest()) 4460 result.append(tempResult); 4461 } 4462 4463 // Now check our negative z-index children. 4464 hitLayer = hitTestList(negZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation, 4465 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); 4466 if (hitLayer) { 4467 if (!depthSortDescendants) 4468 return hitLayer; 4469 candidateLayer = hitLayer; 4470 } 4471 4472 // If we found a layer, return. Child layers, and foreground always render in front of background. 4473 if (candidateLayer) 4474 return candidateLayer; 4475 4476 if (isSelfPaintingLayer()) { 4477 HitTestResult tempResult(result.hitTestLocation()); 4478 bool insideFragmentBackgroundRect = false; 4479 if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestSelf, insideFragmentBackgroundRect) 4480 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { 4481 if (result.isRectBasedTest()) 4482 result.append(tempResult); 4483 else 4484 result = tempResult; 4485 return this; 4486 } 4487 if (insideFragmentBackgroundRect && result.isRectBasedTest()) 4488 result.append(tempResult); 4489 } 4490 4491 return 0; 4492 } 4493 4494 bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragments, const HitTestRequest& request, HitTestResult& result, 4495 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& insideClipRect) const 4496 { 4497 if (layerFragments.isEmpty()) 4498 return false; 4499 4500 for (int i = layerFragments.size() - 1; i >= 0; --i) { 4501 const LayerFragment& fragment = layerFragments.at(i); 4502 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects(hitTestLocation)) 4503 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.intersects(hitTestLocation))) 4504 continue; 4505 insideClipRect = true; 4506 if (hitTestContents(request, result, fragment.layerBounds, hitTestLocation, hitTestFilter)) 4507 return true; 4508 } 4509 4510 return false; 4511 } 4512 4513 bool RenderLayer::hitTestResizerInFragments(const LayerFragments& layerFragments, const HitTestLocation& hitTestLocation) const 4514 { 4515 if (layerFragments.isEmpty()) 4516 return false; 4517 4518 for (int i = layerFragments.size() - 1; i >= 0; --i) { 4519 const LayerFragment& fragment = layerFragments.at(i); 4520 if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(pixelSnappedIntRect(fragment.layerBounds), ResizerForPointer).contains(hitTestLocation.roundedPoint())) 4521 return true; 4522 } 4523 4524 return false; 4525 } 4526 4527 RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, 4528 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset) 4529 { 4530 LayerFragments enclosingPaginationFragments; 4531 LayoutPoint offsetOfPaginationLayerFromRoot; 4532 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox); 4533 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestLocation.region(), hitTestRect, 4534 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent); 4535 4536 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) { 4537 const LayerFragment& fragment = enclosingPaginationFragments.at(i); 4538 4539 // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and 4540 // the enclosing pagination layer. 4541 LayoutRect clipRect = fragment.backgroundRect.rect(); 4542 4543 // Now compute the clips within a given fragment 4544 if (parent() != enclosingPaginationLayer()) { 4545 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot); 4546 4547 ClipRectsContext clipRectsContext(enclosingPaginationLayer(), hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize); 4548 LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect(); 4549 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot); 4550 clipRect.intersect(parentClipRect); 4551 } 4552 4553 if (!hitTestLocation.intersects(clipRect)) 4554 continue; 4555 4556 RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, 4557 transformState, zOffset, fragment.paginationOffset); 4558 if (hitLayer) 4559 return hitLayer; 4560 } 4561 4562 return 0; 4563 } 4564 4565 RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, 4566 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset, 4567 const LayoutPoint& translationOffset) 4568 { 4569 // Create a transform state to accumulate this transform. 4570 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset); 4571 4572 // If the transform can't be inverted, then don't hit test this layer at all. 4573 if (!newTransformState->m_accumulatedTransform.isInvertible()) 4574 return 0; 4575 4576 // Compute the point and the hit test rect in the coords of this layer by using the values 4577 // from the transformState, which store the point and quad in the coords of the last flattened 4578 // layer, and the accumulated transform which lets up map through preserve-3d layers. 4579 // 4580 // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z) 4581 // by our container. 4582 FloatPoint localPoint = newTransformState->mappedPoint(); 4583 FloatQuad localPointQuad = newTransformState->mappedQuad(); 4584 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea(); 4585 HitTestLocation newHitTestLocation; 4586 if (hitTestLocation.isRectBasedTest()) 4587 newHitTestLocation = HitTestLocation(localPoint, localPointQuad); 4588 else 4589 newHitTestLocation = HitTestLocation(localPoint); 4590 4591 // Now do a hit test with the root layer shifted to be us. 4592 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset); 4593 } 4594 4595 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const 4596 { 4597 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 4598 4599 if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - renderBoxLocation()), hitTestFilter)) { 4600 // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is 4601 // a rect-based test. 4602 ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size())); 4603 return false; 4604 } 4605 4606 // For positioned generated content, we might still not have a 4607 // node by the time we get to the layer level, since none of 4608 // the content in the layer has an element. So just walk up 4609 // the tree. 4610 if (!result.innerNode() || !result.innerNonSharedNode()) { 4611 Node* e = enclosingElement(); 4612 if (!result.innerNode()) 4613 result.setInnerNode(e); 4614 if (!result.innerNonSharedNode()) 4615 result.setInnerNonSharedNode(e); 4616 } 4617 4618 return true; 4619 } 4620 4621 RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, 4622 const HitTestRequest& request, HitTestResult& result, 4623 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, 4624 const HitTestingTransformState* transformState, 4625 double* zOffsetForDescendants, double* zOffset, 4626 const HitTestingTransformState* unflattenedTransformState, 4627 bool depthSortDescendants) 4628 { 4629 if (!list) 4630 return 0; 4631 4632 if (!hasSelfPaintingLayerDescendant()) 4633 return 0; 4634 4635 RenderLayer* resultLayer = 0; 4636 for (int i = list->size() - 1; i >= 0; --i) { 4637 RenderLayer* childLayer = list->at(i); 4638 RenderLayer* hitLayer = 0; 4639 HitTestResult tempResult(result.hitTestLocation()); 4640 if (childLayer->isPaginated()) 4641 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants); 4642 else 4643 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants); 4644 4645 // If it a rect-based test, we can safely append the temporary result since it might had hit 4646 // nodes but not necesserily had hitLayer set. 4647 if (result.isRectBasedTest()) 4648 result.append(tempResult); 4649 4650 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) { 4651 resultLayer = hitLayer; 4652 if (!result.isRectBasedTest()) 4653 result = tempResult; 4654 if (!depthSortDescendants) 4655 break; 4656 } 4657 } 4658 4659 return resultLayer; 4660 } 4661 4662 RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, 4663 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset) 4664 { 4665 Vector<RenderLayer*> columnLayers; 4666 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : ancestorStackingContainer(); 4667 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) { 4668 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox())) 4669 columnLayers.append(curr); 4670 if (curr == ancestorLayer) 4671 break; 4672 } 4673 4674 ASSERT(columnLayers.size()); 4675 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset, 4676 columnLayers, columnLayers.size() - 1); 4677 } 4678 4679 RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, 4680 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset, 4681 const Vector<RenderLayer*>& columnLayers, size_t columnIndex) 4682 { 4683 RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer()); 4684 4685 ASSERT(columnBlock && columnBlock->hasColumns()); 4686 if (!columnBlock || !columnBlock->hasColumns()) 4687 return 0; 4688 4689 LayoutPoint layerOffset; 4690 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset); 4691 4692 ColumnInfo* colInfo = columnBlock->columnInfo(); 4693 int colCount = columnBlock->columnCount(colInfo); 4694 4695 // We have to go backwards from the last column to the first. 4696 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); 4697 LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent(); 4698 LayoutUnit currLogicalTopOffset = 0; 4699 int i; 4700 for (i = 0; i < colCount; i++) { 4701 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); 4702 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width()); 4703 if (columnBlock->style()->isFlippedBlocksWritingMode()) 4704 currLogicalTopOffset += blockDelta; 4705 else 4706 currLogicalTopOffset -= blockDelta; 4707 } 4708 for (i = colCount - 1; i >= 0; i--) { 4709 // For each rect, we clip to the rect, and then we adjust our coords. 4710 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); 4711 columnBlock->flipForWritingMode(colRect); 4712 LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft; 4713 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width()); 4714 if (columnBlock->style()->isFlippedBlocksWritingMode()) 4715 currLogicalTopOffset -= blockDelta; 4716 else 4717 currLogicalTopOffset += blockDelta; 4718 4719 LayoutSize offset; 4720 if (isHorizontal) { 4721 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 4722 offset = LayoutSize(currLogicalLeftOffset, currLogicalTopOffset); 4723 else 4724 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop()); 4725 } else { 4726 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 4727 offset = LayoutSize(currLogicalTopOffset, currLogicalLeftOffset); 4728 else 4729 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0); 4730 } 4731 4732 colRect.moveBy(layerOffset); 4733 4734 LayoutRect localClipRect(hitTestRect); 4735 localClipRect.intersect(colRect); 4736 4737 if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect)) { 4738 RenderLayer* hitLayer = 0; 4739 if (!columnIndex) { 4740 // Apply a translation transform to change where the layer paints. 4741 TransformationMatrix oldTransform; 4742 bool oldHasTransform = childLayer->transform(); 4743 if (oldHasTransform) 4744 oldTransform = *childLayer->transform(); 4745 TransformationMatrix newTransform(oldTransform); 4746 newTransform.translateRight(offset.width(), offset.height()); 4747 4748 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform)); 4749 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestLocation, false, transformState, zOffset); 4750 if (oldHasTransform) 4751 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform)); 4752 else 4753 childLayer->m_transform.clear(); 4754 } else { 4755 // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space. 4756 // This involves subtracting out the position of the layer in our current coordinate space. 4757 RenderLayer* nextLayer = columnLayers[columnIndex - 1]; 4758 RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState); 4759 newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform); 4760 FloatPoint localPoint = newTransformState->mappedPoint(); 4761 FloatQuad localPointQuad = newTransformState->mappedQuad(); 4762 LayoutRect localHitTestRect = newTransformState->mappedArea().enclosingBoundingBox(); 4763 HitTestLocation newHitTestLocation; 4764 if (hitTestLocation.isRectBasedTest()) 4765 newHitTestLocation = HitTestLocation(localPoint, localPointQuad); 4766 else 4767 newHitTestLocation = HitTestLocation(localPoint); 4768 newTransformState->flatten(); 4769 4770 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, newHitTestLocation, 4771 newTransformState.get(), zOffset, columnLayers, columnIndex - 1); 4772 } 4773 4774 if (hitLayer) 4775 return hitLayer; 4776 } 4777 } 4778 4779 return 0; 4780 } 4781 4782 void RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext) 4783 { 4784 ClipRectsType clipRectsType = clipRectsContext.clipRectsType; 4785 ASSERT(clipRectsType < NumCachedClipRectsTypes); 4786 if (m_clipRectsCache && m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) { 4787 ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]); 4788 ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy); 4789 4790 #ifdef CHECK_CACHED_CLIP_RECTS 4791 // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default. 4792 ClipRectsContext tempContext(clipRectsContext); 4793 tempContext.clipRectsType = TemporaryClipRects; 4794 ClipRects clipRects; 4795 calculateClipRects(tempContext, clipRects); 4796 ASSERT(clipRects == *m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip).get()); 4797 #endif 4798 return; // We have the correct cached value. 4799 } 4800 4801 // For transformed layers, the root layer was shifted to be us, so there is no need to 4802 // examine the parent. We want to cache clip rects with us as the root. 4803 RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : 0; 4804 if (parentLayer) 4805 parentLayer->updateClipRects(clipRectsContext); 4806 4807 ClipRects clipRects; 4808 calculateClipRects(clipRectsContext, clipRects); 4809 4810 if (!m_clipRectsCache) 4811 m_clipRectsCache = adoptPtr(new ClipRectsCache); 4812 4813 if (parentLayer && parentLayer->clipRects(clipRectsContext) && clipRects == *parentLayer->clipRects(clipRectsContext)) 4814 m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentLayer->clipRects(clipRectsContext)); 4815 else 4816 m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, ClipRects::create(clipRects)); 4817 4818 #ifndef NDEBUG 4819 m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer; 4820 m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy; 4821 #endif 4822 } 4823 4824 void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const 4825 { 4826 if (!parent()) { 4827 // The root layer's clip rect is always infinite. 4828 clipRects.reset(PaintInfo::infiniteRect()); 4829 return; 4830 } 4831 4832 ClipRectsType clipRectsType = clipRectsContext.clipRectsType; 4833 bool useCached = clipRectsType != TemporaryClipRects; 4834 4835 // For transformed layers, the root layer was shifted to be us, so there is no need to 4836 // examine the parent. We want to cache clip rects with us as the root. 4837 RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : 0; 4838 4839 // Ensure that our parent's clip has been calculated so that we can examine the values. 4840 if (parentLayer) { 4841 if (useCached && parentLayer->clipRects(clipRectsContext)) 4842 clipRects = *parentLayer->clipRects(clipRectsContext); 4843 else { 4844 ClipRectsContext parentContext(clipRectsContext); 4845 parentContext.overlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize; // FIXME: why? 4846 parentLayer->calculateClipRects(parentContext, clipRects); 4847 } 4848 } else 4849 clipRects.reset(PaintInfo::infiniteRect()); 4850 4851 // A fixed object is essentially the root of its containing block hierarchy, so when 4852 // we encounter such an object, we reset our clip rects to the fixedClipRect. 4853 if (renderer()->style()->position() == FixedPosition) { 4854 clipRects.setPosClipRect(clipRects.fixedClipRect()); 4855 clipRects.setOverflowClipRect(clipRects.fixedClipRect()); 4856 clipRects.setFixed(true); 4857 } else if (renderer()->style()->hasInFlowPosition()) 4858 clipRects.setPosClipRect(clipRects.overflowClipRect()); 4859 else if (renderer()->style()->position() == AbsolutePosition) 4860 clipRects.setOverflowClipRect(clipRects.posClipRect()); 4861 4862 // Update the clip rects that will be passed to child layers. 4863 if ((renderer()->hasOverflowClip() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || this != clipRectsContext.rootLayer)) || renderer()->hasClip()) { 4864 // This layer establishes a clip of some kind. 4865 4866 // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across 4867 // some transformed layer boundary, for example, in the RenderLayerCompositor overlapMap, where 4868 // clipRects are needed in view space. 4869 LayoutPoint offset; 4870 offset = roundedLayoutPoint(renderer()->localToContainerPoint(FloatPoint(), clipRectsContext.rootLayer->renderer())); 4871 RenderView* view = renderer()->view(); 4872 ASSERT(view); 4873 if (view && clipRects.fixed() && clipRectsContext.rootLayer->renderer() == view) { 4874 offset -= view->frameView()->scrollOffsetForFixedPosition(); 4875 } 4876 4877 if (renderer()->hasOverflowClip()) { 4878 ClipRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy); 4879 if (renderer()->style()->hasBorderRadius()) 4880 newOverflowClip.setHasRadius(true); 4881 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); 4882 if (renderer()->isPositioned()) 4883 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); 4884 } 4885 if (renderer()->hasClip()) { 4886 LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, clipRectsContext.region); 4887 clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); 4888 clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); 4889 clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); 4890 } 4891 } 4892 } 4893 4894 void RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const 4895 { 4896 ASSERT(parent()); 4897 if (clipRectsContext.clipRectsType == TemporaryClipRects) { 4898 parent()->calculateClipRects(clipRectsContext, clipRects); 4899 return; 4900 } 4901 4902 parent()->updateClipRects(clipRectsContext); 4903 clipRects = *parent()->clipRects(clipRectsContext); 4904 } 4905 4906 static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position) 4907 { 4908 if (position == FixedPosition) 4909 return parentRects.fixedClipRect(); 4910 4911 if (position == AbsolutePosition) 4912 return parentRects.posClipRect(); 4913 4914 return parentRects.overflowClipRect(); 4915 } 4916 4917 ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const 4918 { 4919 ASSERT(parent()); 4920 4921 ClipRects parentRects; 4922 4923 // If we cross into a different pagination context, then we can't rely on the cache. 4924 // Just switch over to using TemporaryClipRects. 4925 if (clipRectsContext.clipRectsType != TemporaryClipRects && parent()->enclosingPaginationLayer() != enclosingPaginationLayer()) { 4926 ClipRectsContext tempContext(clipRectsContext); 4927 tempContext.clipRectsType = TemporaryClipRects; 4928 parentClipRects(tempContext, parentRects); 4929 } else 4930 parentClipRects(clipRectsContext, parentRects); 4931 4932 ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position()); 4933 RenderView* view = renderer()->view(); 4934 ASSERT(view); 4935 4936 // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite. 4937 if (parentRects.fixed() && clipRectsContext.rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect()) 4938 backgroundClipRect.move(view->frameView()->scrollOffsetForFixedPosition()); 4939 4940 return backgroundClipRect; 4941 } 4942 4943 void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, 4944 ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const 4945 { 4946 if (clipRectsContext.rootLayer != this && parent()) { 4947 backgroundRect = backgroundClipRect(clipRectsContext); 4948 backgroundRect.intersect(paintDirtyRect); 4949 } else 4950 backgroundRect = paintDirtyRect; 4951 4952 foregroundRect = backgroundRect; 4953 outlineRect = backgroundRect; 4954 4955 LayoutPoint offset; 4956 if (offsetFromRoot) 4957 offset = *offsetFromRoot; 4958 else 4959 convertToLayerCoords(clipRectsContext.rootLayer, offset); 4960 layerBounds = LayoutRect(offset, size()); 4961 4962 // Update the clip rects that will be passed to child layers. 4963 if (renderer()->hasOverflowClip()) { 4964 // This layer establishes a clip of some kind. 4965 if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) { 4966 foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy)); 4967 if (renderer()->style()->hasBorderRadius()) 4968 foregroundRect.setHasRadius(true); 4969 } 4970 4971 // If we establish an overflow clip at all, then go ahead and make sure our background 4972 // rect is intersected with our layer's bounds including our visual overflow, 4973 // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden. 4974 if (renderBox()->hasVisualOverflow()) { 4975 // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though 4976 // we may need to inflate our clip specifically for shadows or outsets. 4977 // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the 4978 // individual region boxes as overflow. 4979 LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect(); 4980 renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped. 4981 layerBoundsWithVisualOverflow.moveBy(offset); 4982 if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) 4983 backgroundRect.intersect(layerBoundsWithVisualOverflow); 4984 } else { 4985 // Shift the bounds to be for our region only. 4986 LayoutRect bounds = renderBox()->borderBoxRectInRegion(clipRectsContext.region); 4987 bounds.moveBy(offset); 4988 if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) 4989 backgroundRect.intersect(bounds); 4990 } 4991 } 4992 4993 // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box. 4994 if (renderer()->hasClip()) { 4995 // Clip applies to *us* as well, so go ahead and update the damageRect. 4996 LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, clipRectsContext.region); 4997 backgroundRect.intersect(newPosClip); 4998 foregroundRect.intersect(newPosClip); 4999 outlineRect.intersect(newPosClip); 5000 } 5001 } 5002 5003 LayoutRect RenderLayer::childrenClipRect() const 5004 { 5005 // FIXME: border-radius not accounted for. 5006 // FIXME: Regions not accounted for. 5007 RenderView* renderView = renderer()->view(); 5008 RenderLayer* clippingRootLayer = clippingRootForPainting(); 5009 LayoutRect layerBounds; 5010 ClipRect backgroundRect, foregroundRect, outlineRect; 5011 ClipRectsContext clipRectsContext(clippingRootLayer, 0, TemporaryClipRects); 5012 // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>). 5013 calculateRects(clipRectsContext, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); 5014 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox(); 5015 } 5016 5017 LayoutRect RenderLayer::selfClipRect() const 5018 { 5019 // FIXME: border-radius not accounted for. 5020 // FIXME: Regions not accounted for. 5021 RenderView* renderView = renderer()->view(); 5022 RenderLayer* clippingRootLayer = clippingRootForPainting(); 5023 LayoutRect layerBounds; 5024 ClipRect backgroundRect, foregroundRect, outlineRect; 5025 ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects); 5026 calculateRects(clipRectsContext, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); 5027 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox(); 5028 } 5029 5030 LayoutRect RenderLayer::localClipRect() const 5031 { 5032 // FIXME: border-radius not accounted for. 5033 // FIXME: Regions not accounted for. 5034 RenderLayer* clippingRootLayer = clippingRootForPainting(); 5035 LayoutRect layerBounds; 5036 ClipRect backgroundRect, foregroundRect, outlineRect; 5037 ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects); 5038 calculateRects(clipRectsContext, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); 5039 5040 LayoutRect clipRect = backgroundRect.rect(); 5041 if (clipRect == PaintInfo::infiniteRect()) 5042 return clipRect; 5043 5044 LayoutPoint clippingRootOffset; 5045 convertToLayerCoords(clippingRootLayer, clippingRootOffset); 5046 clipRect.moveBy(-clippingRootOffset); 5047 5048 return clipRect; 5049 } 5050 5051 void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds) 5052 { 5053 m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds)); 5054 } 5055 5056 void RenderLayer::clearBlockSelectionGapsBounds() 5057 { 5058 m_blockSelectionGapsBounds = IntRect(); 5059 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 5060 child->clearBlockSelectionGapsBounds(); 5061 } 5062 5063 void RenderLayer::repaintBlockSelectionGaps() 5064 { 5065 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 5066 child->repaintBlockSelectionGaps(); 5067 5068 if (m_blockSelectionGapsBounds.isEmpty()) 5069 return; 5070 5071 LayoutRect rect = m_blockSelectionGapsBounds; 5072 rect.move(-scrolledContentOffset()); 5073 if (renderer()->hasOverflowClip() && !usesCompositedScrolling()) 5074 rect.intersect(toRenderBox(renderer())->overflowClipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for. 5075 if (renderer()->hasClip()) 5076 rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for. 5077 if (!rect.isEmpty()) 5078 renderer()->repaintRectangle(rect); 5079 } 5080 5081 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const 5082 { 5083 // Always examine the canvas and the root. 5084 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 5085 // paints the root's background. 5086 if (isRootLayer() || renderer()->isRoot()) 5087 return true; 5088 5089 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we 5090 // can go ahead and return true. 5091 RenderView* view = renderer()->view(); 5092 ASSERT(view); 5093 if (view && !renderer()->isRenderInline()) { 5094 LayoutRect b = layerBounds; 5095 b.inflate(view->maximalOutlineSize()); 5096 if (b.intersects(damageRect)) 5097 return true; 5098 } 5099 5100 // Otherwise we need to compute the bounding box of this single layer and see if it intersects 5101 // the damage rect. 5102 return boundingBox(rootLayer, 0, offsetFromRoot).intersects(damageRect); 5103 } 5104 5105 LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const 5106 { 5107 // There are three special cases we need to consider. 5108 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the 5109 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the 5110 // line boxes of all three lines (including overflow on those lines). 5111 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top 5112 // overflow, we have to create a bounding box that will extend to include this overflow. 5113 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats 5114 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those 5115 // floats. 5116 LayoutRect result; 5117 if (renderer()->isInline() && renderer()->isRenderInline()) 5118 result = toRenderInline(renderer())->linesVisualOverflowBoundingBox(); 5119 else if (renderer()->isTableRow()) { 5120 // Our bounding box is just the union of all of our cells' border/overflow rects. 5121 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { 5122 if (child->isTableCell()) { 5123 LayoutRect bbox = toRenderBox(child)->borderBoxRect(); 5124 result.unite(bbox); 5125 LayoutRect overflowRect = renderBox()->visualOverflowRect(); 5126 if (bbox != overflowRect) 5127 result.unite(overflowRect); 5128 } 5129 } 5130 } else { 5131 RenderBox* box = renderBox(); 5132 ASSERT(box); 5133 if (!(flags & DontConstrainForMask) && box->hasMask()) { 5134 result = box->maskClipRect(); 5135 box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not. 5136 } else { 5137 LayoutRect bbox = box->borderBoxRect(); 5138 result = bbox; 5139 LayoutRect overflowRect = box->visualOverflowRect(); 5140 if (bbox != overflowRect) 5141 result.unite(overflowRect); 5142 } 5143 } 5144 5145 RenderView* view = renderer()->view(); 5146 ASSERT(view); 5147 if (view) 5148 result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables. 5149 5150 return result; 5151 } 5152 5153 LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags, const LayoutPoint* offsetFromRoot) const 5154 { 5155 LayoutRect result = localBoundingBox(flags); 5156 if (renderer()->isBox()) 5157 renderBox()->flipForWritingMode(result); 5158 else 5159 renderer()->containingBlock()->flipForWritingMode(result); 5160 5161 if (enclosingPaginationLayer() && (flags & UseFragmentBoxes)) { 5162 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to 5163 // get our true bounding box. 5164 LayoutPoint offsetWithinPaginationLayer; 5165 convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginationLayer); 5166 result.moveBy(offsetWithinPaginationLayer); 5167 5168 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer()); 5169 result = enclosingFlowThread->fragmentsBoundingBox(result); 5170 5171 LayoutPoint delta; 5172 if (offsetFromRoot) 5173 delta = *offsetFromRoot; 5174 else 5175 enclosingPaginationLayer()->convertToLayerCoords(ancestorLayer, delta); 5176 result.moveBy(delta); 5177 return result; 5178 } 5179 5180 LayoutPoint delta; 5181 if (offsetFromRoot) 5182 delta = *offsetFromRoot; 5183 else 5184 convertToLayerCoords(ancestorLayer, delta); 5185 5186 result.moveBy(delta); 5187 return result; 5188 } 5189 5190 IntRect RenderLayer::absoluteBoundingBox() const 5191 { 5192 return pixelSnappedIntRect(boundingBox(root())); 5193 } 5194 5195 IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const 5196 { 5197 if (!isSelfPaintingLayer()) 5198 return IntRect(); 5199 5200 // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580). 5201 if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant()) 5202 return IntRect(); 5203 5204 RenderLayerModelObject* renderer = this->renderer(); 5205 5206 if (isRootLayer()) { 5207 // The root layer is always just the size of the document. 5208 return renderer->view()->unscaledDocumentRect(); 5209 } 5210 5211 LayoutRect boundingBoxRect = localBoundingBox(flags); 5212 5213 if (renderer->isBox()) 5214 toRenderBox(renderer)->flipForWritingMode(boundingBoxRect); 5215 else 5216 renderer->containingBlock()->flipForWritingMode(boundingBoxRect); 5217 5218 if (renderer->isRoot()) { 5219 // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited), 5220 // then it has to be big enough to cover the viewport in order to display the background. This is akin 5221 // to the code in RenderBox::paintRootBoxFillLayers(). 5222 if (FrameView* frameView = renderer->view()->frameView()) { 5223 LayoutUnit contentsWidth = frameView->contentsWidth(); 5224 LayoutUnit contentsHeight = frameView->contentsHeight(); 5225 5226 boundingBoxRect.setWidth(max(boundingBoxRect.width(), contentsWidth - boundingBoxRect.x())); 5227 boundingBoxRect.setHeight(max(boundingBoxRect.height(), contentsHeight - boundingBoxRect.y())); 5228 } 5229 } 5230 5231 LayoutRect unionBounds = boundingBoxRect; 5232 5233 if (flags & UseLocalClipRectIfPossible) { 5234 LayoutRect localClipRect = this->localClipRect(); 5235 if (localClipRect != PaintInfo::infiniteRect()) { 5236 if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal)) 5237 localClipRect = transform()->mapRect(localClipRect); 5238 5239 LayoutPoint ancestorRelOffset; 5240 convertToLayerCoords(ancestorLayer, ancestorRelOffset); 5241 localClipRect.moveBy(ancestorRelOffset); 5242 return pixelSnappedIntRect(localClipRect); 5243 } 5244 } 5245 5246 // FIXME: should probably just pass 'flags' down to descendants. 5247 CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants) | (flags & IncludeCompositedDescendants); 5248 5249 const_cast<RenderLayer*>(this)->updateLayerListsIfNeeded(); 5250 5251 if (RenderLayer* reflection = reflectionLayer()) { 5252 if (!reflection->isComposited()) { 5253 IntRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags); 5254 unionBounds.unite(childUnionBounds); 5255 } 5256 } 5257 5258 ASSERT(isStackingContainer() || (!posZOrderList() || !posZOrderList()->size())); 5259 5260 #if !ASSERT_DISABLED 5261 LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this)); 5262 #endif 5263 5264 if (Vector<RenderLayer*>* negZOrderList = this->negZOrderList()) { 5265 size_t listSize = negZOrderList->size(); 5266 for (size_t i = 0; i < listSize; ++i) { 5267 RenderLayer* curLayer = negZOrderList->at(i); 5268 if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) { 5269 IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags); 5270 unionBounds.unite(childUnionBounds); 5271 } 5272 } 5273 } 5274 5275 if (Vector<RenderLayer*>* posZOrderList = this->posZOrderList()) { 5276 size_t listSize = posZOrderList->size(); 5277 for (size_t i = 0; i < listSize; ++i) { 5278 RenderLayer* curLayer = posZOrderList->at(i); 5279 if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) { 5280 IntRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags); 5281 unionBounds.unite(childUnionBounds); 5282 } 5283 } 5284 } 5285 5286 if (Vector<RenderLayer*>* normalFlowList = this->normalFlowList()) { 5287 size_t listSize = normalFlowList->size(); 5288 for (size_t i = 0; i < listSize; ++i) { 5289 RenderLayer* curLayer = normalFlowList->at(i); 5290 if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) { 5291 IntRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags); 5292 unionBounds.unite(curAbsBounds); 5293 } 5294 } 5295 } 5296 5297 // FIXME: We can optimize the size of the composited layers, by not enlarging 5298 // filtered areas with the outsets if we know that the filter is going to render in hardware. 5299 // https://bugs.webkit.org/show_bug.cgi?id=81239 5300 if (flags & IncludeLayerFilterOutsets) 5301 renderer->style()->filterOutsets().expandRect(unionBounds); 5302 5303 if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal)) { 5304 TransformationMatrix* affineTrans = transform(); 5305 boundingBoxRect = affineTrans->mapRect(boundingBoxRect); 5306 unionBounds = affineTrans->mapRect(unionBounds); 5307 } 5308 5309 LayoutPoint ancestorRelOffset; 5310 if (offsetFromRoot) 5311 ancestorRelOffset = *offsetFromRoot; 5312 else 5313 convertToLayerCoords(ancestorLayer, ancestorRelOffset); 5314 unionBounds.moveBy(ancestorRelOffset); 5315 5316 return pixelSnappedIntRect(unionBounds); 5317 } 5318 5319 void RenderLayer::clearClipRectsIncludingDescendants(ClipRectsType typeToClear) 5320 { 5321 // FIXME: it's not clear how this layer not having clip rects guarantees that no descendants have any. 5322 if (!m_clipRectsCache) 5323 return; 5324 5325 clearClipRects(typeToClear); 5326 5327 for (RenderLayer* l = firstChild(); l; l = l->nextSibling()) 5328 l->clearClipRectsIncludingDescendants(typeToClear); 5329 } 5330 5331 void RenderLayer::clearClipRects(ClipRectsType typeToClear) 5332 { 5333 if (typeToClear == AllClipRectTypes) 5334 m_clipRectsCache = nullptr; 5335 else { 5336 ASSERT(typeToClear < NumCachedClipRectsTypes); 5337 RefPtr<ClipRects> dummy; 5338 m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, dummy); 5339 m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, dummy); 5340 } 5341 } 5342 5343 RenderLayerBacking* RenderLayer::ensureBacking() 5344 { 5345 if (!m_backing) { 5346 m_backing = adoptPtr(new RenderLayerBacking(this)); 5347 compositor()->layerBecameComposited(this); 5348 5349 updateOrRemoveFilterEffectRenderer(); 5350 5351 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 5352 backing()->setBlendMode(m_blendMode); 5353 } 5354 return m_backing.get(); 5355 } 5356 5357 void RenderLayer::clearBacking(bool layerBeingDestroyed) 5358 { 5359 if (m_backing && !renderer()->documentBeingDestroyed()) 5360 compositor()->layerBecameNonComposited(this); 5361 m_backing.clear(); 5362 5363 if (!layerBeingDestroyed) 5364 updateOrRemoveFilterEffectRenderer(); 5365 } 5366 5367 bool RenderLayer::hasCompositedMask() const 5368 { 5369 return m_backing && m_backing->hasMaskLayer(); 5370 } 5371 5372 GraphicsLayer* RenderLayer::layerForScrolling() const 5373 { 5374 return m_backing ? m_backing->scrollingContentsLayer() : 0; 5375 } 5376 5377 GraphicsLayer* RenderLayer::layerForHorizontalScrollbar() const 5378 { 5379 return m_backing ? m_backing->layerForHorizontalScrollbar() : 0; 5380 } 5381 5382 GraphicsLayer* RenderLayer::layerForVerticalScrollbar() const 5383 { 5384 return m_backing ? m_backing->layerForVerticalScrollbar() : 0; 5385 } 5386 5387 GraphicsLayer* RenderLayer::layerForScrollCorner() const 5388 { 5389 return m_backing ? m_backing->layerForScrollCorner() : 0; 5390 } 5391 5392 bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const 5393 { 5394 return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || !isComposited()); 5395 } 5396 5397 bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const 5398 { 5399 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) 5400 return false; 5401 5402 if (paintsWithTransparency(PaintBehaviorNormal)) 5403 return false; 5404 5405 // We can't use hasVisibleContent(), because that will be true if our renderer is hidden, but some child 5406 // is visible and that child doesn't cover the entire rect. 5407 if (renderer()->style()->visibility() != VISIBLE) 5408 return false; 5409 5410 if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffectsOpacity()) 5411 return false; 5412 5413 // FIXME: Handle simple transforms. 5414 if (paintsWithTransform(PaintBehaviorNormal)) 5415 return false; 5416 5417 // FIXME: Remove this check. 5418 // This function should not be called when layer-lists are dirty. 5419 // It is somehow getting triggered during style update. 5420 if (m_zOrderListsDirty || m_normalFlowListDirty) 5421 return false; 5422 5423 // FIXME: We currently only check the immediate renderer, 5424 // which will miss many cases. 5425 if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect)) 5426 return true; 5427 5428 // We can't consult child layers if we clip, since they might cover 5429 // parts of the rect that are clipped out. 5430 if (renderer()->hasOverflowClip()) 5431 return false; 5432 5433 return listBackgroundIsKnownToBeOpaqueInRect(posZOrderList(), localRect) 5434 || listBackgroundIsKnownToBeOpaqueInRect(negZOrderList(), localRect) 5435 || listBackgroundIsKnownToBeOpaqueInRect(normalFlowList(), localRect); 5436 } 5437 5438 bool RenderLayer::listBackgroundIsKnownToBeOpaqueInRect(const Vector<RenderLayer*>* list, const LayoutRect& localRect) const 5439 { 5440 if (!list || list->isEmpty()) 5441 return false; 5442 5443 for (Vector<RenderLayer*>::const_reverse_iterator iter = list->rbegin(); iter != list->rend(); ++iter) { 5444 const RenderLayer* childLayer = *iter; 5445 if (childLayer->isComposited()) 5446 continue; 5447 5448 if (!childLayer->canUseConvertToLayerCoords()) 5449 continue; 5450 5451 LayoutPoint childOffset; 5452 LayoutRect childLocalRect(localRect); 5453 childLayer->convertToLayerCoords(this, childOffset); 5454 childLocalRect.moveBy(-childOffset); 5455 5456 if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect)) 5457 return true; 5458 } 5459 return false; 5460 } 5461 5462 void RenderLayer::setParent(RenderLayer* parent) 5463 { 5464 if (parent == m_parent) 5465 return; 5466 5467 if (m_parent && !renderer()->documentBeingDestroyed()) 5468 compositor()->layerWillBeRemoved(m_parent, this); 5469 5470 m_parent = parent; 5471 5472 if (m_parent && !renderer()->documentBeingDestroyed()) 5473 compositor()->layerWasAdded(m_parent, this); 5474 } 5475 5476 // Helper for the sorting of layers by z-index. 5477 static inline bool compareZIndex(RenderLayer* first, RenderLayer* second) 5478 { 5479 return first->zIndex() < second->zIndex(); 5480 } 5481 5482 void RenderLayer::dirtyNormalFlowListCanBePromotedToStackingContainer() 5483 { 5484 m_canBePromotedToStackingContainerDirty = true; 5485 5486 if (m_normalFlowListDirty || !normalFlowList()) 5487 return; 5488 5489 for (size_t index = 0; index < normalFlowList()->size(); ++index) 5490 normalFlowList()->at(index)->dirtyNormalFlowListCanBePromotedToStackingContainer(); 5491 } 5492 5493 void RenderLayer::dirtySiblingStackingContextCanBePromotedToStackingContainer() 5494 { 5495 RenderLayer* ancestorStackingContext = this->ancestorStackingContext(); 5496 if (!ancestorStackingContext) 5497 return; 5498 5499 if (!ancestorStackingContext->m_zOrderListsDirty && ancestorStackingContext->posZOrderList()) { 5500 for (size_t index = 0; index < ancestorStackingContext->posZOrderList()->size(); ++index) 5501 ancestorStackingContext->posZOrderList()->at(index)->m_canBePromotedToStackingContainerDirty = true; 5502 } 5503 5504 ancestorStackingContext->dirtyNormalFlowListCanBePromotedToStackingContainer(); 5505 5506 if (!ancestorStackingContext->m_zOrderListsDirty && ancestorStackingContext->negZOrderList()) { 5507 for (size_t index = 0; index < ancestorStackingContext->negZOrderList()->size(); ++index) 5508 ancestorStackingContext->negZOrderList()->at(index)->m_canBePromotedToStackingContainerDirty = true; 5509 } 5510 } 5511 5512 void RenderLayer::dirtyZOrderLists() 5513 { 5514 ASSERT(m_layerListMutationAllowed); 5515 ASSERT(isStackingContainer()); 5516 5517 if (m_posZOrderList) 5518 m_posZOrderList->clear(); 5519 if (m_negZOrderList) 5520 m_negZOrderList->clear(); 5521 m_zOrderListsDirty = true; 5522 5523 m_canBePromotedToStackingContainerDirty = true; 5524 5525 if (!renderer()->documentBeingDestroyed()) { 5526 compositor()->setNeedsUpdateCompositingRequirementsState(); 5527 compositor()->setCompositingLayersNeedRebuild(); 5528 if (acceleratedCompositingForOverflowScrollEnabled()) 5529 compositor()->setShouldReevaluateCompositingAfterLayout(); 5530 } 5531 } 5532 5533 void RenderLayer::dirtyStackingContainerZOrderLists() 5534 { 5535 // Any siblings in the ancestor stacking context could also be affected. 5536 // Changing z-index, for example, could cause us to stack in between a 5537 // sibling's descendants, meaning that we have to recompute 5538 // m_canBePromotedToStackingContainer for that sibling. 5539 dirtySiblingStackingContextCanBePromotedToStackingContainer(); 5540 5541 RenderLayer* stackingContainer = this->ancestorStackingContainer(); 5542 if (stackingContainer) 5543 stackingContainer->dirtyZOrderLists(); 5544 5545 // Any change that could affect our stacking container's z-order list could 5546 // cause other RenderLayers in our stacking context to either opt in or out 5547 // of composited scrolling. It is important that we make our stacking 5548 // context aware of these z-order changes so the appropriate updating can 5549 // happen. 5550 RenderLayer* stackingContext = this->ancestorStackingContext(); 5551 if (stackingContext && stackingContext != stackingContainer) 5552 stackingContext->dirtyZOrderLists(); 5553 } 5554 5555 void RenderLayer::dirtyNormalFlowList() 5556 { 5557 ASSERT(m_layerListMutationAllowed); 5558 5559 if (m_normalFlowList) 5560 m_normalFlowList->clear(); 5561 m_normalFlowListDirty = true; 5562 5563 if (!renderer()->documentBeingDestroyed()) { 5564 compositor()->setCompositingLayersNeedRebuild(); 5565 if (acceleratedCompositingForOverflowScrollEnabled()) 5566 compositor()->setShouldReevaluateCompositingAfterLayout(); 5567 } 5568 } 5569 5570 void RenderLayer::rebuildZOrderLists() 5571 { 5572 ASSERT(m_layerListMutationAllowed); 5573 ASSERT(isDirtyStackingContainer()); 5574 rebuildZOrderLists(m_posZOrderList, m_negZOrderList); 5575 m_zOrderListsDirty = false; 5576 } 5577 5578 void RenderLayer::rebuildZOrderLists(OwnPtr<Vector<RenderLayer*> >& posZOrderList, OwnPtr<Vector<RenderLayer*> >& negZOrderList, const RenderLayer* layerToForceAsStackingContainer, CollectLayersBehavior collectLayersBehavior) 5579 { 5580 bool includeHiddenLayers = compositor()->inCompositingMode(); 5581 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 5582 if (!m_reflection || reflectionLayer() != child) 5583 child->collectLayers(includeHiddenLayers, posZOrderList, negZOrderList, layerToForceAsStackingContainer, collectLayersBehavior); 5584 5585 // Sort the two lists. 5586 if (posZOrderList) 5587 std::stable_sort(posZOrderList->begin(), posZOrderList->end(), compareZIndex); 5588 5589 if (negZOrderList) 5590 std::stable_sort(negZOrderList->begin(), negZOrderList->end(), compareZIndex); 5591 5592 // Append layers for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes. 5593 // The renderers of top layer elements are children of the view, sorted in top layer stacking order. 5594 if (isRootLayer()) { 5595 RenderObject* view = renderer()->view(); 5596 for (RenderObject* child = view->firstChild(); child; child = child->nextSibling()) { 5597 Element* childElement = (child->node() && child->node()->isElementNode()) ? toElement(child->node()) : 0; 5598 if (childElement && childElement->isInTopLayer()) { 5599 RenderLayer* layer = toRenderLayerModelObject(child)->layer(); 5600 posZOrderList->append(layer); 5601 } 5602 } 5603 } 5604 } 5605 5606 void RenderLayer::updateNormalFlowList() 5607 { 5608 if (!m_normalFlowListDirty) 5609 return; 5610 5611 ASSERT(m_layerListMutationAllowed); 5612 5613 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 5614 // Ignore non-overflow layers and reflections. 5615 if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) { 5616 if (!m_normalFlowList) 5617 m_normalFlowList = adoptPtr(new Vector<RenderLayer*>); 5618 m_normalFlowList->append(child); 5619 } 5620 } 5621 5622 m_normalFlowListDirty = false; 5623 } 5624 5625 void RenderLayer::collectLayers(bool includeHiddenLayers, OwnPtr<Vector<RenderLayer*> >& posBuffer, OwnPtr<Vector<RenderLayer*> >& negBuffer, const RenderLayer* layerToForceAsStackingContainer, CollectLayersBehavior collectLayersBehavior) 5626 { 5627 if (isInTopLayer()) 5628 return; 5629 5630 updateDescendantDependentFlags(); 5631 5632 bool isStacking = false; 5633 bool isNormalFlow = false; 5634 5635 switch (collectLayersBehavior) { 5636 case ForceLayerToStackingContainer: 5637 ASSERT(layerToForceAsStackingContainer); 5638 if (this == layerToForceAsStackingContainer) { 5639 isStacking = true; 5640 isNormalFlow = false; 5641 } else { 5642 isStacking = isStackingContext(); 5643 isNormalFlow = shouldBeNormalFlowOnlyIgnoringCompositedScrolling(); 5644 } 5645 break; 5646 case OverflowScrollCanBeStackingContainers: 5647 ASSERT(!layerToForceAsStackingContainer); 5648 isStacking = isStackingContainer(); 5649 isNormalFlow = isNormalFlowOnly(); 5650 break; 5651 case OnlyStackingContextsCanBeStackingContainers: 5652 isStacking = isStackingContext(); 5653 isNormalFlow = shouldBeNormalFlowOnlyIgnoringCompositedScrolling(); 5654 break; 5655 } 5656 5657 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. 5658 bool includeHiddenLayer = includeHiddenLayers || (m_hasVisibleContent || (m_hasVisibleDescendant && isStacking)); 5659 if (includeHiddenLayer && !isNormalFlow && !isOutOfFlowRenderFlowThread()) { 5660 // Determine which buffer the child should be in. 5661 OwnPtr<Vector<RenderLayer*> >& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; 5662 5663 // Create the buffer if it doesn't exist yet. 5664 if (!buffer) 5665 buffer = adoptPtr(new Vector<RenderLayer*>); 5666 5667 // Append ourselves at the end of the appropriate buffer. 5668 buffer->append(this); 5669 } 5670 5671 // Recur into our children to collect more layers, but only if we don't establish 5672 // a stacking context/container. 5673 if ((includeHiddenLayers || m_hasVisibleDescendant) && !isStacking) { 5674 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { 5675 // Ignore reflections. 5676 if (!m_reflection || reflectionLayer() != child) 5677 child->collectLayers(includeHiddenLayers, posBuffer, negBuffer, layerToForceAsStackingContainer, collectLayersBehavior); 5678 } 5679 } 5680 } 5681 5682 void RenderLayer::updateLayerListsIfNeeded() 5683 { 5684 updateZOrderLists(); 5685 updateNormalFlowList(); 5686 5687 if (RenderLayer* reflectionLayer = this->reflectionLayer()) { 5688 reflectionLayer->updateZOrderLists(); 5689 reflectionLayer->updateNormalFlowList(); 5690 } 5691 } 5692 5693 void RenderLayer::repaintIncludingDescendants() 5694 { 5695 renderer()->repaint(); 5696 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) 5697 curr->repaintIncludingDescendants(); 5698 } 5699 5700 void RenderLayer::setBackingNeedsRepaint() 5701 { 5702 ASSERT(isComposited()); 5703 backing()->setContentsNeedDisplay(); 5704 } 5705 5706 void RenderLayer::setBackingNeedsRepaintInRect(const LayoutRect& r) 5707 { 5708 // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here, 5709 // so assert but check that the layer is composited. 5710 ASSERT(isComposited()); 5711 if (!isComposited()) { 5712 // If we're trying to repaint the placeholder document layer, propagate the 5713 // repaint to the native view system. 5714 LayoutRect absRect(r); 5715 LayoutPoint delta; 5716 convertToLayerCoords(root(), delta); 5717 absRect.moveBy(delta); 5718 5719 RenderView* view = renderer()->view(); 5720 if (view) 5721 view->repaintViewRectangle(absRect); 5722 } else 5723 backing()->setContentsNeedDisplayInRect(pixelSnappedIntRect(r)); 5724 } 5725 5726 // Since we're only painting non-composited layers, we know that they all share the same repaintContainer. 5727 void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer) 5728 { 5729 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(renderer()->clippedOverflowRectForRepaint(repaintContainer))); 5730 5731 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) { 5732 if (!curr->isComposited()) 5733 curr->repaintIncludingNonCompositingDescendants(repaintContainer); 5734 } 5735 } 5736 5737 bool RenderLayer::shouldBeNormalFlowOnly() const 5738 { 5739 return shouldBeNormalFlowOnlyIgnoringCompositedScrolling() && !needsCompositedScrolling(); 5740 } 5741 5742 bool RenderLayer::shouldBeNormalFlowOnlyIgnoringCompositedScrolling() const 5743 { 5744 const bool couldBeNormalFlow = renderer()->hasOverflowClip() 5745 || renderer()->hasReflection() 5746 || renderer()->hasMask() 5747 || renderer()->isCanvas() 5748 || renderer()->isVideo() 5749 || renderer()->isEmbeddedObject() 5750 || renderer()->isRenderIFrame() 5751 || (renderer()->style()->specifiesColumns() && !isRootLayer()); 5752 const bool preventsElementFromBeingNormalFlow = renderer()->isPositioned() 5753 || renderer()->hasTransform() 5754 || renderer()->hasClipPath() 5755 || renderer()->hasFilter() 5756 || renderer()->hasBlendMode() 5757 || isTransparent(); 5758 5759 return couldBeNormalFlow && !preventsElementFromBeingNormalFlow; 5760 } 5761 5762 void RenderLayer::updateIsNormalFlowOnly() 5763 { 5764 bool isNormalFlowOnly = shouldBeNormalFlowOnly(); 5765 if (isNormalFlowOnly == m_isNormalFlowOnly) 5766 return; 5767 5768 m_isNormalFlowOnly = isNormalFlowOnly; 5769 if (RenderLayer* p = parent()) 5770 p->dirtyNormalFlowList(); 5771 dirtyStackingContainerZOrderLists(); 5772 } 5773 5774 bool RenderLayer::shouldBeSelfPaintingLayer() const 5775 { 5776 return !isNormalFlowOnly() 5777 || hasOverlayScrollbars() 5778 || needsCompositedScrolling() 5779 || renderer()->hasReflection() 5780 || renderer()->hasMask() 5781 || renderer()->isTableRow() 5782 || renderer()->isCanvas() 5783 || renderer()->isVideo() 5784 || renderer()->isEmbeddedObject() 5785 || renderer()->isRenderIFrame(); 5786 } 5787 5788 void RenderLayer::updateSelfPaintingLayer() 5789 { 5790 bool isSelfPaintingLayer = shouldBeSelfPaintingLayer(); 5791 if (m_isSelfPaintingLayer == isSelfPaintingLayer) 5792 return; 5793 5794 m_isSelfPaintingLayer = isSelfPaintingLayer; 5795 if (!parent()) 5796 return; 5797 if (isSelfPaintingLayer) 5798 parent()->setAncestorChainHasSelfPaintingLayerDescendant(); 5799 else 5800 parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); 5801 } 5802 5803 bool RenderLayer::hasNonEmptyChildRenderers() const 5804 { 5805 // Some HTML can cause whitespace text nodes to have renderers, like: 5806 // <div> 5807 // <img src=...> 5808 // </div> 5809 // so test for 0x0 RenderTexts here 5810 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { 5811 if (!child->hasLayer()) { 5812 if (child->isRenderInline() || !child->isBox()) 5813 return true; 5814 5815 if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0) 5816 return true; 5817 } 5818 } 5819 return false; 5820 } 5821 5822 static bool hasBoxDecorations(const RenderStyle* style) 5823 { 5824 return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter(); 5825 } 5826 5827 bool RenderLayer::hasBoxDecorationsOrBackground() const 5828 { 5829 return hasBoxDecorations(renderer()->style()) || renderer()->hasBackground(); 5830 } 5831 5832 bool RenderLayer::hasVisibleBoxDecorations() const 5833 { 5834 if (!hasVisibleContent()) 5835 return false; 5836 5837 return hasBoxDecorationsOrBackground() || hasOverflowControls(); 5838 } 5839 5840 bool RenderLayer::isVisuallyNonEmpty() const 5841 { 5842 ASSERT(!m_visibleDescendantStatusDirty); 5843 5844 if (hasVisibleContent() && hasNonEmptyChildRenderers()) 5845 return true; 5846 5847 if (renderer()->isReplaced() || renderer()->hasMask()) 5848 return true; 5849 5850 if (hasVisibleBoxDecorations()) 5851 return true; 5852 5853 return false; 5854 } 5855 5856 void RenderLayer::updateVisibilityAfterStyleChange(const RenderStyle* oldStyle) 5857 { 5858 if (!oldStyle || (oldStyle->visibility() != renderer()->style()->visibility())) 5859 compositor()->setNeedsUpdateCompositingRequirementsState(); 5860 } 5861 5862 void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldStyle) 5863 { 5864 bool wasStackingContext = oldStyle ? isStackingContext(oldStyle) : false; 5865 EVisibility oldVisibility = oldStyle ? oldStyle->visibility() : VISIBLE; 5866 int oldZIndex = oldStyle ? oldStyle->zIndex() : 0; 5867 5868 // FIXME: RenderLayer already handles visibility changes through our visiblity dirty bits. This logic could 5869 // likely be folded along with the rest. 5870 bool isStackingContext = this->isStackingContext(); 5871 if (isStackingContext == wasStackingContext && oldVisibility == renderer()->style()->visibility() && oldZIndex == renderer()->style()->zIndex()) 5872 return; 5873 5874 dirtyStackingContainerZOrderLists(); 5875 5876 if (isStackingContainer()) 5877 dirtyZOrderLists(); 5878 else 5879 clearZOrderLists(); 5880 5881 compositor()->setNeedsUpdateCompositingRequirementsState(); 5882 } 5883 5884 static bool overflowRequiresScrollbar(EOverflow overflow) 5885 { 5886 return overflow == OSCROLL; 5887 } 5888 5889 static bool overflowDefinesAutomaticScrollbar(EOverflow overflow) 5890 { 5891 return overflow == OAUTO || overflow == OOVERLAY; 5892 } 5893 5894 void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle) 5895 { 5896 // Overflow are a box concept. 5897 RenderBox* box = renderBox(); 5898 if (!box) 5899 return; 5900 5901 // List box parts handle the scrollbars by themselves so we have nothing to do. 5902 if (box->style()->appearance() == ListboxPart) 5903 return; 5904 5905 EOverflow overflowX = box->style()->overflowX(); 5906 EOverflow overflowY = box->style()->overflowY(); 5907 5908 // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present. 5909 bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefinesAutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX); 5910 bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAutomaticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY); 5911 setHasHorizontalScrollbar(needsHorizontalScrollbar); 5912 setHasVerticalScrollbar(needsVerticalScrollbar); 5913 5914 // With overflow: scroll, scrollbars are always visible but may be disabled. 5915 // When switching to another value, we need to re-enable them (see bug 11985). 5916 if (needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) { 5917 ASSERT(hasHorizontalScrollbar()); 5918 m_hBar->setEnabled(true); 5919 } 5920 5921 if (needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL) { 5922 ASSERT(hasVerticalScrollbar()); 5923 m_vBar->setEnabled(true); 5924 } 5925 5926 if (!m_scrollDimensionsDirty) 5927 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); 5928 } 5929 5930 void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle) 5931 { 5932 if (oldStyle && (renderer()->style()->position() == oldStyle->position())) 5933 return; 5934 5935 bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition); 5936 bool isOutOfFlowPositioned = renderer()->isOutOfFlowPositioned(); 5937 if (!wasOutOfFlowPositioned && !isOutOfFlowPositioned) 5938 return; 5939 5940 // Even if the layer remains out-of-flow, a change to this property 5941 // will likely change its containing block. We must clear these bits 5942 // so that they can be set properly by the RenderLayerCompositor. 5943 for (RenderLayer* ancestor = parent(); ancestor; ancestor = ancestor->parent()) 5944 ancestor->setHasUnclippedDescendant(false); 5945 5946 // Ensures that we reset the above bits correctly. 5947 compositor()->setNeedsUpdateCompositingRequirementsState(); 5948 5949 if (wasOutOfFlowPositioned && isOutOfFlowPositioned) 5950 return; 5951 5952 if (isOutOfFlowPositioned) { 5953 setAncestorChainHasOutOfFlowPositionedDescendant(); 5954 compositor()->addOutOfFlowPositionedLayer(this); 5955 } else { 5956 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); 5957 compositor()->removeOutOfFlowPositionedLayer(this); 5958 } 5959 } 5960 5961 static bool hasOrHadFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle) 5962 { 5963 ASSERT(newStyle); 5964 return (oldStyle && oldStyle->hasFilter()) || newStyle->hasFilter(); 5965 } 5966 5967 inline bool RenderLayer::needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const 5968 { 5969 ASSERT(newStyle); 5970 return oldStyle && (oldStyle->clip() != newStyle->clip() || oldStyle->hasClip() != newStyle->hasClip()); 5971 } 5972 5973 inline bool RenderLayer::needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const 5974 { 5975 ASSERT(newStyle); 5976 return !isComposited() && oldStyle && (oldStyle->overflowX() != newStyle->overflowX()) && ancestorStackingContainer()->hasCompositingDescendant(); 5977 } 5978 5979 inline bool RenderLayer::needsCompositingLayersRebuiltForFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle, bool didPaintWithFilters) const 5980 { 5981 if (!hasOrHadFilters(oldStyle, newStyle)) 5982 return false; 5983 5984 if (renderer()->animation()->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitFilter)) { 5985 // When the compositor is performing the filter animation, we shouldn't touch the compositing layers. 5986 // All of the layers above us should have been promoted to compositing layers already. 5987 return false; 5988 } 5989 5990 FilterOutsets newOutsets = newStyle->filterOutsets(); 5991 if (oldStyle && (oldStyle->filterOutsets() != newOutsets)) { 5992 // When filter outsets change, we need to: 5993 // (1) Recompute the overlap map to promote the correct layers to composited layers. 5994 // (2) Update the composited layer bounds (and child GraphicsLayer positions) on platforms 5995 // whose compositors can't compute their own filter outsets. 5996 return true; 5997 } 5998 5999 #if HAVE(COMPOSITOR_FILTER_OUTSETS) 6000 if ((didPaintWithFilters != paintsWithFilters()) && !newOutsets.isZero()) { 6001 // When the layer used to paint filters in software and now paints filters in the 6002 // compositor, the compositing layer bounds need to change from including filter outsets to 6003 // excluding filter outsets, on platforms whose compositors compute their own outsets. 6004 // Similarly for the reverse change from compositor-painted to software-painted filters. 6005 return true; 6006 } 6007 #endif 6008 6009 return false; 6010 } 6011 6012 void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle) 6013 { 6014 if (!hasOrHadFilters(oldStyle, newStyle)) 6015 return; 6016 6017 updateOrRemoveFilterClients(); 6018 // During an accelerated animation, both WebKit and the compositor animate properties. 6019 // However, WebKit shouldn't ask the compositor to update its filters if the compositor is performing the animation. 6020 bool shouldUpdateFilters = isComposited() && !renderer()->animation()->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitFilter); 6021 if (shouldUpdateFilters) 6022 backing()->updateFilters(renderer()->style()); 6023 updateOrRemoveFilterEffectRenderer(); 6024 } 6025 6026 void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) 6027 { 6028 updateIsNormalFlowOnly(); 6029 6030 updateResizerAreaSet(); 6031 updateScrollbarsAfterStyleChange(oldStyle); 6032 updateStackingContextsAfterStyleChange(oldStyle); 6033 updateVisibilityAfterStyleChange(oldStyle); 6034 // Overlay scrollbars can make this layer self-painting so we need 6035 // to recompute the bit once scrollbars have been updated. 6036 updateSelfPaintingLayer(); 6037 updateOutOfFlowPositioned(oldStyle); 6038 6039 if (!hasReflection() && m_reflection) 6040 removeReflection(); 6041 else if (hasReflection()) { 6042 if (!m_reflection) 6043 createReflection(); 6044 UseCounter::count(renderer()->document(), UseCounter::Reflection); 6045 updateReflectionStyle(); 6046 } 6047 6048 // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa). 6049 if (m_hBar) 6050 m_hBar->styleChanged(); 6051 if (m_vBar) 6052 m_vBar->styleChanged(); 6053 6054 updateScrollCornerStyle(); 6055 updateResizerStyle(); 6056 6057 updateDescendantDependentFlags(); 6058 updateTransform(); 6059 6060 if (RuntimeEnabledFeatures::cssCompositingEnabled()) 6061 updateBlendMode(); 6062 6063 bool didPaintWithFilters = false; 6064 6065 if (paintsWithFilters()) 6066 didPaintWithFilters = true; 6067 updateFilters(oldStyle, renderer()->style()); 6068 6069 const RenderStyle* newStyle = renderer()->style(); 6070 if (compositor()->updateLayerCompositingState(this) 6071 || needsCompositingLayersRebuiltForClip(oldStyle, newStyle) 6072 || needsCompositingLayersRebuiltForOverflow(oldStyle, newStyle) 6073 || needsCompositingLayersRebuiltForFilters(oldStyle, newStyle, didPaintWithFilters)) 6074 compositor()->setCompositingLayersNeedRebuild(); 6075 else if (isComposited()) 6076 backing()->updateGraphicsLayerGeometry(); 6077 } 6078 6079 void RenderLayer::updateResizerAreaSet() { 6080 Frame* frame = renderer()->frame(); 6081 if (!frame) 6082 return; 6083 FrameView* frameView = frame->view(); 6084 if (!frameView) 6085 return; 6086 if (canResize()) 6087 frameView->addResizerArea(this); 6088 else 6089 frameView->removeResizerArea(this); 6090 } 6091 6092 void RenderLayer::updateScrollableAreaSet(bool hasOverflow) 6093 { 6094 Frame* frame = renderer()->frame(); 6095 if (!frame) 6096 return; 6097 6098 FrameView* frameView = frame->view(); 6099 if (!frameView) 6100 return; 6101 6102 bool isVisibleToHitTest = renderer()->visibleToHitTesting(); 6103 if (HTMLFrameOwnerElement* owner = frame->ownerElement()) 6104 isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting(); 6105 6106 if (hasOverflow && isVisibleToHitTest) { 6107 if (frameView->addScrollableArea(this)) 6108 compositor()->setNeedsUpdateCompositingRequirementsState(); 6109 } else { 6110 if (frameView->removeScrollableArea(this)) 6111 setNeedsCompositedScrolling(false); 6112 } 6113 } 6114 6115 void RenderLayer::updateScrollCornerStyle() 6116 { 6117 RenderObject* actualRenderer = rendererForScrollbar(renderer()); 6118 RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0); 6119 if (corner) { 6120 if (!m_scrollCorner) { 6121 m_scrollCorner = RenderScrollbarPart::createAnonymous(renderer()->document()); 6122 m_scrollCorner->setParent(renderer()); 6123 } 6124 m_scrollCorner->setStyle(corner.release()); 6125 } else if (m_scrollCorner) { 6126 m_scrollCorner->destroy(); 6127 m_scrollCorner = 0; 6128 } 6129 } 6130 6131 void RenderLayer::updateResizerStyle() 6132 { 6133 RenderObject* actualRenderer = rendererForScrollbar(renderer()); 6134 RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0); 6135 if (resizer) { 6136 if (!m_resizer) { 6137 m_resizer = RenderScrollbarPart::createAnonymous(renderer()->document()); 6138 m_resizer->setParent(renderer()); 6139 } 6140 m_resizer->setStyle(resizer.release()); 6141 } else if (m_resizer) { 6142 m_resizer->destroy(); 6143 m_resizer = 0; 6144 } 6145 } 6146 6147 RenderLayer* RenderLayer::reflectionLayer() const 6148 { 6149 return m_reflection ? m_reflection->layer() : 0; 6150 } 6151 6152 void RenderLayer::createReflection() 6153 { 6154 ASSERT(!m_reflection); 6155 m_reflection = RenderReplica::createAnonymous(renderer()->document()); 6156 m_reflection->setParent(renderer()); // We create a 1-way connection. 6157 } 6158 6159 void RenderLayer::removeReflection() 6160 { 6161 if (!m_reflection->documentBeingDestroyed()) 6162 m_reflection->removeLayers(this); 6163 6164 m_reflection->setParent(0); 6165 m_reflection->destroy(); 6166 m_reflection = 0; 6167 } 6168 6169 void RenderLayer::updateReflectionStyle() 6170 { 6171 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 6172 newStyle->inheritFrom(renderer()->style()); 6173 6174 // Map in our transform. 6175 TransformOperations transform; 6176 switch (renderer()->style()->boxReflect()->direction()) { 6177 case ReflectionBelow: 6178 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::Translate)); 6179 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::Translate)); 6180 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::Scale)); 6181 break; 6182 case ReflectionAbove: 6183 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::Scale)); 6184 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::Translate)); 6185 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::Translate)); 6186 break; 6187 case ReflectionRight: 6188 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::Translate)); 6189 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); 6190 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::Scale)); 6191 break; 6192 case ReflectionLeft: 6193 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::Scale)); 6194 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::Translate)); 6195 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); 6196 break; 6197 } 6198 newStyle->setTransform(transform); 6199 6200 // Map in our mask. 6201 newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask()); 6202 6203 m_reflection->setStyle(newStyle.release()); 6204 } 6205 6206 bool RenderLayer::isCSSCustomFilterEnabled() const 6207 { 6208 // We only want to enable shaders if WebGL is also enabled on this platform. 6209 const Settings* settings = renderer()->document()->settings(); 6210 return settings && settings->isCSSCustomFilterEnabled() && settings->webGLEnabled(); 6211 } 6212 6213 FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style) 6214 { 6215 const FilterOperations& filters = style->filter(); 6216 if (filters.hasReferenceFilter()) { 6217 for (size_t i = 0; i < filters.size(); ++i) { 6218 FilterOperation* filterOperation = filters.operations().at(i).get(); 6219 if (filterOperation->getOperationType() != FilterOperation::REFERENCE) 6220 continue; 6221 ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation); 6222 // FIXME: Cache the ReferenceFilter if it didn't change. 6223 RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create(); 6224 float zoom = style->effectiveZoom() * WebCore::deviceScaleFactor(renderer()->frame()); 6225 referenceFilter->setFilterResolution(FloatSize(zoom, zoom)); 6226 referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referenceFilter.get(), renderer(), referenceFilter->sourceGraphic(), 6227 referenceOperation)); 6228 referenceOperation->setFilter(referenceFilter.release()); 6229 } 6230 } 6231 6232 if (!filters.hasCustomFilter()) 6233 return filters; 6234 6235 if (!isCSSCustomFilterEnabled()) { 6236 // CSS Custom filters should not parse at all in this case, but there might be 6237 // remaining styles that were parsed when the flag was enabled. Reproduces in DumpRenderTree 6238 // because it resets the flag while the previous test is still loaded. 6239 return FilterOperations(); 6240 } 6241 6242 FilterOperations outputFilters; 6243 for (size_t i = 0; i < filters.size(); ++i) { 6244 RefPtr<FilterOperation> filterOperation = filters.operations().at(i); 6245 if (filterOperation->getOperationType() == FilterOperation::CUSTOM) { 6246 // We have to wait until the program of CSS Shaders is loaded before setting it on the layer. 6247 // Note that we will handle the loading of the shaders and repainting of the layer in updateOrRemoveFilterClients. 6248 const CustomFilterOperation* customOperation = static_cast<const CustomFilterOperation*>(filterOperation.get()); 6249 RefPtr<CustomFilterProgram> program = customOperation->program(); 6250 if (!program->isLoaded()) 6251 continue; 6252 6253 CustomFilterGlobalContext* globalContext = renderer()->view()->customFilterGlobalContext(); 6254 RefPtr<CustomFilterValidatedProgram> validatedProgram = globalContext->getValidatedProgram(program->programInfo()); 6255 if (!validatedProgram->isInitialized()) 6256 continue; 6257 6258 RefPtr<ValidatedCustomFilterOperation> validatedOperation = ValidatedCustomFilterOperation::create(validatedProgram.release(), 6259 customOperation->parameters(), customOperation->meshRows(), customOperation->meshColumns(), customOperation->meshType()); 6260 outputFilters.operations().append(validatedOperation.release()); 6261 continue; 6262 } 6263 outputFilters.operations().append(filterOperation.release()); 6264 } 6265 return outputFilters; 6266 } 6267 6268 void RenderLayer::updateOrRemoveFilterClients() 6269 { 6270 if (!hasFilter()) { 6271 removeFilterInfoIfNeeded(); 6272 return; 6273 } 6274 6275 if (renderer()->style()->filter().hasCustomFilter()) 6276 ensureFilterInfo()->updateCustomFilterClients(renderer()->style()->filter()); 6277 else if (hasFilterInfo()) 6278 filterInfo()->removeCustomFilterClients(); 6279 6280 if (renderer()->style()->filter().hasReferenceFilter()) 6281 ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->filter()); 6282 else if (hasFilterInfo()) 6283 filterInfo()->removeReferenceFilterClients(); 6284 } 6285 6286 void RenderLayer::updateOrRemoveFilterEffectRenderer() 6287 { 6288 // FilterEffectRenderer is only used to render the filters in software mode, 6289 // so we always need to run updateOrRemoveFilterEffectRenderer after the composited 6290 // mode might have changed for this layer. 6291 if (!paintsWithFilters()) { 6292 // Don't delete the whole filter info here, because we might use it 6293 // for loading CSS shader files. 6294 if (RenderLayerFilterInfo* filterInfo = this->filterInfo()) 6295 filterInfo->setRenderer(0); 6296 6297 return; 6298 } 6299 6300 RenderLayerFilterInfo* filterInfo = ensureFilterInfo(); 6301 if (!filterInfo->renderer()) { 6302 RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create(); 6303 RenderingMode renderingMode = renderer()->frame()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; 6304 filterRenderer->setRenderingMode(renderingMode); 6305 filterInfo->setRenderer(filterRenderer.release()); 6306 6307 // We can optimize away code paths in other places if we know that there are no software filters. 6308 renderer()->document()->view()->setHasSoftwareFilters(true); 6309 } 6310 6311 // If the filter fails to build, remove it from the layer. It will still attempt to 6312 // go through regular processing (e.g. compositing), but never apply anything. 6313 if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style()))) 6314 filterInfo->setRenderer(0); 6315 } 6316 6317 void RenderLayer::filterNeedsRepaint() 6318 { 6319 toElement(renderer()->node())->scheduleLayerUpdate(); 6320 if (renderer()->view()) 6321 renderer()->repaint(); 6322 } 6323 6324 void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const 6325 { 6326 if (!size().isEmpty()) { 6327 Vector<LayoutRect> rect; 6328 6329 if (renderBox() && renderBox()->scrollsOverflow()) { 6330 // For scrolling layers, rects are taken to be in the space of the contents. 6331 // We need to include both the entire contents, and also the bounding box 6332 // of the layer in the space of it's parent (eg. for border / scroll bars). 6333 rect.append(m_overflowRect); 6334 rects.set(this, rect); 6335 if (const RenderLayer* parentLayer = parent()) { 6336 LayerHitTestRects::iterator iter = rects.find(parentLayer); 6337 if (iter == rects.end()) 6338 iter = rects.add(parentLayer, Vector<LayoutRect>()).iterator; 6339 iter->value.append(boundingBox(parentLayer)); 6340 } 6341 } else { 6342 rect.append(localBoundingBox()); 6343 rects.set(this, rect); 6344 } 6345 } 6346 6347 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) 6348 child->addLayerHitTestRects(rects); 6349 } 6350 6351 } // namespace WebCore 6352 6353 #ifndef NDEBUG 6354 void showLayerTree(const WebCore::RenderLayer* layer) 6355 { 6356 if (!layer) 6357 return; 6358 6359 if (WebCore::Frame* frame = layer->renderer()->frame()) { 6360 WTF::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState); 6361 fprintf(stderr, "%s\n", output.utf8().data()); 6362 } 6363 } 6364 6365 void showLayerTree(const WebCore::RenderObject* renderer) 6366 { 6367 if (!renderer) 6368 return; 6369 showLayerTree(renderer->enclosingLayer()); 6370 } 6371 #endif 6372