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