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 USA
28 *
29 * Alternatively, the contents of this file may be used under the terms
30 * of either the Mozilla Public License Version 1.1, found at
31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
33 * (the "GPL"), in which case the provisions of the MPL or the GPL are
34 * applicable instead of those above. If you wish to allow use of your
35 * version of this file only under the terms of one of those two
36 * licenses (the MPL or the GPL) and not to allow others to use your
37 * version of this file under the LGPL, indicate your decision by
38 * deletingthe provisions above and replace them with the notice and
39 * other provisions required by the MPL or the GPL, as the case may be.
40 * If you do not delete the provisions above, a recipient may use your
41 * version of this file under any of the LGPL, the MPL or the GPL.
42 */
43
44 #include "config.h"
45 #include "core/rendering/RenderLayer.h"
46
47 #include "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/frame/Settings.h"
56 #include "core/html/HTMLFrameElement.h"
57 #include "core/page/Page.h"
58 #include "core/page/scrolling/ScrollingCoordinator.h"
59 #include "core/rendering/ColumnInfo.h"
60 #include "core/rendering/FilterEffectRenderer.h"
61 #include "core/rendering/HitTestRequest.h"
62 #include "core/rendering/HitTestResult.h"
63 #include "core/rendering/HitTestingTransformState.h"
64 #include "core/rendering/RenderFlowThread.h"
65 #include "core/rendering/RenderGeometryMap.h"
66 #include "core/rendering/RenderInline.h"
67 #include "core/rendering/RenderPart.h"
68 #include "core/rendering/RenderReplica.h"
69 #include "core/rendering/RenderScrollbar.h"
70 #include "core/rendering/RenderScrollbarPart.h"
71 #include "core/rendering/RenderTreeAsText.h"
72 #include "core/rendering/RenderView.h"
73 #include "core/rendering/compositing/CompositedLayerMapping.h"
74 #include "core/rendering/compositing/RenderLayerCompositor.h"
75 #include "core/rendering/svg/ReferenceFilterBuilder.h"
76 #include "core/rendering/svg/RenderSVGResourceClipper.h"
77 #include "platform/LengthFunctions.h"
78 #include "platform/Partitions.h"
79 #include "platform/RuntimeEnabledFeatures.h"
80 #include "platform/TraceEvent.h"
81 #include "platform/geometry/FloatPoint3D.h"
82 #include "platform/geometry/FloatRect.h"
83 #include "platform/geometry/TransformState.h"
84 #include "platform/graphics/GraphicsContextStateSaver.h"
85 #include "platform/graphics/filters/ReferenceFilter.h"
86 #include "platform/graphics/filters/SourceGraphic.h"
87 #include "platform/transforms/ScaleTransformOperation.h"
88 #include "platform/transforms/TransformationMatrix.h"
89 #include "platform/transforms/TranslateTransformOperation.h"
90 #include "public/platform/Platform.h"
91 #include "wtf/StdLibExtras.h"
92 #include "wtf/text/CString.h"
93
94 namespace blink {
95
96 namespace {
97
98 static CompositingQueryMode gCompositingQueryMode =
99 CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases;
100
101 } // namespace
102
103 using namespace HTMLNames;
104
RenderLayer(RenderLayerModelObject * renderer,LayerType type)105 RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type)
106 : m_layerType(type)
107 , m_hasSelfPaintingLayerDescendant(false)
108 , m_hasSelfPaintingLayerDescendantDirty(false)
109 , m_isRootLayer(renderer->isRenderView())
110 , m_usedTransparency(false)
111 , m_visibleContentStatusDirty(true)
112 , m_hasVisibleContent(false)
113 , m_visibleDescendantStatusDirty(false)
114 , m_hasVisibleDescendant(false)
115 , m_hasVisibleNonLayerContent(false)
116 , m_isPaginated(false)
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
~RenderLayer()154 RenderLayer::~RenderLayer()
155 {
156 if (renderer()->frame() && renderer()->frame()->page()) {
157 if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->page()->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
debugName() const178 String RenderLayer::debugName() const
179 {
180 if (isReflection()) {
181 return renderer()->parent()->debugName() + " (reflection)";
182 }
183 return renderer()->debugName();
184 }
185
compositor() const186 RenderLayerCompositor* RenderLayer::compositor() const
187 {
188 if (!renderer()->view())
189 return 0;
190 return renderer()->view()->compositor();
191 }
192
contentChanged(ContentChangeType changeType)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.html
197 DisableCompositingQueryAsserts disabler;
198
199 if (changeType == CanvasChanged)
200 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
201
202 if (changeType == CanvasContextChanged) {
203 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
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(GraphicsLayerUpdateSubtree);
211 }
212
213 if (m_compositedLayerMapping)
214 m_compositedLayerMapping->contentChanged(changeType);
215 }
216
paintsWithFilters() const217 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() != PaintsIntoOwnBacking;
225 }
226
subpixelAccumulation() const227 LayoutSize RenderLayer::subpixelAccumulation() const
228 {
229 return m_subpixelAccumulation;
230 }
231
setSubpixelAccumulation(const LayoutSize & size)232 void RenderLayer::setSubpixelAccumulation(const LayoutSize& size)
233 {
234 m_subpixelAccumulation = size;
235 }
236
updateLayerPositionsAfterLayout()237 void RenderLayer::updateLayerPositionsAfterLayout()
238 {
239 TRACE_EVENT0("blink", "RenderLayer::updateLayerPositionsAfterLayout");
240
241 m_clipper.clearClipRectsIncludingDescendants();
242 updateLayerPositionRecursive();
243
244 {
245 // FIXME: Remove incremental compositing updates after fixing the chicken/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
updateLayerPositionRecursive()253 void RenderLayer::updateLayerPositionRecursive()
254 {
255 if (m_reflectionInfo)
256 m_reflectionInfo->reflection()->layout();
257
258 // FIXME: We should be able to remove this call because we don't care about
259 // any descendant-dependent flags, but code somewhere else is reading these
260 // flags and depending on us to update them.
261 updateDescendantDependentFlags();
262
263 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
264 child->updateLayerPositionRecursive();
265 }
266
updateHasSelfPaintingLayerDescendant() const267 void RenderLayer::updateHasSelfPaintingLayerDescendant() const
268 {
269 ASSERT(m_hasSelfPaintingLayerDescendantDirty);
270
271 m_hasSelfPaintingLayerDescendant = false;
272
273 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
274 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) {
275 m_hasSelfPaintingLayerDescendant = true;
276 break;
277 }
278 }
279
280 m_hasSelfPaintingLayerDescendantDirty = false;
281 }
282
dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()283 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
284 {
285 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
286 layer->m_hasSelfPaintingLayerDescendantDirty = true;
287 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
288 // in this case, there is no need to dirty our ancestors further.
289 if (layer->isSelfPaintingLayer()) {
290 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->m_hasSelfPaintingLayerDescendant);
291 break;
292 }
293 }
294 }
295
scrollsWithViewport() const296 bool RenderLayer::scrollsWithViewport() const
297 {
298 return renderer()->style()->position() == FixedPosition && renderer()->containerForFixedPosition() == renderer()->view();
299 }
300
scrollsWithRespectTo(const RenderLayer * other) const301 bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const
302 {
303 if (scrollsWithViewport() != other->scrollsWithViewport())
304 return true;
305 return ancestorScrollingLayer() != other->ancestorScrollingLayer();
306 }
307
updateTransformationMatrix()308 void RenderLayer::updateTransformationMatrix()
309 {
310 if (m_transform) {
311 RenderBox* box = renderBox();
312 ASSERT(box);
313 m_transform->makeIdentity();
314 box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
315 makeMatrixRenderable(*m_transform, compositor()->hasAcceleratedCompositing());
316 }
317 }
318
updateTransform(const RenderStyle * oldStyle,RenderStyle * newStyle)319 void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle)
320 {
321 if (oldStyle && newStyle->transformDataEquivalent(*oldStyle))
322 return;
323
324 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
325 // so check style too.
326 bool hasTransform = renderer()->hasTransform() && newStyle->hasTransform();
327 bool had3DTransform = has3DTransform();
328
329 bool hadTransform = m_transform;
330 if (hasTransform != hadTransform) {
331 if (hasTransform)
332 m_transform = adoptPtr(new TransformationMatrix);
333 else
334 m_transform.clear();
335
336 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
337 m_clipper.clearClipRectsIncludingDescendants();
338 } else if (hasTransform) {
339 m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects);
340 }
341
342 updateTransformationMatrix();
343
344 if (had3DTransform != has3DTransform())
345 dirty3DTransformedDescendantStatus();
346 }
347
enclosingLayerForContainingBlock(RenderLayer * layer)348 static RenderLayer* enclosingLayerForContainingBlock(RenderLayer* layer)
349 {
350 if (RenderObject* containingBlock = layer->renderer()->containingBlock())
351 return containingBlock->enclosingLayer();
352 return 0;
353 }
354
renderingContextRoot()355 RenderLayer* RenderLayer::renderingContextRoot()
356 {
357 RenderLayer* renderingContext = 0;
358
359 if (shouldPreserve3D())
360 renderingContext = this;
361
362 for (RenderLayer* current = enclosingLayerForContainingBlock(this); current && current->shouldPreserve3D(); current = enclosingLayerForContainingBlock(current))
363 renderingContext = current;
364
365 return renderingContext;
366 }
367
currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const368 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
369 {
370 if (!m_transform)
371 return TransformationMatrix();
372
373 // m_transform includes transform-origin, so we need to recompute the transform here.
374 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
375 RenderBox* box = renderBox();
376 TransformationMatrix currTransform;
377 box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
378 makeMatrixRenderable(currTransform, compositor()->hasAcceleratedCompositing());
379 return currTransform;
380 }
381
382 return *m_transform;
383 }
384
renderableTransform(PaintBehavior paintBehavior) const385 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
386 {
387 if (!m_transform)
388 return TransformationMatrix();
389
390 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
391 TransformationMatrix matrix = *m_transform;
392 makeMatrixRenderable(matrix, false /* flatten 3d */);
393 return matrix;
394 }
395
396 return *m_transform;
397 }
398
enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const399 RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
400 {
401 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
402 while (layer) {
403 if (layer->renderer()->hasOverflowClip())
404 return const_cast<RenderLayer*>(layer);
405
406 layer = layer->parent();
407 }
408 return 0;
409 }
410
checkContainingBlockChainForPagination(RenderLayerModelObject * renderer,RenderBox * ancestorColumnsRenderer)411 static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer)
412 {
413 RenderView* view = renderer->view();
414 RenderLayerModelObject* prevBlock = renderer;
415 RenderBlock* containingBlock;
416 for (containingBlock = renderer->containingBlock();
417 containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer;
418 containingBlock = containingBlock->containingBlock())
419 prevBlock = containingBlock;
420
421 // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
422 if (containingBlock != ancestorColumnsRenderer)
423 return false;
424
425 // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
426 if (prevBlock->isOutOfFlowPositioned())
427 return false;
428
429 // Otherwise we are paginated by the columns block.
430 return true;
431 }
432
useRegionBasedColumns() const433 bool RenderLayer::useRegionBasedColumns() const
434 {
435 return renderer()->document().regionBasedColumnsEnabled();
436 }
437
updatePaginationRecursive(bool needsPaginationUpdate)438 void RenderLayer::updatePaginationRecursive(bool needsPaginationUpdate)
439 {
440 m_isPaginated = false;
441 m_enclosingPaginationLayer = 0;
442
443 if (useRegionBasedColumns() && renderer()->isRenderFlowThread())
444 needsPaginationUpdate = true;
445
446 if (needsPaginationUpdate)
447 updatePagination();
448
449 if (renderer()->hasColumns())
450 needsPaginationUpdate = true;
451
452 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
453 child->updatePaginationRecursive(needsPaginationUpdate);
454 }
455
updatePagination()456 void RenderLayer::updatePagination()
457 {
458 if (compositingState() != NotComposited || !parent())
459 return; // FIXME: We will have to deal with paginated compositing layers someday.
460 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
461
462 // The main difference between the paginated booleans for the old column code and the new column code
463 // is that each paginated layer has to paint on its own with the new code. There is no
464 // recurring into child layers. This means that the m_isPaginated bits for the new column code can't just be set on
465 // "roots" that get split and paint all their descendants. Instead each layer has to be checked individually and
466 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
467 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
468 // to that layer easily.
469 bool regionBasedColumnsUsed = useRegionBasedColumns();
470 if (regionBasedColumnsUsed && renderer()->isRenderFlowThread()) {
471 m_enclosingPaginationLayer = this;
472 return;
473 }
474
475 if (m_stackingNode->isNormalFlowOnly()) {
476 if (regionBasedColumnsUsed) {
477 // Content inside a transform is not considered to be paginated, since we simply
478 // paint the transform multiple times in each column, so we don't have to use
479 // fragments for the transformed content.
480 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
481 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
482 m_enclosingPaginationLayer = 0;
483 } else {
484 m_isPaginated = parent()->renderer()->hasColumns();
485 }
486 return;
487 }
488
489 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
490 // we find one, then we just check its pagination status.
491 if (regionBasedColumnsUsed) {
492 RenderView* view = renderer()->view();
493 RenderBlock* containingBlock;
494 for (containingBlock = renderer()->containingBlock();
495 containingBlock && containingBlock != view;
496 containingBlock = containingBlock->containingBlock()) {
497 if (containingBlock->hasLayer()) {
498 // Content inside a transform is not considered to be paginated, since we simply
499 // paint the transform multiple times in each column, so we don't have to use
500 // fragments for the transformed content.
501 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer();
502 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
503 m_enclosingPaginationLayer = 0;
504 return;
505 }
506 }
507 return;
508 }
509
510 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container.
511 RenderLayerStackingNode* ancestorStackingContextNode = m_stackingNode->ancestorStackingContextNode();
512 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
513 if (curr->renderer()->hasColumns()) {
514 m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
515 return;
516 }
517 if (curr->stackingNode() == ancestorStackingContextNode)
518 return;
519 }
520 }
521
positionFromPaintInvalidationBacking(const RenderObject * renderObject,const RenderLayerModelObject * paintInvalidationContainer,const PaintInvalidationState * paintInvalidationState)522 LayoutPoint RenderLayer::positionFromPaintInvalidationBacking(const RenderObject* renderObject, const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
523 {
524 FloatPoint point = renderObject->localToContainerPoint(FloatPoint(), paintInvalidationContainer, 0, 0, paintInvalidationState);
525
526 // FIXME: Eventually we are going to unify coordinates in GraphicsLayer space.
527 if (paintInvalidationContainer && paintInvalidationContainer->layer()->groupedMapping())
528 mapPointToPaintBackingCoordinates(paintInvalidationContainer, point);
529
530 return LayoutPoint(point);
531 }
532
mapPointToPaintBackingCoordinates(const RenderLayerModelObject * paintInvalidationContainer,FloatPoint & point)533 void RenderLayer::mapPointToPaintBackingCoordinates(const RenderLayerModelObject* paintInvalidationContainer, FloatPoint& point)
534 {
535 RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer();
536 if (!paintInvalidationLayer->groupedMapping()) {
537 point.move(paintInvalidationLayer->compositedLayerMapping()->contentOffsetInCompositingLayer());
538 return;
539 }
540
541 RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclosingTransformedAncestor()->renderer();
542 if (!transformedAncestor)
543 return;
544
545 // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the
546 // transformed ancestor.
547 point = paintInvalidationContainer->localToContainerPoint(point, transformedAncestor);
548
549 point.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor());
550 }
551
mapRectToPaintBackingCoordinates(const RenderLayerModelObject * paintInvalidationContainer,LayoutRect & rect)552 void RenderLayer::mapRectToPaintBackingCoordinates(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect)
553 {
554 RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer();
555 if (!paintInvalidationLayer->groupedMapping()) {
556 rect.move(paintInvalidationLayer->compositedLayerMapping()->contentOffsetInCompositingLayer());
557 return;
558 }
559
560 RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclosingTransformedAncestor()->renderer();
561 if (!transformedAncestor)
562 return;
563
564 // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the
565 // transformed ancestor.
566 rect = LayoutRect(paintInvalidationContainer->localToContainerQuad(FloatRect(rect), transformedAncestor).boundingBox());
567
568 rect.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor());
569 }
570
mapRectToPaintInvalidationBacking(const RenderObject * renderObject,const RenderLayerModelObject * paintInvalidationContainer,LayoutRect & rect,const PaintInvalidationState * paintInvalidationState)571 void RenderLayer::mapRectToPaintInvalidationBacking(const RenderObject* renderObject, const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState)
572 {
573 if (!paintInvalidationContainer->layer()->groupedMapping()) {
574 renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
575 return;
576 }
577
578 // This code adjusts the paint invalidation rectangle to be in the space of the transformed ancestor of the grouped (i.e. squashed)
579 // layer. This is because all layers that squash together need to issue paint invalidations w.r.t. a single container that is
580 // an ancestor of all of them, in order to properly take into account any local transforms etc.
581 // FIXME: remove this special-case code that works around the paint invalidation code structure.
582 renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
583
584 mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
585 }
586
computePaintInvalidationRect(const RenderObject * renderObject,const RenderLayer * paintInvalidationContainer,const PaintInvalidationState * paintInvalidationState)587 LayoutRect RenderLayer::computePaintInvalidationRect(const RenderObject* renderObject, const RenderLayer* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
588 {
589 if (!paintInvalidationContainer->groupedMapping())
590 return renderObject->computePaintInvalidationRect(paintInvalidationContainer->renderer(), paintInvalidationState);
591
592 LayoutRect rect = renderObject->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer->renderer(), paintInvalidationState);
593 mapRectToPaintBackingCoordinates(paintInvalidationContainer->renderer(), rect);
594 return rect;
595 }
596
dirtyVisibleContentStatus()597 void RenderLayer::dirtyVisibleContentStatus()
598 {
599 m_visibleContentStatusDirty = true;
600 if (parent())
601 parent()->dirtyAncestorChainVisibleDescendantStatus();
602 }
603
potentiallyDirtyVisibleContentStatus(EVisibility visibility)604 void RenderLayer::potentiallyDirtyVisibleContentStatus(EVisibility visibility)
605 {
606 if (m_visibleContentStatusDirty)
607 return;
608 if (hasVisibleContent() == (visibility == VISIBLE))
609 return;
610 dirtyVisibleContentStatus();
611 }
612
dirtyAncestorChainVisibleDescendantStatus()613 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
614 {
615 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
616 if (layer->m_visibleDescendantStatusDirty)
617 break;
618
619 layer->m_visibleDescendantStatusDirty = true;
620 }
621 }
622
623 // FIXME: this is quite brute-force. We could be more efficient if we were to
624 // track state and update it as appropriate as changes are made in the Render tree.
updateScrollingStateAfterCompositingChange()625 void RenderLayer::updateScrollingStateAfterCompositingChange()
626 {
627 TRACE_EVENT0("blink", "RenderLayer::updateScrollingStateAfterCompositingChange");
628 m_hasVisibleNonLayerContent = false;
629 for (RenderObject* r = renderer()->slowFirstChild(); r; r = r->nextSibling()) {
630 if (!r->hasLayer()) {
631 m_hasVisibleNonLayerContent = true;
632 break;
633 }
634 }
635
636 m_hasNonCompositedChild = false;
637 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
638 if (child->compositingState() == NotComposited || child->compositingState() == HasOwnBackingButPaintsIntoAncestor) {
639 m_hasNonCompositedChild = true;
640 return;
641 }
642 }
643 }
644
645 // The descendant-dependent flags system is badly broken because we clean dirty
646 // bits in upward tree walks, which means we need to call updateDescendantDependentFlags
647 // at every node in the tree to fully clean all the dirty bits. While we'll in
648 // the process of fixing this issue, updateDescendantDependentFlagsForEntireSubtree
649 // provides a big hammer for actually cleaning all the dirty bits in a subtree.
650 //
651 // FIXME: Remove this function once the descendant-dependent flags system keeps
652 // its dirty bits scoped to subtrees.
updateDescendantDependentFlagsForEntireSubtree()653 void RenderLayer::updateDescendantDependentFlagsForEntireSubtree()
654 {
655 updateDescendantDependentFlags();
656
657 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
658 child->updateDescendantDependentFlagsForEntireSubtree();
659 }
660
updateDescendantDependentFlags()661 void RenderLayer::updateDescendantDependentFlags()
662 {
663 if (m_visibleDescendantStatusDirty) {
664 m_hasVisibleDescendant = false;
665
666 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
667 child->updateDescendantDependentFlags();
668
669 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
670 m_hasVisibleDescendant = true;
671 break;
672 }
673 }
674
675 m_visibleDescendantStatusDirty = false;
676 }
677
678 if (m_visibleContentStatusDirty) {
679 bool previouslyHasVisibleContent = m_hasVisibleContent;
680 if (renderer()->style()->visibility() == VISIBLE)
681 m_hasVisibleContent = true;
682 else {
683 // layer may be hidden but still have some visible content, check for this
684 m_hasVisibleContent = false;
685 RenderObject* r = renderer()->slowFirstChild();
686 while (r) {
687 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
688 m_hasVisibleContent = true;
689 break;
690 }
691 RenderObject* rendererFirstChild = r->slowFirstChild();
692 if (rendererFirstChild && !r->hasLayer())
693 r = rendererFirstChild;
694 else if (r->nextSibling())
695 r = r->nextSibling();
696 else {
697 do {
698 r = r->parent();
699 if (r == renderer())
700 r = 0;
701 } while (r && !r->nextSibling());
702 if (r)
703 r = r->nextSibling();
704 }
705 }
706 }
707 m_visibleContentStatusDirty = false;
708
709 if (hasVisibleContent() != previouslyHasVisibleContent) {
710 setNeedsCompositingInputsUpdate();
711 // We need to tell m_renderer to recheck its rect because we
712 // pretend that invisible RenderObjects have 0x0 rects. Changing
713 // visibility therefore changes our rect and we need to visit
714 // this RenderObject during the invalidateTreeIfNeeded walk.
715 m_renderer->setMayNeedPaintInvalidation(true);
716 }
717 }
718 }
719
dirty3DTransformedDescendantStatus()720 void RenderLayer::dirty3DTransformedDescendantStatus()
721 {
722 RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContextNode();
723 if (!stackingNode)
724 return;
725
726 stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
727
728 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
729 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
730 while (stackingNode && stackingNode->layer()->preserves3D()) {
731 stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
732 stackingNode = stackingNode->ancestorStackingContextNode();
733 }
734 }
735
736 // Return true if this layer or any preserve-3d descendants have 3d.
update3DTransformedDescendantStatus()737 bool RenderLayer::update3DTransformedDescendantStatus()
738 {
739 if (m_3DTransformedDescendantStatusDirty) {
740 m_has3DTransformedDescendant = false;
741
742 m_stackingNode->updateZOrderLists();
743
744 // Transformed or preserve-3d descendants can only be in the z-order lists, not
745 // in the normal flow list, so we only need to check those.
746 RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), PositiveZOrderChildren | NegativeZOrderChildren);
747 while (RenderLayerStackingNode* node = iterator.next())
748 m_has3DTransformedDescendant |= node->layer()->update3DTransformedDescendantStatus();
749
750 m_3DTransformedDescendantStatusDirty = false;
751 }
752
753 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
754 // the m_has3DTransformedDescendant set.
755 if (preserves3D())
756 return has3DTransform() || m_has3DTransformedDescendant;
757
758 return has3DTransform();
759 }
760
size() const761 IntSize RenderLayer::size() const
762 {
763 if (renderer()->isInline() && renderer()->isRenderInline())
764 return toRenderInline(renderer())->linesBoundingBox().size();
765
766 // FIXME: Is snapping the size really needed here?
767 if (RenderBox* box = renderBox())
768 return pixelSnappedIntSize(box->size(), box->location());
769
770 return IntSize();
771 }
772
location() const773 LayoutPoint RenderLayer::location() const
774 {
775 LayoutPoint localPoint;
776 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
777
778 if (renderer()->isInline() && renderer()->isRenderInline()) {
779 RenderInline* inlineFlow = toRenderInline(renderer());
780 IntRect lineBox = inlineFlow->linesBoundingBox();
781 inlineBoundingBoxOffset = toSize(lineBox.location());
782 localPoint += inlineBoundingBoxOffset;
783 } else if (RenderBox* box = renderBox()) {
784 localPoint += box->topLeftLocationOffset();
785 }
786
787 if (!renderer()->isOutOfFlowPositioned() && renderer()->parent()) {
788 // We must adjust our position by walking up the render tree looking for the
789 // nearest enclosing object with a layer.
790 RenderObject* curr = renderer()->parent();
791 while (curr && !curr->hasLayer()) {
792 if (curr->isBox() && !curr->isTableRow()) {
793 // Rows and cells share the same coordinate space (that of the section).
794 // Omit them when computing our xpos/ypos.
795 localPoint += toRenderBox(curr)->topLeftLocationOffset();
796 }
797 curr = curr->parent();
798 }
799 if (curr->isBox() && curr->isTableRow()) {
800 // Put ourselves into the row coordinate space.
801 localPoint -= toRenderBox(curr)->topLeftLocationOffset();
802 }
803 }
804
805 // Subtract our parent's scroll offset.
806 if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
807 RenderLayer* positionedParent = enclosingPositionedAncestor();
808
809 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
810 if (positionedParent->renderer()->hasOverflowClip()) {
811 LayoutSize offset = positionedParent->renderBox()->scrolledContentOffset();
812 localPoint -= offset;
813 }
814
815 if (positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
816 LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(*toRenderBox(renderer()));
817 localPoint += offset;
818 }
819 } else if (parent()) {
820 // FIXME: This code is very wrong. The compositing system doesn't
821 // understand columns and we're hacking around that fact by faking
822 // the position of the RenderLayers when we think we'll end up being
823 // composited. Hopefully we'll be able to unwind this hack when we
824 // implement multi-column using regions.
825 if (hasStyleDeterminedDirectCompositingReasons()) {
826 // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
827 // They won't split across columns properly.
828 if (!parent()->renderer()->hasColumns() && parent()->renderer()->isDocumentElement() && renderer()->view()->hasColumns())
829 localPoint += renderer()->view()->columnOffset(localPoint);
830 else
831 localPoint += parent()->renderer()->columnOffset(localPoint);
832 }
833
834 if (parent()->renderer()->hasOverflowClip()) {
835 IntSize scrollOffset = parent()->renderBox()->scrolledContentOffset();
836 localPoint -= scrollOffset;
837 }
838 }
839
840 localPoint.move(offsetForInFlowPosition());
841
842 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
843 localPoint -= inlineBoundingBoxOffset;
844
845 return localPoint;
846 }
847
offsetForInFlowPosition() const848 const LayoutSize RenderLayer::offsetForInFlowPosition() const
849 {
850 return renderer()->isRelPositioned() ? toRenderBoxModelObject(renderer())->offsetForInFlowPosition() : LayoutSize();
851 }
852
perspectiveTransform() const853 TransformationMatrix RenderLayer::perspectiveTransform() const
854 {
855 if (!renderer()->hasTransform())
856 return TransformationMatrix();
857
858 RenderStyle* style = renderer()->style();
859 if (!style->hasPerspective())
860 return TransformationMatrix();
861
862 // Maybe fetch the perspective from the backing?
863 const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect();
864 const float boxWidth = borderBox.width();
865 const float boxHeight = borderBox.height();
866
867 float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(), boxWidth);
868 float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(), boxHeight);
869
870 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
871 // We want it to be in the top-left, so subtract half the height and width.
872 perspectiveOriginX -= boxWidth / 2.0f;
873 perspectiveOriginY -= boxHeight / 2.0f;
874
875 TransformationMatrix t;
876 t.translate(perspectiveOriginX, perspectiveOriginY);
877 t.applyPerspective(style->perspective());
878 t.translate(-perspectiveOriginX, -perspectiveOriginY);
879
880 return t;
881 }
882
perspectiveOrigin() const883 FloatPoint RenderLayer::perspectiveOrigin() const
884 {
885 if (!renderer()->hasTransform())
886 return FloatPoint();
887
888 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
889 RenderStyle* style = renderer()->style();
890
891 return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width().toFloat()), floatValueForLength(style->perspectiveOriginY(), borderBox.height().toFloat()));
892 }
893
isFixedPositionedContainer(RenderLayer * layer)894 static inline bool isFixedPositionedContainer(RenderLayer* layer)
895 {
896 return layer->isRootLayer() || layer->hasTransform();
897 }
898
enclosingPositionedAncestor() const899 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
900 {
901 RenderLayer* curr = parent();
902 while (curr && !curr->isPositionedContainer())
903 curr = curr->parent();
904
905 return curr;
906 }
907
enclosingTransformedAncestor() const908 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
909 {
910 RenderLayer* curr = parent();
911 while (curr && !curr->isRootLayer() && !curr->renderer()->hasTransform())
912 curr = curr->parent();
913
914 return curr;
915 }
916
computeOffsetFromTransformedAncestor() const917 LayoutPoint RenderLayer::computeOffsetFromTransformedAncestor() const
918 {
919 const AncestorDependentCompositingInputs& properties = ancestorDependentCompositingInputs();
920
921 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
922 // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip are correct.
923 renderer()->mapLocalToContainer(properties.transformAncestor ? properties.transformAncestor->renderer() : 0, transformState, ApplyContainerFlip);
924 transformState.flatten();
925 return LayoutPoint(transformState.lastPlanarPoint());
926 }
927
compositingContainer() const928 const RenderLayer* RenderLayer::compositingContainer() const
929 {
930 if (stackingNode()->isNormalFlowOnly())
931 return parent();
932 if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestorStackingContextNode())
933 return ancestorStackingNode->layer();
934 return 0;
935 }
936
isPaintInvalidationContainer() const937 bool RenderLayer::isPaintInvalidationContainer() const
938 {
939 return compositingState() == PaintsIntoOwnBacking || compositingState() == PaintsIntoGroupedBacking;
940 }
941
942 // Note: enclosingCompositingLayer does not include squashed layers. Compositing stacking children of squashed layers
943 // receive graphics layers that are parented to the compositing ancestor of the squashed layer.
enclosingLayerWithCompositedLayerMapping(IncludeSelfOrNot includeSelf) const944 RenderLayer* RenderLayer::enclosingLayerWithCompositedLayerMapping(IncludeSelfOrNot includeSelf) const
945 {
946 ASSERT(isAllowedToQueryCompositingState());
947
948 if ((includeSelf == IncludeSelf) && compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking)
949 return const_cast<RenderLayer*>(this);
950
951 for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) {
952 if (curr->compositingState() != NotComposited && curr->compositingState() != PaintsIntoGroupedBacking)
953 return const_cast<RenderLayer*>(curr);
954 }
955
956 return 0;
957 }
958
959 // Return the enclosingCompositedLayerForPaintInvalidation for the given RenderLayer
960 // including crossing frame boundaries.
enclosingLayerForPaintInvalidationCrossingFrameBoundaries() const961 RenderLayer* RenderLayer::enclosingLayerForPaintInvalidationCrossingFrameBoundaries() const
962 {
963 const RenderLayer* layer = this;
964 RenderLayer* compositedLayer = 0;
965 while (!compositedLayer) {
966 compositedLayer = layer->enclosingLayerForPaintInvalidation();
967 if (!compositedLayer) {
968 RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
969 if (!owner)
970 break;
971 layer = owner->enclosingLayer();
972 }
973 }
974 return compositedLayer;
975 }
976
enclosingLayerForPaintInvalidation() const977 RenderLayer* RenderLayer::enclosingLayerForPaintInvalidation() const
978 {
979 ASSERT(isAllowedToQueryCompositingState());
980
981 if (isPaintInvalidationContainer())
982 return const_cast<RenderLayer*>(this);
983
984 for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) {
985 if (curr->isPaintInvalidationContainer())
986 return const_cast<RenderLayer*>(curr);
987 }
988
989 return 0;
990 }
991
setNeedsCompositingInputsUpdate()992 void RenderLayer::setNeedsCompositingInputsUpdate()
993 {
994 m_needsAncestorDependentCompositingInputsUpdate = true;
995 m_needsDescendantDependentCompositingInputsUpdate = true;
996
997 for (RenderLayer* current = this; current && !current->m_childNeedsCompositingInputsUpdate; current = current->parent())
998 current->m_childNeedsCompositingInputsUpdate = true;
999
1000 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
1001 }
1002
updateAncestorDependentCompositingInputs(const AncestorDependentCompositingInputs & compositingInputs)1003 void RenderLayer::updateAncestorDependentCompositingInputs(const AncestorDependentCompositingInputs& compositingInputs)
1004 {
1005 m_ancestorDependentCompositingInputs = compositingInputs;
1006 m_needsAncestorDependentCompositingInputsUpdate = false;
1007 }
1008
updateDescendantDependentCompositingInputs(const DescendantDependentCompositingInputs & compositingInputs)1009 void RenderLayer::updateDescendantDependentCompositingInputs(const DescendantDependentCompositingInputs& compositingInputs)
1010 {
1011 m_descendantDependentCompositingInputs = compositingInputs;
1012 m_needsDescendantDependentCompositingInputsUpdate = false;
1013 }
1014
didUpdateCompositingInputs()1015 void RenderLayer::didUpdateCompositingInputs()
1016 {
1017 ASSERT(!needsCompositingInputsUpdate());
1018 m_childNeedsCompositingInputsUpdate = false;
1019 if (m_scrollableArea)
1020 m_scrollableArea->updateNeedsCompositedScrolling();
1021 }
1022
setCompositingReasons(CompositingReasons reasons,CompositingReasons mask)1023 void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingReasons mask)
1024 {
1025 if ((compositingReasons() & mask) == (reasons & mask))
1026 return;
1027 m_compositingReasons = (reasons & mask) | (compositingReasons() & ~mask);
1028 }
1029
setHasCompositingDescendant(bool hasCompositingDescendant)1030 void RenderLayer::setHasCompositingDescendant(bool hasCompositingDescendant)
1031 {
1032 if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescendant))
1033 return;
1034
1035 m_hasCompositingDescendant = hasCompositingDescendant;
1036
1037 if (hasCompositedLayerMapping())
1038 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
1039 }
1040
setShouldIsolateCompositedDescendants(bool shouldIsolateCompositedDescendants)1041 void RenderLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateCompositedDescendants)
1042 {
1043 if (m_shouldIsolateCompositedDescendants == static_cast<unsigned>(shouldIsolateCompositedDescendants))
1044 return;
1045
1046 m_shouldIsolateCompositedDescendants = shouldIsolateCompositedDescendants;
1047
1048 if (hasCompositedLayerMapping())
1049 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
1050 }
1051
hasAncestorWithFilterOutsets() const1052 bool RenderLayer::hasAncestorWithFilterOutsets() const
1053 {
1054 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1055 RenderLayerModelObject* renderer = curr->renderer();
1056 if (renderer->style()->hasFilterOutsets())
1057 return true;
1058 }
1059 return false;
1060 }
1061
transparentPaintingAncestor()1062 RenderLayer* RenderLayer::transparentPaintingAncestor()
1063 {
1064 if (hasCompositedLayerMapping())
1065 return 0;
1066
1067 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1068 if (curr->hasCompositedLayerMapping())
1069 return 0;
1070 if (curr->isTransparent())
1071 return curr;
1072 }
1073 return 0;
1074 }
1075
1076 enum TransparencyClipBoxBehavior {
1077 PaintingTransparencyClipBox,
1078 HitTestingTransparencyClipBox
1079 };
1080
1081 enum TransparencyClipBoxMode {
1082 DescendantsOfTransparencyClipBox,
1083 RootOfTransparencyClipBox
1084 };
1085
1086 static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, const LayoutSize& subPixelAccumulation, PaintBehavior = 0);
1087
expandClipRectForDescendantsAndReflection(LayoutRect & clipRect,const RenderLayer * layer,const RenderLayer * rootLayer,TransparencyClipBoxBehavior transparencyBehavior,const LayoutSize & subPixelAccumulation,PaintBehavior paintBehavior)1088 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
1089 TransparencyClipBoxBehavior transparencyBehavior, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
1090 {
1091 // If we have a mask, then the clip is limited to the border box area (and there is
1092 // no need to examine child layers).
1093 if (!layer->renderer()->hasMask()) {
1094 // Note: we don't have to walk z-order lists since transparent elements always establish
1095 // a stacking container. This means we can just walk the layer tree directly.
1096 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
1097 if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionLayer() != curr)
1098 clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, subPixelAccumulation, paintBehavior));
1099 }
1100 }
1101
1102 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1103 // current transparencyClipBox to catch all child layers.
1104 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1105 // size into the parent layer.
1106 if (layer->renderer()->hasReflection()) {
1107 LayoutPoint delta;
1108 layer->convertToLayerCoords(rootLayer, delta);
1109 clipRect.move(-delta.x(), -delta.y());
1110 clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
1111 clipRect.moveBy(delta);
1112 }
1113 }
1114
transparencyClipBox(const RenderLayer * layer,const RenderLayer * rootLayer,TransparencyClipBoxBehavior transparencyBehavior,TransparencyClipBoxMode transparencyMode,const LayoutSize & subPixelAccumulation,PaintBehavior paintBehavior)1115 static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
1116 TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
1117 {
1118 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1119 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1120 // would be better to respect clips.
1121
1122 if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
1123 || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) {
1124 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1125 // the transformed layer and all of its children.
1126 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0;
1127 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
1128 LayoutPoint delta;
1129 layer->convertToLayerCoords(rootLayerForTransform, delta);
1130
1131 delta.move(subPixelAccumulation);
1132 IntPoint pixelSnappedDelta = roundedIntPoint(delta);
1133 TransformationMatrix transform;
1134 transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y());
1135 transform = transform * *layer->transform();
1136
1137 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
1138 // paints unfragmented.
1139 LayoutRect clipRect = layer->physicalBoundingBox(layer);
1140 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, subPixelAccumulation, paintBehavior);
1141 layer->renderer()->style()->filterOutsets().expandRect(clipRect);
1142 LayoutRect result = transform.mapRect(clipRect);
1143 if (!paginationLayer)
1144 return result;
1145
1146 // We have to break up the transformed extent across our columns.
1147 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
1148 // get our true bounding box.
1149 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
1150 result = enclosingFlowThread->fragmentsBoundingBox(result);
1151
1152 LayoutPoint rootLayerDelta;
1153 paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
1154 result.moveBy(rootLayerDelta);
1155 return result;
1156 }
1157
1158 LayoutRect clipRect = layer->physicalBoundingBox(rootLayer);
1159 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, subPixelAccumulation, paintBehavior);
1160 layer->renderer()->style()->filterOutsets().expandRect(clipRect);
1161 clipRect.move(subPixelAccumulation);
1162 return clipRect;
1163 }
1164
paintingExtent(const RenderLayer * rootLayer,const LayoutRect & paintDirtyRect,const LayoutSize & subPixelAccumulation,PaintBehavior paintBehavior)1165 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
1166 {
1167 return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, subPixelAccumulation, paintBehavior), paintDirtyRect);
1168 }
1169
beginTransparencyLayers(GraphicsContext * context,const RenderLayer * rootLayer,const LayoutRect & paintDirtyRect,const LayoutSize & subPixelAccumulation,PaintBehavior paintBehavior)1170 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
1171 {
1172 bool createTransparencyLayerForBlendMode = m_stackingNode->isStackingContext() && hasDescendantWithBlendMode();
1173 if ((paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency)
1174 return;
1175
1176 RenderLayer* ancestor = transparentPaintingAncestor();
1177 if (ancestor)
1178 ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior);
1179
1180 if (paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) {
1181 m_usedTransparency = true;
1182 context->save();
1183 LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior);
1184 context->clip(clipRect);
1185
1186 if (paintsWithBlendMode())
1187 context->setCompositeOperation(context->compositeOperation(), m_renderer->style()->blendMode());
1188
1189 context->beginTransparencyLayer(renderer()->opacity());
1190
1191 if (paintsWithBlendMode())
1192 context->setCompositeOperation(context->compositeOperation(), WebBlendModeNormal);
1193 #ifdef REVEAL_TRANSPARENCY_LAYERS
1194 context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
1195 context->fillRect(clipRect);
1196 #endif
1197 }
1198 }
1199
operator new(size_t sz)1200 void* RenderLayer::operator new(size_t sz)
1201 {
1202 return partitionAlloc(Partitions::getRenderingPartition(), sz);
1203 }
1204
operator delete(void * ptr)1205 void RenderLayer::operator delete(void* ptr)
1206 {
1207 partitionFree(ptr);
1208 }
1209
addChild(RenderLayer * child,RenderLayer * beforeChild)1210 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1211 {
1212 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1213 if (prevSibling) {
1214 child->setPreviousSibling(prevSibling);
1215 prevSibling->setNextSibling(child);
1216 ASSERT(prevSibling != child);
1217 } else
1218 setFirstChild(child);
1219
1220 if (beforeChild) {
1221 beforeChild->setPreviousSibling(child);
1222 child->setNextSibling(beforeChild);
1223 ASSERT(beforeChild != child);
1224 } else
1225 setLastChild(child);
1226
1227 child->m_parent = this;
1228
1229 setNeedsCompositingInputsUpdate();
1230
1231 if (child->stackingNode()->isNormalFlowOnly())
1232 m_stackingNode->dirtyNormalFlowList();
1233
1234 if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) {
1235 // Dirty the z-order list in which we are contained. The ancestorStackingContextNode() can be null in the
1236 // case where we're building up generated content layers. This is ok, since the lists will start
1237 // off dirty in that case anyway.
1238 child->stackingNode()->dirtyStackingContextZOrderLists();
1239 }
1240
1241 dirtyAncestorChainVisibleDescendantStatus();
1242 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1243
1244 child->updateDescendantDependentFlags();
1245 }
1246
removeChild(RenderLayer * oldChild)1247 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1248 {
1249 if (oldChild->previousSibling())
1250 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1251 if (oldChild->nextSibling())
1252 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1253
1254 if (m_first == oldChild)
1255 m_first = oldChild->nextSibling();
1256 if (m_last == oldChild)
1257 m_last = oldChild->previousSibling();
1258
1259 if (oldChild->stackingNode()->isNormalFlowOnly())
1260 m_stackingNode->dirtyNormalFlowList();
1261 if (!oldChild->stackingNode()->isNormalFlowOnly() || oldChild->firstChild()) {
1262 // Dirty the z-order list in which we are contained. When called via the
1263 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1264 // from the main layer tree, so we need to null-check the
1265 // |stackingContext| value.
1266 oldChild->stackingNode()->dirtyStackingContextZOrderLists();
1267 }
1268
1269 if (renderer()->style()->visibility() != VISIBLE)
1270 dirtyVisibleContentStatus();
1271
1272 oldChild->setPreviousSibling(0);
1273 oldChild->setNextSibling(0);
1274 oldChild->m_parent = 0;
1275
1276 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1277
1278 oldChild->updateDescendantDependentFlags();
1279
1280 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1281 dirtyAncestorChainVisibleDescendantStatus();
1282
1283 return oldChild;
1284 }
1285
removeOnlyThisLayer()1286 void RenderLayer::removeOnlyThisLayer()
1287 {
1288 if (!m_parent)
1289 return;
1290
1291 m_clipper.clearClipRectsIncludingDescendants();
1292
1293 RenderLayer* nextSib = nextSibling();
1294
1295 // Remove the child reflection layer before moving other child layers.
1296 // The reflection layer should not be moved to the parent.
1297 if (m_reflectionInfo)
1298 removeChild(m_reflectionInfo->reflectionLayer());
1299
1300 // Now walk our kids and reattach them to our parent.
1301 RenderLayer* current = m_first;
1302 while (current) {
1303 RenderLayer* next = current->nextSibling();
1304 removeChild(current);
1305 m_parent->addChild(current, nextSib);
1306
1307 // FIXME: We should call a specialized version of this function.
1308 current->updateLayerPositionsAfterLayout();
1309 current = next;
1310 }
1311
1312 // Remove us from the parent.
1313 m_parent->removeChild(this);
1314 m_renderer->destroyLayer();
1315 }
1316
insertOnlyThisLayer()1317 void RenderLayer::insertOnlyThisLayer()
1318 {
1319 if (!m_parent && renderer()->parent()) {
1320 // We need to connect ourselves when our renderer() has a parent.
1321 // Find our enclosingLayer and add ourselves.
1322 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
1323 ASSERT(parentLayer);
1324 RenderLayer* beforeChild = !parentLayer->reflectionInfo() || parentLayer->reflectionInfo()->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
1325 parentLayer->addChild(this, beforeChild);
1326 }
1327
1328 // Remove all descendant layers from the hierarchy and add them to the new position.
1329 for (RenderObject* curr = renderer()->slowFirstChild(); curr; curr = curr->nextSibling())
1330 curr->moveLayers(m_parent, this);
1331
1332 // Clear out all the clip rects.
1333 m_clipper.clearClipRectsIncludingDescendants();
1334 }
1335
1336 // Returns the layer reached on the walk up towards the ancestor.
accumulateOffsetTowardsAncestor(const RenderLayer * layer,const RenderLayer * ancestorLayer,LayoutPoint & location)1337 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location)
1338 {
1339 ASSERT(ancestorLayer != layer);
1340
1341 const RenderLayerModelObject* renderer = layer->renderer();
1342 EPosition position = renderer->style()->position();
1343
1344 // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
1345 RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer->flowThreadContainingBlock() : 0;
1346 if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
1347 fixedFlowThreadContainer = 0;
1348
1349 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
1350 // may need to be revisited in a future patch.
1351 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
1352 // since localToAbsolute maps the coordinates from flow thread to regions coordinates and regions can be
1353 // positioned in a completely different place in the viewport (RenderView).
1354 if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
1355 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1356 // localToAbsolute() on the RenderView.
1357 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed);
1358 location += LayoutSize(absPos.x(), absPos.y());
1359 return ancestorLayer;
1360 }
1361
1362 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
1363 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
1364 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
1365 if (position == FixedPosition && !fixedFlowThreadContainer) {
1366 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1367 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
1368 // so we should always find the ancestor at or before we find the fixed position container.
1369 RenderLayer* fixedPositionContainerLayer = 0;
1370 bool foundAncestor = false;
1371 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
1372 if (currLayer == ancestorLayer)
1373 foundAncestor = true;
1374
1375 if (isFixedPositionedContainer(currLayer)) {
1376 fixedPositionContainerLayer = currLayer;
1377 ASSERT_UNUSED(foundAncestor, foundAncestor);
1378 break;
1379 }
1380 }
1381
1382 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1383
1384 if (fixedPositionContainerLayer != ancestorLayer) {
1385 LayoutPoint fixedContainerCoords;
1386 layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
1387
1388 LayoutPoint ancestorCoords;
1389 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
1390
1391 location += (fixedContainerCoords - ancestorCoords);
1392 } else {
1393 location += toSize(layer->location());
1394 }
1395 return ancestorLayer;
1396 }
1397
1398 RenderLayer* parentLayer;
1399 if (position == AbsolutePosition || position == FixedPosition) {
1400 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
1401 parentLayer = layer->parent();
1402 bool foundAncestorFirst = false;
1403 while (parentLayer) {
1404 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
1405 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
1406 // we are bailing out before reaching root layer.
1407 if (parentLayer->isPositionedContainer())
1408 break;
1409
1410 if (parentLayer == ancestorLayer) {
1411 foundAncestorFirst = true;
1412 break;
1413 }
1414
1415 parentLayer = parentLayer->parent();
1416 }
1417
1418 // We should not reach RenderView layer past the RenderFlowThread layer for any
1419 // children of the RenderFlowThread.
1420 ASSERT(!renderer->flowThreadContainingBlock() || parentLayer != renderer->view()->layer());
1421
1422 if (foundAncestorFirst) {
1423 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
1424 // to enclosingPositionedAncestor and subtract.
1425 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
1426
1427 LayoutPoint thisCoords;
1428 layer->convertToLayerCoords(positionedAncestor, thisCoords);
1429
1430 LayoutPoint ancestorCoords;
1431 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
1432
1433 location += (thisCoords - ancestorCoords);
1434 return ancestorLayer;
1435 }
1436 } else
1437 parentLayer = layer->parent();
1438
1439 if (!parentLayer)
1440 return 0;
1441
1442 location += toSize(layer->location());
1443 return parentLayer;
1444 }
1445
convertToLayerCoords(const RenderLayer * ancestorLayer,LayoutPoint & location) const1446 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const
1447 {
1448 if (ancestorLayer == this)
1449 return;
1450
1451 const RenderLayer* currLayer = this;
1452 while (currLayer && currLayer != ancestorLayer)
1453 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location);
1454 }
1455
convertToLayerCoords(const RenderLayer * ancestorLayer,LayoutRect & rect) const1456 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const
1457 {
1458 LayoutPoint delta;
1459 convertToLayerCoords(ancestorLayer, delta);
1460 rect.move(-delta.x(), -delta.y());
1461 }
1462
didUpdateNeedsCompositedScrolling()1463 void RenderLayer::didUpdateNeedsCompositedScrolling()
1464 {
1465 updateSelfPaintingLayer();
1466 }
1467
updateReflectionInfo(const RenderStyle * oldStyle)1468 void RenderLayer::updateReflectionInfo(const RenderStyle* oldStyle)
1469 {
1470 ASSERT(!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle));
1471 if (renderer()->hasReflection()) {
1472 if (!m_reflectionInfo)
1473 m_reflectionInfo = adoptPtrWillBeNoop(new RenderLayerReflectionInfo(*renderBox()));
1474 m_reflectionInfo->updateAfterStyleChange(oldStyle);
1475 } else if (m_reflectionInfo) {
1476 m_reflectionInfo->destroy();
1477 m_reflectionInfo = nullptr;
1478 }
1479 }
1480
updateStackingNode()1481 void RenderLayer::updateStackingNode()
1482 {
1483 if (requiresStackingNode())
1484 m_stackingNode = adoptPtr(new RenderLayerStackingNode(this));
1485 else
1486 m_stackingNode = nullptr;
1487 }
1488
updateScrollableArea()1489 void RenderLayer::updateScrollableArea()
1490 {
1491 if (requiresScrollableArea())
1492 m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(*this));
1493 else
1494 m_scrollableArea = nullptr;
1495 }
1496
hasOverflowControls() const1497 bool RenderLayer::hasOverflowControls() const
1498 {
1499 return m_scrollableArea && (m_scrollableArea->hasScrollbar() || m_scrollableArea->hasScrollCorner() || renderer()->style()->resize() != RESIZE_NONE);
1500 }
1501
paint(GraphicsContext * context,const LayoutRect & damageRect,PaintBehavior paintBehavior,RenderObject * paintingRoot,PaintLayerFlags paintFlags)1502 void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, PaintLayerFlags paintFlags)
1503 {
1504 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot);
1505 if (shouldPaintLayerInSoftwareMode(paintingInfo, paintFlags))
1506 paintLayer(context, paintingInfo, paintFlags);
1507 }
1508
paintOverlayScrollbars(GraphicsContext * context,const LayoutRect & damageRect,PaintBehavior paintBehavior,RenderObject * paintingRoot)1509 void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot)
1510 {
1511 if (!m_containsDirtyOverlayScrollbars)
1512 return;
1513
1514 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot);
1515 paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars);
1516
1517 m_containsDirtyOverlayScrollbars = false;
1518 }
1519
inContainingBlockChain(RenderLayer * startLayer,RenderLayer * endLayer)1520 static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer)
1521 {
1522 if (startLayer == endLayer)
1523 return true;
1524
1525 RenderView* view = startLayer->renderer()->view();
1526 for (RenderBlock* currentBlock = startLayer->renderer()->containingBlock(); currentBlock && currentBlock != view; currentBlock = currentBlock->containingBlock()) {
1527 if (currentBlock->layer() == endLayer)
1528 return true;
1529 }
1530
1531 return false;
1532 }
1533
clipToRect(const LayerPaintingInfo & localPaintingInfo,GraphicsContext * context,const ClipRect & clipRect,PaintLayerFlags paintFlags,BorderRadiusClippingRule rule)1534 void RenderLayer::clipToRect(const LayerPaintingInfo& localPaintingInfo, GraphicsContext* context, const ClipRect& clipRect,
1535 PaintLayerFlags paintFlags, BorderRadiusClippingRule rule)
1536 {
1537 if (clipRect.rect() == localPaintingInfo.paintDirtyRect && !clipRect.hasRadius())
1538 return;
1539 context->save();
1540 context->clip(pixelSnappedIntRect(clipRect.rect()));
1541
1542 if (!clipRect.hasRadius())
1543 return;
1544
1545 // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
1546 // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
1547 // containing block chain so we check that also.
1548 for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
1549 // Composited scrolling layers handle border-radius clip in the compositor via a mask layer. We do not
1550 // want to apply a border-radius clip to the layer contents itself, because that would require re-rastering
1551 // every frame to update the clip. We only want to make sure that the mask layer is properly clipped so
1552 // that it can in turn clip the scrolled contents in the compositor.
1553 if (layer->needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase))
1554 break;
1555
1556 if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) {
1557 LayoutPoint delta;
1558 layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta);
1559 context->clipRoundedRect(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
1560 }
1561
1562 if (layer == localPaintingInfo.rootLayer)
1563 break;
1564 }
1565 }
1566
restoreClip(GraphicsContext * context,const LayoutRect & paintDirtyRect,const ClipRect & clipRect)1567 void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect)
1568 {
1569 if (clipRect.rect() == paintDirtyRect && !clipRect.hasRadius())
1570 return;
1571 context->restore();
1572 }
1573
shouldSuppressPaintingLayer(RenderLayer * layer)1574 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
1575 {
1576 // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
1577 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
1578 // will do a full paintInvalidationForWholeRenderer().
1579 if (layer->renderer()->document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isDocumentElement())
1580 return true;
1581
1582 return false;
1583 }
1584
paintForFixedRootBackground(const RenderLayer * layer,PaintLayerFlags paintFlags)1585 static bool paintForFixedRootBackground(const RenderLayer* layer, PaintLayerFlags paintFlags)
1586 {
1587 return layer->renderer()->isDocumentElement() && (paintFlags & PaintLayerPaintingRootBackgroundOnly);
1588 }
1589
shouldRespectOverflowClip(PaintLayerFlags paintFlags,const RenderObject * renderer)1590 static ShouldRespectOverflowClip shouldRespectOverflowClip(PaintLayerFlags paintFlags, const RenderObject* renderer)
1591 {
1592 return (paintFlags & PaintLayerPaintingOverflowContents || (paintFlags & PaintLayerPaintingChildClippingMaskPhase && renderer->hasClipPath())) ? IgnoreOverflowClip : RespectOverflowClip;
1593 }
1594
paintLayer(GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)1595 void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
1596 {
1597 // https://code.google.com/p/chromium/issues/detail?id=343772
1598 DisableCompositingQueryAsserts disabler;
1599
1600 if (compositingState() != NotComposited) {
1601 if (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers) {
1602 // FIXME: ok, but what about PaintBehaviorFlattenCompositingLayers? That's for printing.
1603 // FIXME: why isn't the code here global, as opposed to being set on each paintLayer() call?
1604 paintFlags |= PaintLayerUncachedClipRects;
1605 }
1606 }
1607
1608 // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself.
1609 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
1610 return;
1611
1612 if (shouldSuppressPaintingLayer(this))
1613 return;
1614
1615 // If this layer is totally invisible then there is nothing to paint.
1616 if (!renderer()->opacity())
1617 return;
1618
1619 if (paintsWithTransparency(paintingInfo.paintBehavior))
1620 paintFlags |= PaintLayerHaveTransparency;
1621
1622 // PaintLayerAppliedTransform is used in RenderReplica, to avoid applying the transform twice.
1623 if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
1624 TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior);
1625 // If the transform can't be inverted, then don't paint anything.
1626 if (!layerTransform.isInvertible())
1627 return;
1628
1629 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
1630 // layer from the parent now, assuming there is a parent
1631 if (paintFlags & PaintLayerHaveTransparency) {
1632 if (parent())
1633 parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
1634 else
1635 beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
1636 }
1637
1638 if (enclosingPaginationLayer()) {
1639 paintTransformedLayerIntoFragments(context, paintingInfo, paintFlags);
1640 return;
1641 }
1642
1643 // Make sure the parent's clip rects have been calculated.
1644 ClipRect clipRect = paintingInfo.paintDirtyRect;
1645 if (parent()) {
1646 ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize);
1647 if (shouldRespectOverflowClip(paintFlags, renderer()) == IgnoreOverflowClip)
1648 clipRectsContext.setIgnoreOverflowClip();
1649 clipRect = clipper().backgroundClipRect(clipRectsContext);
1650 clipRect.intersect(paintingInfo.paintDirtyRect);
1651
1652 // Push the parent coordinate space's clip.
1653 parent()->clipToRect(paintingInfo, context, clipRect, paintFlags);
1654 }
1655
1656 paintLayerByApplyingTransform(context, paintingInfo, paintFlags);
1657
1658 // Restore the clip.
1659 if (parent())
1660 parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
1661
1662 return;
1663 }
1664
1665 paintLayerContentsAndReflection(context, paintingInfo, paintFlags);
1666 }
1667
paintLayerContentsAndReflection(GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)1668 void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
1669 {
1670 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
1671
1672 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
1673
1674 // Paint the reflection first if we have one.
1675 if (m_reflectionInfo)
1676 m_reflectionInfo->paint(context, paintingInfo, localPaintFlags | PaintLayerPaintingReflection);
1677
1678 localPaintFlags |= PaintLayerPaintingCompositingAllPhases;
1679 paintLayerContents(context, paintingInfo, localPaintFlags);
1680 }
1681
paintLayerContents(GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)1682 void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
1683 {
1684 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
1685 ASSERT(!(paintFlags & PaintLayerAppliedTransform));
1686
1687 bool haveTransparency = paintFlags & PaintLayerHaveTransparency;
1688 bool isSelfPaintingLayer = this->isSelfPaintingLayer();
1689 bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
1690 bool isPaintingScrollingContent = paintFlags & PaintLayerPaintingCompositingScrollingPhase;
1691 bool isPaintingCompositedForeground = paintFlags & PaintLayerPaintingCompositingForegroundPhase;
1692 bool isPaintingCompositedBackground = paintFlags & PaintLayerPaintingCompositingBackgroundPhase;
1693 bool isPaintingOverflowContents = paintFlags & PaintLayerPaintingOverflowContents;
1694 // Outline always needs to be painted even if we have no visible content. Also,
1695 // the outline is painted in the background phase during composited scrolling.
1696 // If it were painted in the foreground phase, it would move with the scrolled
1697 // content. When not composited scrolling, the outline is painted in the
1698 // foreground phase. Since scrolled contents are moved by paint invalidation in this
1699 // case, the outline won't get 'dragged along'.
1700 bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars
1701 && ((isPaintingScrollingContent && isPaintingCompositedBackground)
1702 || (!isPaintingScrollingContent && isPaintingCompositedForeground));
1703 bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
1704
1705 float deviceScaleFactor = blink::deviceScaleFactor(renderer()->frame());
1706 context->setDeviceScaleFactor(deviceScaleFactor);
1707
1708 GraphicsContext* transparencyLayerContext = context;
1709
1710 if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isDocumentElement())
1711 return;
1712
1713 // Ensure our lists are up-to-date.
1714 m_stackingNode->updateLayerListsIfNeeded();
1715
1716 LayoutPoint offsetFromRoot;
1717 convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
1718
1719 if (compositingState() == PaintsIntoOwnBacking)
1720 offsetFromRoot.move(subpixelAccumulation());
1721
1722 LayoutRect rootRelativeBounds;
1723 bool rootRelativeBoundsComputed = false;
1724
1725 // Apply clip-path to context.
1726 GraphicsContextStateSaver clipStateSaver(*context, false);
1727 RenderStyle* style = renderer()->style();
1728 RenderSVGResourceClipper* resourceClipper = 0;
1729 RenderSVGResourceClipper::ClipperState clipperState = RenderSVGResourceClipper::ClipperNotApplied;
1730
1731 // Clip-path, like border radius, must not be applied to the contents of a composited-scrolling container.
1732 // It must, however, still be applied to the mask layer, so that the compositor can properly mask the
1733 // scrolling contents and scrollbars.
1734 if (renderer()->hasClipPath() && style && (!needsCompositedScrolling() || paintFlags & PaintLayerPaintingChildClippingMaskPhase)) {
1735 ASSERT(style->clipPath());
1736 if (style->clipPath()->type() == ClipPathOperation::SHAPE) {
1737 ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style->clipPath());
1738 if (clipPath->isValid()) {
1739 clipStateSaver.save();
1740
1741 if (!rootRelativeBoundsComputed) {
1742 rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
1743 rootRelativeBoundsComputed = true;
1744 }
1745
1746 context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
1747 }
1748 } else if (style->clipPath()->type() == ClipPathOperation::REFERENCE) {
1749 ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style->clipPath());
1750 Document& document = renderer()->document();
1751 // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
1752 Element* element = document.getElementById(referenceClipPathOperation->fragment());
1753 if (isSVGClipPathElement(element) && element->renderer()) {
1754 // FIXME: Saving at this point is not required in the 'mask'-
1755 // case, or if the clip ends up empty.
1756 clipStateSaver.save();
1757 if (!rootRelativeBoundsComputed) {
1758 rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
1759 rootRelativeBoundsComputed = true;
1760 }
1761
1762 resourceClipper = toRenderSVGResourceClipper(toRenderSVGResourceContainer(element->renderer()));
1763 if (!resourceClipper->applyClippingToContext(renderer(), rootRelativeBounds,
1764 paintingInfo.paintDirtyRect, context, clipperState)) {
1765 // No need to post-apply the clipper if this failed.
1766 resourceClipper = 0;
1767 }
1768 }
1769 }
1770 }
1771
1772 // Blending operations must be performed only with the nearest ancestor stacking context.
1773 // Note that there is no need to create a transparency layer if we're painting the root.
1774 bool createTransparencyLayerForBlendMode = !renderer()->isDocumentElement() && m_stackingNode->isStackingContext() && hasDescendantWithBlendMode();
1775
1776 if (createTransparencyLayerForBlendMode)
1777 beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
1778
1779 LayerPaintingInfo localPaintingInfo(paintingInfo);
1780 bool deferredFiltersEnabled = renderer()->document().settings()->deferredFiltersEnabled();
1781 FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters());
1782
1783 LayerFragments layerFragments;
1784 if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
1785 // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
1786 // fragment should paint.
1787 collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect,
1788 (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
1789 shouldRespectOverflowClip(paintFlags, renderer()), &offsetFromRoot, localPaintingInfo.subPixelAccumulation);
1790 updatePaintingInfoForFragments(layerFragments, localPaintingInfo, paintFlags, shouldPaintContent, &offsetFromRoot);
1791 }
1792
1793 if (filterPainter.haveFilterEffect()) {
1794 ASSERT(this->filterInfo());
1795
1796 if (!rootRelativeBoundsComputed)
1797 rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
1798
1799 if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect)) {
1800
1801 // Rewire the old context to a memory buffer, so that we can capture the contents of the layer.
1802 // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer
1803 // on the original context and avoid duplicating "beginFilterEffect" after each transparency layer call. Also, note that
1804 // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method.
1805 // With deferred filters, we don't need a separate context, but we do need to do transparency and clipping before starting
1806 // filter processing.
1807 // FIXME: when the legacy path is removed, remove the transparencyLayerContext as well.
1808 ClipRect backgroundRect;
1809 if (deferredFiltersEnabled) {
1810 if (haveTransparency) {
1811 // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one after filter processing.
1812 beginTransparencyLayers(context, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
1813 }
1814 // We'll handle clipping to the dirty rect before filter rasterization.
1815 // Filter processing will automatically expand the clip rect and the offscreen to accommodate any filter outsets.
1816 // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
1817 backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
1818 clipToRect(localPaintingInfo, context, backgroundRect, paintFlags);
1819 // Subsequent code should not clip to the dirty rect, since we've already
1820 // done it above, and doing it later will defeat the outsets.
1821 localPaintingInfo.clipToDirtyRect = false;
1822 }
1823 context = filterPainter.beginFilterEffect(context);
1824
1825 if (!filterPainter.hasStartedFilterEffect() && deferredFiltersEnabled) {
1826 // If the the filter failed to start, undo the clip immediately
1827 restoreClip(context, localPaintingInfo.paintDirtyRect, backgroundRect);
1828 }
1829
1830 // Check that we didn't fail to allocate the graphics context for the offscreen buffer.
1831 if (filterPainter.hasStartedFilterEffect() && !deferredFiltersEnabled) {
1832 localPaintingInfo.paintDirtyRect = filterPainter.paintInvalidationRect();
1833 // If the filter needs the full source image, we need to avoid using the clip rectangles.
1834 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
1835 // Note that we will still apply the clipping on the final rendering of the filter.
1836 localPaintingInfo.clipToDirtyRect = !filterRenderer()->hasFilterThatMovesPixels();
1837 }
1838 }
1839 }
1840
1841 if (filterPainter.hasStartedFilterEffect() && haveTransparency && !deferredFiltersEnabled) {
1842 // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context.
1843 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
1844 }
1845
1846 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
1847 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
1848 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
1849 // so it will be tested against as we descend through the renderers.
1850 RenderObject* paintingRootForRenderer = 0;
1851 if (localPaintingInfo.paintingRoot && !renderer()->isDescendantOf(localPaintingInfo.paintingRoot))
1852 paintingRootForRenderer = localPaintingInfo.paintingRoot;
1853
1854 ASSERT(!(localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText));
1855 bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
1856
1857 bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly;
1858 bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground);
1859 bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent;
1860 bool shouldPaintNormalFlowAndPosZOrderLists = isPaintingCompositedForeground;
1861 bool shouldPaintOverlayScrollbars = isPaintingOverlayScrollbars;
1862 bool shouldPaintMask = (paintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly;
1863 bool shouldPaintClippingMask = (paintFlags & PaintLayerPaintingChildClippingMaskPhase) && shouldPaintContent && !selectionOnly;
1864
1865 PaintBehavior paintBehavior = PaintBehaviorNormal;
1866 if (paintFlags & PaintLayerPaintingSkipRootBackground)
1867 paintBehavior |= PaintBehaviorSkipRootBackground;
1868 else if (paintFlags & PaintLayerPaintingRootBackgroundOnly)
1869 paintBehavior |= PaintBehaviorRootBackgroundOnly;
1870
1871 if (shouldPaintBackground) {
1872 paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
1873 localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
1874 }
1875
1876 if (shouldPaintNegZOrderList)
1877 paintChildren(NegativeZOrderChildren, context, paintingInfo, paintFlags);
1878
1879 if (shouldPaintOwnContents) {
1880 paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
1881 localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, paintFlags);
1882 }
1883
1884 if (shouldPaintOutline)
1885 paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
1886
1887 if (shouldPaintNormalFlowAndPosZOrderLists)
1888 paintChildren(NormalFlowChildren | PositiveZOrderChildren, context, paintingInfo, paintFlags);
1889
1890 if (shouldPaintOverlayScrollbars)
1891 paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo, paintFlags);
1892
1893 if (filterPainter.hasStartedFilterEffect()) {
1894 // Apply the correct clipping (ie. overflow: hidden).
1895 // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
1896 ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
1897 if (!deferredFiltersEnabled)
1898 clipToRect(localPaintingInfo, transparencyLayerContext, backgroundRect, paintFlags);
1899
1900 context = filterPainter.applyFilterEffect();
1901 restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect);
1902 }
1903
1904 // Make sure that we now use the original transparency context.
1905 ASSERT(transparencyLayerContext == context);
1906
1907 if (shouldPaintMask)
1908 paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer, paintFlags);
1909
1910 if (shouldPaintClippingMask) {
1911 // Paint the border radius mask for the fragments.
1912 paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer, paintFlags);
1913 }
1914
1915 // End our transparency layer
1916 if ((haveTransparency || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency && !(m_reflectionInfo && m_reflectionInfo->isPaintingInsideReflection())) {
1917 context->endLayer();
1918 context->restore();
1919 m_usedTransparency = false;
1920 }
1921
1922 if (resourceClipper)
1923 resourceClipper->postApplyStatefulResource(renderer(), context, clipperState);
1924 }
1925
paintLayerByApplyingTransform(GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags,const LayoutPoint & translationOffset)1926 void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset)
1927 {
1928 // This involves subtracting out the position of the layer in our current coordinate space, but preserving
1929 // the accumulated error for sub-pixel layout.
1930 LayoutPoint delta;
1931 convertToLayerCoords(paintingInfo.rootLayer, delta);
1932 delta.moveBy(translationOffset);
1933 TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
1934 IntPoint roundedDelta = roundedIntPoint(delta);
1935 transform.translateRight(roundedDelta.x(), roundedDelta.y());
1936 LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
1937
1938 // Apply the transform.
1939 GraphicsContextStateSaver stateSaver(*context, false);
1940 if (!transform.isIdentity()) {
1941 stateSaver.save();
1942 context->concatCTM(transform.toAffineTransform());
1943 }
1944
1945 // Now do a paint with the root layer shifted to be us.
1946 LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior,
1947 adjustedSubPixelAccumulation, paintingInfo.paintingRoot);
1948 paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
1949 }
1950
shouldPaintLayerInSoftwareMode(const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)1951 bool RenderLayer::shouldPaintLayerInSoftwareMode(const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
1952 {
1953 DisableCompositingQueryAsserts disabler;
1954
1955 return compositingState() == NotComposited
1956 || compositingState() == HasOwnBackingButPaintsIntoAncestor
1957 || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)
1958 || ((paintFlags & PaintLayerPaintingReflection) && !has3DTransform())
1959 || paintForFixedRootBackground(this, paintFlags);
1960 }
1961
paintChildren(unsigned childrenToVisit,GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)1962 void RenderLayer::paintChildren(unsigned childrenToVisit, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
1963 {
1964 if (!hasSelfPaintingLayerDescendant())
1965 return;
1966
1967 #if ENABLE(ASSERT)
1968 LayerListMutationDetector mutationChecker(m_stackingNode.get());
1969 #endif
1970
1971 RenderLayerStackingNodeIterator iterator(*m_stackingNode, childrenToVisit);
1972 while (RenderLayerStackingNode* child = iterator.next()) {
1973 RenderLayer* childLayer = child->layer();
1974 // If this RenderLayer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents()
1975 // and CompositedLayerMapping::doPaintTask().
1976 if (!childLayer->shouldPaintLayerInSoftwareMode(paintingInfo, paintFlags))
1977 continue;
1978
1979 if (!childLayer->isPaginated())
1980 childLayer->paintLayer(context, paintingInfo, paintFlags);
1981 else
1982 paintPaginatedChildLayer(childLayer, context, paintingInfo, paintFlags);
1983 }
1984 }
1985
collectFragments(LayerFragments & fragments,const RenderLayer * rootLayer,const LayoutRect & dirtyRect,ClipRectsCacheSlot clipRectsCacheSlot,OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy,ShouldRespectOverflowClip respectOverflowClip,const LayoutPoint * offsetFromRoot,const LayoutSize & subPixelAccumulation,const LayoutRect * layerBoundingBox)1986 void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect,
1987 ClipRectsCacheSlot clipRectsCacheSlot, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
1988 const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox)
1989 {
1990 if (!enclosingPaginationLayer() || hasTransform()) {
1991 // For unpaginated layers, there is only one fragment.
1992 LayerFragment fragment;
1993 ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy, subPixelAccumulation);
1994 if (respectOverflowClip == IgnoreOverflowClip)
1995 clipRectsContext.setIgnoreOverflowClip();
1996 clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
1997 fragments.append(fragment);
1998 return;
1999 }
2000
2001 // Compute our offset within the enclosing pagination layer.
2002 LayoutPoint offsetWithinPaginatedLayer;
2003 convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer);
2004
2005 // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
2006 // 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.
2007 ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
2008 if (respectOverflowClip == IgnoreOverflowClip)
2009 paginationClipRectsContext.setIgnoreOverflowClip();
2010 LayoutRect layerBoundsInFlowThread;
2011 ClipRect backgroundRectInFlowThread;
2012 ClipRect foregroundRectInFlowThread;
2013 ClipRect outlineRectInFlowThread;
2014 clipper().calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
2015 outlineRectInFlowThread, &offsetWithinPaginatedLayer);
2016
2017 // Take our bounding box within the flow thread and clip it.
2018 LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer);
2019 layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
2020
2021 // Shift the dirty rect into flow thread coordinates.
2022 LayoutPoint offsetOfPaginationLayerFromRoot;
2023 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
2024 LayoutRect dirtyRectInFlowThread(dirtyRect);
2025 dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot);
2026
2027 // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
2028 // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
2029 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
2030 enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread);
2031
2032 if (fragments.isEmpty())
2033 return;
2034
2035 // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents.
2036 ClipRect ancestorClipRect = dirtyRect;
2037 if (enclosingPaginationLayer()->parent()) {
2038 ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
2039 if (respectOverflowClip == IgnoreOverflowClip)
2040 clipRectsContext.setIgnoreOverflowClip();
2041 ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipRect(clipRectsContext);
2042 ancestorClipRect.intersect(dirtyRect);
2043 }
2044
2045 for (size_t i = 0; i < fragments.size(); ++i) {
2046 LayerFragment& fragment = fragments.at(i);
2047
2048 // Set our four rects with all clipping applied that was internal to the flow thread.
2049 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread);
2050
2051 // Shift to the root-relative physical position used when painting the flow thread in this fragment.
2052 fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
2053
2054 // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
2055 // properly clipped by the overflow.
2056 fragment.intersect(ancestorClipRect.rect());
2057
2058 // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
2059 // clip, so the column clip ends up being all we apply.
2060 fragment.intersect(fragment.paginationClip);
2061 }
2062 }
2063
updatePaintingInfoForFragments(LayerFragments & fragments,const LayerPaintingInfo & localPaintingInfo,PaintLayerFlags localPaintFlags,bool shouldPaintContent,const LayoutPoint * offsetFromRoot)2064 void RenderLayer::updatePaintingInfoForFragments(LayerFragments& fragments, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags localPaintFlags,
2065 bool shouldPaintContent, const LayoutPoint* offsetFromRoot)
2066 {
2067 ASSERT(offsetFromRoot);
2068 for (size_t i = 0; i < fragments.size(); ++i) {
2069 LayerFragment& fragment = fragments.at(i);
2070 fragment.shouldPaintContent = shouldPaintContent;
2071 if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) {
2072 LayoutPoint newOffsetFromRoot = *offsetFromRoot + fragment.paginationOffset;
2073 fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot);
2074 }
2075 }
2076 }
2077
paintTransformedLayerIntoFragments(GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)2078 void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
2079 {
2080 LayerFragments enclosingPaginationFragments;
2081 LayoutPoint offsetOfPaginationLayerFromRoot;
2082 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
2083 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect,
2084 (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
2085 shouldRespectOverflowClip(paintFlags, renderer()), &offsetOfPaginationLayerFromRoot, paintingInfo.subPixelAccumulation, &transformedExtent);
2086
2087 for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) {
2088 const LayerFragment& fragment = enclosingPaginationFragments.at(i);
2089
2090 // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
2091 // the enclosing pagination layer.
2092 LayoutRect clipRect = fragment.backgroundRect.rect();
2093
2094 // Now compute the clips within a given fragment
2095 if (parent() != enclosingPaginationLayer()) {
2096 enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot);
2097
2098 ClipRectsContext clipRectsContext(enclosingPaginationLayer(), (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize);
2099 if (shouldRespectOverflowClip(paintFlags, renderer()) == IgnoreOverflowClip)
2100 clipRectsContext.setIgnoreOverflowClip();
2101 LayoutRect parentClipRect = clipper().backgroundClipRect(clipRectsContext).rect();
2102 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
2103 clipRect.intersect(parentClipRect);
2104 }
2105
2106 parent()->clipToRect(paintingInfo, context, clipRect, paintFlags);
2107 paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset);
2108 parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
2109 }
2110 }
2111
subPixelAccumulationIfNeeded(const LayoutSize & subPixelAccumulation,CompositingState compositingState)2112 static inline LayoutSize subPixelAccumulationIfNeeded(const LayoutSize& subPixelAccumulation, CompositingState compositingState)
2113 {
2114 // Only apply the sub-pixel accumulation if we don't paint into our own backing layer, otherwise the position
2115 // of the renderer already includes any sub-pixel offset.
2116 if (compositingState == PaintsIntoOwnBacking)
2117 return LayoutSize();
2118 return subPixelAccumulation;
2119 }
2120
paintBackgroundForFragments(const LayerFragments & layerFragments,GraphicsContext * context,GraphicsContext * transparencyLayerContext,const LayoutRect & transparencyPaintDirtyRect,bool haveTransparency,const LayerPaintingInfo & localPaintingInfo,PaintBehavior paintBehavior,RenderObject * paintingRootForRenderer,PaintLayerFlags paintFlags)2121 void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
2122 const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
2123 RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
2124 {
2125 for (size_t i = 0; i < layerFragments.size(); ++i) {
2126 const LayerFragment& fragment = layerFragments.at(i);
2127 if (!fragment.shouldPaintContent)
2128 continue;
2129
2130 // Begin transparency layers lazily now that we know we have to paint something.
2131 if (haveTransparency || paintsWithBlendMode())
2132 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
2133
2134 if (localPaintingInfo.clipToDirtyRect) {
2135 // Paint our background first, before painting any child layers.
2136 // Establish the clip used to paint our background.
2137 clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
2138 }
2139
2140 // Paint the background.
2141 // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
2142 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
2143 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
2144
2145 if (localPaintingInfo.clipToDirtyRect)
2146 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
2147 }
2148 }
2149
paintForegroundForFragments(const LayerFragments & layerFragments,GraphicsContext * context,GraphicsContext * transparencyLayerContext,const LayoutRect & transparencyPaintDirtyRect,bool haveTransparency,const LayerPaintingInfo & localPaintingInfo,PaintBehavior paintBehavior,RenderObject * paintingRootForRenderer,bool selectionOnly,PaintLayerFlags paintFlags)2150 void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
2151 const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
2152 RenderObject* paintingRootForRenderer, bool selectionOnly, PaintLayerFlags paintFlags)
2153 {
2154 // Begin transparency if we have something to paint.
2155 if (haveTransparency || paintsWithBlendMode()) {
2156 for (size_t i = 0; i < layerFragments.size(); ++i) {
2157 const LayerFragment& fragment = layerFragments.at(i);
2158 if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) {
2159 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
2160 break;
2161 }
2162 }
2163 }
2164
2165 // Optimize clipping for the single fragment case.
2166 bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
2167 if (shouldClip)
2168 clipToRect(localPaintingInfo, context, layerFragments[0].foregroundRect, paintFlags);
2169
2170 // We have to loop through every fragment multiple times, since we have to issue paint invalidations in each specific phase in order for
2171 // interleaving of the fragments to work properly.
2172 paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, layerFragments,
2173 context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
2174
2175 if (!selectionOnly) {
2176 paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
2177 paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
2178 paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
2179 }
2180
2181 if (shouldClip)
2182 restoreClip(context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect);
2183 }
2184
paintForegroundForFragmentsWithPhase(PaintPhase phase,const LayerFragments & layerFragments,GraphicsContext * context,const LayerPaintingInfo & localPaintingInfo,PaintBehavior paintBehavior,RenderObject * paintingRootForRenderer,PaintLayerFlags paintFlags)2185 void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context,
2186 const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
2187 {
2188 bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1;
2189
2190 for (size_t i = 0; i < layerFragments.size(); ++i) {
2191 const LayerFragment& fragment = layerFragments.at(i);
2192 if (!fragment.shouldPaintContent || fragment.foregroundRect.isEmpty())
2193 continue;
2194
2195 if (shouldClip)
2196 clipToRect(localPaintingInfo, context, fragment.foregroundRect, paintFlags);
2197
2198 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
2199 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
2200
2201 if (shouldClip)
2202 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
2203 }
2204 }
2205
paintOutlineForFragments(const LayerFragments & layerFragments,GraphicsContext * context,const LayerPaintingInfo & localPaintingInfo,PaintBehavior paintBehavior,RenderObject * paintingRootForRenderer,PaintLayerFlags paintFlags)2206 void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
2207 PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
2208 {
2209 for (size_t i = 0; i < layerFragments.size(); ++i) {
2210 const LayerFragment& fragment = layerFragments.at(i);
2211 if (fragment.outlineRect.isEmpty())
2212 continue;
2213
2214 // Paint our own outline
2215 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
2216 clipToRect(localPaintingInfo, context, fragment.outlineRect, paintFlags, DoNotIncludeSelfForBorderRadius);
2217 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
2218 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect);
2219 }
2220 }
2221
paintMaskForFragments(const LayerFragments & layerFragments,GraphicsContext * context,const LayerPaintingInfo & localPaintingInfo,RenderObject * paintingRootForRenderer,PaintLayerFlags paintFlags)2222 void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
2223 RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
2224 {
2225 for (size_t i = 0; i < layerFragments.size(); ++i) {
2226 const LayerFragment& fragment = layerFragments.at(i);
2227 if (!fragment.shouldPaintContent)
2228 continue;
2229
2230 if (localPaintingInfo.clipToDirtyRect)
2231 clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
2232
2233 // Paint the mask.
2234 // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
2235 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
2236 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
2237
2238 if (localPaintingInfo.clipToDirtyRect)
2239 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
2240 }
2241 }
2242
paintChildClippingMaskForFragments(const LayerFragments & layerFragments,GraphicsContext * context,const LayerPaintingInfo & localPaintingInfo,RenderObject * paintingRootForRenderer,PaintLayerFlags paintFlags)2243 void RenderLayer::paintChildClippingMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
2244 RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
2245 {
2246 for (size_t i = 0; i < layerFragments.size(); ++i) {
2247 const LayerFragment& fragment = layerFragments.at(i);
2248 if (!fragment.shouldPaintContent)
2249 continue;
2250
2251 if (localPaintingInfo.clipToDirtyRect)
2252 clipToRect(localPaintingInfo, context, fragment.foregroundRect, paintFlags, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self.
2253
2254 // Paint the the clipped mask.
2255 PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseClippingMask, PaintBehaviorNormal, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
2256 renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
2257
2258 if (localPaintingInfo.clipToDirtyRect)
2259 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
2260 }
2261 }
2262
paintOverflowControlsForFragments(const LayerFragments & layerFragments,GraphicsContext * context,const LayerPaintingInfo & localPaintingInfo,PaintLayerFlags paintFlags)2263 void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags paintFlags)
2264 {
2265 for (size_t i = 0; i < layerFragments.size(); ++i) {
2266 const LayerFragment& fragment = layerFragments.at(i);
2267 clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags);
2268 if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea())
2269 scrollableArea->paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))), pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
2270 restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
2271 }
2272 }
2273
paintPaginatedChildLayer(RenderLayer * childLayer,GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags)2274 void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
2275 {
2276 // We need to do multiple passes, breaking up our child layer into strips.
2277 Vector<RenderLayer*> columnLayers;
2278 RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode();
2279 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
2280 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
2281 columnLayers.append(curr);
2282 if (curr->stackingNode() == ancestorNode)
2283 break;
2284 }
2285
2286 // It is possible for paintLayer() to be called after the child layer ceases to be paginated but before
2287 // updatePaginationRecusive() is called and resets the isPaginated() flag, see <rdar://problem/10098679>.
2288 // If this is the case, just bail out, since the upcoming call to updatePaginationRecusive() will paint invalidate the layer.
2289 // FIXME: Is this true anymore? This seems very suspicious.
2290 if (!columnLayers.size())
2291 return;
2292
2293 paintChildLayerIntoColumns(childLayer, context, paintingInfo, paintFlags, columnLayers, columnLayers.size() - 1);
2294 }
2295
paintChildLayerIntoColumns(RenderLayer * childLayer,GraphicsContext * context,const LayerPaintingInfo & paintingInfo,PaintLayerFlags paintFlags,const Vector<RenderLayer * > & columnLayers,size_t colIndex)2296 void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo,
2297 PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
2298 {
2299 RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
2300
2301 ASSERT(columnBlock && columnBlock->hasColumns());
2302 if (!columnBlock || !columnBlock->hasColumns())
2303 return;
2304
2305 LayoutPoint layerOffset;
2306 // FIXME: It looks suspicious to call convertToLayerCoords here
2307 // as canUseConvertToLayerCoords is true for this layer.
2308 columnBlock->layer()->convertToLayerCoords(paintingInfo.rootLayer, layerOffset);
2309
2310 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
2311
2312 ColumnInfo* colInfo = columnBlock->columnInfo();
2313 unsigned colCount = columnBlock->columnCount(colInfo);
2314 LayoutUnit currLogicalTopOffset = 0;
2315 for (unsigned i = 0; i < colCount; i++) {
2316 // For each rect, we clip to the rect, and then we adjust our coords.
2317 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
2318 columnBlock->flipForWritingMode(colRect);
2319 LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
2320 LayoutSize offset;
2321 if (isHorizontal) {
2322 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
2323 offset = LayoutSize(logicalLeftOffset, currLogicalTopOffset);
2324 else
2325 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
2326 } else {
2327 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
2328 offset = LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2329 else
2330 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
2331 }
2332
2333 colRect.moveBy(layerOffset);
2334
2335 LayoutRect localDirtyRect(paintingInfo.paintDirtyRect);
2336 localDirtyRect.intersect(colRect);
2337
2338 if (!localDirtyRect.isEmpty()) {
2339 GraphicsContextStateSaver stateSaver(*context);
2340
2341 // Each strip pushes a clip, since column boxes are specified as being
2342 // like overflow:hidden.
2343 context->clip(enclosingIntRect(colRect));
2344
2345 if (!colIndex) {
2346 // Apply a translation transform to change where the layer paints.
2347 TransformationMatrix oldTransform;
2348 bool oldHasTransform = childLayer->transform();
2349 if (oldHasTransform)
2350 oldTransform = *childLayer->transform();
2351 TransformationMatrix newTransform(oldTransform);
2352 newTransform.translateRight(roundToInt(offset.width()), roundToInt(offset.height()));
2353
2354 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
2355
2356 LayerPaintingInfo localPaintingInfo(paintingInfo);
2357 localPaintingInfo.paintDirtyRect = localDirtyRect;
2358 childLayer->paintLayer(context, localPaintingInfo, paintFlags);
2359
2360 if (oldHasTransform)
2361 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
2362 else
2363 childLayer->m_transform.clear();
2364 } else {
2365 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
2366 // This involves subtracting out the position of the layer in our current coordinate space.
2367 LayoutPoint childOffset;
2368 columnLayers[colIndex - 1]->convertToLayerCoords(paintingInfo.rootLayer, childOffset);
2369 TransformationMatrix transform;
2370 transform.translateRight(roundToInt(childOffset.x() + offset.width()), roundToInt(childOffset.y() + offset.height()));
2371
2372 // Apply the transform.
2373 context->concatCTM(transform.toAffineTransform());
2374
2375 // Now do a paint with the root layer shifted to be the next multicol block.
2376 LayerPaintingInfo columnPaintingInfo(paintingInfo);
2377 columnPaintingInfo.rootLayer = columnLayers[colIndex - 1];
2378 columnPaintingInfo.paintDirtyRect = transform.inverse().mapRect(localDirtyRect);
2379 paintChildLayerIntoColumns(childLayer, context, columnPaintingInfo, paintFlags, columnLayers, colIndex - 1);
2380 }
2381 }
2382
2383 // Move to the next position.
2384 LayoutUnit blockDelta = isHorizontal ? colRect.height() : colRect.width();
2385 if (columnBlock->style()->isFlippedBlocksWritingMode())
2386 currLogicalTopOffset += blockDelta;
2387 else
2388 currLogicalTopOffset -= blockDelta;
2389 }
2390 }
2391
frameVisibleRect(RenderObject * renderer)2392 static inline LayoutRect frameVisibleRect(RenderObject* renderer)
2393 {
2394 FrameView* frameView = renderer->document().view();
2395 if (!frameView)
2396 return LayoutRect();
2397
2398 return frameView->visibleContentRect();
2399 }
2400
hitTest(const HitTestRequest & request,HitTestResult & result)2401 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
2402 {
2403 return hitTest(request, result.hitTestLocation(), result);
2404 }
2405
hitTest(const HitTestRequest & request,const HitTestLocation & hitTestLocation,HitTestResult & result)2406 bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result)
2407 {
2408 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
2409
2410 // RenderView should make sure to update layout before entering hit testing
2411 ASSERT(!renderer()->frame()->view()->layoutPending());
2412 ASSERT(!renderer()->document().renderView()->needsLayout());
2413
2414 LayoutRect hitTestArea = renderer()->view()->documentRect();
2415 if (!request.ignoreClipping())
2416 hitTestArea.intersect(frameVisibleRect(renderer()));
2417
2418 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false);
2419 if (!insideLayer) {
2420 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
2421 // return ourselves. We do this so mouse events continue getting delivered after a drag has
2422 // exited the WebView, and so hit testing over a scrollbar hits the content document.
2423 // In addtion, it is possible for the mouse to stay in the document but there is no element.
2424 // At that time, the events of the mouse should be fired.
2425 LayoutPoint hitPoint = hitTestLocation.point();
2426 if (!request.isChildFrameHitTest() && ((request.active() || request.release()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y()))) && isRootLayer()) {
2427 renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
2428 insideLayer = this;
2429 }
2430 }
2431
2432 // Now determine if the result is inside an anchor - if the urlElement isn't already set.
2433 Node* node = result.innerNode();
2434 if (node && !result.URLElement())
2435 result.setURLElement(node->enclosingLinkEventParentOrSelf());
2436
2437 // Now return whether we were inside this layer (this will always be true for the root
2438 // layer).
2439 return insideLayer;
2440 }
2441
enclosingElement() const2442 Node* RenderLayer::enclosingElement() const
2443 {
2444 for (RenderObject* r = renderer(); r; r = r->parent()) {
2445 if (Node* e = r->node())
2446 return e;
2447 }
2448 ASSERT_NOT_REACHED();
2449 return 0;
2450 }
2451
isInTopLayer() const2452 bool RenderLayer::isInTopLayer() const
2453 {
2454 Node* node = renderer()->node();
2455 return node && node->isElementNode() && toElement(node)->isInTopLayer();
2456 }
2457
2458 // Compute the z-offset of the point in the transformState.
2459 // This is effectively projecting a ray normal to the plane of ancestor, finding where that
2460 // ray intersects target, and computing the z delta between those two points.
computeZOffset(const HitTestingTransformState & transformState)2461 static double computeZOffset(const HitTestingTransformState& transformState)
2462 {
2463 // We got an affine transform, so no z-offset
2464 if (transformState.m_accumulatedTransform.isAffine())
2465 return 0;
2466
2467 // Flatten the point into the target plane
2468 FloatPoint targetPoint = transformState.mappedPoint();
2469
2470 // Now map the point back through the transform, which computes Z.
2471 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
2472 return backmappedPoint.z();
2473 }
2474
createLocalTransformState(RenderLayer * rootLayer,RenderLayer * containerLayer,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,const HitTestingTransformState * containerTransformState,const LayoutPoint & translationOffset) const2475 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
2476 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
2477 const HitTestingTransformState* containerTransformState,
2478 const LayoutPoint& translationOffset) const
2479 {
2480 RefPtr<HitTestingTransformState> transformState;
2481 LayoutPoint offset;
2482 if (containerTransformState) {
2483 // If we're already computing transform state, then it's relative to the container (which we know is non-null).
2484 transformState = HitTestingTransformState::create(*containerTransformState);
2485 convertToLayerCoords(containerLayer, offset);
2486 } else {
2487 // If this is the first time we need to make transform state, then base it off of hitTestLocation,
2488 // which is relative to rootLayer.
2489 transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
2490 convertToLayerCoords(rootLayer, offset);
2491 }
2492 offset.moveBy(translationOffset);
2493
2494 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
2495 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
2496 TransformationMatrix containerTransform;
2497 renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform);
2498 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
2499 } else {
2500 transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform);
2501 }
2502
2503 return transformState;
2504 }
2505
2506
isHitCandidate(const RenderLayer * hitLayer,bool canDepthSort,double * zOffset,const HitTestingTransformState * transformState)2507 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
2508 {
2509 if (!hitLayer)
2510 return false;
2511
2512 // The hit layer is depth-sorting with other layers, so just say that it was hit.
2513 if (canDepthSort)
2514 return true;
2515
2516 // We need to look at z-depth to decide if this layer was hit.
2517 if (zOffset) {
2518 ASSERT(transformState);
2519 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
2520 double childZOffset = computeZOffset(*transformState);
2521 if (childZOffset > *zOffset) {
2522 *zOffset = childZOffset;
2523 return true;
2524 }
2525 return false;
2526 }
2527
2528 return true;
2529 }
2530
2531 // hitTestLocation and hitTestRect are relative to rootLayer.
2532 // A 'flattening' layer is one preserves3D() == false.
2533 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
2534 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer.
2535 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
2536 //
2537 // If zOffset is non-null (which indicates that the caller wants z offset information),
2538 // *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
hitTestLayer(RenderLayer * rootLayer,RenderLayer * containerLayer,const HitTestRequest & request,HitTestResult & result,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,bool appliedTransform,const HitTestingTransformState * transformState,double * zOffset)2539 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
2540 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform,
2541 const HitTestingTransformState* transformState, double* zOffset)
2542 {
2543 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
2544 return 0;
2545
2546 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
2547
2548 // Apply a transform if we have one.
2549 if (transform() && !appliedTransform) {
2550 if (enclosingPaginationLayer())
2551 return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
2552
2553 // Make sure the parent's clip rects have been calculated.
2554 if (parent()) {
2555 ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize));
2556 // Go ahead and test the enclosing clip now.
2557 if (!clipRect.intersects(hitTestLocation))
2558 return 0;
2559 }
2560
2561 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
2562 }
2563
2564 // Ensure our lists and 3d status are up-to-date.
2565 m_stackingNode->updateLayerListsIfNeeded();
2566 update3DTransformedDescendantStatus();
2567
2568 RefPtr<HitTestingTransformState> localTransformState;
2569 if (appliedTransform) {
2570 // We computed the correct state in the caller (above code), so just reference it.
2571 ASSERT(transformState);
2572 localTransformState = const_cast<HitTestingTransformState*>(transformState);
2573 } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
2574 // We need transform state for the first time, or to offset the container state, so create it here.
2575 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
2576 }
2577
2578 // Check for hit test on backface if backface-visibility is 'hidden'
2579 if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
2580 TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
2581 // If the z-vector of the matrix is negative, the back is facing towards the viewer.
2582 if (invertedMatrix.m33() < 0)
2583 return 0;
2584 }
2585
2586 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
2587 if (localTransformState && !preserves3D()) {
2588 // Keep a copy of the pre-flattening state, for computing z-offsets for the container
2589 unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
2590 // This layer is flattening, so flatten the state passed to descendants.
2591 localTransformState->flatten();
2592 }
2593
2594 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
2595 // descendants.
2596 double localZOffset = -std::numeric_limits<double>::infinity();
2597 double* zOffsetForDescendantsPtr = 0;
2598 double* zOffsetForContentsPtr = 0;
2599
2600 bool depthSortDescendants = false;
2601 if (preserves3D()) {
2602 depthSortDescendants = true;
2603 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
2604 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
2605 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
2606 } else if (zOffset) {
2607 zOffsetForDescendantsPtr = 0;
2608 // Container needs us to give back a z offset for the hit layer.
2609 zOffsetForContentsPtr = zOffset;
2610 }
2611
2612 // This variable tracks which layer the mouse ends up being inside.
2613 RenderLayer* candidateLayer = 0;
2614
2615 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
2616 RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
2617 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
2618 if (hitLayer) {
2619 if (!depthSortDescendants)
2620 return hitLayer;
2621 candidateLayer = hitLayer;
2622 }
2623
2624 // Now check our overflow objects.
2625 hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
2626 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
2627 if (hitLayer) {
2628 if (!depthSortDescendants)
2629 return hitLayer;
2630 candidateLayer = hitLayer;
2631 }
2632
2633 // Collect the fragments. This will compute the clip rectangles for each layer fragment.
2634 LayerFragments layerFragments;
2635 collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
2636
2637 if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation)) {
2638 renderer()->updateHitTestResult(result, hitTestLocation.point());
2639 return this;
2640 }
2641
2642 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check
2643 // every fragment in reverse order.
2644 if (isSelfPaintingLayer()) {
2645 // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
2646 HitTestResult tempResult(result.hitTestLocation());
2647 bool insideFragmentForegroundRect = false;
2648 if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestDescendants, insideFragmentForegroundRect)
2649 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
2650 if (result.isRectBasedTest())
2651 result.append(tempResult);
2652 else
2653 result = tempResult;
2654 if (!depthSortDescendants)
2655 return this;
2656 // Foreground can depth-sort with descendant layers, so keep this as a candidate.
2657 candidateLayer = this;
2658 } else if (insideFragmentForegroundRect && result.isRectBasedTest())
2659 result.append(tempResult);
2660 }
2661
2662 // Now check our negative z-index children.
2663 hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
2664 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
2665 if (hitLayer) {
2666 if (!depthSortDescendants)
2667 return hitLayer;
2668 candidateLayer = hitLayer;
2669 }
2670
2671 // If we found a layer, return. Child layers, and foreground always render in front of background.
2672 if (candidateLayer)
2673 return candidateLayer;
2674
2675 if (isSelfPaintingLayer()) {
2676 HitTestResult tempResult(result.hitTestLocation());
2677 bool insideFragmentBackgroundRect = false;
2678 if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestSelf, insideFragmentBackgroundRect)
2679 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
2680 if (result.isRectBasedTest())
2681 result.append(tempResult);
2682 else
2683 result = tempResult;
2684 return this;
2685 }
2686 if (insideFragmentBackgroundRect && result.isRectBasedTest())
2687 result.append(tempResult);
2688 }
2689
2690 return 0;
2691 }
2692
hitTestContentsForFragments(const LayerFragments & layerFragments,const HitTestRequest & request,HitTestResult & result,const HitTestLocation & hitTestLocation,HitTestFilter hitTestFilter,bool & insideClipRect) const2693 bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragments, const HitTestRequest& request, HitTestResult& result,
2694 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& insideClipRect) const
2695 {
2696 if (layerFragments.isEmpty())
2697 return false;
2698
2699 for (int i = layerFragments.size() - 1; i >= 0; --i) {
2700 const LayerFragment& fragment = layerFragments.at(i);
2701 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects(hitTestLocation))
2702 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.intersects(hitTestLocation)))
2703 continue;
2704 insideClipRect = true;
2705 if (hitTestContents(request, result, fragment.layerBounds, hitTestLocation, hitTestFilter))
2706 return true;
2707 }
2708
2709 return false;
2710 }
2711
hitTestTransformedLayerInFragments(RenderLayer * rootLayer,RenderLayer * containerLayer,const HitTestRequest & request,HitTestResult & result,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,const HitTestingTransformState * transformState,double * zOffset)2712 RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
2713 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
2714 {
2715 LayerFragments enclosingPaginationFragments;
2716 LayoutPoint offsetOfPaginationLayerFromRoot;
2717 // FIXME: We're missing a sub-pixel offset here crbug.com/348728
2718 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox, LayoutSize());
2719 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestRect,
2720 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent);
2721
2722 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
2723 const LayerFragment& fragment = enclosingPaginationFragments.at(i);
2724
2725 // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
2726 // the enclosing pagination layer.
2727 LayoutRect clipRect = fragment.backgroundRect.rect();
2728
2729 // Now compute the clips within a given fragment
2730 if (parent() != enclosingPaginationLayer()) {
2731 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
2732 LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsContext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbarSize)).rect();
2733 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
2734 clipRect.intersect(parentClipRect);
2735 }
2736
2737 if (!hitTestLocation.intersects(clipRect))
2738 continue;
2739
2740 RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation,
2741 transformState, zOffset, fragment.paginationOffset);
2742 if (hitLayer)
2743 return hitLayer;
2744 }
2745
2746 return 0;
2747 }
2748
hitTestLayerByApplyingTransform(RenderLayer * rootLayer,RenderLayer * containerLayer,const HitTestRequest & request,HitTestResult & result,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,const HitTestingTransformState * transformState,double * zOffset,const LayoutPoint & translationOffset)2749 RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
2750 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
2751 const LayoutPoint& translationOffset)
2752 {
2753 // Create a transform state to accumulate this transform.
2754 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
2755
2756 // If the transform can't be inverted, then don't hit test this layer at all.
2757 if (!newTransformState->m_accumulatedTransform.isInvertible())
2758 return 0;
2759
2760 // Compute the point and the hit test rect in the coords of this layer by using the values
2761 // from the transformState, which store the point and quad in the coords of the last flattened
2762 // layer, and the accumulated transform which lets up map through preserve-3d layers.
2763 //
2764 // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
2765 // by our container.
2766 FloatPoint localPoint = newTransformState->mappedPoint();
2767 FloatQuad localPointQuad = newTransformState->mappedQuad();
2768 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
2769 HitTestLocation newHitTestLocation;
2770 if (hitTestLocation.isRectBasedTest())
2771 newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
2772 else
2773 newHitTestLocation = HitTestLocation(localPoint);
2774
2775 // Now do a hit test with the root layer shifted to be us.
2776 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset);
2777 }
2778
hitTestContents(const HitTestRequest & request,HitTestResult & result,const LayoutRect & layerBounds,const HitTestLocation & hitTestLocation,HitTestFilter hitTestFilter) const2779 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const
2780 {
2781 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
2782
2783 if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - renderBoxLocation()), hitTestFilter)) {
2784 // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
2785 // a rect-based test.
2786 ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
2787 return false;
2788 }
2789
2790 // For positioned generated content, we might still not have a
2791 // node by the time we get to the layer level, since none of
2792 // the content in the layer has an element. So just walk up
2793 // the tree.
2794 if (!result.innerNode() || !result.innerNonSharedNode()) {
2795 Node* e = enclosingElement();
2796 if (!result.innerNode())
2797 result.setInnerNode(e);
2798 if (!result.innerNonSharedNode())
2799 result.setInnerNonSharedNode(e);
2800 }
2801
2802 return true;
2803 }
2804
hitTestChildren(ChildrenIteration childrentoVisit,RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,const HitTestingTransformState * transformState,double * zOffsetForDescendants,double * zOffset,const HitTestingTransformState * unflattenedTransformState,bool depthSortDescendants)2805 RenderLayer* RenderLayer::hitTestChildren(ChildrenIteration childrentoVisit, RenderLayer* rootLayer,
2806 const HitTestRequest& request, HitTestResult& result,
2807 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
2808 const HitTestingTransformState* transformState,
2809 double* zOffsetForDescendants, double* zOffset,
2810 const HitTestingTransformState* unflattenedTransformState,
2811 bool depthSortDescendants)
2812 {
2813 if (!hasSelfPaintingLayerDescendant())
2814 return 0;
2815
2816 RenderLayer* resultLayer = 0;
2817 RenderLayerStackingNodeReverseIterator iterator(*m_stackingNode, childrentoVisit);
2818 while (RenderLayerStackingNode* child = iterator.next()) {
2819 RenderLayer* childLayer = child->layer();
2820 RenderLayer* hitLayer = 0;
2821 HitTestResult tempResult(result.hitTestLocation());
2822 if (childLayer->isPaginated())
2823 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants);
2824 else
2825 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
2826
2827 // If it a rect-based test, we can safely append the temporary result since it might had hit
2828 // nodes but not necesserily had hitLayer set.
2829 if (result.isRectBasedTest())
2830 result.append(tempResult);
2831
2832 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
2833 resultLayer = hitLayer;
2834 if (!result.isRectBasedTest())
2835 result = tempResult;
2836 if (!depthSortDescendants)
2837 break;
2838 }
2839 }
2840
2841 return resultLayer;
2842 }
2843
hitTestPaginatedChildLayer(RenderLayer * childLayer,RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,const HitTestingTransformState * transformState,double * zOffset)2844 RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
2845 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
2846 {
2847 Vector<RenderLayer*> columnLayers;
2848 RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode();
2849 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
2850 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
2851 columnLayers.append(curr);
2852 if (curr->stackingNode() == ancestorNode)
2853 break;
2854 }
2855
2856 ASSERT(columnLayers.size());
2857 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset,
2858 columnLayers, columnLayers.size() - 1);
2859 }
2860
hitTestChildLayerColumns(RenderLayer * childLayer,RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const LayoutRect & hitTestRect,const HitTestLocation & hitTestLocation,const HitTestingTransformState * transformState,double * zOffset,const Vector<RenderLayer * > & columnLayers,size_t columnIndex)2861 RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
2862 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
2863 const Vector<RenderLayer*>& columnLayers, size_t columnIndex)
2864 {
2865 RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer());
2866
2867 ASSERT(columnBlock && columnBlock->hasColumns());
2868 if (!columnBlock || !columnBlock->hasColumns())
2869 return 0;
2870
2871 LayoutPoint layerOffset;
2872 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset);
2873
2874 ColumnInfo* colInfo = columnBlock->columnInfo();
2875 int colCount = columnBlock->columnCount(colInfo);
2876
2877 // We have to go backwards from the last column to the first.
2878 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
2879 LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent();
2880 LayoutUnit currLogicalTopOffset = 0;
2881 int i;
2882 for (i = 0; i < colCount; i++) {
2883 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
2884 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
2885 if (columnBlock->style()->isFlippedBlocksWritingMode())
2886 currLogicalTopOffset += blockDelta;
2887 else
2888 currLogicalTopOffset -= blockDelta;
2889 }
2890 for (i = colCount - 1; i >= 0; i--) {
2891 // For each rect, we clip to the rect, and then we adjust our coords.
2892 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
2893 columnBlock->flipForWritingMode(colRect);
2894 LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
2895 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
2896 if (columnBlock->style()->isFlippedBlocksWritingMode())
2897 currLogicalTopOffset -= blockDelta;
2898 else
2899 currLogicalTopOffset += blockDelta;
2900
2901 LayoutSize offset;
2902 if (isHorizontal) {
2903 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
2904 offset = LayoutSize(currLogicalLeftOffset, currLogicalTopOffset);
2905 else
2906 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
2907 } else {
2908 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
2909 offset = LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
2910 else
2911 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
2912 }
2913
2914 colRect.moveBy(layerOffset);
2915
2916 LayoutRect localClipRect(hitTestRect);
2917 localClipRect.intersect(colRect);
2918
2919 if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect)) {
2920 RenderLayer* hitLayer = 0;
2921 if (!columnIndex) {
2922 // Apply a translation transform to change where the layer paints.
2923 TransformationMatrix oldTransform;
2924 bool oldHasTransform = childLayer->transform();
2925 if (oldHasTransform)
2926 oldTransform = *childLayer->transform();
2927 TransformationMatrix newTransform(oldTransform);
2928 newTransform.translateRight(offset.width(), offset.height());
2929
2930 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
2931 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestLocation, false, transformState, zOffset);
2932 if (oldHasTransform)
2933 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
2934 else
2935 childLayer->m_transform.clear();
2936 } else {
2937 // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space.
2938 // This involves subtracting out the position of the layer in our current coordinate space.
2939 RenderLayer* nextLayer = columnLayers[columnIndex - 1];
2940 RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState);
2941 newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
2942 FloatPoint localPoint = newTransformState->mappedPoint();
2943 FloatQuad localPointQuad = newTransformState->mappedQuad();
2944 LayoutRect localHitTestRect = newTransformState->mappedArea().enclosingBoundingBox();
2945 HitTestLocation newHitTestLocation;
2946 if (hitTestLocation.isRectBasedTest())
2947 newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
2948 else
2949 newHitTestLocation = HitTestLocation(localPoint);
2950 newTransformState->flatten();
2951
2952 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, newHitTestLocation,
2953 newTransformState.get(), zOffset, columnLayers, columnIndex - 1);
2954 }
2955
2956 if (hitLayer)
2957 return hitLayer;
2958 }
2959 }
2960
2961 return 0;
2962 }
2963
blockSelectionGapsBoundsChanged()2964 void RenderLayer::blockSelectionGapsBoundsChanged()
2965 {
2966 setNeedsCompositingInputsUpdate();
2967 }
2968
addBlockSelectionGapsBounds(const LayoutRect & bounds)2969 void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds)
2970 {
2971 m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds));
2972 blockSelectionGapsBoundsChanged();
2973 }
2974
clearBlockSelectionGapsBounds()2975 void RenderLayer::clearBlockSelectionGapsBounds()
2976 {
2977 m_blockSelectionGapsBounds = IntRect();
2978 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
2979 child->clearBlockSelectionGapsBounds();
2980 blockSelectionGapsBoundsChanged();
2981 }
2982
invalidatePaintForBlockSelectionGaps()2983 void RenderLayer::invalidatePaintForBlockSelectionGaps()
2984 {
2985 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
2986 child->invalidatePaintForBlockSelectionGaps();
2987
2988 if (m_blockSelectionGapsBounds.isEmpty())
2989 return;
2990
2991 LayoutRect rect = m_blockSelectionGapsBounds;
2992 if (renderer()->hasOverflowClip()) {
2993 RenderBox* box = renderBox();
2994 rect.move(-box->scrolledContentOffset());
2995 if (!scrollableArea()->usesCompositedScrolling())
2996 rect.intersect(box->overflowClipRect(LayoutPoint()));
2997 }
2998 if (renderer()->hasClip())
2999 rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint()));
3000 if (!rect.isEmpty())
3001 renderer()->invalidatePaintRectangle(rect);
3002 }
3003
blockSelectionGapsBounds() const3004 IntRect RenderLayer::blockSelectionGapsBounds() const
3005 {
3006 if (!renderer()->isRenderBlock())
3007 return IntRect();
3008
3009 RenderBlock* renderBlock = toRenderBlock(renderer());
3010 LayoutRect gapRects = renderBlock->selectionGapRectsForPaintInvalidation(renderBlock);
3011
3012 return pixelSnappedIntRect(gapRects);
3013 }
3014
hasBlockSelectionGapBounds() const3015 bool RenderLayer::hasBlockSelectionGapBounds() const
3016 {
3017 // FIXME: it would be more accurate to return !blockSelectionGapsBounds().isEmpty(), but this is impossible
3018 // at the moment because it causes invalid queries to layout-dependent code (crbug.com/372802).
3019 // ASSERT(renderer()->document().lifecycle().state() >= DocumentLifecycle::LayoutClean);
3020
3021 if (!renderer()->isRenderBlock())
3022 return false;
3023
3024 return toRenderBlock(renderer())->shouldPaintSelectionGaps();
3025 }
3026
intersectsDamageRect(const LayoutRect & layerBounds,const LayoutRect & damageRect,const RenderLayer * rootLayer,const LayoutPoint * offsetFromRoot) const3027 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const
3028 {
3029 // Always examine the canvas and the root.
3030 // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView
3031 // paints the root's background.
3032 if (isRootLayer() || renderer()->isDocumentElement())
3033 return true;
3034
3035 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
3036 // can go ahead and return true.
3037 RenderView* view = renderer()->view();
3038 ASSERT(view);
3039 if (view && !renderer()->isRenderInline()) {
3040 if (layerBounds.intersects(damageRect))
3041 return true;
3042 }
3043
3044 // Otherwise we need to compute the bounding box of this single layer and see if it intersects
3045 // the damage rect.
3046 return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
3047 }
3048
logicalBoundingBox() const3049 LayoutRect RenderLayer::logicalBoundingBox() const
3050 {
3051 // There are three special cases we need to consider.
3052 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
3053 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the
3054 // line boxes of all three lines (including overflow on those lines).
3055 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
3056 // overflow, we have to create a bounding box that will extend to include this overflow.
3057 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
3058 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
3059 // floats.
3060 LayoutRect result;
3061 if (renderer()->isInline() && renderer()->isRenderInline()) {
3062 result = toRenderInline(renderer())->linesVisualOverflowBoundingBox();
3063 } else if (renderer()->isTableRow()) {
3064 // Our bounding box is just the union of all of our cells' border/overflow rects.
3065 for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) {
3066 if (child->isTableCell()) {
3067 LayoutRect bbox = toRenderBox(child)->borderBoxRect();
3068 result.unite(bbox);
3069 LayoutRect overflowRect = renderBox()->visualOverflowRect();
3070 if (bbox != overflowRect)
3071 result.unite(overflowRect);
3072 }
3073 }
3074 } else {
3075 RenderBox* box = renderBox();
3076 ASSERT(box);
3077 result = box->borderBoxRect();
3078 result.unite(box->visualOverflowRect());
3079 }
3080
3081 ASSERT(renderer()->view());
3082 return result;
3083 }
3084
physicalBoundingBox(const RenderLayer * ancestorLayer,const LayoutPoint * offsetFromRoot) const3085 LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const
3086 {
3087 LayoutRect result = logicalBoundingBox();
3088 if (m_renderer->isBox())
3089 renderBox()->flipForWritingMode(result);
3090 else
3091 m_renderer->containingBlock()->flipForWritingMode(result);
3092
3093 LayoutPoint delta;
3094 if (offsetFromRoot)
3095 delta = *offsetFromRoot;
3096 else
3097 convertToLayerCoords(ancestorLayer, delta);
3098
3099 result.moveBy(delta);
3100 return result;
3101 }
3102
expandRectForReflectionAndStackingChildren(const RenderLayer * ancestorLayer,RenderLayer::CalculateBoundsOptions options,LayoutRect & result)3103 static void expandRectForReflectionAndStackingChildren(const RenderLayer* ancestorLayer, RenderLayer::CalculateBoundsOptions options, LayoutRect& result)
3104 {
3105 if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping())
3106 result.unite(ancestorLayer->reflectionInfo()->reflectionLayer()->boundingBoxForCompositing(ancestorLayer));
3107
3108 ASSERT(ancestorLayer->stackingNode()->isStackingContext() || !ancestorLayer->stackingNode()->hasPositiveZOrderList());
3109
3110 #if ENABLE(ASSERT)
3111 LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(ancestorLayer)->stackingNode());
3112 #endif
3113
3114 RenderLayerStackingNodeIterator iterator(*ancestorLayer->stackingNode(), AllChildren);
3115 while (RenderLayerStackingNode* node = iterator.next()) {
3116 // Here we exclude both directly composited layers and squashing layers
3117 // because those RenderLayers don't paint into the graphics layer
3118 // for this RenderLayer. For example, the bounds of squashed RenderLayers
3119 // will be included in the computation of the appropriate squashing
3120 // GraphicsLayer.
3121 if (options != RenderLayer::ApplyBoundsChickenEggHacks && node->layer()->compositingState() != NotComposited)
3122 continue;
3123 result.unite(node->layer()->boundingBoxForCompositing(ancestorLayer, options));
3124 }
3125 }
3126
physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer * ancestorLayer,const LayoutPoint & offsetFromRoot) const3127 LayoutRect RenderLayer::physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const
3128 {
3129 LayoutPoint origin;
3130 LayoutRect result = physicalBoundingBox(ancestorLayer, &origin);
3131
3132 const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
3133
3134 expandRectForReflectionAndStackingChildren(this, DoNotApplyBoundsChickenEggHacks, result);
3135
3136 result.moveBy(offsetFromRoot);
3137 return result;
3138 }
3139
boundingBoxForCompositing(const RenderLayer * ancestorLayer,CalculateBoundsOptions options) const3140 LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLayer, CalculateBoundsOptions options) const
3141 {
3142 if (!isSelfPaintingLayer())
3143 return LayoutRect();
3144
3145 if (!ancestorLayer)
3146 ancestorLayer = this;
3147
3148 // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
3149 if (this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
3150 return LayoutRect();
3151
3152 // The root layer is always just the size of the document.
3153 if (isRootLayer())
3154 return m_renderer->view()->unscaledDocumentRect();
3155
3156 const bool shouldIncludeTransform = paintsWithTransform(PaintBehaviorNormal) || (options == ApplyBoundsChickenEggHacks && transform());
3157
3158 LayoutRect localClipRect = clipper().localClipRect();
3159 if (localClipRect != PaintInfo::infiniteRect()) {
3160 if (shouldIncludeTransform)
3161 localClipRect = transform()->mapRect(localClipRect);
3162
3163 LayoutPoint delta;
3164 convertToLayerCoords(ancestorLayer, delta);
3165 localClipRect.moveBy(delta);
3166 return localClipRect;
3167 }
3168
3169 LayoutPoint origin;
3170 LayoutRect result = physicalBoundingBox(ancestorLayer, &origin);
3171
3172 const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
3173
3174 // Reflections are implemented with RenderLayers that hang off of the reflected layer. However,
3175 // the reflection layer subtree does not include the subtree of the parent RenderLayer, so
3176 // a recursive computation of stacking children yields no results. This breaks cases when there are stacking
3177 // children of the parent, that need to be included in reflected composited bounds.
3178 // Fix this by including composited bounds of stacking children of the reflected RenderLayer.
3179 if (hasCompositedLayerMapping() && parent() && parent()->reflectionInfo() && parent()->reflectionInfo()->reflectionLayer() == this)
3180 expandRectForReflectionAndStackingChildren(parent(), options, result);
3181 else
3182 expandRectForReflectionAndStackingChildren(this, options, result);
3183
3184 // FIXME: We can optimize the size of the composited layers, by not enlarging
3185 // filtered areas with the outsets if we know that the filter is going to render in hardware.
3186 // https://bugs.webkit.org/show_bug.cgi?id=81239
3187 m_renderer->style()->filterOutsets().expandRect(result);
3188
3189 if (shouldIncludeTransform)
3190 result = transform()->mapRect(result);
3191
3192 LayoutPoint delta;
3193 convertToLayerCoords(ancestorLayer, delta);
3194 result.moveBy(delta);
3195 return result;
3196 }
3197
compositingState() const3198 CompositingState RenderLayer::compositingState() const
3199 {
3200 ASSERT(isAllowedToQueryCompositingState());
3201
3202 // This is computed procedurally so there is no redundant state variable that
3203 // can get out of sync from the real actual compositing state.
3204
3205 if (m_groupedMapping) {
3206 ASSERT(compositor()->layerSquashingEnabled());
3207 ASSERT(!m_compositedLayerMapping);
3208 return PaintsIntoGroupedBacking;
3209 }
3210
3211 if (!m_compositedLayerMapping)
3212 return NotComposited;
3213
3214 if (compositedLayerMapping()->paintsIntoCompositedAncestor())
3215 return HasOwnBackingButPaintsIntoAncestor;
3216
3217 return PaintsIntoOwnBacking;
3218 }
3219
isAllowedToQueryCompositingState() const3220 bool RenderLayer::isAllowedToQueryCompositingState() const
3221 {
3222 if (gCompositingQueryMode == CompositingQueriesAreAllowed)
3223 return true;
3224 return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate;
3225 }
3226
compositedLayerMapping() const3227 CompositedLayerMapping* RenderLayer::compositedLayerMapping() const
3228 {
3229 ASSERT(isAllowedToQueryCompositingState());
3230 return m_compositedLayerMapping.get();
3231 }
3232
graphicsLayerBacking() const3233 GraphicsLayer* RenderLayer::graphicsLayerBacking() const
3234 {
3235 switch (compositingState()) {
3236 case NotComposited:
3237 return 0;
3238 case PaintsIntoGroupedBacking:
3239 return groupedMapping()->squashingLayer();
3240 default:
3241 return compositedLayerMapping()->mainGraphicsLayer();
3242 }
3243 }
3244
graphicsLayerBackingForScrolling() const3245 GraphicsLayer* RenderLayer::graphicsLayerBackingForScrolling() const
3246 {
3247 switch (compositingState()) {
3248 case NotComposited:
3249 return 0;
3250 case PaintsIntoGroupedBacking:
3251 return groupedMapping()->squashingLayer();
3252 default:
3253 return compositedLayerMapping()->scrollingContentsLayer() ? compositedLayerMapping()->scrollingContentsLayer() : compositedLayerMapping()->mainGraphicsLayer();
3254 }
3255 }
3256
ensureCompositedLayerMapping()3257 CompositedLayerMapping* RenderLayer::ensureCompositedLayerMapping()
3258 {
3259 if (!m_compositedLayerMapping) {
3260 m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this));
3261 m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
3262
3263 updateOrRemoveFilterEffectRenderer();
3264 }
3265 return m_compositedLayerMapping.get();
3266 }
3267
clearCompositedLayerMapping(bool layerBeingDestroyed)3268 void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed)
3269 {
3270 if (!layerBeingDestroyed) {
3271 // We need to make sure our decendants get a geometry update. In principle,
3272 // we could call setNeedsGraphicsLayerUpdate on our children, but that would
3273 // require walking the z-order lists to find them. Instead, we over-invalidate
3274 // by marking our parent as needing a geometry update.
3275 if (RenderLayer* compositingParent = enclosingLayerWithCompositedLayerMapping(ExcludeSelf))
3276 compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
3277 }
3278
3279 m_compositedLayerMapping.clear();
3280
3281 if (!layerBeingDestroyed)
3282 updateOrRemoveFilterEffectRenderer();
3283 }
3284
setGroupedMapping(CompositedLayerMapping * groupedMapping,bool layerBeingDestroyed)3285 void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool layerBeingDestroyed)
3286 {
3287 if (groupedMapping == m_groupedMapping)
3288 return;
3289
3290 if (!layerBeingDestroyed && m_groupedMapping) {
3291 m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
3292 m_groupedMapping->removeRenderLayerFromSquashingGraphicsLayer(this);
3293 }
3294 m_groupedMapping = groupedMapping;
3295 if (!layerBeingDestroyed && m_groupedMapping)
3296 m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
3297 }
3298
hasCompositedMask() const3299 bool RenderLayer::hasCompositedMask() const
3300 {
3301 return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer();
3302 }
3303
hasCompositedClippingMask() const3304 bool RenderLayer::hasCompositedClippingMask() const
3305 {
3306 return m_compositedLayerMapping && m_compositedLayerMapping->hasChildClippingMaskLayer();
3307 }
3308
clipsCompositingDescendantsWithBorderRadius() const3309 bool RenderLayer::clipsCompositingDescendantsWithBorderRadius() const
3310 {
3311 RenderStyle* style = renderer()->style();
3312 if (!style)
3313 return false;
3314
3315 return compositor()->clipsCompositingDescendants(this) && style->hasBorderRadius();
3316 }
3317
paintsWithTransform(PaintBehavior paintBehavior) const3318 bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
3319 {
3320 return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || compositingState() != PaintsIntoOwnBacking);
3321 }
3322
paintsWithBlendMode() const3323 bool RenderLayer::paintsWithBlendMode() const
3324 {
3325 return m_renderer->hasBlendMode() && compositingState() != PaintsIntoOwnBacking;
3326 }
3327
backgroundIsKnownToBeOpaqueInRect(const LayoutRect & localRect) const3328 bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
3329 {
3330 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
3331 return false;
3332
3333 if (paintsWithTransparency(PaintBehaviorNormal))
3334 return false;
3335
3336 // We can't use hasVisibleContent(), because that will be true if our renderer is hidden, but some child
3337 // is visible and that child doesn't cover the entire rect.
3338 if (renderer()->style()->visibility() != VISIBLE)
3339 return false;
3340
3341 if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffectsOpacity())
3342 return false;
3343
3344 // FIXME: Handle simple transforms.
3345 if (paintsWithTransform(PaintBehaviorNormal))
3346 return false;
3347
3348 // FIXME: Remove this check.
3349 // This function should not be called when layer-lists are dirty.
3350 // It is somehow getting triggered during style update.
3351 if (m_stackingNode->zOrderListsDirty() || m_stackingNode->normalFlowListDirty())
3352 return false;
3353
3354 // FIXME: We currently only check the immediate renderer,
3355 // which will miss many cases.
3356 if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect))
3357 return true;
3358
3359 // We can't consult child layers if we clip, since they might cover
3360 // parts of the rect that are clipped out.
3361 if (renderer()->hasOverflowClip())
3362 return false;
3363
3364 return childBackgroundIsKnownToBeOpaqueInRect(localRect);
3365 }
3366
childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect & localRect) const3367 bool RenderLayer::childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
3368 {
3369 RenderLayerStackingNodeReverseIterator revertseIterator(*m_stackingNode, PositiveZOrderChildren | NormalFlowChildren | NegativeZOrderChildren);
3370 while (RenderLayerStackingNode* child = revertseIterator.next()) {
3371 const RenderLayer* childLayer = child->layer();
3372 // Stop at composited paint boundaries.
3373 if (childLayer->isPaintInvalidationContainer())
3374 continue;
3375
3376 if (!childLayer->canUseConvertToLayerCoords())
3377 continue;
3378
3379 LayoutPoint childOffset;
3380 LayoutRect childLocalRect(localRect);
3381 childLayer->convertToLayerCoords(this, childOffset);
3382 childLocalRect.moveBy(-childOffset);
3383
3384 if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
3385 return true;
3386 }
3387 return false;
3388 }
3389
shouldBeSelfPaintingLayer() const3390 bool RenderLayer::shouldBeSelfPaintingLayer() const
3391 {
3392 if (renderer()->isRenderPart() && toRenderPart(renderer())->requiresAcceleratedCompositing())
3393 return true;
3394 return m_layerType == NormalLayer
3395 || (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars())
3396 || needsCompositedScrolling();
3397 }
3398
updateSelfPaintingLayer()3399 void RenderLayer::updateSelfPaintingLayer()
3400 {
3401 bool isSelfPaintingLayer = shouldBeSelfPaintingLayer();
3402 if (this->isSelfPaintingLayer() == isSelfPaintingLayer)
3403 return;
3404
3405 m_isSelfPaintingLayer = isSelfPaintingLayer;
3406
3407 if (parent())
3408 parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
3409 }
3410
hasNonEmptyChildRenderers() const3411 bool RenderLayer::hasNonEmptyChildRenderers() const
3412 {
3413 // Some HTML can cause whitespace text nodes to have renderers, like:
3414 // <div>
3415 // <img src=...>
3416 // </div>
3417 // so test for 0x0 RenderTexts here
3418 for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) {
3419 if (!child->hasLayer()) {
3420 if (child->isRenderInline() || !child->isBox())
3421 return true;
3422
3423 if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
3424 return true;
3425 }
3426 }
3427 return false;
3428 }
3429
hasBoxDecorationsOrBackground() const3430 bool RenderLayer::hasBoxDecorationsOrBackground() const
3431 {
3432 return renderer()->style()->hasBoxDecorations() || renderer()->style()->hasBackground();
3433 }
3434
hasVisibleBoxDecorations() const3435 bool RenderLayer::hasVisibleBoxDecorations() const
3436 {
3437 if (!hasVisibleContent())
3438 return false;
3439
3440 return hasBoxDecorationsOrBackground() || hasOverflowControls();
3441 }
3442
isVisuallyNonEmpty() const3443 bool RenderLayer::isVisuallyNonEmpty() const
3444 {
3445 ASSERT(!m_visibleDescendantStatusDirty);
3446
3447 if (hasVisibleContent() && hasNonEmptyChildRenderers())
3448 return true;
3449
3450 if (renderer()->isReplaced() || renderer()->hasMask())
3451 return true;
3452
3453 if (hasVisibleBoxDecorations())
3454 return true;
3455
3456 return false;
3457 }
3458
updateFilters(const RenderStyle * oldStyle,const RenderStyle * newStyle)3459 void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
3460 {
3461 if (!newStyle->hasFilter() && (!oldStyle || !oldStyle->hasFilter()))
3462 return;
3463
3464 updateOrRemoveFilterClients();
3465 updateOrRemoveFilterEffectRenderer();
3466 }
3467
attemptDirectCompositingUpdate(StyleDifference diff,const RenderStyle * oldStyle)3468 bool RenderLayer::attemptDirectCompositingUpdate(StyleDifference diff, const RenderStyle* oldStyle)
3469 {
3470 CompositingReasons oldPotentialCompositingReasonsFromStyle = m_potentialCompositingReasonsFromStyle;
3471 compositor()->updatePotentialCompositingReasonsFromStyle(this);
3472
3473 // This function implements an optimization for transforms and opacity.
3474 // A common pattern is for a touchmove handler to update the transform
3475 // and/or an opacity of an element every frame while the user moves their
3476 // finger across the screen. The conditions below recognize when the
3477 // compositing state is set up to receive a direct transform or opacity
3478 // update.
3479
3480 if (!diff.hasAtMostPropertySpecificDifferences(StyleDifference::TransformChanged | StyleDifference::OpacityChanged))
3481 return false;
3482 // The potentialCompositingReasonsFromStyle could have changed without
3483 // a corresponding StyleDifference if an animation started or ended.
3484 if (m_potentialCompositingReasonsFromStyle != oldPotentialCompositingReasonsFromStyle)
3485 return false;
3486 // We could add support for reflections if we updated the transform on
3487 // the reflection layers.
3488 if (renderer()->hasReflection())
3489 return false;
3490 // If we're unwinding a scheduleSVGFilterLayerUpdateHack(), then we can't
3491 // perform a direct compositing update because the filters code is going
3492 // to produce different output this time around. We can remove this code
3493 // once we fix the chicken/egg bugs in the filters code and delete the
3494 // scheduleSVGFilterLayerUpdateHack().
3495 if (renderer()->node() && renderer()->node()->svgFilterNeedsLayerUpdate())
3496 return false;
3497 if (!m_compositedLayerMapping)
3498 return false;
3499
3500 // To cut off almost all the work in the compositing update for
3501 // this case, we treat inline transforms has having assumed overlap
3502 // (similar to how we treat animated transforms). Notice that we read
3503 // CompositingReasonInlineTransform from the m_compositingReasons, which
3504 // means that the inline transform actually triggered assumed overlap in
3505 // the overlap map.
3506 if (diff.transformChanged() && !(m_compositingReasons & CompositingReasonInlineTransform))
3507 return false;
3508
3509 // We composite transparent RenderLayers differently from non-transparent
3510 // RenderLayers even when the non-transparent RenderLayers are already a
3511 // stacking context.
3512 if (diff.opacityChanged() && m_renderer->style()->hasOpacity() != oldStyle->hasOpacity())
3513 return false;
3514
3515 updateTransform(oldStyle, renderer()->style());
3516
3517 // FIXME: Consider introducing a smaller graphics layer update scope
3518 // that just handles transforms and opacity. GraphicsLayerUpdateLocal
3519 // will also program bounds, clips, and many other properties that could
3520 // not possibly have changed.
3521 m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
3522 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange);
3523 return true;
3524 }
3525
styleChanged(StyleDifference diff,const RenderStyle * oldStyle)3526 void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
3527 {
3528 if (attemptDirectCompositingUpdate(diff, oldStyle))
3529 return;
3530
3531 m_stackingNode->updateIsNormalFlowOnly();
3532 m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);
3533
3534 if (m_scrollableArea)
3535 m_scrollableArea->updateAfterStyleChange(oldStyle);
3536
3537 // Overlay scrollbars can make this layer self-painting so we need
3538 // to recompute the bit once scrollbars have been updated.
3539 updateSelfPaintingLayer();
3540
3541 if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) {
3542 ASSERT(!oldStyle || diff.needsFullLayout());
3543 updateReflectionInfo(oldStyle);
3544 }
3545
3546 updateDescendantDependentFlags();
3547
3548 updateTransform(oldStyle, renderer()->style());
3549 updateFilters(oldStyle, renderer()->style());
3550
3551 setNeedsCompositingInputsUpdate();
3552 }
3553
scrollsOverflow() const3554 bool RenderLayer::scrollsOverflow() const
3555 {
3556 if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea())
3557 return scrollableArea->scrollsOverflow();
3558
3559 return false;
3560 }
3561
computeFilterOperations(const RenderStyle * style)3562 FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style)
3563 {
3564 const FilterOperations& filters = style->filter();
3565 if (filters.hasReferenceFilter()) {
3566 for (size_t i = 0; i < filters.size(); ++i) {
3567 FilterOperation* filterOperation = filters.operations().at(i).get();
3568 if (filterOperation->type() != FilterOperation::REFERENCE)
3569 continue;
3570 ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation);
3571 // FIXME: Cache the ReferenceFilter if it didn't change.
3572 RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create();
3573 float zoom = style->effectiveZoom();
3574 referenceFilter->setAbsoluteTransform(AffineTransform().scale(zoom, zoom));
3575 referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referenceFilter.get(), renderer(), referenceFilter->sourceGraphic(),
3576 referenceOperation));
3577 referenceOperation->setFilter(referenceFilter.release());
3578 }
3579 }
3580
3581 return filters;
3582 }
3583
updateOrRemoveFilterClients()3584 void RenderLayer::updateOrRemoveFilterClients()
3585 {
3586 if (!hasFilter()) {
3587 removeFilterInfoIfNeeded();
3588 return;
3589 }
3590
3591 if (renderer()->style()->filter().hasReferenceFilter())
3592 ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->filter());
3593 else if (hasFilterInfo())
3594 filterInfo()->removeReferenceFilterClients();
3595 }
3596
updateOrRemoveFilterEffectRenderer()3597 void RenderLayer::updateOrRemoveFilterEffectRenderer()
3598 {
3599 // FilterEffectRenderer is only used to render the filters in software mode,
3600 // so we always need to run updateOrRemoveFilterEffectRenderer after the composited
3601 // mode might have changed for this layer.
3602 if (!paintsWithFilters()) {
3603 // Don't delete the whole filter info here, because we might use it
3604 // for loading CSS shader files.
3605 if (RenderLayerFilterInfo* filterInfo = this->filterInfo())
3606 filterInfo->setRenderer(nullptr);
3607
3608 return;
3609 }
3610
3611 RenderLayerFilterInfo* filterInfo = ensureFilterInfo();
3612 if (!filterInfo->renderer()) {
3613 RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create();
3614 filterInfo->setRenderer(filterRenderer.release());
3615 }
3616
3617 // If the filter fails to build, remove it from the layer. It will still attempt to
3618 // go through regular processing (e.g. compositing), but never apply anything.
3619 if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style())))
3620 filterInfo->setRenderer(nullptr);
3621 }
3622
filterNeedsPaintInvalidation()3623 void RenderLayer::filterNeedsPaintInvalidation()
3624 {
3625 {
3626 DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().lifecycle());
3627 // It's possible for scheduleSVGFilterLayerUpdateHack to schedule a style recalc, which
3628 // is a problem because this function can be called while performing layout.
3629 // Presumably this represents an illegal data flow of layout or compositing
3630 // information into the style system.
3631 toElement(renderer()->node())->scheduleSVGFilterLayerUpdateHack();
3632 }
3633
3634 renderer()->setShouldDoFullPaintInvalidation(true);
3635 }
3636
addLayerHitTestRects(LayerHitTestRects & rects) const3637 void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const
3638 {
3639 computeSelfHitTestRects(rects);
3640 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3641 child->addLayerHitTestRects(rects);
3642 }
3643
computeSelfHitTestRects(LayerHitTestRects & rects) const3644 void RenderLayer::computeSelfHitTestRects(LayerHitTestRects& rects) const
3645 {
3646 if (!size().isEmpty()) {
3647 Vector<LayoutRect> rect;
3648
3649 if (renderBox() && renderBox()->scrollsOverflow()) {
3650 // For scrolling layers, rects are taken to be in the space of the contents.
3651 // We need to include the bounding box of the layer in the space of its parent
3652 // (eg. for border / scroll bars) and if it's composited then the entire contents
3653 // as well as they may be on another composited layer. Skip reporting contents
3654 // for non-composited layers as they'll get projected to the same layer as the
3655 // bounding box.
3656 if (compositingState() != NotComposited)
3657 rect.append(m_scrollableArea->overflowRect());
3658
3659 rects.set(this, rect);
3660 if (const RenderLayer* parentLayer = parent()) {
3661 LayerHitTestRects::iterator iter = rects.find(parentLayer);
3662 if (iter == rects.end()) {
3663 rects.add(parentLayer, Vector<LayoutRect>()).storedValue->value.append(physicalBoundingBox(parentLayer));
3664 } else {
3665 iter->value.append(physicalBoundingBox(parentLayer));
3666 }
3667 }
3668 } else {
3669 rect.append(logicalBoundingBox());
3670 rects.set(this, rect);
3671 }
3672 }
3673 }
3674
setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants()3675 void RenderLayer::setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants()
3676 {
3677 renderer()->setShouldDoFullPaintInvalidation(true);
3678
3679 // Disable for reading compositingState() in isPaintInvalidationContainer() below.
3680 DisableCompositingQueryAsserts disabler;
3681
3682 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
3683 if (!child->isPaintInvalidationContainer())
3684 child->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
3685 }
3686 }
3687
DisableCompositingQueryAsserts()3688 DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
3689 : m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { }
3690
3691 } // namespace blink
3692
3693 #ifndef NDEBUG
showLayerTree(const blink::RenderLayer * layer)3694 void showLayerTree(const blink::RenderLayer* layer)
3695 {
3696 if (!layer)
3697 return;
3698
3699 if (blink::LocalFrame* frame = layer->renderer()->frame()) {
3700 WTF::String output = externalRepresentation(frame, blink::RenderAsTextShowAllLayers | blink::RenderAsTextShowLayerNesting | blink::RenderAsTextShowCompositedLayers | blink::RenderAsTextShowAddresses | blink::RenderAsTextShowIDAndClass | blink::RenderAsTextDontUpdateLayout | blink::RenderAsTextShowLayoutState);
3701 fprintf(stderr, "%s\n", output.utf8().data());
3702 }
3703 }
3704
showLayerTree(const blink::RenderObject * renderer)3705 void showLayerTree(const blink::RenderObject* renderer)
3706 {
3707 if (!renderer)
3708 return;
3709 showLayerTree(renderer->enclosingLayer());
3710 }
3711 #endif
3712