| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights
reserved. | |
| 3 * | |
| 4 * Portions are Copyright (C) 1998 Netscape Communications Corporation. | |
| 5 * | |
| 6 * Other contributors: | |
| 7 * Robert O'Callahan <roc+@cs.cmu.edu> | |
| 8 * David Baron <dbaron@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 US
A | |
| 28 * | |
| 29 * Alternatively, the contents of this file may be used under the terms | |
| 30 * of either the Mozilla Public License Version 1.1, found at | |
| 31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public | |
| 32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html | |
| 33 * (the "GPL"), in which case the provisions of the MPL or the GPL are | |
| 34 * applicable instead of those above. If you wish to allow use of your | |
| 35 * version of this file only under the terms of one of those two | |
| 36 * licenses (the MPL or the GPL) and not to allow others to use your | |
| 37 * version of this file under the LGPL, indicate your decision by | |
| 38 * deletingthe provisions above and replace them with the notice and | |
| 39 * other provisions required by the MPL or the GPL, as the case may be. | |
| 40 * If you do not delete the provisions above, a recipient may use your | |
| 41 * version of this file under any of the LGPL, the MPL or the GPL. | |
| 42 */ | |
| 43 | |
| 44 #include "config.h" | |
| 45 #include "core/rendering/RenderLayer.h" | |
| 46 | |
| 47 #include "core/CSSPropertyNames.h" | |
| 48 #include "core/HTMLNames.h" | |
| 49 #include "core/css/PseudoStyleRequest.h" | |
| 50 #include "core/dom/Document.h" | |
| 51 #include "core/dom/shadow/ShadowRoot.h" | |
| 52 #include "core/frame/DeprecatedScheduleStyleRecalcDuringLayout.h" | |
| 53 #include "core/frame/FrameView.h" | |
| 54 #include "core/frame/LocalFrame.h" | |
| 55 #include "core/html/HTMLFrameElement.h" | |
| 56 #include "core/layout/HitTestRequest.h" | |
| 57 #include "core/layout/HitTestResult.h" | |
| 58 #include "core/layout/HitTestingTransformState.h" | |
| 59 #include "core/layout/LayoutTreeAsText.h" | |
| 60 #include "core/layout/compositing/CompositedLayerMapping.h" | |
| 61 #include "core/layout/compositing/RenderLayerCompositor.h" | |
| 62 #include "core/page/Page.h" | |
| 63 #include "core/page/scrolling/ScrollingCoordinator.h" | |
| 64 #include "core/rendering/ColumnInfo.h" | |
| 65 #include "core/rendering/FilterEffectRenderer.h" | |
| 66 #include "core/rendering/RenderFlowThread.h" | |
| 67 #include "core/rendering/RenderGeometryMap.h" | |
| 68 #include "core/rendering/RenderInline.h" | |
| 69 #include "core/rendering/RenderPart.h" | |
| 70 #include "core/rendering/RenderReplica.h" | |
| 71 #include "core/rendering/RenderScrollbar.h" | |
| 72 #include "core/rendering/RenderScrollbarPart.h" | |
| 73 #include "core/rendering/RenderView.h" | |
| 74 #include "core/rendering/svg/ReferenceFilterBuilder.h" | |
| 75 #include "core/rendering/svg/RenderSVGRoot.h" | |
| 76 #include "platform/LengthFunctions.h" | |
| 77 #include "platform/Partitions.h" | |
| 78 #include "platform/RuntimeEnabledFeatures.h" | |
| 79 #include "platform/TraceEvent.h" | |
| 80 #include "platform/geometry/FloatPoint3D.h" | |
| 81 #include "platform/geometry/FloatRect.h" | |
| 82 #include "platform/geometry/TransformState.h" | |
| 83 #include "platform/graphics/filters/ReferenceFilter.h" | |
| 84 #include "platform/graphics/filters/SourceGraphic.h" | |
| 85 #include "platform/transforms/ScaleTransformOperation.h" | |
| 86 #include "platform/transforms/TransformationMatrix.h" | |
| 87 #include "platform/transforms/TranslateTransformOperation.h" | |
| 88 #include "public/platform/Platform.h" | |
| 89 #include "wtf/StdLibExtras.h" | |
| 90 #include "wtf/text/CString.h" | |
| 91 | |
| 92 namespace blink { | |
| 93 | |
| 94 namespace { | |
| 95 | |
| 96 static CompositingQueryMode gCompositingQueryMode = | |
| 97 CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases; | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 101 using namespace HTMLNames; | |
| 102 | |
| 103 RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type) | |
| 104 : m_layerType(type) | |
| 105 , m_hasSelfPaintingLayerDescendant(false) | |
| 106 , m_hasSelfPaintingLayerDescendantDirty(false) | |
| 107 , m_isRootLayer(renderer->isRenderView()) | |
| 108 , m_visibleContentStatusDirty(true) | |
| 109 , m_hasVisibleContent(false) | |
| 110 , m_visibleDescendantStatusDirty(false) | |
| 111 , m_hasVisibleDescendant(false) | |
| 112 , m_hasVisibleNonLayerContent(false) | |
| 113 , m_isPaginated(false) | |
| 114 #if ENABLE(ASSERT) | |
| 115 , m_needsPositionUpdate(true) | |
| 116 #endif | |
| 117 , m_3DTransformedDescendantStatusDirty(true) | |
| 118 , m_has3DTransformedDescendant(false) | |
| 119 , m_containsDirtyOverlayScrollbars(false) | |
| 120 , m_hasFilterInfo(false) | |
| 121 , m_needsAncestorDependentCompositingInputsUpdate(true) | |
| 122 , m_needsDescendantDependentCompositingInputsUpdate(true) | |
| 123 , m_childNeedsCompositingInputsUpdate(true) | |
| 124 , m_hasCompositingDescendant(false) | |
| 125 , m_hasNonCompositedChild(false) | |
| 126 , m_shouldIsolateCompositedDescendants(false) | |
| 127 , m_lostGroupedMapping(false) | |
| 128 , m_renderer(renderer) | |
| 129 , m_parent(0) | |
| 130 , m_previous(0) | |
| 131 , m_next(0) | |
| 132 , m_first(0) | |
| 133 , m_last(0) | |
| 134 , m_staticInlinePosition(0) | |
| 135 , m_staticBlockPosition(0) | |
| 136 , m_enclosingPaginationLayer(0) | |
| 137 , m_potentialCompositingReasonsFromStyle(CompositingReasonNone) | |
| 138 , m_compositingReasons(CompositingReasonNone) | |
| 139 , m_groupedMapping(0) | |
| 140 , m_clipper(*renderer) | |
| 141 { | |
| 142 updateStackingNode(); | |
| 143 | |
| 144 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer(); | |
| 145 | |
| 146 if (!renderer->slowFirstChild() && renderer->style()) { | |
| 147 m_visibleContentStatusDirty = false; | |
| 148 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; | |
| 149 } | |
| 150 | |
| 151 updateScrollableArea(); | |
| 152 } | |
| 153 | |
| 154 RenderLayer::~RenderLayer() | |
| 155 { | |
| 156 if (renderer()->frame() && renderer()->frame()->page()) { | |
| 157 if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->pa
ge()->scrollingCoordinator()) | |
| 158 scrollingCoordinator->willDestroyRenderLayer(this); | |
| 159 } | |
| 160 | |
| 161 removeFilterInfoIfNeeded(); | |
| 162 | |
| 163 if (groupedMapping()) { | |
| 164 DisableCompositingQueryAsserts disabler; | |
| 165 groupedMapping()->removeRenderLayerFromSquashingGraphicsLayer(this); | |
| 166 setGroupedMapping(0); | |
| 167 } | |
| 168 | |
| 169 // Child layers will be deleted by their corresponding render objects, so | |
| 170 // we don't need to delete them ourselves. | |
| 171 | |
| 172 clearCompositedLayerMapping(true); | |
| 173 | |
| 174 if (m_reflectionInfo) | |
| 175 m_reflectionInfo->destroy(); | |
| 176 } | |
| 177 | |
| 178 String RenderLayer::debugName() const | |
| 179 { | |
| 180 if (isReflection()) { | |
| 181 return renderer()->parent()->debugName() + " (reflection)"; | |
| 182 } | |
| 183 return renderer()->debugName(); | |
| 184 } | |
| 185 | |
| 186 RenderLayerCompositor* RenderLayer::compositor() const | |
| 187 { | |
| 188 if (!renderer()->view()) | |
| 189 return 0; | |
| 190 return renderer()->view()->compositor(); | |
| 191 } | |
| 192 | |
| 193 void RenderLayer::contentChanged(ContentChangeType changeType) | |
| 194 { | |
| 195 // updateLayerCompositingState will query compositingReasons for accelerated
overflow scrolling. | |
| 196 // This is tripped by LayoutTests/compositing/content-changed-chicken-egg.ht
ml | |
| 197 DisableCompositingQueryAsserts disabler; | |
| 198 | |
| 199 if (changeType == CanvasChanged) | |
| 200 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositin
gInputChange); | |
| 201 | |
| 202 if (changeType == CanvasContextChanged) { | |
| 203 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositin
gInputChange); | |
| 204 | |
| 205 // Although we're missing test coverage, we need to call | |
| 206 // GraphicsLayer::setContentsToPlatformLayer with the new platform | |
| 207 // layer for this canvas. | |
| 208 // See http://crbug.com/349195 | |
| 209 if (hasCompositedLayerMapping()) | |
| 210 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerU
pdateSubtree); | |
| 211 } | |
| 212 | |
| 213 if (m_compositedLayerMapping) | |
| 214 m_compositedLayerMapping->contentChanged(changeType); | |
| 215 } | |
| 216 | |
| 217 bool RenderLayer::paintsWithFilters() const | |
| 218 { | |
| 219 if (!renderer()->hasFilter()) | |
| 220 return false; | |
| 221 | |
| 222 // https://code.google.com/p/chromium/issues/detail?id=343759 | |
| 223 DisableCompositingQueryAsserts disabler; | |
| 224 return !m_compositedLayerMapping || compositingState() != PaintsIntoOwnBacki
ng; | |
| 225 } | |
| 226 | |
| 227 LayoutSize RenderLayer::subpixelAccumulation() const | |
| 228 { | |
| 229 return m_subpixelAccumulation; | |
| 230 } | |
| 231 | |
| 232 void RenderLayer::setSubpixelAccumulation(const LayoutSize& size) | |
| 233 { | |
| 234 m_subpixelAccumulation = size; | |
| 235 } | |
| 236 | |
| 237 void RenderLayer::updateLayerPositionsAfterLayout() | |
| 238 { | |
| 239 TRACE_EVENT0("blink,benchmark", "RenderLayer::updateLayerPositionsAfterLayou
t"); | |
| 240 | |
| 241 m_clipper.clearClipRectsIncludingDescendants(); | |
| 242 updateLayerPositionRecursive(); | |
| 243 | |
| 244 { | |
| 245 // FIXME: Remove incremental compositing updates after fixing the chicke
n/egg issues | |
| 246 // https://code.google.com/p/chromium/issues/detail?id=343756 | |
| 247 DisableCompositingQueryAsserts disabler; | |
| 248 bool needsPaginationUpdate = isPaginated() || enclosingPaginationLayer()
; | |
| 249 updatePaginationRecursive(needsPaginationUpdate); | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 void RenderLayer::updateLayerPositionRecursive() | |
| 254 { | |
| 255 updateLayerPosition(); | |
| 256 | |
| 257 if (m_reflectionInfo) | |
| 258 m_reflectionInfo->reflection()->layout(); | |
| 259 | |
| 260 // FIXME: We should be able to remove this call because we don't care about | |
| 261 // any descendant-dependent flags, but code somewhere else is reading these | |
| 262 // flags and depending on us to update them. | |
| 263 updateDescendantDependentFlags(); | |
| 264 | |
| 265 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 266 child->updateLayerPositionRecursive(); | |
| 267 } | |
| 268 | |
| 269 void RenderLayer::updateHasSelfPaintingLayerDescendant() const | |
| 270 { | |
| 271 ASSERT(m_hasSelfPaintingLayerDescendantDirty); | |
| 272 | |
| 273 m_hasSelfPaintingLayerDescendant = false; | |
| 274 | |
| 275 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
{ | |
| 276 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendan
t()) { | |
| 277 m_hasSelfPaintingLayerDescendant = true; | |
| 278 break; | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 m_hasSelfPaintingLayerDescendantDirty = false; | |
| 283 } | |
| 284 | |
| 285 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus() | |
| 286 { | |
| 287 for (RenderLayer* layer = this; layer; layer = layer->parent()) { | |
| 288 layer->m_hasSelfPaintingLayerDescendantDirty = true; | |
| 289 // If we have reached a self-painting layer, we know our parent should h
ave a self-painting descendant | |
| 290 // in this case, there is no need to dirty our ancestors further. | |
| 291 if (layer->isSelfPaintingLayer()) { | |
| 292 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty
|| parent()->m_hasSelfPaintingLayerDescendant); | |
| 293 break; | |
| 294 } | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 bool RenderLayer::scrollsWithViewport() const | |
| 299 { | |
| 300 return renderer()->style()->position() == FixedPosition && renderer()->conta
inerForFixedPosition() == renderer()->view(); | |
| 301 } | |
| 302 | |
| 303 bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const | |
| 304 { | |
| 305 if (scrollsWithViewport() != other->scrollsWithViewport()) | |
| 306 return true; | |
| 307 return ancestorScrollingLayer() != other->ancestorScrollingLayer(); | |
| 308 } | |
| 309 | |
| 310 void RenderLayer::updateLayerPositionsAfterOverflowScroll() | |
| 311 { | |
| 312 m_clipper.clearClipRectsIncludingDescendants(); | |
| 313 updateLayerPositionsAfterScrollRecursive(); | |
| 314 } | |
| 315 | |
| 316 void RenderLayer::updateLayerPositionsAfterScrollRecursive() | |
| 317 { | |
| 318 if (updateLayerPosition()) | |
| 319 m_renderer->setPreviousPaintInvalidationRect(m_renderer->boundsRectForPa
intInvalidation(m_renderer->containerForPaintInvalidation())); | |
| 320 | |
| 321 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 322 child->updateLayerPositionsAfterScrollRecursive(); | |
| 323 } | |
| 324 | |
| 325 void RenderLayer::updateTransformationMatrix() | |
| 326 { | |
| 327 if (m_transform) { | |
| 328 RenderBox* box = renderBox(); | |
| 329 ASSERT(box); | |
| 330 m_transform->makeIdentity(); | |
| 331 box->style()->applyTransform(*m_transform, LayoutSize(box->pixelSnappedS
ize()), RenderStyle::IncludeTransformOrigin); | |
| 332 makeMatrixRenderable(*m_transform, compositor()->hasAcceleratedCompositi
ng()); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newS
tyle) | |
| 337 { | |
| 338 if (oldStyle && newStyle->transformDataEquivalent(*oldStyle)) | |
| 339 return; | |
| 340 | |
| 341 // hasTransform() on the renderer is also true when there is transform-style
: preserve-3d or perspective set, | |
| 342 // so check style too. | |
| 343 bool hasTransform = renderer()->hasTransformRelatedProperty() && newStyle->h
asTransform(); | |
| 344 bool had3DTransform = has3DTransform(); | |
| 345 | |
| 346 bool hadTransform = m_transform; | |
| 347 if (hasTransform != hadTransform) { | |
| 348 if (hasTransform) | |
| 349 m_transform = adoptPtr(new TransformationMatrix); | |
| 350 else | |
| 351 m_transform.clear(); | |
| 352 | |
| 353 // Layers with transforms act as clip rects roots, so clear the cached c
lip rects here. | |
| 354 m_clipper.clearClipRectsIncludingDescendants(); | |
| 355 } else if (hasTransform) { | |
| 356 m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects); | |
| 357 } | |
| 358 | |
| 359 updateTransformationMatrix(); | |
| 360 | |
| 361 if (had3DTransform != has3DTransform()) | |
| 362 dirty3DTransformedDescendantStatus(); | |
| 363 } | |
| 364 | |
| 365 static RenderLayer* enclosingLayerForContainingBlock(RenderLayer* layer) | |
| 366 { | |
| 367 if (RenderObject* containingBlock = layer->renderer()->containingBlock()) | |
| 368 return containingBlock->enclosingLayer(); | |
| 369 return 0; | |
| 370 } | |
| 371 | |
| 372 RenderLayer* RenderLayer::renderingContextRoot() | |
| 373 { | |
| 374 RenderLayer* renderingContext = 0; | |
| 375 | |
| 376 if (shouldPreserve3D()) | |
| 377 renderingContext = this; | |
| 378 | |
| 379 for (RenderLayer* current = enclosingLayerForContainingBlock(this); current
&& current->shouldPreserve3D(); current = enclosingLayerForContainingBlock(curre
nt)) | |
| 380 renderingContext = current; | |
| 381 | |
| 382 return renderingContext; | |
| 383 } | |
| 384 | |
| 385 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOr
igin applyOrigin) const | |
| 386 { | |
| 387 if (!m_transform) | |
| 388 return TransformationMatrix(); | |
| 389 | |
| 390 // m_transform includes transform-origin, so we need to recompute the transf
orm here. | |
| 391 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) { | |
| 392 RenderBox* box = renderBox(); | |
| 393 TransformationMatrix currTransform; | |
| 394 box->style()->applyTransform(currTransform, LayoutSize(box->pixelSnapped
Size()), RenderStyle::ExcludeTransformOrigin); | |
| 395 makeMatrixRenderable(currTransform, compositor()->hasAcceleratedComposit
ing()); | |
| 396 return currTransform; | |
| 397 } | |
| 398 | |
| 399 return *m_transform; | |
| 400 } | |
| 401 | |
| 402 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavio
r) const | |
| 403 { | |
| 404 if (!m_transform) | |
| 405 return TransformationMatrix(); | |
| 406 | |
| 407 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) { | |
| 408 TransformationMatrix matrix = *m_transform; | |
| 409 makeMatrixRenderable(matrix, false /* flatten 3d */); | |
| 410 return matrix; | |
| 411 } | |
| 412 | |
| 413 return *m_transform; | |
| 414 } | |
| 415 | |
| 416 static bool checkContainingBlockChainForPagination(RenderLayerModelObject* rende
rer, RenderBox* ancestorColumnsRenderer) | |
| 417 { | |
| 418 RenderView* view = renderer->view(); | |
| 419 RenderLayerModelObject* prevBlock = renderer; | |
| 420 RenderBlock* containingBlock; | |
| 421 for (containingBlock = renderer->containingBlock(); | |
| 422 containingBlock && containingBlock != view && containingBlock != ancest
orColumnsRenderer; | |
| 423 containingBlock = containingBlock->containingBlock()) | |
| 424 prevBlock = containingBlock; | |
| 425 | |
| 426 // If the columns block wasn't in our containing block chain, then we aren't
paginated by it. | |
| 427 if (containingBlock != ancestorColumnsRenderer) | |
| 428 return false; | |
| 429 | |
| 430 // If the previous block is absolutely positioned, then we can't be paginate
d by the columns block. | |
| 431 if (prevBlock->isOutOfFlowPositioned()) | |
| 432 return false; | |
| 433 | |
| 434 // Otherwise we are paginated by the columns block. | |
| 435 return true; | |
| 436 } | |
| 437 | |
| 438 // Convert a bounding box from flow thread coordinates, relative to |layer|, to
visual coordinates, relative to |ancestorLayer|. | |
| 439 // See http://www.chromium.org/developers/design-documents/multi-column-layout f
or more info on these coordinate types. | |
| 440 static void convertFromFlowThreadToVisualBoundingBoxInAncestor(const RenderLayer
* layer, const RenderLayer* ancestorLayer, LayoutRect& rect) | |
| 441 { | |
| 442 RenderLayer* paginationLayer = layer->enclosingPaginationLayer(); | |
| 443 ASSERT(paginationLayer); | |
| 444 RenderFlowThread* flowThread = toRenderFlowThread(paginationLayer->renderer(
)); | |
| 445 | |
| 446 // First make the flow thread rectangle relative to the flow thread, not to
|layer|. | |
| 447 LayoutPoint offsetWithinPaginationLayer; | |
| 448 layer->convertToLayerCoords(paginationLayer, offsetWithinPaginationLayer); | |
| 449 rect.moveBy(offsetWithinPaginationLayer); | |
| 450 | |
| 451 // Then make the rectangle visual, relative to the fragmentation context. Sp
lit our box up into | |
| 452 // the actual fragment boxes that render in the columns/pages and unite thos
e together to get | |
| 453 // our true bounding box. | |
| 454 rect = flowThread->fragmentsBoundingBox(rect); | |
| 455 | |
| 456 // Finally, make the visual rectangle relative to |ancestorLayer|. | |
| 457 if (ancestorLayer->enclosingPaginationLayer() != paginationLayer) { | |
| 458 rect.moveBy(paginationLayer->visualOffsetFromAncestor(ancestorLayer)); | |
| 459 return; | |
| 460 } | |
| 461 // The ancestor layer is inside the same pagination layer as |layer|, so we
need to subtract | |
| 462 // the visual distance from the ancestor layer to the pagination layer. | |
| 463 rect.moveBy(-ancestorLayer->visualOffsetFromAncestor(paginationLayer)); | |
| 464 } | |
| 465 | |
| 466 bool RenderLayer::useRegionBasedColumns() const | |
| 467 { | |
| 468 return renderer()->document().regionBasedColumnsEnabled(); | |
| 469 } | |
| 470 | |
| 471 void RenderLayer::updatePaginationRecursive(bool needsPaginationUpdate) | |
| 472 { | |
| 473 m_isPaginated = false; | |
| 474 m_enclosingPaginationLayer = 0; | |
| 475 | |
| 476 if (useRegionBasedColumns() && renderer()->isRenderFlowThread()) | |
| 477 needsPaginationUpdate = true; | |
| 478 | |
| 479 if (needsPaginationUpdate) | |
| 480 updatePagination(); | |
| 481 | |
| 482 if (renderer()->hasColumns()) | |
| 483 needsPaginationUpdate = true; | |
| 484 | |
| 485 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 486 child->updatePaginationRecursive(needsPaginationUpdate); | |
| 487 } | |
| 488 | |
| 489 void RenderLayer::updatePagination() | |
| 490 { | |
| 491 bool usesRegionBasedColumns = useRegionBasedColumns(); | |
| 492 if ((!usesRegionBasedColumns && compositingState() != NotComposited) || !par
ent()) | |
| 493 return; // FIXME: For now the RenderView can't be paginated. Eventually
printing will move to a model where it is though. | |
| 494 | |
| 495 // The main difference between the paginated booleans for the old column cod
e and the new column code | |
| 496 // is that each paginated layer has to paint on its own with the new code. T
here is no | |
| 497 // recurring into child layers. This means that the m_isPaginated bits for t
he new column code can't just be set on | |
| 498 // "roots" that get split and paint all their descendants. Instead each laye
r has to be checked individually and | |
| 499 // genuinely know if it is going to have to split itself up when painting on
ly its contents (and not any other descendant | |
| 500 // layers). We track an enclosingPaginationLayer instead of using a simple b
it, since we want to be able to get back | |
| 501 // to that layer easily. | |
| 502 if (usesRegionBasedColumns && renderer()->isRenderFlowThread()) { | |
| 503 m_enclosingPaginationLayer = this; | |
| 504 return; | |
| 505 } | |
| 506 | |
| 507 if (m_stackingNode->isNormalFlowOnly()) { | |
| 508 if (usesRegionBasedColumns) { | |
| 509 // Content inside a transform is not considered to be paginated, sin
ce we simply | |
| 510 // paint the transform multiple times in each column, so we don't ha
ve to use | |
| 511 // fragments for the transformed content. | |
| 512 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(); | |
| 513 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTra
nsformRelatedProperty()) | |
| 514 m_enclosingPaginationLayer = 0; | |
| 515 } else { | |
| 516 m_isPaginated = parent()->renderer()->hasColumns(); | |
| 517 } | |
| 518 return; | |
| 519 } | |
| 520 | |
| 521 // For the new columns code, we want to walk up our containing block chain l
ooking for an enclosing layer. Once | |
| 522 // we find one, then we just check its pagination status. | |
| 523 if (usesRegionBasedColumns) { | |
| 524 RenderView* view = renderer()->view(); | |
| 525 RenderBlock* containingBlock; | |
| 526 for (containingBlock = renderer()->containingBlock(); | |
| 527 containingBlock && containingBlock != view; | |
| 528 containingBlock = containingBlock->containingBlock()) { | |
| 529 if (containingBlock->hasLayer()) { | |
| 530 // Content inside a transform is not considered to be paginated,
since we simply | |
| 531 // paint the transform multiple times in each column, so we don'
t have to use | |
| 532 // fragments for the transformed content. | |
| 533 m_enclosingPaginationLayer = containingBlock->layer()->enclosing
PaginationLayer(); | |
| 534 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->ha
sTransformRelatedProperty()) | |
| 535 m_enclosingPaginationLayer = 0; | |
| 536 return; | |
| 537 } | |
| 538 } | |
| 539 return; | |
| 540 } | |
| 541 | |
| 542 // If we're not normal flow, then we need to look for a multi-column object
between us and our stacking container. | |
| 543 RenderLayerStackingNode* ancestorStackingContextNode = m_stackingNode->ances
torStackingContextNode(); | |
| 544 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { | |
| 545 if (curr->renderer()->hasColumns()) { | |
| 546 m_isPaginated = checkContainingBlockChainForPagination(renderer(), c
urr->renderBox()); | |
| 547 return; | |
| 548 } | |
| 549 if (curr->stackingNode() == ancestorStackingContextNode) | |
| 550 return; | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 void RenderLayer::clearPaginationRecursive() | |
| 555 { | |
| 556 m_enclosingPaginationLayer = 0; | |
| 557 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 558 child->clearPaginationRecursive(); | |
| 559 } | |
| 560 | |
| 561 LayoutPoint RenderLayer::positionFromPaintInvalidationBacking(const RenderObject
* renderObject, const RenderLayerModelObject* paintInvalidationContainer, const
PaintInvalidationState* paintInvalidationState) | |
| 562 { | |
| 563 FloatPoint point = renderObject->localToContainerPoint(FloatPoint(), paintIn
validationContainer, 0, 0, paintInvalidationState); | |
| 564 | |
| 565 // FIXME: Eventually we are going to unify coordinates in GraphicsLayer spac
e. | |
| 566 if (paintInvalidationContainer && paintInvalidationContainer->layer()->group
edMapping()) | |
| 567 mapPointToPaintBackingCoordinates(paintInvalidationContainer, point); | |
| 568 | |
| 569 return LayoutPoint(point); | |
| 570 } | |
| 571 | |
| 572 void RenderLayer::mapPointToPaintBackingCoordinates(const RenderLayerModelObject
* paintInvalidationContainer, FloatPoint& point) | |
| 573 { | |
| 574 RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer(); | |
| 575 if (!paintInvalidationLayer->groupedMapping()) { | |
| 576 point.move(paintInvalidationLayer->compositedLayerMapping()->contentOffs
etInCompositingLayer()); | |
| 577 return; | |
| 578 } | |
| 579 | |
| 580 RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclos
ingTransformedAncestor()->renderer(); | |
| 581 if (!transformedAncestor) | |
| 582 return; | |
| 583 | |
| 584 // |paintInvalidationContainer| may have a local 2D transform on it, so take
that into account when mapping into the space of the | |
| 585 // transformed ancestor. | |
| 586 point = paintInvalidationContainer->localToContainerPoint(point, transformed
Ancestor); | |
| 587 | |
| 588 point.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromT
ransformedAncestor()); | |
| 589 } | |
| 590 | |
| 591 void RenderLayer::mapRectToPaintBackingCoordinates(const RenderLayerModelObject*
paintInvalidationContainer, LayoutRect& rect) | |
| 592 { | |
| 593 RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer(); | |
| 594 if (!paintInvalidationLayer->groupedMapping()) { | |
| 595 rect.move(paintInvalidationLayer->compositedLayerMapping()->contentOffse
tInCompositingLayer()); | |
| 596 return; | |
| 597 } | |
| 598 | |
| 599 RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclos
ingTransformedAncestor()->renderer(); | |
| 600 if (!transformedAncestor) | |
| 601 return; | |
| 602 | |
| 603 // |paintInvalidationContainer| may have a local 2D transform on it, so take
that into account when mapping into the space of the | |
| 604 // transformed ancestor. | |
| 605 rect = LayoutRect(paintInvalidationContainer->localToContainerQuad(FloatRect
(rect), transformedAncestor).boundingBox()); | |
| 606 | |
| 607 rect.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTr
ansformedAncestor()); | |
| 608 } | |
| 609 | |
| 610 void RenderLayer::mapRectToPaintInvalidationBacking(const RenderObject* renderOb
ject, const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect
, const PaintInvalidationState* paintInvalidationState) | |
| 611 { | |
| 612 if (!paintInvalidationContainer->layer()->groupedMapping()) { | |
| 613 renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContain
er, rect, paintInvalidationState); | |
| 614 return; | |
| 615 } | |
| 616 | |
| 617 // This code adjusts the paint invalidation rectangle to be in the space of
the transformed ancestor of the grouped (i.e. squashed) | |
| 618 // layer. This is because all layers that squash together need to issue pain
t invalidations w.r.t. a single container that is | |
| 619 // an ancestor of all of them, in order to properly take into account any lo
cal transforms etc. | |
| 620 // FIXME: remove this special-case code that works around the paint invalida
tion code structure. | |
| 621 renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer,
rect, paintInvalidationState); | |
| 622 | |
| 623 mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect); | |
| 624 } | |
| 625 | |
| 626 LayoutRect RenderLayer::computePaintInvalidationRect(const RenderObject* renderO
bject, const RenderLayer* paintInvalidationContainer, const PaintInvalidationSta
te* paintInvalidationState) | |
| 627 { | |
| 628 if (!paintInvalidationContainer->groupedMapping()) | |
| 629 return renderObject->computePaintInvalidationRect(paintInvalidationConta
iner->renderer(), paintInvalidationState); | |
| 630 | |
| 631 LayoutRect rect = renderObject->clippedOverflowRectForPaintInvalidation(pain
tInvalidationContainer->renderer(), paintInvalidationState); | |
| 632 mapRectToPaintBackingCoordinates(paintInvalidationContainer->renderer(), rec
t); | |
| 633 return rect; | |
| 634 } | |
| 635 | |
| 636 void RenderLayer::dirtyVisibleContentStatus() | |
| 637 { | |
| 638 m_visibleContentStatusDirty = true; | |
| 639 if (parent()) | |
| 640 parent()->dirtyAncestorChainVisibleDescendantStatus(); | |
| 641 } | |
| 642 | |
| 643 void RenderLayer::potentiallyDirtyVisibleContentStatus(EVisibility visibility) | |
| 644 { | |
| 645 if (m_visibleContentStatusDirty) | |
| 646 return; | |
| 647 if (hasVisibleContent() == (visibility == VISIBLE)) | |
| 648 return; | |
| 649 dirtyVisibleContentStatus(); | |
| 650 } | |
| 651 | |
| 652 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus() | |
| 653 { | |
| 654 for (RenderLayer* layer = this; layer; layer = layer->parent()) { | |
| 655 if (layer->m_visibleDescendantStatusDirty) | |
| 656 break; | |
| 657 | |
| 658 layer->m_visibleDescendantStatusDirty = true; | |
| 659 } | |
| 660 } | |
| 661 | |
| 662 // FIXME: this is quite brute-force. We could be more efficient if we were to | |
| 663 // track state and update it as appropriate as changes are made in the Render tr
ee. | |
| 664 void RenderLayer::updateScrollingStateAfterCompositingChange() | |
| 665 { | |
| 666 TRACE_EVENT0("blink", "RenderLayer::updateScrollingStateAfterCompositingChan
ge"); | |
| 667 m_hasVisibleNonLayerContent = false; | |
| 668 for (RenderObject* r = renderer()->slowFirstChild(); r; r = r->nextSibling()
) { | |
| 669 if (!r->hasLayer()) { | |
| 670 m_hasVisibleNonLayerContent = true; | |
| 671 break; | |
| 672 } | |
| 673 } | |
| 674 | |
| 675 m_hasNonCompositedChild = false; | |
| 676 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
{ | |
| 677 if (child->compositingState() == NotComposited) { | |
| 678 m_hasNonCompositedChild = true; | |
| 679 return; | |
| 680 } | |
| 681 } | |
| 682 } | |
| 683 | |
| 684 // The descendant-dependent flags system is badly broken because we clean dirty | |
| 685 // bits in upward tree walks, which means we need to call updateDescendantDepend
entFlags | |
| 686 // at every node in the tree to fully clean all the dirty bits. While we'll in | |
| 687 // the process of fixing this issue, updateDescendantDependentFlagsForEntireSubt
ree | |
| 688 // provides a big hammer for actually cleaning all the dirty bits in a subtree. | |
| 689 // | |
| 690 // FIXME: Remove this function once the descendant-dependent flags system keeps | |
| 691 // its dirty bits scoped to subtrees. | |
| 692 void RenderLayer::updateDescendantDependentFlagsForEntireSubtree() | |
| 693 { | |
| 694 updateDescendantDependentFlags(); | |
| 695 | |
| 696 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 697 child->updateDescendantDependentFlagsForEntireSubtree(); | |
| 698 } | |
| 699 | |
| 700 void RenderLayer::updateDescendantDependentFlags() | |
| 701 { | |
| 702 if (m_visibleDescendantStatusDirty) { | |
| 703 m_hasVisibleDescendant = false; | |
| 704 | |
| 705 for (RenderLayer* child = firstChild(); child; child = child->nextSiblin
g()) { | |
| 706 child->updateDescendantDependentFlags(); | |
| 707 | |
| 708 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) { | |
| 709 m_hasVisibleDescendant = true; | |
| 710 break; | |
| 711 } | |
| 712 } | |
| 713 | |
| 714 m_visibleDescendantStatusDirty = false; | |
| 715 } | |
| 716 | |
| 717 if (m_visibleContentStatusDirty) { | |
| 718 bool previouslyHasVisibleContent = m_hasVisibleContent; | |
| 719 if (renderer()->style()->visibility() == VISIBLE) | |
| 720 m_hasVisibleContent = true; | |
| 721 else { | |
| 722 // layer may be hidden but still have some visible content, check fo
r this | |
| 723 m_hasVisibleContent = false; | |
| 724 RenderObject* r = renderer()->slowFirstChild(); | |
| 725 while (r) { | |
| 726 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { | |
| 727 m_hasVisibleContent = true; | |
| 728 break; | |
| 729 } | |
| 730 RenderObject* rendererFirstChild = r->slowFirstChild(); | |
| 731 if (rendererFirstChild && !r->hasLayer()) | |
| 732 r = rendererFirstChild; | |
| 733 else if (r->nextSibling()) | |
| 734 r = r->nextSibling(); | |
| 735 else { | |
| 736 do { | |
| 737 r = r->parent(); | |
| 738 if (r == renderer()) | |
| 739 r = 0; | |
| 740 } while (r && !r->nextSibling()); | |
| 741 if (r) | |
| 742 r = r->nextSibling(); | |
| 743 } | |
| 744 } | |
| 745 } | |
| 746 m_visibleContentStatusDirty = false; | |
| 747 | |
| 748 if (hasVisibleContent() != previouslyHasVisibleContent) { | |
| 749 setNeedsCompositingInputsUpdate(); | |
| 750 // We need to tell m_renderer to recheck its rect because we | |
| 751 // pretend that invisible RenderObjects have 0x0 rects. Changing | |
| 752 // visibility therefore changes our rect and we need to visit | |
| 753 // this RenderObject during the invalidateTreeIfNeeded walk. | |
| 754 m_renderer->setMayNeedPaintInvalidation(); | |
| 755 } | |
| 756 } | |
| 757 } | |
| 758 | |
| 759 void RenderLayer::dirty3DTransformedDescendantStatus() | |
| 760 { | |
| 761 RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingCont
extNode(); | |
| 762 if (!stackingNode) | |
| 763 return; | |
| 764 | |
| 765 stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true; | |
| 766 | |
| 767 // This propagates up through preserve-3d hierarchies to the enclosing flatt
ening layer. | |
| 768 // Note that preserves3D() creates stacking context, so we can just run up t
he stacking containers. | |
| 769 while (stackingNode && stackingNode->layer()->preserves3D()) { | |
| 770 stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true; | |
| 771 stackingNode = stackingNode->ancestorStackingContextNode(); | |
| 772 } | |
| 773 } | |
| 774 | |
| 775 // Return true if this layer or any preserve-3d descendants have 3d. | |
| 776 bool RenderLayer::update3DTransformedDescendantStatus() | |
| 777 { | |
| 778 if (m_3DTransformedDescendantStatusDirty) { | |
| 779 m_has3DTransformedDescendant = false; | |
| 780 | |
| 781 m_stackingNode->updateZOrderLists(); | |
| 782 | |
| 783 // Transformed or preserve-3d descendants can only be in the z-order lis
ts, not | |
| 784 // in the normal flow list, so we only need to check those. | |
| 785 RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), Positive
ZOrderChildren | NegativeZOrderChildren); | |
| 786 while (RenderLayerStackingNode* node = iterator.next()) | |
| 787 m_has3DTransformedDescendant |= node->layer()->update3DTransformedDe
scendantStatus(); | |
| 788 | |
| 789 m_3DTransformedDescendantStatusDirty = false; | |
| 790 } | |
| 791 | |
| 792 // If we live in a 3d hierarchy, then the layer at the root of that hierarch
y needs | |
| 793 // the m_has3DTransformedDescendant set. | |
| 794 if (preserves3D()) | |
| 795 return has3DTransform() || m_has3DTransformedDescendant; | |
| 796 | |
| 797 return has3DTransform(); | |
| 798 } | |
| 799 | |
| 800 bool RenderLayer::updateLayerPosition() | |
| 801 { | |
| 802 LayoutPoint localPoint; | |
| 803 LayoutPoint inlineBoundingBoxOffset; // We don't put this into the RenderLay
er x/y for inlines, so we need to subtract it out when done. | |
| 804 | |
| 805 if (renderer()->isInline() && renderer()->isRenderInline()) { | |
| 806 RenderInline* inlineFlow = toRenderInline(renderer()); | |
| 807 IntRect lineBox = inlineFlow->linesBoundingBox(); | |
| 808 m_size = lineBox.size(); | |
| 809 inlineBoundingBoxOffset = lineBox.location(); | |
| 810 localPoint.moveBy(inlineBoundingBoxOffset); | |
| 811 } else if (RenderBox* box = renderBox()) { | |
| 812 m_size = pixelSnappedIntSize(box->size(), box->location()); | |
| 813 localPoint.moveBy(box->topLeftLocation()); | |
| 814 } | |
| 815 | |
| 816 if (!renderer()->isOutOfFlowPositioned() && !renderer()->isColumnSpanAll() &
& renderer()->parent()) { | |
| 817 // We must adjust our position by walking up the render tree looking for
the | |
| 818 // nearest enclosing object with a layer. | |
| 819 RenderObject* curr = renderer()->parent(); | |
| 820 while (curr && !curr->hasLayer()) { | |
| 821 if (curr->isBox() && !curr->isTableRow()) { | |
| 822 // Rows and cells share the same coordinate space (that of the s
ection). | |
| 823 // Omit them when computing our xpos/ypos. | |
| 824 localPoint.moveBy(toRenderBox(curr)->topLeftLocation()); | |
| 825 } | |
| 826 curr = curr->parent(); | |
| 827 } | |
| 828 if (curr->isBox() && curr->isTableRow()) { | |
| 829 // Put ourselves into the row coordinate space. | |
| 830 localPoint.moveBy(-toRenderBox(curr)->topLeftLocation()); | |
| 831 } | |
| 832 } | |
| 833 | |
| 834 // Subtract our parent's scroll offset. | |
| 835 if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) { | |
| 836 RenderLayer* positionedParent = enclosingPositionedAncestor(); | |
| 837 | |
| 838 // For positioned layers, we subtract out the enclosing positioned layer
's scroll offset. | |
| 839 if (positionedParent->renderer()->hasOverflowClip()) { | |
| 840 IntSize offset = positionedParent->renderBox()->scrolledContentOffse
t(); | |
| 841 localPoint -= offset; | |
| 842 } | |
| 843 | |
| 844 if (positionedParent->renderer()->isRelPositioned() && positionedParent-
>renderer()->isRenderInline()) { | |
| 845 LayoutSize offset = toRenderInline(positionedParent->renderer())->of
fsetForInFlowPositionedInline(*toRenderBox(renderer())); | |
| 846 localPoint += offset; | |
| 847 } | |
| 848 } else if (parent()) { | |
| 849 // FIXME: This code is very wrong, but luckily only needed in the old/cu
rrent multicol | |
| 850 // implementation. The compositing system doesn't understand columns and
we're hacking | |
| 851 // around that fact by faking the position of the RenderLayers when we t
hink we'll end up | |
| 852 // being composited. | |
| 853 if (hasStyleDeterminedDirectCompositingReasons() && !useRegionBasedColum
ns()) { | |
| 854 // FIXME: Composited layers ignore pagination, so about the best we
can do is make sure they're offset into the appropriate column. | |
| 855 // They won't split across columns properly. | |
| 856 if (!parent()->renderer()->hasColumns() && parent()->renderer()->isD
ocumentElement() && renderer()->view()->hasColumns()) | |
| 857 localPoint += renderer()->view()->columnOffset(localPoint); | |
| 858 else | |
| 859 localPoint += parent()->renderer()->columnOffset(localPoint); | |
| 860 } | |
| 861 | |
| 862 if (parent()->renderer()->hasOverflowClip()) { | |
| 863 IntSize scrollOffset = parent()->renderBox()->scrolledContentOffset(
); | |
| 864 localPoint -= scrollOffset; | |
| 865 } | |
| 866 } | |
| 867 | |
| 868 bool positionOrOffsetChanged = false; | |
| 869 if (renderer()->isRelPositioned()) { | |
| 870 LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFl
owPosition(); | |
| 871 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition; | |
| 872 m_offsetForInFlowPosition = newOffset; | |
| 873 localPoint.move(m_offsetForInFlowPosition); | |
| 874 } else { | |
| 875 m_offsetForInFlowPosition = LayoutSize(); | |
| 876 } | |
| 877 | |
| 878 // FIXME: We'd really like to just get rid of the concept of a layer rectang
le and rely on the renderers. | |
| 879 localPoint.moveBy(-inlineBoundingBoxOffset); | |
| 880 | |
| 881 if (m_location != localPoint) | |
| 882 positionOrOffsetChanged = true; | |
| 883 m_location = localPoint; | |
| 884 | |
| 885 #if ENABLE(ASSERT) | |
| 886 m_needsPositionUpdate = false; | |
| 887 #endif | |
| 888 return positionOrOffsetChanged; | |
| 889 } | |
| 890 | |
| 891 TransformationMatrix RenderLayer::perspectiveTransform() const | |
| 892 { | |
| 893 if (!renderer()->hasTransformRelatedProperty()) | |
| 894 return TransformationMatrix(); | |
| 895 | |
| 896 RenderStyle* style = renderer()->style(); | |
| 897 if (!style->hasPerspective()) | |
| 898 return TransformationMatrix(); | |
| 899 | |
| 900 // Maybe fetch the perspective from the backing? | |
| 901 const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect
(); | |
| 902 const float boxWidth = borderBox.width(); | |
| 903 const float boxHeight = borderBox.height(); | |
| 904 | |
| 905 float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(),
boxWidth); | |
| 906 float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(),
boxHeight); | |
| 907 | |
| 908 // A perspective origin of 0,0 makes the vanishing point in the center of th
e element. | |
| 909 // We want it to be in the top-left, so subtract half the height and width. | |
| 910 perspectiveOriginX -= boxWidth / 2.0f; | |
| 911 perspectiveOriginY -= boxHeight / 2.0f; | |
| 912 | |
| 913 TransformationMatrix t; | |
| 914 t.translate(perspectiveOriginX, perspectiveOriginY); | |
| 915 t.applyPerspective(style->perspective()); | |
| 916 t.translate(-perspectiveOriginX, -perspectiveOriginY); | |
| 917 | |
| 918 return t; | |
| 919 } | |
| 920 | |
| 921 FloatPoint RenderLayer::perspectiveOrigin() const | |
| 922 { | |
| 923 if (!renderer()->hasTransformRelatedProperty()) | |
| 924 return FloatPoint(); | |
| 925 | |
| 926 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect(); | |
| 927 RenderStyle* style = renderer()->style(); | |
| 928 | |
| 929 return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox
.width().toFloat()), floatValueForLength(style->perspectiveOriginY(), borderBox.
height().toFloat())); | |
| 930 } | |
| 931 | |
| 932 static inline bool isFixedPositionedContainer(RenderLayer* layer) | |
| 933 { | |
| 934 return layer->isRootLayer() || layer->hasTransformRelatedProperty(); | |
| 935 } | |
| 936 | |
| 937 RenderLayer* RenderLayer::enclosingPositionedAncestor() const | |
| 938 { | |
| 939 RenderLayer* curr = parent(); | |
| 940 while (curr && !curr->isPositionedContainer()) | |
| 941 curr = curr->parent(); | |
| 942 | |
| 943 return curr; | |
| 944 } | |
| 945 | |
| 946 RenderLayer* RenderLayer::enclosingTransformedAncestor() const | |
| 947 { | |
| 948 RenderLayer* curr = parent(); | |
| 949 while (curr && !curr->isRootLayer() && !curr->renderer()->hasTransformRelate
dProperty()) | |
| 950 curr = curr->parent(); | |
| 951 | |
| 952 return curr; | |
| 953 } | |
| 954 | |
| 955 LayoutPoint RenderLayer::computeOffsetFromTransformedAncestor() const | |
| 956 { | |
| 957 const AncestorDependentCompositingInputs& properties = ancestorDependentComp
ositingInputs(); | |
| 958 | |
| 959 TransformState transformState(TransformState::ApplyTransformDirection, Float
Point()); | |
| 960 // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip
are correct. | |
| 961 renderer()->mapLocalToContainer(properties.transformAncestor ? properties.tr
ansformAncestor->renderer() : 0, transformState, ApplyContainerFlip); | |
| 962 transformState.flatten(); | |
| 963 return LayoutPoint(transformState.lastPlanarPoint()); | |
| 964 } | |
| 965 | |
| 966 const RenderLayer* RenderLayer::compositingContainer() const | |
| 967 { | |
| 968 if (stackingNode()->isNormalFlowOnly()) | |
| 969 return parent(); | |
| 970 if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestor
StackingContextNode()) | |
| 971 return ancestorStackingNode->layer(); | |
| 972 return 0; | |
| 973 } | |
| 974 | |
| 975 bool RenderLayer::isPaintInvalidationContainer() const | |
| 976 { | |
| 977 return compositingState() == PaintsIntoOwnBacking || compositingState() == P
aintsIntoGroupedBacking; | |
| 978 } | |
| 979 | |
| 980 // Note: enclosingCompositingLayer does not include squashed layers. Compositing
stacking children of squashed layers | |
| 981 // receive graphics layers that are parented to the compositing ancestor of the
squashed layer. | |
| 982 RenderLayer* RenderLayer::enclosingLayerWithCompositedLayerMapping(IncludeSelfOr
Not includeSelf) const | |
| 983 { | |
| 984 ASSERT(isAllowedToQueryCompositingState()); | |
| 985 | |
| 986 if ((includeSelf == IncludeSelf) && compositingState() != NotComposited && c
ompositingState() != PaintsIntoGroupedBacking) | |
| 987 return const_cast<RenderLayer*>(this); | |
| 988 | |
| 989 for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->co
mpositingContainer()) { | |
| 990 if (curr->compositingState() != NotComposited && curr->compositingState(
) != PaintsIntoGroupedBacking) | |
| 991 return const_cast<RenderLayer*>(curr); | |
| 992 } | |
| 993 | |
| 994 return 0; | |
| 995 } | |
| 996 | |
| 997 // Return the enclosingCompositedLayerForPaintInvalidation for the given RenderL
ayer | |
| 998 // including crossing frame boundaries. | |
| 999 RenderLayer* RenderLayer::enclosingLayerForPaintInvalidationCrossingFrameBoundar
ies() const | |
| 1000 { | |
| 1001 const RenderLayer* layer = this; | |
| 1002 RenderLayer* compositedLayer = 0; | |
| 1003 while (!compositedLayer) { | |
| 1004 compositedLayer = layer->enclosingLayerForPaintInvalidation(); | |
| 1005 if (!compositedLayer) { | |
| 1006 RenderObject* owner = layer->renderer()->frame()->ownerRenderer(); | |
| 1007 if (!owner) | |
| 1008 break; | |
| 1009 layer = owner->enclosingLayer(); | |
| 1010 } | |
| 1011 } | |
| 1012 return compositedLayer; | |
| 1013 } | |
| 1014 | |
| 1015 RenderLayer* RenderLayer::enclosingLayerForPaintInvalidation() const | |
| 1016 { | |
| 1017 ASSERT(isAllowedToQueryCompositingState()); | |
| 1018 | |
| 1019 if (isPaintInvalidationContainer()) | |
| 1020 return const_cast<RenderLayer*>(this); | |
| 1021 | |
| 1022 for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->co
mpositingContainer()) { | |
| 1023 if (curr->isPaintInvalidationContainer()) | |
| 1024 return const_cast<RenderLayer*>(curr); | |
| 1025 } | |
| 1026 | |
| 1027 return 0; | |
| 1028 } | |
| 1029 | |
| 1030 void RenderLayer::setNeedsCompositingInputsUpdate() | |
| 1031 { | |
| 1032 m_needsAncestorDependentCompositingInputsUpdate = true; | |
| 1033 m_needsDescendantDependentCompositingInputsUpdate = true; | |
| 1034 | |
| 1035 for (RenderLayer* current = this; current && !current->m_childNeedsCompositi
ngInputsUpdate; current = current->parent()) | |
| 1036 current->m_childNeedsCompositingInputsUpdate = true; | |
| 1037 | |
| 1038 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInp
utChange); | |
| 1039 } | |
| 1040 | |
| 1041 void RenderLayer::updateAncestorDependentCompositingInputs(const AncestorDepende
ntCompositingInputs& compositingInputs) | |
| 1042 { | |
| 1043 m_ancestorDependentCompositingInputs = compositingInputs; | |
| 1044 m_needsAncestorDependentCompositingInputsUpdate = false; | |
| 1045 } | |
| 1046 | |
| 1047 void RenderLayer::updateDescendantDependentCompositingInputs(const DescendantDep
endentCompositingInputs& compositingInputs) | |
| 1048 { | |
| 1049 m_descendantDependentCompositingInputs = compositingInputs; | |
| 1050 m_needsDescendantDependentCompositingInputsUpdate = false; | |
| 1051 } | |
| 1052 | |
| 1053 void RenderLayer::didUpdateCompositingInputs() | |
| 1054 { | |
| 1055 ASSERT(!needsCompositingInputsUpdate()); | |
| 1056 m_childNeedsCompositingInputsUpdate = false; | |
| 1057 if (m_scrollableArea) | |
| 1058 m_scrollableArea->updateNeedsCompositedScrolling(); | |
| 1059 } | |
| 1060 | |
| 1061 bool RenderLayer::hasNonIsolatedDescendantWithBlendMode() const | |
| 1062 { | |
| 1063 if (descendantDependentCompositingInputs().hasNonIsolatedDescendantWithBlend
Mode) | |
| 1064 return true; | |
| 1065 if (renderer()->isSVGRoot()) | |
| 1066 return toRenderSVGRoot(renderer())->hasNonIsolatedBlendingDescendants(); | |
| 1067 return false; | |
| 1068 } | |
| 1069 | |
| 1070 void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingR
easons mask) | |
| 1071 { | |
| 1072 if ((compositingReasons() & mask) == (reasons & mask)) | |
| 1073 return; | |
| 1074 m_compositingReasons = (reasons & mask) | (compositingReasons() & ~mask); | |
| 1075 } | |
| 1076 | |
| 1077 void RenderLayer::setHasCompositingDescendant(bool hasCompositingDescendant) | |
| 1078 { | |
| 1079 if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescen
dant)) | |
| 1080 return; | |
| 1081 | |
| 1082 m_hasCompositingDescendant = hasCompositingDescendant; | |
| 1083 | |
| 1084 if (hasCompositedLayerMapping()) | |
| 1085 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdat
eLocal); | |
| 1086 } | |
| 1087 | |
| 1088 void RenderLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateCompos
itedDescendants) | |
| 1089 { | |
| 1090 if (m_shouldIsolateCompositedDescendants == static_cast<unsigned>(shouldIsol
ateCompositedDescendants)) | |
| 1091 return; | |
| 1092 | |
| 1093 m_shouldIsolateCompositedDescendants = shouldIsolateCompositedDescendants; | |
| 1094 | |
| 1095 if (hasCompositedLayerMapping()) | |
| 1096 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdat
eLocal); | |
| 1097 } | |
| 1098 | |
| 1099 bool RenderLayer::hasAncestorWithFilterOutsets() const | |
| 1100 { | |
| 1101 for (const RenderLayer* curr = this; curr; curr = curr->parent()) { | |
| 1102 RenderLayerModelObject* renderer = curr->renderer(); | |
| 1103 if (renderer->style()->hasFilterOutsets()) | |
| 1104 return true; | |
| 1105 } | |
| 1106 return false; | |
| 1107 } | |
| 1108 | |
| 1109 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons
t RenderLayer* layer, const RenderLayer* rootLayer, | |
| 1110 RenderLayer::TransparencyClipBoxBehavior transparencyBehavior, const LayoutS
ize& subPixelAccumulation, PaintBehavior paintBehavior) | |
| 1111 { | |
| 1112 // If we have a mask, then the clip is limited to the border box area (and t
here is | |
| 1113 // no need to examine child layers). | |
| 1114 if (!layer->renderer()->hasMask()) { | |
| 1115 // Note: we don't have to walk z-order lists since transparent elements
always establish | |
| 1116 // a stacking container. This means we can just walk the layer tree dire
ctly. | |
| 1117 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSib
ling()) { | |
| 1118 if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionL
ayer() != curr) | |
| 1119 clipRect.unite(RenderLayer::transparencyClipBox(curr, rootLayer,
transparencyBehavior, RenderLayer::DescendantsOfTransparencyClipBox, subPixelAc
cumulation, paintBehavior)); | |
| 1120 } | |
| 1121 } | |
| 1122 | |
| 1123 // If we have a reflection, then we need to account for that when we push th
e clip. Reflect our entire | |
| 1124 // current transparencyClipBox to catch all child layers. | |
| 1125 // FIXME: Accelerated compositing will eventually want to do something smart
here to avoid incorporating this | |
| 1126 // size into the parent layer. | |
| 1127 if (layer->renderer()->hasReflection()) { | |
| 1128 LayoutPoint delta; | |
| 1129 layer->convertToLayerCoords(rootLayer, delta); | |
| 1130 clipRect.move(-delta.x(), -delta.y()); | |
| 1131 clipRect.unite(layer->renderBox()->reflectedRect(clipRect)); | |
| 1132 clipRect.moveBy(delta); | |
| 1133 } | |
| 1134 } | |
| 1135 | |
| 1136 LayoutRect RenderLayer::transparencyClipBox(const RenderLayer* layer, const Rend
erLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior, | |
| 1137 TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumula
tion, PaintBehavior paintBehavior) | |
| 1138 { | |
| 1139 // FIXME: Although this function completely ignores CSS-imposed clipping, we
did already intersect with the | |
| 1140 // paintDirtyRect, and that should cut down on the amount we have to paint.
Still it | |
| 1141 // would be better to respect clips. | |
| 1142 | |
| 1143 if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClip
Box && layer->paintsWithTransform(paintBehavior)) | |
| 1144 || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasT
ransformRelatedProperty()))) { | |
| 1145 // The best we can do here is to use enclosed bounding boxes to establis
h a "fuzzy" enough clip to encompass | |
| 1146 // the transformed layer and all of its children. | |
| 1147 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTr
ansparencyClipBox ? layer->enclosingPaginationLayer() : 0; | |
| 1148 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationL
ayer : rootLayer; | |
| 1149 LayoutPoint delta; | |
| 1150 layer->convertToLayerCoords(rootLayerForTransform, delta); | |
| 1151 | |
| 1152 delta.move(subPixelAccumulation); | |
| 1153 IntPoint pixelSnappedDelta = roundedIntPoint(delta); | |
| 1154 TransformationMatrix transform; | |
| 1155 transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y()); | |
| 1156 transform = transform * *layer->transform(); | |
| 1157 | |
| 1158 // We don't use fragment boxes when collecting a transformed layer's bou
nding box, since it always | |
| 1159 // paints unfragmented. | |
| 1160 LayoutRect clipRect = layer->physicalBoundingBox(layer); | |
| 1161 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transp
arencyBehavior, subPixelAccumulation, paintBehavior); | |
| 1162 clipRect.expand(layer->renderer()->style()->filterOutsets()); | |
| 1163 LayoutRect result = transform.mapRect(clipRect); | |
| 1164 if (!paginationLayer) | |
| 1165 return result; | |
| 1166 | |
| 1167 // We have to break up the transformed extent across our columns. | |
| 1168 // Split our box up into the actual fragment boxes that render in the co
lumns/pages and unite those together to | |
| 1169 // get our true bounding box. | |
| 1170 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLay
er->renderer()); | |
| 1171 result = enclosingFlowThread->fragmentsBoundingBox(result); | |
| 1172 | |
| 1173 LayoutPoint rootLayerDelta; | |
| 1174 paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta); | |
| 1175 result.moveBy(rootLayerDelta); | |
| 1176 return result; | |
| 1177 } | |
| 1178 | |
| 1179 LayoutRect clipRect = layer->fragmentsBoundingBox(rootLayer); | |
| 1180 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transp
arencyBehavior, subPixelAccumulation, paintBehavior); | |
| 1181 clipRect.expand(layer->renderer()->style()->filterOutsets()); | |
| 1182 clipRect.move(subPixelAccumulation); | |
| 1183 return clipRect; | |
| 1184 } | |
| 1185 | |
| 1186 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const Layou
tRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior pai
ntBehavior) | |
| 1187 { | |
| 1188 return intersection(transparencyClipBox(this, rootLayer, PaintingTransparenc
yClipBox, RootOfTransparencyClipBox, subPixelAccumulation, paintBehavior), paint
DirtyRect); | |
| 1189 } | |
| 1190 | |
| 1191 void* RenderLayer::operator new(size_t sz) | |
| 1192 { | |
| 1193 return partitionAlloc(Partitions::getRenderingPartition(), sz); | |
| 1194 } | |
| 1195 | |
| 1196 void RenderLayer::operator delete(void* ptr) | |
| 1197 { | |
| 1198 partitionFree(ptr); | |
| 1199 } | |
| 1200 | |
| 1201 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) | |
| 1202 { | |
| 1203 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : la
stChild(); | |
| 1204 if (prevSibling) { | |
| 1205 child->setPreviousSibling(prevSibling); | |
| 1206 prevSibling->setNextSibling(child); | |
| 1207 ASSERT(prevSibling != child); | |
| 1208 } else | |
| 1209 setFirstChild(child); | |
| 1210 | |
| 1211 if (beforeChild) { | |
| 1212 beforeChild->setPreviousSibling(child); | |
| 1213 child->setNextSibling(beforeChild); | |
| 1214 ASSERT(beforeChild != child); | |
| 1215 } else | |
| 1216 setLastChild(child); | |
| 1217 | |
| 1218 child->m_parent = this; | |
| 1219 | |
| 1220 setNeedsCompositingInputsUpdate(); | |
| 1221 | |
| 1222 if (child->stackingNode()->isNormalFlowOnly()) | |
| 1223 m_stackingNode->dirtyNormalFlowList(); | |
| 1224 | |
| 1225 if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) { | |
| 1226 // Dirty the z-order list in which we are contained. The ancestorStackin
gContextNode() can be null in the | |
| 1227 // case where we're building up generated content layers. This is ok, si
nce the lists will start | |
| 1228 // off dirty in that case anyway. | |
| 1229 child->stackingNode()->dirtyStackingContextZOrderLists(); | |
| 1230 } | |
| 1231 | |
| 1232 dirtyAncestorChainVisibleDescendantStatus(); | |
| 1233 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); | |
| 1234 | |
| 1235 child->updateDescendantDependentFlags(); | |
| 1236 } | |
| 1237 | |
| 1238 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) | |
| 1239 { | |
| 1240 if (oldChild->previousSibling()) | |
| 1241 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); | |
| 1242 if (oldChild->nextSibling()) | |
| 1243 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling())
; | |
| 1244 | |
| 1245 if (m_first == oldChild) | |
| 1246 m_first = oldChild->nextSibling(); | |
| 1247 if (m_last == oldChild) | |
| 1248 m_last = oldChild->previousSibling(); | |
| 1249 | |
| 1250 if (oldChild->stackingNode()->isNormalFlowOnly()) | |
| 1251 m_stackingNode->dirtyNormalFlowList(); | |
| 1252 if (!oldChild->stackingNode()->isNormalFlowOnly() || oldChild->firstChild())
{ | |
| 1253 // Dirty the z-order list in which we are contained. When called via th
e | |
| 1254 // reattachment process in removeOnlyThisLayer, the layer may already be
disconnected | |
| 1255 // from the main layer tree, so we need to null-check the | |
| 1256 // |stackingContext| value. | |
| 1257 oldChild->stackingNode()->dirtyStackingContextZOrderLists(); | |
| 1258 } | |
| 1259 | |
| 1260 if (renderer()->style()->visibility() != VISIBLE) | |
| 1261 dirtyVisibleContentStatus(); | |
| 1262 | |
| 1263 oldChild->setPreviousSibling(0); | |
| 1264 oldChild->setNextSibling(0); | |
| 1265 oldChild->m_parent = 0; | |
| 1266 | |
| 1267 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); | |
| 1268 | |
| 1269 oldChild->updateDescendantDependentFlags(); | |
| 1270 | |
| 1271 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) | |
| 1272 dirtyAncestorChainVisibleDescendantStatus(); | |
| 1273 | |
| 1274 if (oldChild->enclosingPaginationLayer()) | |
| 1275 oldChild->clearPaginationRecursive(); | |
| 1276 | |
| 1277 return oldChild; | |
| 1278 } | |
| 1279 | |
| 1280 void RenderLayer::removeOnlyThisLayer() | |
| 1281 { | |
| 1282 if (!m_parent) | |
| 1283 return; | |
| 1284 | |
| 1285 { | |
| 1286 DisableCompositingQueryAsserts disabler; // We need the current composit
ing status. | |
| 1287 if (isPaintInvalidationContainer()) { | |
| 1288 // Our children will be reparented and contained by a new paint inva
lidation container, | |
| 1289 // so need paint invalidation. CompositingUpdate can't see this laye
r (which has been | |
| 1290 // removed) so won't do this for us. | |
| 1291 setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants()
; | |
| 1292 } | |
| 1293 } | |
| 1294 | |
| 1295 m_clipper.clearClipRectsIncludingDescendants(); | |
| 1296 | |
| 1297 RenderLayer* nextSib = nextSibling(); | |
| 1298 | |
| 1299 // Remove the child reflection layer before moving other child layers. | |
| 1300 // The reflection layer should not be moved to the parent. | |
| 1301 if (m_reflectionInfo) | |
| 1302 removeChild(m_reflectionInfo->reflectionLayer()); | |
| 1303 | |
| 1304 // Now walk our kids and reattach them to our parent. | |
| 1305 RenderLayer* current = m_first; | |
| 1306 while (current) { | |
| 1307 RenderLayer* next = current->nextSibling(); | |
| 1308 removeChild(current); | |
| 1309 m_parent->addChild(current, nextSib); | |
| 1310 | |
| 1311 // FIXME: We should call a specialized version of this function. | |
| 1312 current->updateLayerPositionsAfterLayout(); | |
| 1313 current = next; | |
| 1314 } | |
| 1315 | |
| 1316 // Remove us from the parent. | |
| 1317 m_parent->removeChild(this); | |
| 1318 m_renderer->destroyLayer(); | |
| 1319 } | |
| 1320 | |
| 1321 void RenderLayer::insertOnlyThisLayer() | |
| 1322 { | |
| 1323 if (!m_parent && renderer()->parent()) { | |
| 1324 // We need to connect ourselves when our renderer() has a parent. | |
| 1325 // Find our enclosingLayer and add ourselves. | |
| 1326 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); | |
| 1327 ASSERT(parentLayer); | |
| 1328 RenderLayer* beforeChild = !parentLayer->reflectionInfo() || parentLayer
->reflectionInfo()->reflectionLayer() != this ? renderer()->parent()->findNextLa
yer(parentLayer, renderer()) : 0; | |
| 1329 parentLayer->addChild(this, beforeChild); | |
| 1330 } | |
| 1331 | |
| 1332 // Remove all descendant layers from the hierarchy and add them to the new p
osition. | |
| 1333 for (RenderObject* curr = renderer()->slowFirstChild(); curr; curr = curr->n
extSibling()) | |
| 1334 curr->moveLayers(m_parent, this); | |
| 1335 | |
| 1336 // Clear out all the clip rects. | |
| 1337 m_clipper.clearClipRectsIncludingDescendants(); | |
| 1338 } | |
| 1339 | |
| 1340 // Returns the layer reached on the walk up towards the ancestor. | |
| 1341 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
er* layer, const RenderLayer* ancestorLayer, LayoutPoint& location) | |
| 1342 { | |
| 1343 ASSERT(ancestorLayer != layer); | |
| 1344 | |
| 1345 const RenderLayerModelObject* renderer = layer->renderer(); | |
| 1346 EPosition position = renderer->style()->position(); | |
| 1347 | |
| 1348 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in
a RenderFlowThread | |
| 1349 // may need to be revisited in a future patch. | |
| 1350 // If the fixed renderer is inside a RenderFlowThread, we should not compute
location using localToAbsolute, | |
| 1351 // since localToAbsolute maps the coordinates from flow thread to regions co
ordinates and regions can be | |
| 1352 // positioned in a completely different place in the viewport (RenderView). | |
| 1353 if (position == FixedPosition && (!ancestorLayer || ancestorLayer == rendere
r->view()->layer())) { | |
| 1354 // If the fixed layer's container is the root, just add in the offset of
the view. We can obtain this by calling | |
| 1355 // localToAbsolute() on the RenderView. | |
| 1356 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed); | |
| 1357 location += LayoutSize(absPos.x(), absPos.y()); | |
| 1358 return ancestorLayer; | |
| 1359 } | |
| 1360 | |
| 1361 // For the fixed positioned elements inside a render flow thread, we should
also skip the code path below | |
| 1362 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positione
d element child of a transformed | |
| 1363 // element in render flow thread, we will hit the fixed positioned container
before hitting the ancestor layer. | |
| 1364 if (position == FixedPosition) { | |
| 1365 // For a fixed layers, we need to walk up to the root to see if there's
a fixed position container | |
| 1366 // (e.g. a transformed layer). It's an error to call convertToLayerCoord
s() across a layer with a transform, | |
| 1367 // so we should always find the ancestor at or before we find the fixed
position container. | |
| 1368 RenderLayer* fixedPositionContainerLayer = 0; | |
| 1369 bool foundAncestor = false; | |
| 1370 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = cu
rrLayer->parent()) { | |
| 1371 if (currLayer == ancestorLayer) | |
| 1372 foundAncestor = true; | |
| 1373 | |
| 1374 if (isFixedPositionedContainer(currLayer)) { | |
| 1375 fixedPositionContainerLayer = currLayer; | |
| 1376 ASSERT_UNUSED(foundAncestor, foundAncestor); | |
| 1377 break; | |
| 1378 } | |
| 1379 } | |
| 1380 | |
| 1381 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderVie
w's layer at least. | |
| 1382 | |
| 1383 if (fixedPositionContainerLayer != ancestorLayer) { | |
| 1384 LayoutPoint fixedContainerCoords; | |
| 1385 layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContai
nerCoords); | |
| 1386 | |
| 1387 LayoutPoint ancestorCoords; | |
| 1388 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, anc
estorCoords); | |
| 1389 | |
| 1390 location += (fixedContainerCoords - ancestorCoords); | |
| 1391 } else { | |
| 1392 // RenderView has been handled in the first top-level 'if' block abo
ve. | |
| 1393 ASSERT(ancestorLayer != renderer->view()->layer()); | |
| 1394 ASSERT(ancestorLayer->hasTransformRelatedProperty()); | |
| 1395 | |
| 1396 location += layer->location(); | |
| 1397 | |
| 1398 // The spec (http://dev.w3.org/csswg/css-transforms/#transform-rende
ring) doesn't say if a | |
| 1399 // fixed-position element under a scrollable transformed element sho
uld scroll. However, | |
| 1400 // other parts of blink scroll the fixed-position element, and the f
ollowing keeps the consistency. | |
| 1401 if (RenderLayerScrollableArea* scrollableArea = ancestorLayer->scrol
lableArea()) | |
| 1402 location -= LayoutSize(scrollableArea->scrollOffset()); | |
| 1403 } | |
| 1404 return ancestorLayer; | |
| 1405 } | |
| 1406 | |
| 1407 RenderLayer* parentLayer; | |
| 1408 if (position == AbsolutePosition) { | |
| 1409 // Do what enclosingPositionedAncestor() does, but check for ancestorLay
er along the way. | |
| 1410 parentLayer = layer->parent(); | |
| 1411 bool foundAncestorFirst = false; | |
| 1412 while (parentLayer) { | |
| 1413 // RenderFlowThread is a positioned container, child of RenderView,
positioned at (0,0). | |
| 1414 // This implies that, for out-of-flow positioned elements inside a R
enderFlowThread, | |
| 1415 // we are bailing out before reaching root layer. | |
| 1416 if (parentLayer->isPositionedContainer()) | |
| 1417 break; | |
| 1418 | |
| 1419 if (parentLayer == ancestorLayer) { | |
| 1420 foundAncestorFirst = true; | |
| 1421 break; | |
| 1422 } | |
| 1423 | |
| 1424 parentLayer = parentLayer->parent(); | |
| 1425 } | |
| 1426 | |
| 1427 // We should not reach RenderView layer past the RenderFlowThread layer
for any | |
| 1428 // children of the RenderFlowThread. | |
| 1429 ASSERT(!renderer->flowThreadContainingBlock() || parentLayer != renderer
->view()->layer()); | |
| 1430 | |
| 1431 if (foundAncestorFirst) { | |
| 1432 // Found ancestorLayer before the abs. positioned container, so comp
ute offset of both relative | |
| 1433 // to enclosingPositionedAncestor and subtract. | |
| 1434 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAn
cestor(); | |
| 1435 | |
| 1436 LayoutPoint thisCoords; | |
| 1437 layer->convertToLayerCoords(positionedAncestor, thisCoords); | |
| 1438 | |
| 1439 LayoutPoint ancestorCoords; | |
| 1440 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoor
ds); | |
| 1441 | |
| 1442 location += (thisCoords - ancestorCoords); | |
| 1443 return ancestorLayer; | |
| 1444 } | |
| 1445 } else if (renderer->isColumnSpanAll()) { | |
| 1446 RenderBlock* multicolContainer = renderer->containingBlock(); | |
| 1447 ASSERT(toRenderBlockFlow(multicolContainer)->multiColumnFlowThread()); | |
| 1448 parentLayer = multicolContainer->layer(); | |
| 1449 ASSERT(parentLayer); | |
| 1450 } else { | |
| 1451 parentLayer = layer->parent(); | |
| 1452 } | |
| 1453 | |
| 1454 if (!parentLayer) | |
| 1455 return 0; | |
| 1456 | |
| 1457 location += layer->location(); | |
| 1458 return parentLayer; | |
| 1459 } | |
| 1460 | |
| 1461 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutP
oint& location) const | |
| 1462 { | |
| 1463 if (ancestorLayer == this) | |
| 1464 return; | |
| 1465 | |
| 1466 const RenderLayer* currLayer = this; | |
| 1467 while (currLayer && currLayer != ancestorLayer) | |
| 1468 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, lo
cation); | |
| 1469 } | |
| 1470 | |
| 1471 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutR
ect& rect) const | |
| 1472 { | |
| 1473 LayoutPoint delta; | |
| 1474 convertToLayerCoords(ancestorLayer, delta); | |
| 1475 rect.moveBy(delta); | |
| 1476 } | |
| 1477 | |
| 1478 LayoutPoint RenderLayer::visualOffsetFromAncestor(const RenderLayer* ancestorLay
er) const | |
| 1479 { | |
| 1480 LayoutPoint offset; | |
| 1481 if (ancestorLayer == this) | |
| 1482 return offset; | |
| 1483 RenderLayer* paginationLayer = enclosingPaginationLayer(); | |
| 1484 if (paginationLayer == this) | |
| 1485 paginationLayer = parent()->enclosingPaginationLayer(); | |
| 1486 if (!paginationLayer) { | |
| 1487 convertToLayerCoords(ancestorLayer, offset); | |
| 1488 return offset; | |
| 1489 } | |
| 1490 | |
| 1491 RenderFlowThread* flowThread = toRenderFlowThread(paginationLayer->renderer(
)); | |
| 1492 convertToLayerCoords(paginationLayer, offset); | |
| 1493 offset = flowThread->flowThreadPointToVisualPoint(offset); | |
| 1494 if (ancestorLayer == paginationLayer) | |
| 1495 return offset; | |
| 1496 | |
| 1497 if (ancestorLayer->enclosingPaginationLayer() != paginationLayer) { | |
| 1498 offset.moveBy(paginationLayer->visualOffsetFromAncestor(ancestorLayer)); | |
| 1499 } else { | |
| 1500 // The ancestor layer is also inside the pagination layer, so we need to
subtract the visual | |
| 1501 // distance from the ancestor layer to the pagination layer. | |
| 1502 offset.moveBy(-ancestorLayer->visualOffsetFromAncestor(paginationLayer))
; | |
| 1503 } | |
| 1504 return offset; | |
| 1505 } | |
| 1506 | |
| 1507 void RenderLayer::didUpdateNeedsCompositedScrolling() | |
| 1508 { | |
| 1509 updateSelfPaintingLayer(); | |
| 1510 } | |
| 1511 | |
| 1512 void RenderLayer::updateReflectionInfo(const RenderStyle* oldStyle) | |
| 1513 { | |
| 1514 ASSERT(!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)
); | |
| 1515 if (renderer()->hasReflection()) { | |
| 1516 if (!m_reflectionInfo) | |
| 1517 m_reflectionInfo = adoptPtr(new RenderLayerReflectionInfo(*renderBox
())); | |
| 1518 m_reflectionInfo->updateAfterStyleChange(oldStyle); | |
| 1519 } else if (m_reflectionInfo) { | |
| 1520 m_reflectionInfo->destroy(); | |
| 1521 m_reflectionInfo = nullptr; | |
| 1522 } | |
| 1523 } | |
| 1524 | |
| 1525 void RenderLayer::updateStackingNode() | |
| 1526 { | |
| 1527 if (requiresStackingNode()) | |
| 1528 m_stackingNode = adoptPtr(new RenderLayerStackingNode(this)); | |
| 1529 else | |
| 1530 m_stackingNode = nullptr; | |
| 1531 } | |
| 1532 | |
| 1533 void RenderLayer::updateScrollableArea() | |
| 1534 { | |
| 1535 if (requiresScrollableArea()) | |
| 1536 m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(*this)); | |
| 1537 else | |
| 1538 m_scrollableArea = nullptr; | |
| 1539 } | |
| 1540 | |
| 1541 bool RenderLayer::hasOverflowControls() const | |
| 1542 { | |
| 1543 return m_scrollableArea && (m_scrollableArea->hasScrollbar() || m_scrollable
Area->scrollCorner() || renderer()->style()->resize() != RESIZE_NONE); | |
| 1544 } | |
| 1545 | |
| 1546 void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer*
rootLayer, const LayoutRect& dirtyRect, | |
| 1547 ClipRectsCacheSlot clipRectsCacheSlot, OverlayScrollbarSizeRelevancy inOverl
ayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const L
ayoutPoint* offsetFromRoot, | |
| 1548 const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox) | |
| 1549 { | |
| 1550 if (!enclosingPaginationLayer() || hasTransformRelatedProperty()) { | |
| 1551 // For unpaginated layers, there is only one fragment. | |
| 1552 LayerFragment fragment; | |
| 1553 ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverl
ayScrollbarSizeRelevancy, subPixelAccumulation); | |
| 1554 if (respectOverflowClip == IgnoreOverflowClip) | |
| 1555 clipRectsContext.setIgnoreOverflowClip(); | |
| 1556 clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBoun
ds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offs
etFromRoot); | |
| 1557 fragments.append(fragment); | |
| 1558 return; | |
| 1559 } | |
| 1560 | |
| 1561 // Compute our offset within the enclosing pagination layer. | |
| 1562 LayoutPoint offsetWithinPaginatedLayer; | |
| 1563 convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer)
; | |
| 1564 | |
| 1565 // Calculate clip rects relative to the enclosingPaginationLayer. The purpos
e of this call is to determine our bounds clipped to intermediate | |
| 1566 // 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. | |
| 1567 ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clip
RectsCacheSlot, inOverlayScrollbarSizeRelevancy); | |
| 1568 if (respectOverflowClip == IgnoreOverflowClip) | |
| 1569 paginationClipRectsContext.setIgnoreOverflowClip(); | |
| 1570 LayoutRect layerBoundsInFlowThread; | |
| 1571 ClipRect backgroundRectInFlowThread; | |
| 1572 ClipRect foregroundRectInFlowThread; | |
| 1573 ClipRect outlineRectInFlowThread; | |
| 1574 clipper().calculateRects(paginationClipRectsContext, LayoutRect::infiniteInt
Rect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlo
wThread, | |
| 1575 outlineRectInFlowThread, &offsetWithinPaginatedLayer); | |
| 1576 | |
| 1577 // Take our bounding box within the flow thread and clip it. | |
| 1578 LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingB
ox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer
); | |
| 1579 layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect()); | |
| 1580 | |
| 1581 // Make the dirty rect relative to the fragmentation context (multicol conta
iner, etc.). | |
| 1582 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginati
onLayer()->renderer()); | |
| 1583 LayoutPoint offsetOfPaginationLayerFromRoot; // Visual offset from the root
layer to the nearest fragmentation context. | |
| 1584 bool rootLayerIsInsidePaginationLayer = rootLayer->enclosingPaginationLayer(
) == enclosingPaginationLayer(); | |
| 1585 if (rootLayerIsInsidePaginationLayer) { | |
| 1586 // The root layer is in the same fragmentation context as this layer, so
we need to look | |
| 1587 // inside it and subtract the offset between the fragmentation context a
nd the root layer. | |
| 1588 offsetOfPaginationLayerFromRoot = -rootLayer->visualOffsetFromAncestor(e
nclosingPaginationLayer()); | |
| 1589 } else { | |
| 1590 offsetOfPaginationLayerFromRoot = enclosingPaginationLayer()->visualOffs
etFromAncestor(rootLayer); | |
| 1591 } | |
| 1592 LayoutRect dirtyRectInFlowThread(dirtyRect); | |
| 1593 dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot); | |
| 1594 | |
| 1595 // Tell the flow thread to collect the fragments. We pass enough information
to create a minimal number of fragments based off the pages/columns | |
| 1596 // that intersect the actual dirtyRect as well as the pages/columns that int
ersect our layer's bounding box. | |
| 1597 enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlow
Thread, dirtyRectInFlowThread); | |
| 1598 | |
| 1599 if (fragments.isEmpty()) | |
| 1600 return; | |
| 1601 | |
| 1602 // Get the parent clip rects of the pagination layer, since we need to inter
sect with that when painting column contents. | |
| 1603 ClipRect ancestorClipRect = dirtyRect; | |
| 1604 if (const RenderLayer* paginationParentLayer = enclosingPaginationLayer()->p
arent()) { | |
| 1605 const RenderLayer* ancestorLayer = rootLayerIsInsidePaginationLayer ? pa
ginationParentLayer : rootLayer; | |
| 1606 ClipRectsContext clipRectsContext(ancestorLayer, clipRectsCacheSlot, inO
verlayScrollbarSizeRelevancy); | |
| 1607 if (respectOverflowClip == IgnoreOverflowClip) | |
| 1608 clipRectsContext.setIgnoreOverflowClip(); | |
| 1609 ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipR
ect(clipRectsContext); | |
| 1610 if (rootLayerIsInsidePaginationLayer) | |
| 1611 ancestorClipRect.moveBy(-rootLayer->visualOffsetFromAncestor(ancesto
rLayer)); | |
| 1612 ancestorClipRect.intersect(dirtyRect); | |
| 1613 } | |
| 1614 | |
| 1615 for (size_t i = 0; i < fragments.size(); ++i) { | |
| 1616 LayerFragment& fragment = fragments.at(i); | |
| 1617 | |
| 1618 // Set our four rects with all clipping applied that was internal to the
flow thread. | |
| 1619 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, f
oregroundRectInFlowThread, outlineRectInFlowThread); | |
| 1620 | |
| 1621 // Shift to the root-relative physical position used when painting the f
low thread in this fragment. | |
| 1622 fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromR
oot); | |
| 1623 | |
| 1624 // Intersect the fragment with our ancestor's background clip so that e.
g., columns in an overflow:hidden block are | |
| 1625 // properly clipped by the overflow. | |
| 1626 fragment.intersect(ancestorClipRect.rect()); | |
| 1627 | |
| 1628 // Now intersect with our pagination clip. This will typically mean we'r
e just intersecting the dirty rect with the column | |
| 1629 // clip, so the column clip ends up being all we apply. | |
| 1630 fragment.intersect(fragment.paginationClip); | |
| 1631 } | |
| 1632 } | |
| 1633 | |
| 1634 static inline LayoutRect frameVisibleRect(RenderObject* renderer) | |
| 1635 { | |
| 1636 FrameView* frameView = renderer->document().view(); | |
| 1637 if (!frameView) | |
| 1638 return LayoutRect(); | |
| 1639 | |
| 1640 return frameView->visibleContentRect(); | |
| 1641 } | |
| 1642 | |
| 1643 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) | |
| 1644 { | |
| 1645 return hitTest(request, result.hitTestLocation(), result); | |
| 1646 } | |
| 1647 | |
| 1648 bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation&
hitTestLocation, HitTestResult& result) | |
| 1649 { | |
| 1650 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); | |
| 1651 | |
| 1652 // RenderView should make sure to update layout before entering hit testing | |
| 1653 ASSERT(!renderer()->frame()->view()->layoutPending()); | |
| 1654 ASSERT(!renderer()->document().renderView()->needsLayout()); | |
| 1655 | |
| 1656 // Start with frameVisibleRect to ensure we include the scrollbars. | |
| 1657 LayoutRect hitTestArea = frameVisibleRect(renderer()); | |
| 1658 if (request.ignoreClipping()) | |
| 1659 hitTestArea.unite(renderer()->view()->documentRect()); | |
| 1660 | |
| 1661 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestAre
a, hitTestLocation, false); | |
| 1662 if (!insideLayer) { | |
| 1663 // We didn't hit any layer. If we are the root layer and the mouse is --
or just was -- down, | |
| 1664 // return ourselves. We do this so mouse events continue getting deliver
ed after a drag has | |
| 1665 // exited the WebView, and so hit testing over a scrollbar hits the cont
ent document. | |
| 1666 // In addtion, it is possible for the mouse to stay in the document but
there is no element. | |
| 1667 // At that time, the events of the mouse should be fired. | |
| 1668 LayoutPoint hitPoint = hitTestLocation.point(); | |
| 1669 if (!request.isChildFrameHitTest() && ((request.active() || request.rele
ase()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y())))
&& isRootLayer()) { | |
| 1670 renderer()->updateHitTestResult(result, toRenderView(renderer())->fl
ipForWritingMode(hitTestLocation.point())); | |
| 1671 insideLayer = this; | |
| 1672 } | |
| 1673 } | |
| 1674 | |
| 1675 // Now determine if the result is inside an anchor - if the urlElement isn't
already set. | |
| 1676 Node* node = result.innerNode(); | |
| 1677 if (node && !result.URLElement()) | |
| 1678 result.setURLElement(node->enclosingLinkEventParentOrSelf()); | |
| 1679 | |
| 1680 // Now return whether we were inside this layer (this will always be true fo
r the root | |
| 1681 // layer). | |
| 1682 return insideLayer; | |
| 1683 } | |
| 1684 | |
| 1685 Node* RenderLayer::enclosingElement() const | |
| 1686 { | |
| 1687 for (RenderObject* r = renderer(); r; r = r->parent()) { | |
| 1688 if (Node* e = r->node()) | |
| 1689 return e; | |
| 1690 } | |
| 1691 ASSERT_NOT_REACHED(); | |
| 1692 return 0; | |
| 1693 } | |
| 1694 | |
| 1695 bool RenderLayer::isInTopLayer() const | |
| 1696 { | |
| 1697 Node* node = renderer()->node(); | |
| 1698 return node && node->isElementNode() && toElement(node)->isInTopLayer(); | |
| 1699 } | |
| 1700 | |
| 1701 // Compute the z-offset of the point in the transformState. | |
| 1702 // This is effectively projecting a ray normal to the plane of ancestor, finding
where that | |
| 1703 // ray intersects target, and computing the z delta between those two points. | |
| 1704 static double computeZOffset(const HitTestingTransformState& transformState) | |
| 1705 { | |
| 1706 // We got an affine transform, so no z-offset | |
| 1707 if (transformState.m_accumulatedTransform.isAffine()) | |
| 1708 return 0; | |
| 1709 | |
| 1710 // Flatten the point into the target plane | |
| 1711 FloatPoint targetPoint = transformState.mappedPoint(); | |
| 1712 | |
| 1713 // Now map the point back through the transform, which computes Z. | |
| 1714 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoin
t(FloatPoint3D(targetPoint)); | |
| 1715 return backmappedPoint.z(); | |
| 1716 } | |
| 1717 | |
| 1718 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(Rend
erLayer* rootLayer, RenderLayer* containerLayer, | |
| 1719 const LayoutRect& hitTestRect, const Hit
TestLocation& hitTestLocation, | |
| 1720 const HitTestingTransformState* containe
rTransformState, | |
| 1721 const LayoutPoint& translationOffset) co
nst | |
| 1722 { | |
| 1723 RefPtr<HitTestingTransformState> transformState; | |
| 1724 LayoutPoint offset; | |
| 1725 if (containerTransformState) { | |
| 1726 // If we're already computing transform state, then it's relative to the
container (which we know is non-null). | |
| 1727 transformState = HitTestingTransformState::create(*containerTransformSta
te); | |
| 1728 convertToLayerCoords(containerLayer, offset); | |
| 1729 } else { | |
| 1730 // If this is the first time we need to make transform state, then base
it off of hitTestLocation, | |
| 1731 // which is relative to rootLayer. | |
| 1732 transformState = HitTestingTransformState::create(hitTestLocation.transf
ormedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect)); | |
| 1733 convertToLayerCoords(rootLayer, offset); | |
| 1734 } | |
| 1735 offset.moveBy(translationOffset); | |
| 1736 | |
| 1737 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer(
) : 0; | |
| 1738 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) { | |
| 1739 TransformationMatrix containerTransform; | |
| 1740 renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(of
fset), containerTransform); | |
| 1741 transformState->applyTransform(containerTransform, HitTestingTransformSt
ate::AccumulateTransform); | |
| 1742 } else { | |
| 1743 transformState->translate(offset.x(), offset.y(), HitTestingTransformSta
te::AccumulateTransform); | |
| 1744 } | |
| 1745 | |
| 1746 return transformState; | |
| 1747 } | |
| 1748 | |
| 1749 | |
| 1750 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, doubl
e* zOffset, const HitTestingTransformState* transformState) | |
| 1751 { | |
| 1752 if (!hitLayer) | |
| 1753 return false; | |
| 1754 | |
| 1755 // The hit layer is depth-sorting with other layers, so just say that it was
hit. | |
| 1756 if (canDepthSort) | |
| 1757 return true; | |
| 1758 | |
| 1759 // We need to look at z-depth to decide if this layer was hit. | |
| 1760 if (zOffset) { | |
| 1761 ASSERT(transformState); | |
| 1762 // This is actually computing our z, but that's OK because the hitLayer
is coplanar with us. | |
| 1763 double childZOffset = computeZOffset(*transformState); | |
| 1764 if (childZOffset > *zOffset) { | |
| 1765 *zOffset = childZOffset; | |
| 1766 return true; | |
| 1767 } | |
| 1768 return false; | |
| 1769 } | |
| 1770 | |
| 1771 return true; | |
| 1772 } | |
| 1773 | |
| 1774 // hitTestLocation and hitTestRect are relative to rootLayer. | |
| 1775 // A 'flattening' layer is one preserves3D() == false. | |
| 1776 // transformState.m_accumulatedTransform holds the transform from the containing
flattening layer. | |
| 1777 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the c
ontaining flattening layer. | |
| 1778 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of
the containing flattening layer. | |
| 1779 // | |
| 1780 // If zOffset is non-null (which indicates that the caller wants z offset inform
ation), | |
| 1781 // *zOffset on return is the z offset of the hit point relative to the containi
ng flattening layer. | |
| 1782 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
ainerLayer, const HitTestRequest& request, HitTestResult& result, | |
| 1783 const LayoutRect& hitTestRect, const HitT
estLocation& hitTestLocation, bool appliedTransform, | |
| 1784 const HitTestingTransformState* transform
State, double* zOffset) | |
| 1785 { | |
| 1786 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) | |
| 1787 return 0; | |
| 1788 | |
| 1789 // The natural thing would be to keep HitTestingTransformState on the stack,
but it's big, so we heap-allocate. | |
| 1790 | |
| 1791 // Apply a transform if we have one. | |
| 1792 if (transform() && !appliedTransform) { | |
| 1793 if (enclosingPaginationLayer()) | |
| 1794 return hitTestTransformedLayerInFragments(rootLayer, containerLayer,
request, result, hitTestRect, hitTestLocation, transformState, zOffset); | |
| 1795 | |
| 1796 // Make sure the parent's clip rects have been calculated. | |
| 1797 if (parent()) { | |
| 1798 ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(ro
otLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize)); | |
| 1799 // Go ahead and test the enclosing clip now. | |
| 1800 if (!clipRect.intersects(hitTestLocation)) | |
| 1801 return 0; | |
| 1802 } | |
| 1803 | |
| 1804 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, reques
t, result, hitTestRect, hitTestLocation, transformState, zOffset); | |
| 1805 } | |
| 1806 | |
| 1807 // Ensure our lists and 3d status are up-to-date. | |
| 1808 m_stackingNode->updateLayerListsIfNeeded(); | |
| 1809 update3DTransformedDescendantStatus(); | |
| 1810 | |
| 1811 RefPtr<HitTestingTransformState> localTransformState; | |
| 1812 if (appliedTransform) { | |
| 1813 // We computed the correct state in the caller (above code), so just ref
erence it. | |
| 1814 ASSERT(transformState); | |
| 1815 localTransformState = const_cast<HitTestingTransformState*>(transformSta
te); | |
| 1816 } else if (transformState || m_has3DTransformedDescendant || preserves3D())
{ | |
| 1817 // We need transform state for the first time, or to offset the containe
r state, so create it here. | |
| 1818 localTransformState = createLocalTransformState(rootLayer, containerLaye
r, hitTestRect, hitTestLocation, transformState); | |
| 1819 } | |
| 1820 | |
| 1821 // Check for hit test on backface if backface-visibility is 'hidden' | |
| 1822 if (localTransformState && renderer()->style()->backfaceVisibility() == Back
faceVisibilityHidden) { | |
| 1823 TransformationMatrix invertedMatrix = localTransformState->m_accumulated
Transform.inverse(); | |
| 1824 // If the z-vector of the matrix is negative, the back is facing towards
the viewer. | |
| 1825 if (invertedMatrix.m33() < 0) | |
| 1826 return 0; | |
| 1827 } | |
| 1828 | |
| 1829 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformS
tate; | |
| 1830 if (localTransformState && !preserves3D()) { | |
| 1831 // Keep a copy of the pre-flattening state, for computing z-offsets for
the container | |
| 1832 unflattenedTransformState = HitTestingTransformState::create(*localTrans
formState); | |
| 1833 // This layer is flattening, so flatten the state passed to descendants. | |
| 1834 localTransformState->flatten(); | |
| 1835 } | |
| 1836 | |
| 1837 // The following are used for keeping track of the z-depth of the hit point
of 3d-transformed | |
| 1838 // descendants. | |
| 1839 double localZOffset = -std::numeric_limits<double>::infinity(); | |
| 1840 double* zOffsetForDescendantsPtr = 0; | |
| 1841 double* zOffsetForContentsPtr = 0; | |
| 1842 | |
| 1843 bool depthSortDescendants = false; | |
| 1844 if (preserves3D()) { | |
| 1845 depthSortDescendants = true; | |
| 1846 // Our layers can depth-test with our container, so share the z depth po
inter with the container, if it passed one down. | |
| 1847 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; | |
| 1848 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; | |
| 1849 } else if (zOffset) { | |
| 1850 zOffsetForDescendantsPtr = 0; | |
| 1851 // Container needs us to give back a z offset for the hit layer. | |
| 1852 zOffsetForContentsPtr = zOffset; | |
| 1853 } | |
| 1854 | |
| 1855 // This variable tracks which layer the mouse ends up being inside. | |
| 1856 RenderLayer* candidateLayer = 0; | |
| 1857 | |
| 1858 // Begin by walking our list of positive layers from highest z-index down to
the lowest z-index. | |
| 1859 RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, r
equest, result, hitTestRect, hitTestLocation, | |
| 1860 localTransformState.get(), zOffsetForDes
cendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); | |
| 1861 if (hitLayer) { | |
| 1862 if (!depthSortDescendants) | |
| 1863 return hitLayer; | |
| 1864 candidateLayer = hitLayer; | |
| 1865 } | |
| 1866 | |
| 1867 // Now check our overflow objects. | |
| 1868 hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, h
itTestRect, hitTestLocation, | |
| 1869 localTransformState.get(), zOffsetForDescendantsPtr,
zOffset, unflattenedTransformState.get(), depthSortDescendants); | |
| 1870 if (hitLayer) { | |
| 1871 if (!depthSortDescendants) | |
| 1872 return hitLayer; | |
| 1873 candidateLayer = hitLayer; | |
| 1874 } | |
| 1875 | |
| 1876 // Collect the fragments. This will compute the clip rectangles for each lay
er fragment. | |
| 1877 LayerFragments layerFragments; | |
| 1878 collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRec
ts, IncludeOverlayScrollbarSize); | |
| 1879 | |
| 1880 if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFra
gments, hitTestLocation)) { | |
| 1881 renderer()->updateHitTestResult(result, hitTestLocation.point()); | |
| 1882 return this; | |
| 1883 } | |
| 1884 | |
| 1885 // Next we want to see if the mouse pos is inside the child RenderObjects of
the layer. Check | |
| 1886 // every fragment in reverse order. | |
| 1887 if (isSelfPaintingLayer()) { | |
| 1888 // Hit test with a temporary HitTestResult, because we only want to comm
it to 'result' if we know we're frontmost. | |
| 1889 HitTestResult tempResult(result.hitTestLocation()); | |
| 1890 bool insideFragmentForegroundRect = false; | |
| 1891 if (hitTestContentsForFragments(layerFragments, request, tempResult, hit
TestLocation, HitTestDescendants, insideFragmentForegroundRect) | |
| 1892 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra
nsformState.get())) { | |
| 1893 if (result.isRectBasedTest()) | |
| 1894 result.append(tempResult); | |
| 1895 else | |
| 1896 result = tempResult; | |
| 1897 if (!depthSortDescendants) | |
| 1898 return this; | |
| 1899 // Foreground can depth-sort with descendant layers, so keep this as
a candidate. | |
| 1900 candidateLayer = this; | |
| 1901 } else if (insideFragmentForegroundRect && result.isRectBasedTest()) | |
| 1902 result.append(tempResult); | |
| 1903 } | |
| 1904 | |
| 1905 // Now check our negative z-index children. | |
| 1906 hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, resul
t, hitTestRect, hitTestLocation, | |
| 1907 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene
dTransformState.get(), depthSortDescendants); | |
| 1908 if (hitLayer) { | |
| 1909 if (!depthSortDescendants) | |
| 1910 return hitLayer; | |
| 1911 candidateLayer = hitLayer; | |
| 1912 } | |
| 1913 | |
| 1914 // If we found a layer, return. Child layers, and foreground always render i
n front of background. | |
| 1915 if (candidateLayer) | |
| 1916 return candidateLayer; | |
| 1917 | |
| 1918 if (isSelfPaintingLayer()) { | |
| 1919 HitTestResult tempResult(result.hitTestLocation()); | |
| 1920 bool insideFragmentBackgroundRect = false; | |
| 1921 if (hitTestContentsForFragments(layerFragments, request, tempResult, hit
TestLocation, HitTestSelf, insideFragmentBackgroundRect) | |
| 1922 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra
nsformState.get())) { | |
| 1923 if (result.isRectBasedTest()) | |
| 1924 result.append(tempResult); | |
| 1925 else | |
| 1926 result = tempResult; | |
| 1927 return this; | |
| 1928 } | |
| 1929 if (insideFragmentBackgroundRect && result.isRectBasedTest()) | |
| 1930 result.append(tempResult); | |
| 1931 } | |
| 1932 | |
| 1933 return 0; | |
| 1934 } | |
| 1935 | |
| 1936 bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragmen
ts, const HitTestRequest& request, HitTestResult& result, | |
| 1937 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& i
nsideClipRect) const | |
| 1938 { | |
| 1939 if (layerFragments.isEmpty()) | |
| 1940 return false; | |
| 1941 | |
| 1942 for (int i = layerFragments.size() - 1; i >= 0; --i) { | |
| 1943 const LayerFragment& fragment = layerFragments.at(i); | |
| 1944 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects
(hitTestLocation)) | |
| 1945 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.
intersects(hitTestLocation))) | |
| 1946 continue; | |
| 1947 insideClipRect = true; | |
| 1948 if (hitTestContents(request, result, fragment.layerBounds, hitTestLocati
on, hitTestFilter)) | |
| 1949 return true; | |
| 1950 } | |
| 1951 | |
| 1952 return false; | |
| 1953 } | |
| 1954 | |
| 1955 RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa
yer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult&
result, | |
| 1956 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const
HitTestingTransformState* transformState, double* zOffset) | |
| 1957 { | |
| 1958 LayerFragments enclosingPaginationFragments; | |
| 1959 LayoutPoint offsetOfPaginationLayerFromRoot; | |
| 1960 // FIXME: We're missing a sub-pixel offset here crbug.com/348728 | |
| 1961 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPagination
Layer(), HitTestingTransparencyClipBox, RenderLayer::RootOfTransparencyClipBox,
LayoutSize()); | |
| 1962 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, r
ootLayer, hitTestRect, | |
| 1963 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip,
&offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent); | |
| 1964 | |
| 1965 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) { | |
| 1966 const LayerFragment& fragment = enclosingPaginationFragments.at(i); | |
| 1967 | |
| 1968 // Apply the page/column clip for this fragment, as well as any clips es
tablished by layers in between us and | |
| 1969 // the enclosing pagination layer. | |
| 1970 LayoutRect clipRect = fragment.backgroundRect.rect(); | |
| 1971 | |
| 1972 // Now compute the clips within a given fragment | |
| 1973 if (parent() != enclosingPaginationLayer()) { | |
| 1974 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOf
PaginationLayerFromRoot); | |
| 1975 LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsCo
ntext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbar
Size)).rect(); | |
| 1976 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPagination
LayerFromRoot); | |
| 1977 clipRect.intersect(parentClipRect); | |
| 1978 } | |
| 1979 | |
| 1980 if (!hitTestLocation.intersects(clipRect)) | |
| 1981 continue; | |
| 1982 | |
| 1983 RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, conta
inerLayer, request, result, hitTestRect, hitTestLocation, | |
| 1984 transformState, zOffset, fragment.paginationOffset); | |
| 1985 if (hitLayer) | |
| 1986 return hitLayer; | |
| 1987 } | |
| 1988 | |
| 1989 return 0; | |
| 1990 } | |
| 1991 | |
| 1992 RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer
, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& res
ult, | |
| 1993 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const
HitTestingTransformState* transformState, double* zOffset, | |
| 1994 const LayoutPoint& translationOffset) | |
| 1995 { | |
| 1996 // Create a transform state to accumulate this transform. | |
| 1997 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformSta
te(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, tran
slationOffset); | |
| 1998 | |
| 1999 // If the transform can't be inverted, then don't hit test this layer at all
. | |
| 2000 if (!newTransformState->m_accumulatedTransform.isInvertible()) | |
| 2001 return 0; | |
| 2002 | |
| 2003 // Compute the point and the hit test rect in the coords of this layer by us
ing the values | |
| 2004 // from the transformState, which store the point and quad in the coords of
the last flattened | |
| 2005 // layer, and the accumulated transform which lets up map through preserve-3
d layers. | |
| 2006 // | |
| 2007 // We can't just map hitTestLocation and hitTestRect because they may have b
een flattened (losing z) | |
| 2008 // by our container. | |
| 2009 FloatPoint localPoint = newTransformState->mappedPoint(); | |
| 2010 FloatQuad localPointQuad = newTransformState->mappedQuad(); | |
| 2011 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea(); | |
| 2012 HitTestLocation newHitTestLocation; | |
| 2013 if (hitTestLocation.isRectBasedTest()) | |
| 2014 newHitTestLocation = HitTestLocation(localPoint, localPointQuad); | |
| 2015 else | |
| 2016 newHitTestLocation = HitTestLocation(localPoint); | |
| 2017 | |
| 2018 // Now do a hit test with the root layer shifted to be us. | |
| 2019 return hitTestLayer(this, containerLayer, request, result, localHitTestRect,
newHitTestLocation, true, newTransformState.get(), zOffset); | |
| 2020 } | |
| 2021 | |
| 2022 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult&
result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, H
itTestFilter hitTestFilter) const | |
| 2023 { | |
| 2024 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); | |
| 2025 | |
| 2026 if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(lay
erBounds.location() - renderBoxLocation()), hitTestFilter)) { | |
| 2027 // It's wrong to set innerNode, but then claim that you didn't hit anyth
ing, unless it is | |
| 2028 // a rect-based test. | |
| 2029 ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBa
sedTestResult().size())); | |
| 2030 return false; | |
| 2031 } | |
| 2032 | |
| 2033 // For positioned generated content, we might still not have a | |
| 2034 // node by the time we get to the layer level, since none of | |
| 2035 // the content in the layer has an element. So just walk up | |
| 2036 // the tree. | |
| 2037 if (!result.innerNode() || !result.innerNonSharedNode()) { | |
| 2038 Node* e = enclosingElement(); | |
| 2039 if (!result.innerNode()) | |
| 2040 result.setInnerNode(e); | |
| 2041 if (!result.innerNonSharedNode()) | |
| 2042 result.setInnerNonSharedNode(e); | |
| 2043 } | |
| 2044 | |
| 2045 return true; | |
| 2046 } | |
| 2047 | |
| 2048 RenderLayer* RenderLayer::hitTestChildren(ChildrenIteration childrentoVisit, Ren
derLayer* rootLayer, | |
| 2049 const HitTestRequest& request, HitTestResult& result, | |
| 2050 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, | |
| 2051 const HitTestingTransformState* transformState, | |
| 2052 double* zOffsetForDescendants, double* zOffset, | |
| 2053 const HitTestingTransformState* unflattenedTransformState, | |
| 2054 bool depthSortDescendants) | |
| 2055 { | |
| 2056 if (!hasSelfPaintingLayerDescendant()) | |
| 2057 return 0; | |
| 2058 | |
| 2059 RenderLayer* resultLayer = 0; | |
| 2060 RenderLayerStackingNodeReverseIterator iterator(*m_stackingNode, childrentoV
isit); | |
| 2061 while (RenderLayerStackingNode* child = iterator.next()) { | |
| 2062 RenderLayer* childLayer = child->layer(); | |
| 2063 RenderLayer* hitLayer = 0; | |
| 2064 HitTestResult tempResult(result.hitTestLocation()); | |
| 2065 if (childLayer->isPaginated()) | |
| 2066 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request
, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendant
s); | |
| 2067 else | |
| 2068 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempRe
sult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants
); | |
| 2069 | |
| 2070 // If it a rect-based test, we can safely append the temporary result si
nce it might had hit | |
| 2071 // nodes but not necesserily had hitLayer set. | |
| 2072 if (result.isRectBasedTest()) | |
| 2073 result.append(tempResult); | |
| 2074 | |
| 2075 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedT
ransformState)) { | |
| 2076 resultLayer = hitLayer; | |
| 2077 if (!result.isRectBasedTest()) | |
| 2078 result = tempResult; | |
| 2079 if (!depthSortDescendants) | |
| 2080 break; | |
| 2081 } | |
| 2082 } | |
| 2083 | |
| 2084 return resultLayer; | |
| 2085 } | |
| 2086 | |
| 2087 RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, Re
nderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, | |
| 2088 const LayoutRect& hitTestRe
ct, const HitTestLocation& hitTestLocation, const HitTestingTransformState* tran
sformState, double* zOffset) | |
| 2089 { | |
| 2090 Vector<RenderLayer*> columnLayers; | |
| 2091 RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ?
parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode(); | |
| 2092 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent())
{ | |
| 2093 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagina
tion(childLayer->renderer(), curr->renderBox())) | |
| 2094 columnLayers.append(curr); | |
| 2095 if (curr->stackingNode() == ancestorNode) | |
| 2096 break; | |
| 2097 } | |
| 2098 | |
| 2099 ASSERT(columnLayers.size()); | |
| 2100 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitT
estRect, hitTestLocation, transformState, zOffset, | |
| 2101 columnLayers, columnLayers.size() - 1); | |
| 2102 } | |
| 2103 | |
| 2104 RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
erLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, | |
| 2105 const LayoutRect& hitTestRect
, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transf
ormState, double* zOffset, | |
| 2106 const Vector<RenderLayer*>& c
olumnLayers, size_t columnIndex) | |
| 2107 { | |
| 2108 RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer
()); | |
| 2109 | |
| 2110 ASSERT(columnBlock && columnBlock->hasColumns()); | |
| 2111 if (!columnBlock || !columnBlock->hasColumns()) | |
| 2112 return 0; | |
| 2113 | |
| 2114 LayoutPoint layerOffset; | |
| 2115 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset); | |
| 2116 | |
| 2117 ColumnInfo* colInfo = columnBlock->columnInfo(); | |
| 2118 int colCount = columnBlock->columnCount(colInfo); | |
| 2119 | |
| 2120 // We have to go backwards from the last column to the first. | |
| 2121 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); | |
| 2122 LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent(); | |
| 2123 LayoutUnit currLogicalTopOffset = 0; | |
| 2124 int i; | |
| 2125 for (i = 0; i < colCount; i++) { | |
| 2126 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); | |
| 2127 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.widt
h()); | |
| 2128 if (columnBlock->style()->isFlippedBlocksWritingMode()) | |
| 2129 currLogicalTopOffset += blockDelta; | |
| 2130 else | |
| 2131 currLogicalTopOffset -= blockDelta; | |
| 2132 } | |
| 2133 for (i = colCount - 1; i >= 0; i--) { | |
| 2134 // For each rect, we clip to the rect, and then we adjust our coords. | |
| 2135 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); | |
| 2136 columnBlock->flipForWritingMode(colRect); | |
| 2137 LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect
.y()) - logicalLeft; | |
| 2138 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.widt
h()); | |
| 2139 if (columnBlock->style()->isFlippedBlocksWritingMode()) | |
| 2140 currLogicalTopOffset -= blockDelta; | |
| 2141 else | |
| 2142 currLogicalTopOffset += blockDelta; | |
| 2143 | |
| 2144 LayoutSize offset; | |
| 2145 if (isHorizontal) { | |
| 2146 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
| 2147 offset = LayoutSize(currLogicalLeftOffset, currLogicalTopOffset)
; | |
| 2148 else | |
| 2149 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - colu
mnBlock->borderTop() - columnBlock->paddingTop()); | |
| 2150 } else { | |
| 2151 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
| 2152 offset = LayoutSize(currLogicalTopOffset, currLogicalLeftOffset)
; | |
| 2153 else | |
| 2154 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnB
lock->borderLeft() - columnBlock->paddingLeft(), 0); | |
| 2155 } | |
| 2156 | |
| 2157 colRect.moveBy(layerOffset); | |
| 2158 | |
| 2159 LayoutRect localClipRect(hitTestRect); | |
| 2160 localClipRect.intersect(colRect); | |
| 2161 | |
| 2162 if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect
)) { | |
| 2163 RenderLayer* hitLayer = 0; | |
| 2164 if (!columnIndex) { | |
| 2165 // Apply a translation transform to change where the layer paint
s. | |
| 2166 TransformationMatrix oldTransform; | |
| 2167 bool oldHasTransform = childLayer->transform(); | |
| 2168 if (oldHasTransform) | |
| 2169 oldTransform = *childLayer->transform(); | |
| 2170 TransformationMatrix newTransform(oldTransform); | |
| 2171 newTransform.translateRight(offset.width(), offset.height()); | |
| 2172 | |
| 2173 childLayer->m_transform = adoptPtr(new TransformationMatrix(newT
ransform)); | |
| 2174 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0],
request, result, localClipRect, hitTestLocation, false, transformState, zOffset)
; | |
| 2175 if (oldHasTransform) | |
| 2176 childLayer->m_transform = adoptPtr(new TransformationMatrix(
oldTransform)); | |
| 2177 else | |
| 2178 childLayer->m_transform.clear(); | |
| 2179 } else { | |
| 2180 // Adjust the transform such that the renderer's upper left corn
er will be at (0,0) in user space. | |
| 2181 // This involves subtracting out the position of the layer in ou
r current coordinate space. | |
| 2182 RenderLayer* nextLayer = columnLayers[columnIndex - 1]; | |
| 2183 RefPtr<HitTestingTransformState> newTransformState = nextLayer->
createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation,
transformState); | |
| 2184 newTransformState->translate(offset.width(), offset.height(), Hi
tTestingTransformState::AccumulateTransform); | |
| 2185 FloatPoint localPoint = newTransformState->mappedPoint(); | |
| 2186 FloatQuad localPointQuad = newTransformState->mappedQuad(); | |
| 2187 LayoutRect localHitTestRect = newTransformState->mappedArea().en
closingBoundingBox(); | |
| 2188 HitTestLocation newHitTestLocation; | |
| 2189 if (hitTestLocation.isRectBasedTest()) | |
| 2190 newHitTestLocation = HitTestLocation(localPoint, localPointQ
uad); | |
| 2191 else | |
| 2192 newHitTestLocation = HitTestLocation(localPoint); | |
| 2193 newTransformState->flatten(); | |
| 2194 | |
| 2195 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[col
umnIndex - 1], request, result, localHitTestRect, newHitTestLocation, | |
| 2196 newTransformState.get(), zOf
fset, columnLayers, columnIndex - 1); | |
| 2197 } | |
| 2198 | |
| 2199 if (hitLayer) | |
| 2200 return hitLayer; | |
| 2201 } | |
| 2202 } | |
| 2203 | |
| 2204 return 0; | |
| 2205 } | |
| 2206 | |
| 2207 void RenderLayer::blockSelectionGapsBoundsChanged() | |
| 2208 { | |
| 2209 setNeedsCompositingInputsUpdate(); | |
| 2210 } | |
| 2211 | |
| 2212 void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds) | |
| 2213 { | |
| 2214 m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds)); | |
| 2215 blockSelectionGapsBoundsChanged(); | |
| 2216 } | |
| 2217 | |
| 2218 void RenderLayer::clearBlockSelectionGapsBounds() | |
| 2219 { | |
| 2220 m_blockSelectionGapsBounds = IntRect(); | |
| 2221 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 2222 child->clearBlockSelectionGapsBounds(); | |
| 2223 blockSelectionGapsBoundsChanged(); | |
| 2224 } | |
| 2225 | |
| 2226 void RenderLayer::invalidatePaintForBlockSelectionGaps() | |
| 2227 { | |
| 2228 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 2229 child->invalidatePaintForBlockSelectionGaps(); | |
| 2230 | |
| 2231 if (m_blockSelectionGapsBounds.isEmpty()) | |
| 2232 return; | |
| 2233 | |
| 2234 LayoutRect rect = m_blockSelectionGapsBounds; | |
| 2235 if (renderer()->hasOverflowClip()) { | |
| 2236 RenderBox* box = renderBox(); | |
| 2237 rect.move(-box->scrolledContentOffset()); | |
| 2238 if (!scrollableArea()->usesCompositedScrolling()) | |
| 2239 rect.intersect(box->overflowClipRect(LayoutPoint())); | |
| 2240 } | |
| 2241 if (renderer()->hasClip()) | |
| 2242 rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint())); | |
| 2243 if (!rect.isEmpty()) | |
| 2244 renderer()->invalidatePaintRectangle(rect); | |
| 2245 } | |
| 2246 | |
| 2247 IntRect RenderLayer::blockSelectionGapsBounds() const | |
| 2248 { | |
| 2249 if (!renderer()->isRenderBlockFlow()) | |
| 2250 return IntRect(); | |
| 2251 | |
| 2252 RenderBlockFlow* renderBlockFlow = toRenderBlockFlow(renderer()); | |
| 2253 LayoutRect gapRects = renderBlockFlow->selectionGapRectsForPaintInvalidation
(renderBlockFlow); | |
| 2254 | |
| 2255 return pixelSnappedIntRect(gapRects); | |
| 2256 } | |
| 2257 | |
| 2258 bool RenderLayer::hasBlockSelectionGapBounds() const | |
| 2259 { | |
| 2260 // FIXME: it would be more accurate to return !blockSelectionGapsBounds().is
Empty(), but this is impossible | |
| 2261 // at the moment because it causes invalid queries to layout-dependent code
(crbug.com/372802). | |
| 2262 // ASSERT(renderer()->document().lifecycle().state() >= DocumentLifecycle::L
ayoutClean); | |
| 2263 | |
| 2264 if (!renderer()->isRenderBlock()) | |
| 2265 return false; | |
| 2266 | |
| 2267 return toRenderBlock(renderer())->shouldPaintSelectionGaps(); | |
| 2268 } | |
| 2269 | |
| 2270 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const Layo
utRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromR
oot) const | |
| 2271 { | |
| 2272 // Always examine the canvas and the root. | |
| 2273 // FIXME: Could eliminate the isDocumentElement() check if we fix background
painting so that the RenderView | |
| 2274 // paints the root's background. | |
| 2275 if (isRootLayer() || renderer()->isDocumentElement()) | |
| 2276 return true; | |
| 2277 | |
| 2278 // If we aren't an inline flow, and our layer bounds do intersect the damage
rect, then we | |
| 2279 // can go ahead and return true. | |
| 2280 RenderView* view = renderer()->view(); | |
| 2281 ASSERT(view); | |
| 2282 if (view && !renderer()->isRenderInline()) { | |
| 2283 if (layerBounds.intersects(damageRect)) | |
| 2284 return true; | |
| 2285 } | |
| 2286 | |
| 2287 // Otherwise we need to compute the bounding box of this single layer and se
e if it intersects | |
| 2288 // the damage rect. | |
| 2289 return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect)
; | |
| 2290 } | |
| 2291 | |
| 2292 LayoutRect RenderLayer::logicalBoundingBox() const | |
| 2293 { | |
| 2294 // There are three special cases we need to consider. | |
| 2295 // (1) Inline Flows. For inline flows we will create a bounding box that fu
lly encompasses all of the lines occupied by the | |
| 2296 // inline. In other words, if some <span> wraps to three lines, we'll creat
e a bounding box that fully encloses the | |
| 2297 // line boxes of all three lines (including overflow on those lines). | |
| 2298 // (2) Left/Top Overflow. The width/height of layers already includes right
/bottom overflow. However, in the case of left/top | |
| 2299 // overflow, we have to create a bounding box that will extend to include th
is overflow. | |
| 2300 // (3) Floats. When a layer has overhanging floats that it paints, we need
to make sure to include these overhanging floats | |
| 2301 // as part of our bounding box. We do this because we are the responsible l
ayer for both hit testing and painting those | |
| 2302 // floats. | |
| 2303 LayoutRect result; | |
| 2304 if (renderer()->isInline() && renderer()->isRenderInline()) { | |
| 2305 result = toRenderInline(renderer())->linesVisualOverflowBoundingBox(); | |
| 2306 } else if (renderer()->isTableRow()) { | |
| 2307 // Our bounding box is just the union of all of our cells' border/overfl
ow rects. | |
| 2308 for (RenderObject* child = renderer()->slowFirstChild(); child; child =
child->nextSibling()) { | |
| 2309 if (child->isTableCell()) { | |
| 2310 LayoutRect bbox = toRenderBox(child)->borderBoxRect(); | |
| 2311 result.unite(bbox); | |
| 2312 LayoutRect overflowRect = renderBox()->visualOverflowRect(); | |
| 2313 if (bbox != overflowRect) | |
| 2314 result.unite(overflowRect); | |
| 2315 } | |
| 2316 } | |
| 2317 } else { | |
| 2318 RenderBox* box = renderBox(); | |
| 2319 ASSERT(box); | |
| 2320 result = box->borderBoxRect(); | |
| 2321 result.unite(box->visualOverflowRect()); | |
| 2322 } | |
| 2323 | |
| 2324 ASSERT(renderer()->view()); | |
| 2325 return result; | |
| 2326 } | |
| 2327 | |
| 2328 static inline LayoutRect flippedLogicalBoundingBox(LayoutRect boundingBox, Rende
rObject* renderer) | |
| 2329 { | |
| 2330 LayoutRect result = boundingBox; | |
| 2331 if (renderer->isBox()) | |
| 2332 toRenderBox(renderer)->flipForWritingMode(result); | |
| 2333 else | |
| 2334 renderer->containingBlock()->flipForWritingMode(result); | |
| 2335 return result; | |
| 2336 } | |
| 2337 | |
| 2338 LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, co
nst LayoutPoint* offsetFromRoot) const | |
| 2339 { | |
| 2340 LayoutRect result = flippedLogicalBoundingBox(logicalBoundingBox(), renderer
()); | |
| 2341 if (offsetFromRoot) | |
| 2342 result.moveBy(*offsetFromRoot); | |
| 2343 else | |
| 2344 convertToLayerCoords(ancestorLayer, result); | |
| 2345 return result; | |
| 2346 } | |
| 2347 | |
| 2348 LayoutRect RenderLayer::fragmentsBoundingBox(const RenderLayer* ancestorLayer) c
onst | |
| 2349 { | |
| 2350 if (!enclosingPaginationLayer()) | |
| 2351 return physicalBoundingBox(ancestorLayer); | |
| 2352 | |
| 2353 LayoutRect result = flippedLogicalBoundingBox(logicalBoundingBox(), renderer
()); | |
| 2354 convertFromFlowThreadToVisualBoundingBoxInAncestor(this, ancestorLayer, resu
lt); | |
| 2355 return result; | |
| 2356 } | |
| 2357 | |
| 2358 LayoutRect RenderLayer::boundingBoxForCompositingOverlapTest() const | |
| 2359 { | |
| 2360 return overlapBoundsIncludeChildren() ? boundingBoxForCompositing() : fragme
ntsBoundingBox(this); | |
| 2361 } | |
| 2362 | |
| 2363 static void expandRectForReflectionAndStackingChildren(const RenderLayer* ancest
orLayer, RenderLayer::CalculateBoundsOptions options, LayoutRect& result) | |
| 2364 { | |
| 2365 if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->ref
lectionLayer()->hasCompositedLayerMapping()) | |
| 2366 result.unite(ancestorLayer->reflectionInfo()->reflectionLayer()->boundin
gBoxForCompositing(ancestorLayer)); | |
| 2367 | |
| 2368 ASSERT(ancestorLayer->stackingNode()->isStackingContext() || !ancestorLayer-
>stackingNode()->hasPositiveZOrderList()); | |
| 2369 | |
| 2370 #if ENABLE(ASSERT) | |
| 2371 LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(ancestorL
ayer)->stackingNode()); | |
| 2372 #endif | |
| 2373 | |
| 2374 RenderLayerStackingNodeIterator iterator(*ancestorLayer->stackingNode(), All
Children); | |
| 2375 while (RenderLayerStackingNode* node = iterator.next()) { | |
| 2376 // Here we exclude both directly composited layers and squashing layers | |
| 2377 // because those RenderLayers don't paint into the graphics layer | |
| 2378 // for this RenderLayer. For example, the bounds of squashed RenderLayer
s | |
| 2379 // will be included in the computation of the appropriate squashing | |
| 2380 // GraphicsLayer. | |
| 2381 if (options != RenderLayer::ApplyBoundsChickenEggHacks && node->layer()-
>compositingState() != NotComposited) | |
| 2382 continue; | |
| 2383 result.unite(node->layer()->boundingBoxForCompositing(ancestorLayer, opt
ions)); | |
| 2384 } | |
| 2385 } | |
| 2386 | |
| 2387 LayoutRect RenderLayer::physicalBoundingBoxIncludingReflectionAndStackingChildre
n(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const | |
| 2388 { | |
| 2389 LayoutPoint origin; | |
| 2390 LayoutRect result = physicalBoundingBox(ancestorLayer, &origin); | |
| 2391 | |
| 2392 const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded(); | |
| 2393 | |
| 2394 expandRectForReflectionAndStackingChildren(this, DoNotApplyBoundsChickenEggH
acks, result); | |
| 2395 | |
| 2396 result.moveBy(offsetFromRoot); | |
| 2397 return result; | |
| 2398 } | |
| 2399 | |
| 2400 LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLay
er, CalculateBoundsOptions options) const | |
| 2401 { | |
| 2402 if (!isSelfPaintingLayer()) | |
| 2403 return LayoutRect(); | |
| 2404 | |
| 2405 if (!ancestorLayer) | |
| 2406 ancestorLayer = this; | |
| 2407 | |
| 2408 // FIXME: This could be improved to do a check like hasVisibleNonCompositing
DescendantLayers() (bug 92580). | |
| 2409 if (this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant()
) | |
| 2410 return LayoutRect(); | |
| 2411 | |
| 2412 // The root layer is always just the size of the document. | |
| 2413 if (isRootLayer()) | |
| 2414 return m_renderer->view()->unscaledDocumentRect(); | |
| 2415 | |
| 2416 // The layer created for the RenderFlowThread is just a helper for painting
and hit-testing, | |
| 2417 // and should not contribute to the bounding box. The RenderMultiColumnSets
will contribute | |
| 2418 // the correct size for the rendered content of the multicol container. | |
| 2419 if (useRegionBasedColumns() && renderer()->isRenderFlowThread()) | |
| 2420 return LayoutRect(); | |
| 2421 | |
| 2422 LayoutRect result = clipper().localClipRect(); | |
| 2423 if (result == LayoutRect::infiniteIntRect()) { | |
| 2424 LayoutPoint origin; | |
| 2425 result = physicalBoundingBox(ancestorLayer, &origin); | |
| 2426 | |
| 2427 const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded
(); | |
| 2428 | |
| 2429 // Reflections are implemented with RenderLayers that hang off of the re
flected layer. However, | |
| 2430 // the reflection layer subtree does not include the subtree of the pare
nt RenderLayer, so | |
| 2431 // a recursive computation of stacking children yields no results. This
breaks cases when there are stacking | |
| 2432 // children of the parent, that need to be included in reflected composi
ted bounds. | |
| 2433 // Fix this by including composited bounds of stacking children of the r
eflected RenderLayer. | |
| 2434 if (hasCompositedLayerMapping() && parent() && parent()->reflectionInfo(
) && parent()->reflectionInfo()->reflectionLayer() == this) | |
| 2435 expandRectForReflectionAndStackingChildren(parent(), options, result
); | |
| 2436 else | |
| 2437 expandRectForReflectionAndStackingChildren(this, options, result); | |
| 2438 | |
| 2439 // FIXME: We can optimize the size of the composited layers, by not enla
rging | |
| 2440 // filtered areas with the outsets if we know that the filter is going t
o render in hardware. | |
| 2441 // https://bugs.webkit.org/show_bug.cgi?id=81239 | |
| 2442 result.expand(m_renderer->style()->filterOutsets()); | |
| 2443 } | |
| 2444 | |
| 2445 if (paintsWithTransform(PaintBehaviorNormal) || (options == ApplyBoundsChick
enEggHacks && transform())) | |
| 2446 result = transform()->mapRect(result); | |
| 2447 | |
| 2448 if (enclosingPaginationLayer()) { | |
| 2449 convertFromFlowThreadToVisualBoundingBoxInAncestor(this, ancestorLayer,
result); | |
| 2450 return result; | |
| 2451 } | |
| 2452 LayoutPoint delta; | |
| 2453 convertToLayerCoords(ancestorLayer, delta); | |
| 2454 result.moveBy(delta); | |
| 2455 return result; | |
| 2456 } | |
| 2457 | |
| 2458 CompositingState RenderLayer::compositingState() const | |
| 2459 { | |
| 2460 ASSERT(isAllowedToQueryCompositingState()); | |
| 2461 | |
| 2462 // This is computed procedurally so there is no redundant state variable tha
t | |
| 2463 // can get out of sync from the real actual compositing state. | |
| 2464 | |
| 2465 if (m_groupedMapping) { | |
| 2466 ASSERT(!m_compositedLayerMapping); | |
| 2467 return PaintsIntoGroupedBacking; | |
| 2468 } | |
| 2469 | |
| 2470 if (!m_compositedLayerMapping) | |
| 2471 return NotComposited; | |
| 2472 | |
| 2473 return PaintsIntoOwnBacking; | |
| 2474 } | |
| 2475 | |
| 2476 bool RenderLayer::isAllowedToQueryCompositingState() const | |
| 2477 { | |
| 2478 if (gCompositingQueryMode == CompositingQueriesAreAllowed) | |
| 2479 return true; | |
| 2480 return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCo
mpositingUpdate; | |
| 2481 } | |
| 2482 | |
| 2483 CompositedLayerMapping* RenderLayer::compositedLayerMapping() const | |
| 2484 { | |
| 2485 ASSERT(isAllowedToQueryCompositingState()); | |
| 2486 return m_compositedLayerMapping.get(); | |
| 2487 } | |
| 2488 | |
| 2489 GraphicsLayer* RenderLayer::graphicsLayerBacking() const | |
| 2490 { | |
| 2491 switch (compositingState()) { | |
| 2492 case NotComposited: | |
| 2493 return 0; | |
| 2494 case PaintsIntoGroupedBacking: | |
| 2495 return groupedMapping()->squashingLayer(); | |
| 2496 default: | |
| 2497 return compositedLayerMapping()->mainGraphicsLayer(); | |
| 2498 } | |
| 2499 } | |
| 2500 | |
| 2501 GraphicsLayer* RenderLayer::graphicsLayerBackingForScrolling() const | |
| 2502 { | |
| 2503 switch (compositingState()) { | |
| 2504 case NotComposited: | |
| 2505 return 0; | |
| 2506 case PaintsIntoGroupedBacking: | |
| 2507 return groupedMapping()->squashingLayer(); | |
| 2508 default: | |
| 2509 return compositedLayerMapping()->scrollingContentsLayer() ? compositedLa
yerMapping()->scrollingContentsLayer() : compositedLayerMapping()->mainGraphicsL
ayer(); | |
| 2510 } | |
| 2511 } | |
| 2512 | |
| 2513 void RenderLayer::ensureCompositedLayerMapping() | |
| 2514 { | |
| 2515 if (m_compositedLayerMapping) | |
| 2516 return; | |
| 2517 | |
| 2518 m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this)); | |
| 2519 m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSub
tree); | |
| 2520 | |
| 2521 updateOrRemoveFilterEffectRenderer(); | |
| 2522 } | |
| 2523 | |
| 2524 void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed) | |
| 2525 { | |
| 2526 if (!layerBeingDestroyed) { | |
| 2527 // We need to make sure our decendants get a geometry update. In princip
le, | |
| 2528 // we could call setNeedsGraphicsLayerUpdate on our children, but that w
ould | |
| 2529 // require walking the z-order lists to find them. Instead, we over-inva
lidate | |
| 2530 // by marking our parent as needing a geometry update. | |
| 2531 if (RenderLayer* compositingParent = enclosingLayerWithCompositedLayerMa
pping(ExcludeSelf)) | |
| 2532 compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUp
date(GraphicsLayerUpdateSubtree); | |
| 2533 } | |
| 2534 | |
| 2535 m_compositedLayerMapping.clear(); | |
| 2536 | |
| 2537 if (!layerBeingDestroyed) | |
| 2538 updateOrRemoveFilterEffectRenderer(); | |
| 2539 } | |
| 2540 | |
| 2541 void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool
layerBeingDestroyed) | |
| 2542 { | |
| 2543 if (groupedMapping == m_groupedMapping) | |
| 2544 return; | |
| 2545 | |
| 2546 if (!layerBeingDestroyed && m_groupedMapping) { | |
| 2547 m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree
); | |
| 2548 m_groupedMapping->removeRenderLayerFromSquashingGraphicsLayer(this); | |
| 2549 } | |
| 2550 m_groupedMapping = groupedMapping; | |
| 2551 if (!layerBeingDestroyed && m_groupedMapping) | |
| 2552 m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree
); | |
| 2553 } | |
| 2554 | |
| 2555 bool RenderLayer::hasCompositedMask() const | |
| 2556 { | |
| 2557 return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer(); | |
| 2558 } | |
| 2559 | |
| 2560 bool RenderLayer::hasCompositedClippingMask() const | |
| 2561 { | |
| 2562 return m_compositedLayerMapping && m_compositedLayerMapping->hasChildClippin
gMaskLayer(); | |
| 2563 } | |
| 2564 | |
| 2565 bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const | |
| 2566 { | |
| 2567 return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayer
s) || compositingState() != PaintsIntoOwnBacking); | |
| 2568 } | |
| 2569 | |
| 2570 bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect)
const | |
| 2571 { | |
| 2572 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) | |
| 2573 return false; | |
| 2574 | |
| 2575 if (paintsWithTransparency(PaintBehaviorNormal)) | |
| 2576 return false; | |
| 2577 | |
| 2578 // We can't use hasVisibleContent(), because that will be true if our render
er is hidden, but some child | |
| 2579 // is visible and that child doesn't cover the entire rect. | |
| 2580 if (renderer()->style()->visibility() != VISIBLE) | |
| 2581 return false; | |
| 2582 | |
| 2583 if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffect
sOpacity()) | |
| 2584 return false; | |
| 2585 | |
| 2586 // FIXME: Handle simple transforms. | |
| 2587 if (paintsWithTransform(PaintBehaviorNormal)) | |
| 2588 return false; | |
| 2589 | |
| 2590 // FIXME: Remove this check. | |
| 2591 // This function should not be called when layer-lists are dirty. | |
| 2592 // It is somehow getting triggered during style update. | |
| 2593 if (m_stackingNode->zOrderListsDirty() || m_stackingNode->normalFlowListDirt
y()) | |
| 2594 return false; | |
| 2595 | |
| 2596 // FIXME: We currently only check the immediate renderer, | |
| 2597 // which will miss many cases. | |
| 2598 if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect)) | |
| 2599 return true; | |
| 2600 | |
| 2601 // We can't consult child layers if we clip, since they might cover | |
| 2602 // parts of the rect that are clipped out. | |
| 2603 if (renderer()->hasOverflowClip()) | |
| 2604 return false; | |
| 2605 | |
| 2606 return childBackgroundIsKnownToBeOpaqueInRect(localRect); | |
| 2607 } | |
| 2608 | |
| 2609 bool RenderLayer::childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect& local
Rect) const | |
| 2610 { | |
| 2611 RenderLayerStackingNodeReverseIterator revertseIterator(*m_stackingNode, Pos
itiveZOrderChildren | NormalFlowChildren | NegativeZOrderChildren); | |
| 2612 while (RenderLayerStackingNode* child = revertseIterator.next()) { | |
| 2613 const RenderLayer* childLayer = child->layer(); | |
| 2614 // Stop at composited paint boundaries. | |
| 2615 if (childLayer->isPaintInvalidationContainer()) | |
| 2616 continue; | |
| 2617 | |
| 2618 if (!childLayer->canUseConvertToLayerCoords()) | |
| 2619 continue; | |
| 2620 | |
| 2621 LayoutPoint childOffset; | |
| 2622 LayoutRect childLocalRect(localRect); | |
| 2623 childLayer->convertToLayerCoords(this, childOffset); | |
| 2624 childLocalRect.moveBy(-childOffset); | |
| 2625 | |
| 2626 if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect)) | |
| 2627 return true; | |
| 2628 } | |
| 2629 return false; | |
| 2630 } | |
| 2631 | |
| 2632 bool RenderLayer::shouldBeSelfPaintingLayer() const | |
| 2633 { | |
| 2634 if (renderer()->isRenderPart() && toRenderPart(renderer())->requiresAccelera
tedCompositing()) | |
| 2635 return true; | |
| 2636 return m_layerType == NormalLayer | |
| 2637 || (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars()) | |
| 2638 || needsCompositedScrolling(); | |
| 2639 } | |
| 2640 | |
| 2641 void RenderLayer::updateSelfPaintingLayer() | |
| 2642 { | |
| 2643 bool isSelfPaintingLayer = shouldBeSelfPaintingLayer(); | |
| 2644 if (this->isSelfPaintingLayer() == isSelfPaintingLayer) | |
| 2645 return; | |
| 2646 | |
| 2647 m_isSelfPaintingLayer = isSelfPaintingLayer; | |
| 2648 | |
| 2649 if (parent()) | |
| 2650 parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); | |
| 2651 } | |
| 2652 | |
| 2653 bool RenderLayer::hasNonEmptyChildRenderers() const | |
| 2654 { | |
| 2655 // Some HTML can cause whitespace text nodes to have renderers, like: | |
| 2656 // <div> | |
| 2657 // <img src=...> | |
| 2658 // </div> | |
| 2659 // so test for 0x0 RenderTexts here | |
| 2660 for (RenderObject* child = renderer()->slowFirstChild(); child; child = chil
d->nextSibling()) { | |
| 2661 if (!child->hasLayer()) { | |
| 2662 if (child->isRenderInline() || !child->isBox()) | |
| 2663 return true; | |
| 2664 | |
| 2665 if (!toRenderBox(child)->size().isEmpty()) | |
| 2666 return true; | |
| 2667 } | |
| 2668 } | |
| 2669 return false; | |
| 2670 } | |
| 2671 | |
| 2672 bool RenderLayer::hasBoxDecorationsOrBackground() const | |
| 2673 { | |
| 2674 return renderer()->style()->hasBoxDecorations() || renderer()->style()->hasB
ackground(); | |
| 2675 } | |
| 2676 | |
| 2677 bool RenderLayer::hasVisibleBoxDecorations() const | |
| 2678 { | |
| 2679 if (!hasVisibleContent()) | |
| 2680 return false; | |
| 2681 | |
| 2682 return hasBoxDecorationsOrBackground() || hasOverflowControls(); | |
| 2683 } | |
| 2684 | |
| 2685 void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle*
newStyle) | |
| 2686 { | |
| 2687 if (!newStyle->hasFilter() && (!oldStyle || !oldStyle->hasFilter())) | |
| 2688 return; | |
| 2689 | |
| 2690 updateOrRemoveFilterClients(); | |
| 2691 updateOrRemoveFilterEffectRenderer(); | |
| 2692 } | |
| 2693 | |
| 2694 bool RenderLayer::attemptDirectCompositingUpdate(StyleDifference diff, const Ren
derStyle* oldStyle) | |
| 2695 { | |
| 2696 CompositingReasons oldPotentialCompositingReasonsFromStyle = m_potentialComp
ositingReasonsFromStyle; | |
| 2697 compositor()->updatePotentialCompositingReasonsFromStyle(this); | |
| 2698 | |
| 2699 // This function implements an optimization for transforms and opacity. | |
| 2700 // A common pattern is for a touchmove handler to update the transform | |
| 2701 // and/or an opacity of an element every frame while the user moves their | |
| 2702 // finger across the screen. The conditions below recognize when the | |
| 2703 // compositing state is set up to receive a direct transform or opacity | |
| 2704 // update. | |
| 2705 | |
| 2706 if (!diff.hasAtMostPropertySpecificDifferences(StyleDifference::TransformCha
nged | StyleDifference::OpacityChanged)) | |
| 2707 return false; | |
| 2708 // The potentialCompositingReasonsFromStyle could have changed without | |
| 2709 // a corresponding StyleDifference if an animation started or ended. | |
| 2710 if (m_potentialCompositingReasonsFromStyle != oldPotentialCompositingReasons
FromStyle) | |
| 2711 return false; | |
| 2712 // We could add support for reflections if we updated the transform on | |
| 2713 // the reflection layers. | |
| 2714 if (renderer()->hasReflection()) | |
| 2715 return false; | |
| 2716 // If we're unwinding a scheduleSVGFilterLayerUpdateHack(), then we can't | |
| 2717 // perform a direct compositing update because the filters code is going | |
| 2718 // to produce different output this time around. We can remove this code | |
| 2719 // once we fix the chicken/egg bugs in the filters code and delete the | |
| 2720 // scheduleSVGFilterLayerUpdateHack(). | |
| 2721 if (renderer()->node() && renderer()->node()->svgFilterNeedsLayerUpdate()) | |
| 2722 return false; | |
| 2723 if (!m_compositedLayerMapping) | |
| 2724 return false; | |
| 2725 | |
| 2726 // To cut off almost all the work in the compositing update for | |
| 2727 // this case, we treat inline transforms has having assumed overlap | |
| 2728 // (similar to how we treat animated transforms). Notice that we read | |
| 2729 // CompositingReasonInlineTransform from the m_compositingReasons, which | |
| 2730 // means that the inline transform actually triggered assumed overlap in | |
| 2731 // the overlap map. | |
| 2732 if (diff.transformChanged() && !(m_compositingReasons & CompositingReasonInl
ineTransform)) | |
| 2733 return false; | |
| 2734 | |
| 2735 // We composite transparent RenderLayers differently from non-transparent | |
| 2736 // RenderLayers even when the non-transparent RenderLayers are already a | |
| 2737 // stacking context. | |
| 2738 if (diff.opacityChanged() && m_renderer->style()->hasOpacity() != oldStyle->
hasOpacity()) | |
| 2739 return false; | |
| 2740 | |
| 2741 updateTransform(oldStyle, renderer()->style()); | |
| 2742 | |
| 2743 // FIXME: Consider introducing a smaller graphics layer update scope | |
| 2744 // that just handles transforms and opacity. GraphicsLayerUpdateLocal | |
| 2745 // will also program bounds, clips, and many other properties that could | |
| 2746 // not possibly have changed. | |
| 2747 m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLoc
al); | |
| 2748 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange
); | |
| 2749 return true; | |
| 2750 } | |
| 2751 | |
| 2752 void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
) | |
| 2753 { | |
| 2754 if (attemptDirectCompositingUpdate(diff, oldStyle)) | |
| 2755 return; | |
| 2756 | |
| 2757 m_stackingNode->updateIsNormalFlowOnly(); | |
| 2758 m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle); | |
| 2759 | |
| 2760 if (m_scrollableArea) | |
| 2761 m_scrollableArea->updateAfterStyleChange(oldStyle); | |
| 2762 | |
| 2763 // Overlay scrollbars can make this layer self-painting so we need | |
| 2764 // to recompute the bit once scrollbars have been updated. | |
| 2765 updateSelfPaintingLayer(); | |
| 2766 | |
| 2767 if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) { | |
| 2768 ASSERT(!oldStyle || diff.needsFullLayout()); | |
| 2769 updateReflectionInfo(oldStyle); | |
| 2770 } | |
| 2771 | |
| 2772 updateDescendantDependentFlags(); | |
| 2773 | |
| 2774 updateTransform(oldStyle, renderer()->style()); | |
| 2775 updateFilters(oldStyle, renderer()->style()); | |
| 2776 | |
| 2777 setNeedsCompositingInputsUpdate(); | |
| 2778 } | |
| 2779 | |
| 2780 bool RenderLayer::scrollsOverflow() const | |
| 2781 { | |
| 2782 if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea()) | |
| 2783 return scrollableArea->scrollsOverflow(); | |
| 2784 | |
| 2785 return false; | |
| 2786 } | |
| 2787 | |
| 2788 FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style) | |
| 2789 { | |
| 2790 const FilterOperations& filters = style->filter(); | |
| 2791 if (filters.hasReferenceFilter()) { | |
| 2792 for (size_t i = 0; i < filters.size(); ++i) { | |
| 2793 FilterOperation* filterOperation = filters.operations().at(i).get(); | |
| 2794 if (filterOperation->type() != FilterOperation::REFERENCE) | |
| 2795 continue; | |
| 2796 ReferenceFilterOperation* referenceOperation = toReferenceFilterOper
ation(filterOperation); | |
| 2797 // FIXME: Cache the ReferenceFilter if it didn't change. | |
| 2798 RefPtrWillBeRawPtr<ReferenceFilter> referenceFilter = ReferenceFilte
r::create(style->effectiveZoom()); | |
| 2799 referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referen
ceFilter.get(), renderer(), referenceFilter->sourceGraphic(), | |
| 2800 referenceOperation)); | |
| 2801 referenceOperation->setFilter(referenceFilter.release()); | |
| 2802 } | |
| 2803 } | |
| 2804 | |
| 2805 return filters; | |
| 2806 } | |
| 2807 | |
| 2808 void RenderLayer::updateOrRemoveFilterClients() | |
| 2809 { | |
| 2810 if (!hasFilter()) { | |
| 2811 removeFilterInfoIfNeeded(); | |
| 2812 return; | |
| 2813 } | |
| 2814 | |
| 2815 if (renderer()->style()->filter().hasReferenceFilter()) | |
| 2816 ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->fi
lter()); | |
| 2817 else if (hasFilterInfo()) | |
| 2818 filterInfo()->removeReferenceFilterClients(); | |
| 2819 } | |
| 2820 | |
| 2821 void RenderLayer::updateOrRemoveFilterEffectRenderer() | |
| 2822 { | |
| 2823 // FilterEffectRenderer is only used to render the filters in software mode, | |
| 2824 // so we always need to run updateOrRemoveFilterEffectRenderer after the com
posited | |
| 2825 // mode might have changed for this layer. | |
| 2826 if (!paintsWithFilters()) { | |
| 2827 // Don't delete the whole filter info here, because we might use it | |
| 2828 // for loading CSS shader files. | |
| 2829 if (RenderLayerFilterInfo* filterInfo = this->filterInfo()) | |
| 2830 filterInfo->setRenderer(nullptr); | |
| 2831 | |
| 2832 return; | |
| 2833 } | |
| 2834 | |
| 2835 RenderLayerFilterInfo* filterInfo = ensureFilterInfo(); | |
| 2836 if (!filterInfo->renderer()) { | |
| 2837 RefPtrWillBeRawPtr<FilterEffectRenderer> filterRenderer = FilterEffectRe
nderer::create(); | |
| 2838 filterInfo->setRenderer(filterRenderer.release()); | |
| 2839 } | |
| 2840 | |
| 2841 // If the filter fails to build, remove it from the layer. It will still att
empt to | |
| 2842 // go through regular processing (e.g. compositing), but never apply anythin
g. | |
| 2843 if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(rende
rer()->style()))) | |
| 2844 filterInfo->setRenderer(nullptr); | |
| 2845 } | |
| 2846 | |
| 2847 void RenderLayer::filterNeedsPaintInvalidation() | |
| 2848 { | |
| 2849 { | |
| 2850 DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().
lifecycle()); | |
| 2851 // It's possible for scheduleSVGFilterLayerUpdateHack to schedule a styl
e recalc, which | |
| 2852 // is a problem because this function can be called while performing lay
out. | |
| 2853 // Presumably this represents an illegal data flow of layout or composit
ing | |
| 2854 // information into the style system. | |
| 2855 toElement(renderer()->node())->scheduleSVGFilterLayerUpdateHack(); | |
| 2856 } | |
| 2857 | |
| 2858 renderer()->setShouldDoFullPaintInvalidation(); | |
| 2859 } | |
| 2860 | |
| 2861 void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const | |
| 2862 { | |
| 2863 computeSelfHitTestRects(rects); | |
| 2864 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
| 2865 child->addLayerHitTestRects(rects); | |
| 2866 } | |
| 2867 | |
| 2868 void RenderLayer::computeSelfHitTestRects(LayerHitTestRects& rects) const | |
| 2869 { | |
| 2870 if (!size().isEmpty()) { | |
| 2871 Vector<LayoutRect> rect; | |
| 2872 | |
| 2873 if (renderBox() && renderBox()->scrollsOverflow()) { | |
| 2874 // For scrolling layers, rects are taken to be in the space of the c
ontents. | |
| 2875 // We need to include the bounding box of the layer in the space of
its parent | |
| 2876 // (eg. for border / scroll bars) and if it's composited then the en
tire contents | |
| 2877 // as well as they may be on another composited layer. Skip reportin
g contents | |
| 2878 // for non-composited layers as they'll get projected to the same la
yer as the | |
| 2879 // bounding box. | |
| 2880 if (compositingState() != NotComposited) | |
| 2881 rect.append(m_scrollableArea->overflowRect()); | |
| 2882 | |
| 2883 rects.set(this, rect); | |
| 2884 if (const RenderLayer* parentLayer = parent()) { | |
| 2885 LayerHitTestRects::iterator iter = rects.find(parentLayer); | |
| 2886 if (iter == rects.end()) { | |
| 2887 rects.add(parentLayer, Vector<LayoutRect>()).storedValue->va
lue.append(physicalBoundingBox(parentLayer)); | |
| 2888 } else { | |
| 2889 iter->value.append(physicalBoundingBox(parentLayer)); | |
| 2890 } | |
| 2891 } | |
| 2892 } else { | |
| 2893 rect.append(logicalBoundingBox()); | |
| 2894 rects.set(this, rect); | |
| 2895 } | |
| 2896 } | |
| 2897 } | |
| 2898 | |
| 2899 void RenderLayer::setShouldDoFullPaintInvalidationIncludingNonCompositingDescend
ants() | |
| 2900 { | |
| 2901 renderer()->setShouldDoFullPaintInvalidation(); | |
| 2902 | |
| 2903 // Disable for reading compositingState() in isPaintInvalidationContainer()
below. | |
| 2904 DisableCompositingQueryAsserts disabler; | |
| 2905 | |
| 2906 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
{ | |
| 2907 if (!child->isPaintInvalidationContainer()) | |
| 2908 child->setShouldDoFullPaintInvalidationIncludingNonCompositingDescen
dants(); | |
| 2909 } | |
| 2910 } | |
| 2911 | |
| 2912 DisableCompositingQueryAsserts::DisableCompositingQueryAsserts() | |
| 2913 : m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { } | |
| 2914 | |
| 2915 } // namespace blink | |
| 2916 | |
| 2917 #ifndef NDEBUG | |
| 2918 void showLayerTree(const blink::RenderLayer* layer) | |
| 2919 { | |
| 2920 if (!layer) | |
| 2921 return; | |
| 2922 | |
| 2923 if (blink::LocalFrame* frame = layer->renderer()->frame()) { | |
| 2924 WTF::String output = externalRepresentation(frame, blink::LayoutAsTextSh
owAllLayers | blink::LayoutAsTextShowLayerNesting | blink::LayoutAsTextShowCompo
sitedLayers | blink::LayoutAsTextShowAddresses | blink::LayoutAsTextShowIDAndCla
ss | blink::LayoutAsTextDontUpdateLayout | blink::LayoutAsTextShowLayoutState); | |
| 2925 fprintf(stderr, "%s\n", output.utf8().data()); | |
| 2926 } | |
| 2927 } | |
| 2928 | |
| 2929 void showLayerTree(const blink::RenderObject* renderer) | |
| 2930 { | |
| 2931 if (!renderer) | |
| 2932 return; | |
| 2933 showLayerTree(renderer->enclosingLayer()); | |
| 2934 } | |
| 2935 #endif | |
| OLD | NEW |