1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "Layers.h"
8 #include <algorithm> // for max, min
9 #include "apz/src/AsyncPanZoomController.h"
10 #include "CompositableHost.h" // for CompositableHost
11 #include "ImageContainer.h" // for ImageContainer, etc
12 #include "ImageLayers.h" // for ImageLayer
13 #include "LayerSorter.h" // for SortLayersBy3DZOrder
14 #include "LayersLogging.h" // for AppendToString
15 #include "LayerUserData.h"
16 #include "ReadbackLayer.h" // for ReadbackLayer
17 #include "UnitTransforms.h" // for ViewAs
18 #include "gfxEnv.h"
19 #include "gfxPlatform.h" // for gfxPlatform
20 #include "gfxPrefs.h"
21 #include "gfxUtils.h" // for gfxUtils, etc
22 #include "gfx2DGlue.h"
23 #include "mozilla/DebugOnly.h" // for DebugOnly
24 #include "mozilla/IntegerPrintfMacros.h"
25 #include "mozilla/Telemetry.h" // for Accumulate
26 #include "mozilla/ToString.h"
27 #include "mozilla/gfx/2D.h" // for DrawTarget
28 #include "mozilla/gfx/BaseSize.h" // for BaseSize
29 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
30 #include "mozilla/gfx/Polygon.h" // for Polygon
31 #include "mozilla/layers/AsyncCanvasRenderer.h"
32 #include "mozilla/layers/BSPTree.h" // for BSPTree
33 #include "mozilla/layers/CompositableClient.h" // for CompositableClient
34 #include "mozilla/layers/Compositor.h" // for Compositor
35 #include "mozilla/layers/CompositorTypes.h"
36 #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite
37 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
38 #include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
39 #include "mozilla/layers/LayersTypes.h" // for TextureDumpMode
40 #include "mozilla/layers/PersistentBufferProvider.h"
41 #include "mozilla/layers/ShadowLayers.h" // for ShadowableLayer
42 #include "nsAString.h"
43 #include "nsCSSValue.h" // for nsCSSValue::Array, etc
44 #include "nsDisplayList.h" // for nsDisplayItem
45 #include "nsPrintfCString.h" // for nsPrintfCString
46 #include "protobuf/LayerScopePacket.pb.h"
47 #include "mozilla/Compression.h"
48 #include "TreeTraversal.h" // for ForEachNode
49
50 #include <list>
51 #include <set>
52
53 uint8_t gLayerManagerLayerBuilder;
54
55 namespace mozilla {
56 namespace layers {
57
FILEOrDefault(FILE * aFile)58 FILE* FILEOrDefault(FILE* aFile) { return aFile ? aFile : stderr; }
59
60 typedef FrameMetrics::ViewID ViewID;
61
62 using namespace mozilla::gfx;
63 using namespace mozilla::Compression;
64
65 //--------------------------------------------------
66 // LayerManager
67
GetLog()68 /* static */ mozilla::LogModule* LayerManager::GetLog() {
69 static LazyLogModule sLog("Layers");
70 return sLog;
71 }
72
GetRootScrollableLayerId()73 FrameMetrics::ViewID LayerManager::GetRootScrollableLayerId() {
74 if (!mRoot) {
75 return FrameMetrics::NULL_SCROLL_ID;
76 }
77
78 LayerMetricsWrapper layerMetricsRoot = LayerMetricsWrapper(mRoot);
79
80 LayerMetricsWrapper rootScrollableLayerMetrics =
81 BreadthFirstSearch<ForwardIterator>(
82 layerMetricsRoot, [](LayerMetricsWrapper aLayerMetrics) {
83 return aLayerMetrics.Metrics().IsScrollable();
84 });
85
86 return rootScrollableLayerMetrics.IsValid()
87 ? rootScrollableLayerMetrics.Metrics().GetScrollId()
88 : FrameMetrics::NULL_SCROLL_ID;
89 }
90
GetRootContentLayer()91 LayerMetricsWrapper LayerManager::GetRootContentLayer() {
92 if (!mRoot) {
93 return LayerMetricsWrapper();
94 }
95
96 LayerMetricsWrapper root(mRoot);
97
98 return BreadthFirstSearch<ForwardIterator>(
99 root, [](LayerMetricsWrapper aLayerMetrics) {
100 return aLayerMetrics.Metrics().IsRootContent();
101 });
102 }
103
CreateOptimalDrawTarget(const gfx::IntSize & aSize,SurfaceFormat aFormat)104 already_AddRefed<DrawTarget> LayerManager::CreateOptimalDrawTarget(
105 const gfx::IntSize& aSize, SurfaceFormat aFormat) {
106 return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aSize,
107 aFormat);
108 }
109
CreateOptimalMaskDrawTarget(const gfx::IntSize & aSize)110 already_AddRefed<DrawTarget> LayerManager::CreateOptimalMaskDrawTarget(
111 const gfx::IntSize& aSize) {
112 return CreateOptimalDrawTarget(aSize, SurfaceFormat::A8);
113 }
114
CreateDrawTarget(const IntSize & aSize,SurfaceFormat aFormat)115 already_AddRefed<DrawTarget> LayerManager::CreateDrawTarget(
116 const IntSize& aSize, SurfaceFormat aFormat) {
117 return gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(aSize,
118 aFormat);
119 }
120
121 already_AddRefed<PersistentBufferProvider>
CreatePersistentBufferProvider(const mozilla::gfx::IntSize & aSize,mozilla::gfx::SurfaceFormat aFormat)122 LayerManager::CreatePersistentBufferProvider(
123 const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat) {
124 RefPtr<PersistentBufferProviderBasic> bufferProvider =
125 PersistentBufferProviderBasic::Create(
126 aSize, aFormat,
127 gfxPlatform::GetPlatform()->GetPreferredCanvasBackend());
128
129 if (!bufferProvider) {
130 bufferProvider = PersistentBufferProviderBasic::Create(
131 aSize, aFormat, gfxPlatform::GetPlatform()->GetFallbackCanvasBackend());
132 }
133
134 return bufferProvider.forget();
135 }
136
CreateImageContainer(ImageContainer::Mode flag)137 already_AddRefed<ImageContainer> LayerManager::CreateImageContainer(
138 ImageContainer::Mode flag) {
139 RefPtr<ImageContainer> container = new ImageContainer(flag);
140 return container.forget();
141 }
142
AreComponentAlphaLayersEnabled()143 bool LayerManager::AreComponentAlphaLayersEnabled() {
144 return gfxPrefs::ComponentAlphaEnabled();
145 }
146
LayerUserDataDestroy(void * data)147 /*static*/ void LayerManager::LayerUserDataDestroy(void* data) {
148 delete static_cast<LayerUserData*>(data);
149 }
150
RemoveUserData(void * aKey)151 UniquePtr<LayerUserData> LayerManager::RemoveUserData(void* aKey) {
152 UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(
153 mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
154 return d;
155 }
156
157 //--------------------------------------------------
158 // Layer
159
Layer(LayerManager * aManager,void * aImplData)160 Layer::Layer(LayerManager* aManager, void* aImplData)
161 : mManager(aManager),
162 mParent(nullptr),
163 mNextSibling(nullptr),
164 mPrevSibling(nullptr),
165 mImplData(aImplData),
166 mAnimationInfo(aManager),
167 mUseTileSourceRect(false)
168 #ifdef DEBUG
169 ,
170 mDebugColorIndex(0)
171 #endif
172 {
173 }
174
~Layer()175 Layer::~Layer() {}
176
SetCompositorAnimations(const CompositorAnimations & aCompositorAnimations)177 void Layer::SetCompositorAnimations(
178 const CompositorAnimations& aCompositorAnimations) {
179 MOZ_LAYERS_LOG_IF_SHADOWABLE(
180 this, ("Layer::Mutated(%p) SetCompositorAnimations with id=%" PRIu64,
181 this, mAnimationInfo.GetCompositorAnimationsId()));
182
183 mAnimationInfo.SetCompositorAnimations(aCompositorAnimations);
184
185 Mutated();
186 }
187
StartPendingAnimations(const TimeStamp & aReadyTime)188 void Layer::StartPendingAnimations(const TimeStamp& aReadyTime) {
189 ForEachNode<ForwardIterator>(this, [&aReadyTime](Layer* layer) {
190 if (layer->mAnimationInfo.StartPendingAnimations(aReadyTime)) {
191 layer->Mutated();
192 }
193 });
194 }
195
SetAsyncPanZoomController(uint32_t aIndex,AsyncPanZoomController * controller)196 void Layer::SetAsyncPanZoomController(uint32_t aIndex,
197 AsyncPanZoomController* controller) {
198 MOZ_ASSERT(aIndex < GetScrollMetadataCount());
199 mApzcs[aIndex] = controller;
200 }
201
GetAsyncPanZoomController(uint32_t aIndex) const202 AsyncPanZoomController* Layer::GetAsyncPanZoomController(
203 uint32_t aIndex) const {
204 MOZ_ASSERT(aIndex < GetScrollMetadataCount());
205 #ifdef DEBUG
206 if (mApzcs[aIndex]) {
207 MOZ_ASSERT(GetFrameMetrics(aIndex).IsScrollable());
208 }
209 #endif
210 return mApzcs[aIndex];
211 }
212
ScrollMetadataChanged()213 void Layer::ScrollMetadataChanged() {
214 mApzcs.SetLength(GetScrollMetadataCount());
215 }
216
ApplyPendingUpdatesToSubtree()217 void Layer::ApplyPendingUpdatesToSubtree() {
218 ForEachNode<ForwardIterator>(this, [](Layer* layer) {
219 layer->ApplyPendingUpdatesForThisTransaction();
220 });
221
222 // Once we're done recursing through the whole tree, clear the pending
223 // updates from the manager.
224 Manager()->ClearPendingScrollInfoUpdate();
225 }
226
IsOpaqueForVisibility()227 bool Layer::IsOpaqueForVisibility() {
228 return GetEffectiveOpacity() == 1.0f &&
229 GetEffectiveMixBlendMode() == CompositionOp::OP_OVER;
230 }
231
CanUseOpaqueSurface()232 bool Layer::CanUseOpaqueSurface() {
233 // If the visible content in the layer is opaque, there is no need
234 // for an alpha channel.
235 if (GetContentFlags() & CONTENT_OPAQUE) return true;
236 // Also, if this layer is the bottommost layer in a container which
237 // doesn't need an alpha channel, we can use an opaque surface for this
238 // layer too. Any transparent areas must be covered by something else
239 // in the container.
240 ContainerLayer* parent = GetParent();
241 return parent && parent->GetFirstChild() == this &&
242 parent->CanUseOpaqueSurface();
243 }
244
245 // NB: eventually these methods will be defined unconditionally, and
246 // can be moved into Layers.h
GetLocalClipRect()247 const Maybe<ParentLayerIntRect>& Layer::GetLocalClipRect() {
248 if (HostLayer* shadow = AsHostLayer()) {
249 return shadow->GetShadowClipRect();
250 }
251 return GetClipRect();
252 }
253
GetLocalVisibleRegion()254 const LayerIntRegion& Layer::GetLocalVisibleRegion() {
255 if (HostLayer* shadow = AsHostLayer()) {
256 return shadow->GetShadowVisibleRegion();
257 }
258 return GetVisibleRegion();
259 }
260
SnapTransformTranslation(const Matrix4x4 & aTransform,Matrix * aResidualTransform)261 Matrix4x4 Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
262 Matrix* aResidualTransform) {
263 if (aResidualTransform) {
264 *aResidualTransform = Matrix();
265 }
266
267 if (!mManager->IsSnappingEffectiveTransforms()) {
268 return aTransform;
269 }
270
271 Matrix matrix2D;
272 if (aTransform.CanDraw2D(&matrix2D) && !matrix2D.HasNonTranslation() &&
273 matrix2D.HasNonIntegerTranslation()) {
274 auto snappedTranslation = IntPoint::Round(matrix2D.GetTranslation());
275 Matrix snappedMatrix =
276 Matrix::Translation(snappedTranslation.x, snappedTranslation.y);
277 Matrix4x4 result = Matrix4x4::From2D(snappedMatrix);
278 if (aResidualTransform) {
279 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
280 // (I.e., appying snappedMatrix after aResidualTransform gives the
281 // ideal transform.)
282 *aResidualTransform =
283 Matrix::Translation(matrix2D._31 - snappedTranslation.x,
284 matrix2D._32 - snappedTranslation.y);
285 }
286 return result;
287 }
288
289 return SnapTransformTranslation3D(aTransform, aResidualTransform);
290 }
291
SnapTransformTranslation3D(const Matrix4x4 & aTransform,Matrix * aResidualTransform)292 Matrix4x4 Layer::SnapTransformTranslation3D(const Matrix4x4& aTransform,
293 Matrix* aResidualTransform) {
294 if (aTransform.IsSingular() || aTransform.HasPerspectiveComponent() ||
295 aTransform.HasNonTranslation() ||
296 !aTransform.HasNonIntegerTranslation()) {
297 // For a singular transform, there is no reversed matrix, so we
298 // don't snap it.
299 // For a perspective transform, the content is transformed in
300 // non-linear, so we don't snap it too.
301 return aTransform;
302 }
303
304 // Snap for 3D Transforms
305
306 Point3D transformedOrigin = aTransform.TransformPoint(Point3D());
307
308 // Compute the transformed snap by rounding the values of
309 // transformed origin.
310 auto transformedSnapXY =
311 IntPoint::Round(transformedOrigin.x, transformedOrigin.y);
312 Matrix4x4 inverse = aTransform;
313 inverse.Invert();
314 // see Matrix4x4::ProjectPoint()
315 Float transformedSnapZ =
316 inverse._33 == 0 ? 0
317 : (-(transformedSnapXY.x * inverse._13 +
318 transformedSnapXY.y * inverse._23 + inverse._43) /
319 inverse._33);
320 Point3D transformedSnap =
321 Point3D(transformedSnapXY.x, transformedSnapXY.y, transformedSnapZ);
322 if (transformedOrigin == transformedSnap) {
323 return aTransform;
324 }
325
326 // Compute the snap from the transformed snap.
327 Point3D snap = inverse.TransformPoint(transformedSnap);
328 if (snap.z > 0.001 || snap.z < -0.001) {
329 // Allow some level of accumulated computation error.
330 MOZ_ASSERT(inverse._33 == 0.0);
331 return aTransform;
332 }
333
334 // The difference between the origin and snap is the residual transform.
335 if (aResidualTransform) {
336 // The residual transform is to translate the snap to the origin
337 // of the content buffer.
338 *aResidualTransform = Matrix::Translation(-snap.x, -snap.y);
339 }
340
341 // Translate transformed origin to transformed snap since the
342 // residual transform would trnslate the snap to the origin.
343 Point3D transformedShift = transformedSnap - transformedOrigin;
344 Matrix4x4 result = aTransform;
345 result.PostTranslate(transformedShift.x, transformedShift.y,
346 transformedShift.z);
347
348 // For non-2d transform, residual translation could be more than
349 // 0.5 pixels for every axis.
350
351 return result;
352 }
353
SnapTransform(const Matrix4x4 & aTransform,const gfxRect & aSnapRect,Matrix * aResidualTransform)354 Matrix4x4 Layer::SnapTransform(const Matrix4x4& aTransform,
355 const gfxRect& aSnapRect,
356 Matrix* aResidualTransform) {
357 if (aResidualTransform) {
358 *aResidualTransform = Matrix();
359 }
360
361 Matrix matrix2D;
362 Matrix4x4 result;
363 if (mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) &&
364 gfxSize(1.0, 1.0) <= aSnapRect.Size() &&
365 matrix2D.PreservesAxisAlignedRectangles()) {
366 auto transformedTopLeft =
367 IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.TopLeft())));
368 auto transformedTopRight =
369 IntPoint::Round(matrix2D.TransformPoint(ToPoint(aSnapRect.TopRight())));
370 auto transformedBottomRight = IntPoint::Round(
371 matrix2D.TransformPoint(ToPoint(aSnapRect.BottomRight())));
372
373 Matrix snappedMatrix = gfxUtils::TransformRectToRect(
374 aSnapRect, transformedTopLeft, transformedTopRight,
375 transformedBottomRight);
376
377 result = Matrix4x4::From2D(snappedMatrix);
378 if (aResidualTransform && !snappedMatrix.IsSingular()) {
379 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
380 // (i.e., appying snappedMatrix after aResidualTransform gives the
381 // ideal transform.
382 Matrix snappedMatrixInverse = snappedMatrix;
383 snappedMatrixInverse.Invert();
384 *aResidualTransform = matrix2D * snappedMatrixInverse;
385 }
386 } else {
387 result = aTransform;
388 }
389 return result;
390 }
391
AncestorLayerMayChangeTransform(Layer * aLayer)392 static bool AncestorLayerMayChangeTransform(Layer* aLayer) {
393 for (Layer* l = aLayer; l; l = l->GetParent()) {
394 if (l->GetContentFlags() & Layer::CONTENT_MAY_CHANGE_TRANSFORM) {
395 return true;
396 }
397
398 if (l->GetParent() && l->GetParent()->AsRefLayer()) {
399 return false;
400 }
401 }
402 return false;
403 }
404
MayResample()405 bool Layer::MayResample() {
406 Matrix transform2d;
407 return !GetEffectiveTransform().Is2D(&transform2d) ||
408 ThebesMatrix(transform2d).HasNonIntegerTranslation() ||
409 AncestorLayerMayChangeTransform(this);
410 }
411
CalculateScissorRect(const RenderTargetIntRect & aCurrentScissorRect)412 RenderTargetIntRect Layer::CalculateScissorRect(
413 const RenderTargetIntRect& aCurrentScissorRect) {
414 ContainerLayer* container = GetParent();
415 ContainerLayer* containerChild = nullptr;
416 NS_ASSERTION(GetParent(), "This can't be called on the root!");
417
418 // Find the layer creating the 3D context.
419 while (container->Extend3DContext() && !container->UseIntermediateSurface()) {
420 containerChild = container;
421 container = container->GetParent();
422 MOZ_ASSERT(container);
423 }
424
425 // Find the nearest layer with a clip, or this layer.
426 // ContainerState::SetupScrollingMetadata() may install a clip on
427 // the layer.
428 Layer* clipLayer = containerChild && containerChild->GetLocalClipRect()
429 ? containerChild
430 : this;
431
432 // Establish initial clip rect: it's either the one passed in, or
433 // if the parent has an intermediate surface, it's the extents of that
434 // surface.
435 RenderTargetIntRect currentClip;
436 if (container->UseIntermediateSurface()) {
437 currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
438 } else {
439 currentClip = aCurrentScissorRect;
440 }
441
442 if (!clipLayer->GetLocalClipRect()) {
443 return currentClip;
444 }
445
446 if (GetLocalVisibleRegion().IsEmpty()) {
447 // When our visible region is empty, our parent may not have created the
448 // intermediate surface that we would require for correct clipping; however,
449 // this does not matter since we are invisible.
450 // Make sure we still compute a clip rect if we want to draw checkboarding
451 // for this layer, since we want to do this even if the layer is invisible.
452 return RenderTargetIntRect(currentClip.TopLeft(),
453 RenderTargetIntSize(0, 0));
454 }
455
456 const RenderTargetIntRect clipRect = ViewAs<RenderTargetPixel>(
457 *clipLayer->GetLocalClipRect(),
458 PixelCastJustification::RenderTargetIsParentLayerForRoot);
459 if (clipRect.IsEmpty()) {
460 // We might have a non-translation transform in the container so we can't
461 // use the code path below.
462 return RenderTargetIntRect(currentClip.TopLeft(),
463 RenderTargetIntSize(0, 0));
464 }
465
466 RenderTargetIntRect scissor = clipRect;
467 if (!container->UseIntermediateSurface()) {
468 gfx::Matrix matrix;
469 DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
470 // See DefaultComputeEffectiveTransforms below
471 NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
472 "Non preserves axis aligned transform with clipped child "
473 "should have forced intermediate surface");
474 gfx::Rect r(scissor.X(), scissor.Y(), scissor.Width(), scissor.Height());
475 gfxRect trScissor = gfx::ThebesRect(matrix.TransformBounds(r));
476 trScissor.Round();
477 IntRect tmp;
478 if (!gfxUtils::GfxRectToIntRect(trScissor, &tmp)) {
479 return RenderTargetIntRect(currentClip.TopLeft(),
480 RenderTargetIntSize(0, 0));
481 }
482 scissor = ViewAs<RenderTargetPixel>(tmp);
483
484 // Find the nearest ancestor with an intermediate surface
485 do {
486 container = container->GetParent();
487 } while (container && !container->UseIntermediateSurface());
488 }
489
490 if (container) {
491 scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
492 }
493 return currentClip.Intersect(scissor);
494 }
495
GetScrolledClipRect() const496 Maybe<ParentLayerIntRect> Layer::GetScrolledClipRect() const {
497 const Maybe<LayerClip> clip = mSimpleAttrs.ScrolledClip();
498 return clip ? Some(clip->GetClipRect()) : Nothing();
499 }
500
GetScrollMetadata(uint32_t aIndex) const501 const ScrollMetadata& Layer::GetScrollMetadata(uint32_t aIndex) const {
502 MOZ_ASSERT(aIndex < GetScrollMetadataCount());
503 return mScrollMetadata[aIndex];
504 }
505
GetFrameMetrics(uint32_t aIndex) const506 const FrameMetrics& Layer::GetFrameMetrics(uint32_t aIndex) const {
507 return GetScrollMetadata(aIndex).GetMetrics();
508 }
509
HasScrollableFrameMetrics() const510 bool Layer::HasScrollableFrameMetrics() const {
511 for (uint32_t i = 0; i < GetScrollMetadataCount(); i++) {
512 if (GetFrameMetrics(i).IsScrollable()) {
513 return true;
514 }
515 }
516 return false;
517 }
518
IsScrollableWithoutContent() const519 bool Layer::IsScrollableWithoutContent() const {
520 // A scrollable container layer with no children
521 return AsContainerLayer() && HasScrollableFrameMetrics() && !GetFirstChild();
522 }
523
GetTransform() const524 Matrix4x4 Layer::GetTransform() const {
525 Matrix4x4 transform = mSimpleAttrs.Transform();
526 transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f);
527 if (const ContainerLayer* c = AsContainerLayer()) {
528 transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
529 }
530 return transform;
531 }
532
GetTransformTyped() const533 const CSSTransformMatrix Layer::GetTransformTyped() const {
534 return ViewAs<CSSTransformMatrix>(GetTransform());
535 }
536
GetLocalTransform()537 Matrix4x4 Layer::GetLocalTransform() {
538 if (HostLayer* shadow = AsHostLayer()) {
539 return shadow->GetShadowTransform();
540 }
541 return GetTransform();
542 }
543
GetLocalTransformTyped()544 const LayerToParentLayerMatrix4x4 Layer::GetLocalTransformTyped() {
545 return ViewAs<LayerToParentLayerMatrix4x4>(GetLocalTransform());
546 }
547
HasOpacityAnimation() const548 bool Layer::HasOpacityAnimation() const {
549 return mAnimationInfo.HasOpacityAnimation();
550 }
551
HasTransformAnimation() const552 bool Layer::HasTransformAnimation() const {
553 return mAnimationInfo.HasTransformAnimation();
554 }
555
ApplyPendingUpdatesForThisTransaction()556 void Layer::ApplyPendingUpdatesForThisTransaction() {
557 if (mPendingTransform && *mPendingTransform != mSimpleAttrs.Transform()) {
558 MOZ_LAYERS_LOG_IF_SHADOWABLE(
559 this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
560 mSimpleAttrs.SetTransform(*mPendingTransform);
561 MutatedSimple();
562 }
563 mPendingTransform = nullptr;
564
565 if (mAnimationInfo.ApplyPendingUpdatesForThisTransaction()) {
566 MOZ_LAYERS_LOG_IF_SHADOWABLE(
567 this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
568 Mutated();
569 }
570
571 for (size_t i = 0; i < mScrollMetadata.Length(); i++) {
572 FrameMetrics& fm = mScrollMetadata[i].GetMetrics();
573 Maybe<ScrollUpdateInfo> update =
574 Manager()->GetPendingScrollInfoUpdate(fm.GetScrollId());
575 if (update) {
576 fm.UpdatePendingScrollInfo(update.value());
577 Mutated();
578 }
579 }
580 }
581
GetLocalOpacity()582 float Layer::GetLocalOpacity() {
583 float opacity = mSimpleAttrs.Opacity();
584 if (HostLayer* shadow = AsHostLayer()) opacity = shadow->GetShadowOpacity();
585 return std::min(std::max(opacity, 0.0f), 1.0f);
586 }
587
GetEffectiveOpacity()588 float Layer::GetEffectiveOpacity() {
589 float opacity = GetLocalOpacity();
590 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
591 c = c->GetParent()) {
592 opacity *= c->GetLocalOpacity();
593 }
594 return opacity;
595 }
596
GetEffectiveMixBlendMode()597 CompositionOp Layer::GetEffectiveMixBlendMode() {
598 if (mSimpleAttrs.MixBlendMode() != CompositionOp::OP_OVER)
599 return mSimpleAttrs.MixBlendMode();
600 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
601 c = c->GetParent()) {
602 if (c->mSimpleAttrs.MixBlendMode() != CompositionOp::OP_OVER)
603 return c->mSimpleAttrs.MixBlendMode();
604 }
605
606 return mSimpleAttrs.MixBlendMode();
607 }
608
ComputeTransformToPreserve3DRoot()609 Matrix4x4 Layer::ComputeTransformToPreserve3DRoot() {
610 Matrix4x4 transform = GetLocalTransform();
611 for (Layer* layer = GetParent(); layer && layer->Extend3DContext();
612 layer = layer->GetParent()) {
613 transform = transform * layer->GetLocalTransform();
614 }
615 return transform;
616 }
617
ComputeEffectiveTransformForMaskLayers(const gfx::Matrix4x4 & aTransformToSurface)618 void Layer::ComputeEffectiveTransformForMaskLayers(
619 const gfx::Matrix4x4& aTransformToSurface) {
620 if (GetMaskLayer()) {
621 ComputeEffectiveTransformForMaskLayer(GetMaskLayer(), aTransformToSurface);
622 }
623 for (size_t i = 0; i < GetAncestorMaskLayerCount(); i++) {
624 Layer* maskLayer = GetAncestorMaskLayerAt(i);
625 ComputeEffectiveTransformForMaskLayer(maskLayer, aTransformToSurface);
626 }
627 }
628
ComputeEffectiveTransformForMaskLayer(Layer * aMaskLayer,const gfx::Matrix4x4 & aTransformToSurface)629 /* static */ void Layer::ComputeEffectiveTransformForMaskLayer(
630 Layer* aMaskLayer, const gfx::Matrix4x4& aTransformToSurface) {
631 aMaskLayer->mEffectiveTransform = aTransformToSurface;
632
633 #ifdef DEBUG
634 bool maskIs2D = aMaskLayer->GetTransform().CanDraw2D();
635 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
636 #endif
637 // The mask layer can have an async transform applied to it in some
638 // situations, so be sure to use its GetLocalTransform() rather than
639 // its GetTransform().
640 aMaskLayer->mEffectiveTransform =
641 aMaskLayer->GetLocalTransform() * aMaskLayer->mEffectiveTransform;
642 }
643
TransformRectToRenderTarget(const LayerIntRect & aRect)644 RenderTargetRect Layer::TransformRectToRenderTarget(const LayerIntRect& aRect) {
645 LayerRect rect(aRect);
646 RenderTargetRect quad = RenderTargetRect::FromUnknownRect(
647 GetEffectiveTransform().TransformBounds(rect.ToUnknownRect()));
648 return quad;
649 }
650
GetVisibleRegionRelativeToRootLayer(nsIntRegion & aResult,IntPoint * aLayerOffset)651 bool Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
652 IntPoint* aLayerOffset) {
653 MOZ_ASSERT(aLayerOffset, "invalid offset pointer");
654
655 if (!GetParent()) {
656 return false;
657 }
658
659 IntPoint offset;
660 aResult = GetLocalVisibleRegion().ToUnknownRegion();
661 for (Layer* layer = this; layer; layer = layer->GetParent()) {
662 gfx::Matrix matrix;
663 if (!layer->GetLocalTransform().Is2D(&matrix) || !matrix.IsTranslation()) {
664 return false;
665 }
666
667 // The offset of |layer| to its parent.
668 auto currentLayerOffset = IntPoint::Round(matrix.GetTranslation());
669
670 // Translate the accumulated visible region of |this| by the offset of
671 // |layer|.
672 aResult.MoveBy(currentLayerOffset.x, currentLayerOffset.y);
673
674 // If the parent layer clips its lower layers, clip the visible region
675 // we're accumulating.
676 if (layer->GetLocalClipRect()) {
677 aResult.AndWith(layer->GetLocalClipRect()->ToUnknownRect());
678 }
679
680 // Now we need to walk across the list of siblings for this parent layer,
681 // checking to see if any of these layer trees obscure |this|. If so,
682 // remove these areas from the visible region as well. This will pick up
683 // chrome overlays like a tab modal prompt.
684 Layer* sibling;
685 for (sibling = layer->GetNextSibling(); sibling;
686 sibling = sibling->GetNextSibling()) {
687 gfx::Matrix siblingMatrix;
688 if (!sibling->GetLocalTransform().Is2D(&siblingMatrix) ||
689 !siblingMatrix.IsTranslation()) {
690 continue;
691 }
692
693 // Retreive the translation from sibling to |layer|. The accumulated
694 // visible region is currently oriented with |layer|.
695 auto siblingOffset = IntPoint::Round(siblingMatrix.GetTranslation());
696 nsIntRegion siblingVisibleRegion(
697 sibling->GetLocalVisibleRegion().ToUnknownRegion());
698 // Translate the siblings region to |layer|'s origin.
699 siblingVisibleRegion.MoveBy(-siblingOffset.x, -siblingOffset.y);
700 // Apply the sibling's clip.
701 // Layer clip rects are not affected by the layer's transform.
702 Maybe<ParentLayerIntRect> clipRect = sibling->GetLocalClipRect();
703 if (clipRect) {
704 siblingVisibleRegion.AndWith(clipRect->ToUnknownRect());
705 }
706 // Subtract the sibling visible region from the visible region of |this|.
707 aResult.SubOut(siblingVisibleRegion);
708 }
709
710 // Keep track of the total offset for aLayerOffset. We use this in plugin
711 // positioning code.
712 offset += currentLayerOffset;
713 }
714
715 *aLayerOffset = IntPoint(offset.x, offset.y);
716 return true;
717 }
718
GetAnimationData()719 InfallibleTArray<AnimData>& Layer::GetAnimationData() {
720 return mAnimationInfo.GetAnimationData();
721 }
722
GetCombinedClipRect() const723 Maybe<ParentLayerIntRect> Layer::GetCombinedClipRect() const {
724 Maybe<ParentLayerIntRect> clip = GetClipRect();
725
726 clip = IntersectMaybeRects(clip, GetScrolledClipRect());
727
728 for (size_t i = 0; i < mScrollMetadata.Length(); i++) {
729 clip = IntersectMaybeRects(clip, mScrollMetadata[i].GetClipRect());
730 }
731
732 return clip;
733 }
734
ContainerLayer(LayerManager * aManager,void * aImplData)735 ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
736 : Layer(aManager, aImplData),
737 mFirstChild(nullptr),
738 mLastChild(nullptr),
739 mPreXScale(1.0f),
740 mPreYScale(1.0f),
741 mInheritedXScale(1.0f),
742 mInheritedYScale(1.0f),
743 mPresShellResolution(1.0f),
744 mScaleToResolution(false),
745 mUseIntermediateSurface(false),
746 mSupportsComponentAlphaChildren(false),
747 mMayHaveReadbackChild(false),
748 mChildrenChanged(false) {}
749
~ContainerLayer()750 ContainerLayer::~ContainerLayer() {}
751
InsertAfter(Layer * aChild,Layer * aAfter)752 bool ContainerLayer::InsertAfter(Layer* aChild, Layer* aAfter) {
753 if (aChild->Manager() != Manager()) {
754 NS_ERROR("Child has wrong manager");
755 return false;
756 }
757 if (aChild->GetParent()) {
758 NS_ERROR("aChild already in the tree");
759 return false;
760 }
761 if (aChild->GetNextSibling() || aChild->GetPrevSibling()) {
762 NS_ERROR("aChild already has siblings?");
763 return false;
764 }
765 if (aAfter &&
766 (aAfter->Manager() != Manager() || aAfter->GetParent() != this)) {
767 NS_ERROR("aAfter is not our child");
768 return false;
769 }
770
771 aChild->SetParent(this);
772 if (aAfter == mLastChild) {
773 mLastChild = aChild;
774 }
775 if (!aAfter) {
776 aChild->SetNextSibling(mFirstChild);
777 if (mFirstChild) {
778 mFirstChild->SetPrevSibling(aChild);
779 }
780 mFirstChild = aChild;
781 NS_ADDREF(aChild);
782 DidInsertChild(aChild);
783 return true;
784 }
785
786 Layer* next = aAfter->GetNextSibling();
787 aChild->SetNextSibling(next);
788 aChild->SetPrevSibling(aAfter);
789 if (next) {
790 next->SetPrevSibling(aChild);
791 }
792 aAfter->SetNextSibling(aChild);
793 NS_ADDREF(aChild);
794 DidInsertChild(aChild);
795 return true;
796 }
797
RemoveAllChildren()798 void ContainerLayer::RemoveAllChildren() {
799 // Optimizes "while (mFirstChild) ContainerLayer::RemoveChild(mFirstChild);"
800 Layer* current = mFirstChild;
801
802 // This is inlining DidRemoveChild() on each layer; we can skip the calls
803 // to NotifyPaintedLayerRemoved as it gets taken care of when as we call
804 // NotifyRemoved prior to removing any layers.
805 while (current) {
806 Layer* next = current->GetNextSibling();
807 if (current->GetType() == TYPE_READBACK) {
808 static_cast<ReadbackLayer*>(current)->NotifyRemoved();
809 }
810 current = next;
811 }
812
813 current = mFirstChild;
814 mFirstChild = nullptr;
815 while (current) {
816 MOZ_ASSERT(!current->GetPrevSibling());
817
818 Layer* next = current->GetNextSibling();
819 current->SetParent(nullptr);
820 current->SetNextSibling(nullptr);
821 if (next) {
822 next->SetPrevSibling(nullptr);
823 }
824 NS_RELEASE(current);
825 current = next;
826 }
827 }
828
829 // Note that ContainerLayer::RemoveAllChildren is an optimized
830 // version of this code; if you make changes to ContainerLayer::RemoveChild
831 // consider whether the matching changes need to be made to
832 // ContainerLayer::RemoveAllChildren
RemoveChild(Layer * aChild)833 bool ContainerLayer::RemoveChild(Layer* aChild) {
834 if (aChild->Manager() != Manager()) {
835 NS_ERROR("Child has wrong manager");
836 return false;
837 }
838 if (aChild->GetParent() != this) {
839 NS_ERROR("aChild not our child");
840 return false;
841 }
842
843 Layer* prev = aChild->GetPrevSibling();
844 Layer* next = aChild->GetNextSibling();
845 if (prev) {
846 prev->SetNextSibling(next);
847 } else {
848 this->mFirstChild = next;
849 }
850 if (next) {
851 next->SetPrevSibling(prev);
852 } else {
853 this->mLastChild = prev;
854 }
855
856 aChild->SetNextSibling(nullptr);
857 aChild->SetPrevSibling(nullptr);
858 aChild->SetParent(nullptr);
859
860 this->DidRemoveChild(aChild);
861 NS_RELEASE(aChild);
862 return true;
863 }
864
RepositionChild(Layer * aChild,Layer * aAfter)865 bool ContainerLayer::RepositionChild(Layer* aChild, Layer* aAfter) {
866 if (aChild->Manager() != Manager()) {
867 NS_ERROR("Child has wrong manager");
868 return false;
869 }
870 if (aChild->GetParent() != this) {
871 NS_ERROR("aChild not our child");
872 return false;
873 }
874 if (aAfter &&
875 (aAfter->Manager() != Manager() || aAfter->GetParent() != this)) {
876 NS_ERROR("aAfter is not our child");
877 return false;
878 }
879 if (aChild == aAfter) {
880 NS_ERROR("aChild cannot be the same as aAfter");
881 return false;
882 }
883
884 Layer* prev = aChild->GetPrevSibling();
885 Layer* next = aChild->GetNextSibling();
886 if (prev == aAfter) {
887 // aChild is already in the correct position, nothing to do.
888 return true;
889 }
890 if (prev) {
891 prev->SetNextSibling(next);
892 } else {
893 mFirstChild = next;
894 }
895 if (next) {
896 next->SetPrevSibling(prev);
897 } else {
898 mLastChild = prev;
899 }
900 if (!aAfter) {
901 aChild->SetPrevSibling(nullptr);
902 aChild->SetNextSibling(mFirstChild);
903 if (mFirstChild) {
904 mFirstChild->SetPrevSibling(aChild);
905 }
906 mFirstChild = aChild;
907 return true;
908 }
909
910 Layer* afterNext = aAfter->GetNextSibling();
911 if (afterNext) {
912 afterNext->SetPrevSibling(aChild);
913 } else {
914 mLastChild = aChild;
915 }
916 aAfter->SetNextSibling(aChild);
917 aChild->SetPrevSibling(aAfter);
918 aChild->SetNextSibling(afterNext);
919 return true;
920 }
921
FillSpecificAttributes(SpecificLayerAttributes & aAttrs)922 void ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) {
923 aAttrs = ContainerLayerAttributes(mPreXScale, mPreYScale, mInheritedXScale,
924 mInheritedYScale, mPresShellResolution,
925 mScaleToResolution);
926 }
927
Creates3DContextWithExtendingChildren()928 bool ContainerLayer::Creates3DContextWithExtendingChildren() {
929 if (Extend3DContext()) {
930 return false;
931 }
932 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
933 if (child->Extend3DContext()) {
934 return true;
935 }
936 }
937 return false;
938 }
939
HasMultipleChildren()940 bool ContainerLayer::HasMultipleChildren() {
941 uint32_t count = 0;
942 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
943 const Maybe<ParentLayerIntRect>& clipRect = child->GetLocalClipRect();
944 if (clipRect && clipRect->IsEmpty()) continue;
945 if (child->GetLocalVisibleRegion().IsEmpty()) continue;
946 ++count;
947 if (count > 1) return true;
948 }
949
950 return false;
951 }
952
953 /**
954 * Collect all leaf descendants of the current 3D context.
955 */
Collect3DContextLeaves(nsTArray<Layer * > & aToSort)956 void ContainerLayer::Collect3DContextLeaves(nsTArray<Layer*>& aToSort) {
957 ForEachNode<ForwardIterator>((Layer*)this, [this, &aToSort](Layer* layer) {
958 ContainerLayer* container = layer->AsContainerLayer();
959 if (layer == this || (container && container->Extend3DContext() &&
960 !container->UseIntermediateSurface())) {
961 return TraversalFlag::Continue;
962 }
963 aToSort.AppendElement(layer);
964 return TraversalFlag::Skip;
965 });
966 }
967
SortLayersWithBSPTree(nsTArray<Layer * > & aArray)968 static nsTArray<LayerPolygon> SortLayersWithBSPTree(nsTArray<Layer*>& aArray) {
969 std::list<LayerPolygon> inputLayers;
970
971 // Build a list of polygons to be sorted.
972 for (Layer* layer : aArray) {
973 // Ignore invisible layers.
974 if (!layer->IsVisible()) {
975 continue;
976 }
977
978 const gfx::IntRect& bounds =
979 layer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
980
981 const gfx::Matrix4x4& transform = layer->GetEffectiveTransform();
982
983 if (transform.IsSingular()) {
984 // Transform cannot be inverted.
985 continue;
986 }
987
988 gfx::Polygon polygon = gfx::Polygon::FromRect(gfx::Rect(bounds));
989
990 // Transform the polygon to screen space.
991 polygon.TransformToScreenSpace(transform);
992
993 if (polygon.GetPoints().Length() >= 3) {
994 inputLayers.push_back(LayerPolygon(layer, Move(polygon)));
995 }
996 }
997
998 if (inputLayers.empty()) {
999 return nsTArray<LayerPolygon>();
1000 }
1001
1002 // Build a BSP tree from the list of polygons.
1003 BSPTree tree(inputLayers);
1004
1005 nsTArray<LayerPolygon> orderedLayers(tree.GetDrawOrder());
1006
1007 // Transform the polygons back to layer space.
1008 for (LayerPolygon& layerPolygon : orderedLayers) {
1009 gfx::Matrix4x4 inverse =
1010 layerPolygon.layer->GetEffectiveTransform().Inverse();
1011
1012 MOZ_ASSERT(layerPolygon.geometry);
1013 layerPolygon.geometry->TransformToLayerSpace(inverse);
1014 }
1015
1016 return orderedLayers;
1017 }
1018
StripLayerGeometry(const nsTArray<LayerPolygon> & aLayers)1019 static nsTArray<LayerPolygon> StripLayerGeometry(
1020 const nsTArray<LayerPolygon>& aLayers) {
1021 nsTArray<LayerPolygon> layers;
1022 std::set<Layer*> uniqueLayers;
1023
1024 for (const LayerPolygon& layerPolygon : aLayers) {
1025 auto result = uniqueLayers.insert(layerPolygon.layer);
1026
1027 if (result.second) {
1028 // Layer was added to the set.
1029 layers.AppendElement(LayerPolygon(layerPolygon.layer));
1030 }
1031 }
1032
1033 return layers;
1034 }
1035
SortChildrenBy3DZOrder(SortMode aSortMode)1036 nsTArray<LayerPolygon> ContainerLayer::SortChildrenBy3DZOrder(
1037 SortMode aSortMode) {
1038 AutoTArray<Layer*, 10> toSort;
1039 nsTArray<LayerPolygon> drawOrder;
1040
1041 for (Layer* layer = GetFirstChild(); layer; layer = layer->GetNextSibling()) {
1042 ContainerLayer* container = layer->AsContainerLayer();
1043
1044 if (container && container->Extend3DContext() &&
1045 !container->UseIntermediateSurface()) {
1046 // Collect 3D layers in toSort array.
1047 container->Collect3DContextLeaves(toSort);
1048
1049 // Sort the 3D layers.
1050 if (toSort.Length() > 0) {
1051 nsTArray<LayerPolygon> sorted = SortLayersWithBSPTree(toSort);
1052 drawOrder.AppendElements(Move(sorted));
1053
1054 toSort.ClearAndRetainStorage();
1055 }
1056
1057 continue;
1058 }
1059
1060 drawOrder.AppendElement(LayerPolygon(layer));
1061 }
1062
1063 if (aSortMode == SortMode::WITHOUT_GEOMETRY) {
1064 // Compositor does not support arbitrary layers, strip the layer geometry
1065 // and duplicate layers.
1066 return StripLayerGeometry(drawOrder);
1067 }
1068
1069 return drawOrder;
1070 }
1071
AnyAncestorOrThisIs3DContextLeaf()1072 bool ContainerLayer::AnyAncestorOrThisIs3DContextLeaf() {
1073 Layer* parent = this;
1074 while (parent != nullptr) {
1075 if (parent->Is3DContextLeaf()) {
1076 return true;
1077 }
1078
1079 parent = parent->GetParent();
1080 }
1081
1082 return false;
1083 }
1084
DefaultComputeEffectiveTransforms(const Matrix4x4 & aTransformToSurface)1085 void ContainerLayer::DefaultComputeEffectiveTransforms(
1086 const Matrix4x4& aTransformToSurface) {
1087 Matrix residual;
1088 Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
1089
1090 // Keep 3D transforms for leaves to keep z-order sorting correct.
1091 if (!Extend3DContext() && !Is3DContextLeaf()) {
1092 idealTransform.ProjectTo2D();
1093 }
1094
1095 bool useIntermediateSurface;
1096 if (HasMaskLayers() || GetForceIsolatedGroup()) {
1097 useIntermediateSurface = true;
1098 #ifdef MOZ_DUMP_PAINTING
1099 } else if (gfxEnv::DumpPaintIntermediate() && !Extend3DContext()) {
1100 useIntermediateSurface = true;
1101 #endif
1102 } else {
1103 /* Don't use an intermediate surface for opacity when it's within a 3d
1104 * context, since we'd rather keep the 3d effects. This matches the
1105 * WebKit/blink behaviour, but is changing in the latest spec.
1106 */
1107 float opacity = GetEffectiveOpacity();
1108 CompositionOp blendMode = GetEffectiveMixBlendMode();
1109 if ((HasMultipleChildren() || Creates3DContextWithExtendingChildren()) &&
1110 ((opacity != 1.0f && !Extend3DContext()) ||
1111 (blendMode != CompositionOp::OP_OVER))) {
1112 useIntermediateSurface = true;
1113 } else if ((!idealTransform.Is2D() || AnyAncestorOrThisIs3DContextLeaf()) &&
1114 Creates3DContextWithExtendingChildren()) {
1115 useIntermediateSurface = true;
1116 } else if (blendMode != CompositionOp::OP_OVER &&
1117 Manager()->BlendingRequiresIntermediateSurface()) {
1118 useIntermediateSurface = true;
1119 } else {
1120 useIntermediateSurface = false;
1121 gfx::Matrix contTransform;
1122 bool checkClipRect = false;
1123 bool checkMaskLayers = false;
1124
1125 if (!idealTransform.Is2D(&contTransform)) {
1126 // In 3D case, always check if we should use IntermediateSurface.
1127 checkClipRect = true;
1128 checkMaskLayers = true;
1129 } else {
1130 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
1131 if (!contTransform.PreservesAxisAlignedRectangles()) {
1132 #else
1133 if (gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) {
1134 #endif
1135 checkClipRect = true;
1136 }
1137 /* In 2D case, only translation and/or positive scaling can be done w/o
1138 * using IntermediateSurface. Otherwise, when rotation or flip happen,
1139 * we should check whether to use IntermediateSurface.
1140 */
1141 if (contTransform.HasNonAxisAlignedTransform() ||
1142 contTransform.HasNegativeScaling()) {
1143 checkMaskLayers = true;
1144 }
1145 }
1146
1147 if (checkClipRect || checkMaskLayers) {
1148 for (Layer* child = GetFirstChild(); child;
1149 child = child->GetNextSibling()) {
1150 const Maybe<ParentLayerIntRect>& clipRect = child->GetLocalClipRect();
1151 /* We can't (easily) forward our transform to children with a
1152 * non-empty clip rect since it would need to be adjusted for the
1153 * transform. See the calculations performed by CalculateScissorRect
1154 * above. Nor for a child with a mask layer.
1155 */
1156 if (checkClipRect && (clipRect && !clipRect->IsEmpty() &&
1157 !child->GetLocalVisibleRegion().IsEmpty())) {
1158 useIntermediateSurface = true;
1159 break;
1160 }
1161 if (checkMaskLayers && child->HasMaskLayers()) {
1162 useIntermediateSurface = true;
1163 break;
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170 NS_ASSERTION(!Extend3DContext() || !useIntermediateSurface,
1171 "Can't have an intermediate surface with preserve-3d!");
1172
1173 if (useIntermediateSurface) {
1174 mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
1175 } else {
1176 mEffectiveTransform = idealTransform;
1177 }
1178
1179 // For layers extending 3d context, its ideal transform should be
1180 // applied on children.
1181 if (!Extend3DContext()) {
1182 // Without this projection, non-container children would get a 3D
1183 // transform while 2D is expected.
1184 idealTransform.ProjectTo2D();
1185 }
1186 mUseIntermediateSurface = useIntermediateSurface;
1187 if (useIntermediateSurface) {
1188 ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual));
1189 } else {
1190 ComputeEffectiveTransformsForChildren(idealTransform);
1191 }
1192
1193 ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
1194 }
1195
1196 void ContainerLayer::DefaultComputeSupportsComponentAlphaChildren(
1197 bool* aNeedsSurfaceCopy) {
1198 if (!(GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT) ||
1199 !Manager()->AreComponentAlphaLayersEnabled()) {
1200 mSupportsComponentAlphaChildren = false;
1201 if (aNeedsSurfaceCopy) {
1202 *aNeedsSurfaceCopy = false;
1203 }
1204 return;
1205 }
1206
1207 mSupportsComponentAlphaChildren = false;
1208 bool needsSurfaceCopy = false;
1209 CompositionOp blendMode = GetEffectiveMixBlendMode();
1210 if (UseIntermediateSurface()) {
1211 if (GetLocalVisibleRegion().GetNumRects() == 1 &&
1212 (GetContentFlags() & Layer::CONTENT_OPAQUE)) {
1213 mSupportsComponentAlphaChildren = true;
1214 } else {
1215 gfx::Matrix transform;
1216 if (HasOpaqueAncestorLayer(this) &&
1217 GetEffectiveTransform().Is2D(&transform) &&
1218 !gfx::ThebesMatrix(transform).HasNonIntegerTranslation() &&
1219 blendMode == gfx::CompositionOp::OP_OVER) {
1220 mSupportsComponentAlphaChildren = true;
1221 needsSurfaceCopy = true;
1222 }
1223 }
1224 } else if (blendMode == gfx::CompositionOp::OP_OVER) {
1225 mSupportsComponentAlphaChildren =
1226 (GetContentFlags() & Layer::CONTENT_OPAQUE) ||
1227 (GetParent() && GetParent()->SupportsComponentAlphaChildren());
1228 }
1229
1230 if (aNeedsSurfaceCopy) {
1231 *aNeedsSurfaceCopy = mSupportsComponentAlphaChildren && needsSurfaceCopy;
1232 }
1233 }
1234
1235 void ContainerLayer::ComputeEffectiveTransformsForChildren(
1236 const Matrix4x4& aTransformToSurface) {
1237 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
1238 l->ComputeEffectiveTransforms(aTransformToSurface);
1239 }
1240 }
1241
1242 /* static */ bool ContainerLayer::HasOpaqueAncestorLayer(Layer* aLayer) {
1243 for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
1244 if (l->GetContentFlags() & Layer::CONTENT_OPAQUE) return true;
1245 }
1246 return false;
1247 }
1248
1249 // Note that ContainerLayer::RemoveAllChildren contains an optimized
1250 // version of this code; if you make changes to ContainerLayer::DidRemoveChild
1251 // consider whether the matching changes need to be made to
1252 // ContainerLayer::RemoveAllChildren
1253 void ContainerLayer::DidRemoveChild(Layer* aLayer) {
1254 PaintedLayer* tl = aLayer->AsPaintedLayer();
1255 if (tl && tl->UsedForReadback()) {
1256 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
1257 if (l->GetType() == TYPE_READBACK) {
1258 static_cast<ReadbackLayer*>(l)->NotifyPaintedLayerRemoved(tl);
1259 }
1260 }
1261 }
1262 if (aLayer->GetType() == TYPE_READBACK) {
1263 static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
1264 }
1265 }
1266
1267 void ContainerLayer::DidInsertChild(Layer* aLayer) {
1268 if (aLayer->GetType() == TYPE_READBACK) {
1269 mMayHaveReadbackChild = true;
1270 }
1271 }
1272
1273 void RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) {
1274 aAttrs = RefLayerAttributes(GetReferentId(), mEventRegionsOverride);
1275 }
1276
1277 /**
1278 * StartFrameTimeRecording, together with StopFrameTimeRecording
1279 * enable recording of frame intervals.
1280 *
1281 * To allow concurrent consumers, a cyclic array is used which serves all
1282 * consumers, practically stateless with regard to consumers.
1283 *
1284 * To save resources, the buffer is allocated on first call to
1285 * StartFrameTimeRecording and recording is paused if no consumer which called
1286 * StartFrameTimeRecording is able to get valid results (because the cyclic
1287 * buffer was overwritten since that call).
1288 *
1289 * To determine availability of the data upon StopFrameTimeRecording:
1290 * - mRecording.mNextIndex increases on each RecordFrame, and never resets.
1291 * - Cyclic buffer position is realized as mNextIndex % bufferSize.
1292 * - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is
1293 * called, the required start index is passed as an arg, and we're able to
1294 * calculate the required length. If this length is bigger than bufferSize, it
1295 * means data was overwritten. otherwise, we can return the entire sequence.
1296 * - To determine if we need to pause, mLatestStartIndex is updated to
1297 * mNextIndex on each call to StartFrameTimeRecording. If this index gets
1298 * overwritten, it means that all earlier start indices obtained via
1299 * StartFrameTimeRecording were also overwritten, hence, no point in
1300 * recording, so pause.
1301 * - mCurrentRunStartIndex indicates the oldest index of the recording after
1302 * which the recording was not paused. If StopFrameTimeRecording is invoked
1303 * with a start index older than this, it means that some frames were not
1304 * recorded, so data is invalid.
1305 */
1306 uint32_t LayerManager::StartFrameTimeRecording(int32_t aBufferSize) {
1307 if (mRecording.mIsPaused) {
1308 mRecording.mIsPaused = false;
1309
1310 if (!mRecording.mIntervals.Length()) { // Initialize recording buffers
1311 mRecording.mIntervals.SetLength(aBufferSize);
1312 }
1313
1314 // After being paused, recent values got invalid. Update them to now.
1315 mRecording.mLastFrameTime = TimeStamp::Now();
1316
1317 // Any recording which started before this is invalid, since we were paused.
1318 mRecording.mCurrentRunStartIndex = mRecording.mNextIndex;
1319 }
1320
1321 // If we'll overwrite this index, there are no more consumers with aStartIndex
1322 // for which we're able to provide the full recording, so no point in keep
1323 // recording.
1324 mRecording.mLatestStartIndex = mRecording.mNextIndex;
1325 return mRecording.mNextIndex;
1326 }
1327
1328 void LayerManager::RecordFrame() {
1329 if (!mRecording.mIsPaused) {
1330 TimeStamp now = TimeStamp::Now();
1331 uint32_t i = mRecording.mNextIndex % mRecording.mIntervals.Length();
1332 mRecording.mIntervals[i] =
1333 static_cast<float>((now - mRecording.mLastFrameTime).ToMilliseconds());
1334 mRecording.mNextIndex++;
1335 mRecording.mLastFrameTime = now;
1336
1337 if (mRecording.mNextIndex >
1338 (mRecording.mLatestStartIndex + mRecording.mIntervals.Length())) {
1339 // We've just overwritten the most recent recording start -> pause.
1340 mRecording.mIsPaused = true;
1341 }
1342 }
1343 }
1344
1345 void LayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
1346 nsTArray<float>& aFrameIntervals) {
1347 uint32_t bufferSize = mRecording.mIntervals.Length();
1348 uint32_t length = mRecording.mNextIndex - aStartIndex;
1349 if (mRecording.mIsPaused || length > bufferSize ||
1350 aStartIndex < mRecording.mCurrentRunStartIndex) {
1351 // aStartIndex is too old. Also if aStartIndex was issued before
1352 // mRecordingNextIndex overflowed (uint32_t)
1353 // and stopped after the overflow (would happen once every 828 days of
1354 // constant 60fps).
1355 length = 0;
1356 }
1357
1358 if (!length) {
1359 aFrameIntervals.Clear();
1360 return; // empty recording, return empty arrays.
1361 }
1362 // Set length in advance to avoid possibly repeated reallocations
1363 aFrameIntervals.SetLength(length);
1364
1365 uint32_t cyclicPos = aStartIndex % bufferSize;
1366 for (uint32_t i = 0; i < length; i++, cyclicPos++) {
1367 if (cyclicPos == bufferSize) {
1368 cyclicPos = 0;
1369 }
1370 aFrameIntervals[i] = mRecording.mIntervals[cyclicPos];
1371 }
1372 }
1373
1374 static void PrintInfo(std::stringstream& aStream, HostLayer* aLayerComposite);
1375
1376 #ifdef MOZ_DUMP_PAINTING
1377 template <typename T>
1378 void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf) {
1379 nsCString string(aObj->Name());
1380 string.Append('-');
1381 string.AppendInt((uint64_t)aObj);
1382 if (gfxUtils::sDumpPaintFile != stderr) {
1383 fprintf_stderr(gfxUtils::sDumpPaintFile, R"(array["%s"]=")",
1384 string.BeginReading());
1385 }
1386 gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile);
1387 if (gfxUtils::sDumpPaintFile != stderr) {
1388 fprintf_stderr(gfxUtils::sDumpPaintFile, R"(";)");
1389 }
1390 }
1391
1392 void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf) {
1393 WriteSnapshotToDumpFile_internal(aLayer, aSurf);
1394 }
1395
1396 void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf) {
1397 WriteSnapshotToDumpFile_internal(aManager, aSurf);
1398 }
1399
1400 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget) {
1401 RefPtr<SourceSurface> surf = aTarget->Snapshot();
1402 RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
1403 WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
1404 }
1405 #endif
1406
1407 void Layer::Dump(std::stringstream& aStream, const char* aPrefix,
1408 bool aDumpHtml, bool aSorted,
1409 const Maybe<gfx::Polygon>& aGeometry) {
1410 #ifdef MOZ_DUMP_PAINTING
1411 bool dumpCompositorTexture = gfxEnv::DumpCompositorTextures() &&
1412 AsHostLayer() &&
1413 AsHostLayer()->GetCompositableHost();
1414 bool dumpClientTexture = gfxEnv::DumpPaint() && AsShadowableLayer() &&
1415 AsShadowableLayer()->GetCompositableClient();
1416 nsCString layerId(Name());
1417 layerId.Append('-');
1418 layerId.AppendInt((uint64_t)this);
1419 #endif
1420 if (aDumpHtml) {
1421 aStream << nsPrintfCString(R"(<li><a id="%p" )", this).get();
1422 #ifdef MOZ_DUMP_PAINTING
1423 if (dumpCompositorTexture || dumpClientTexture) {
1424 aStream << nsPrintfCString(R"lit(href="javascript:ViewImage('%s')")lit",
1425 layerId.BeginReading())
1426 .get();
1427 }
1428 #endif
1429 aStream << ">";
1430 }
1431 DumpSelf(aStream, aPrefix, aGeometry);
1432
1433 #ifdef MOZ_DUMP_PAINTING
1434 if (dumpCompositorTexture) {
1435 AsHostLayer()->GetCompositableHost()->Dump(aStream, aPrefix, aDumpHtml);
1436 } else if (dumpClientTexture) {
1437 if (aDumpHtml) {
1438 aStream << nsPrintfCString(R"(<script>array["%s"]=")",
1439 layerId.BeginReading())
1440 .get();
1441 }
1442 AsShadowableLayer()->GetCompositableClient()->Dump(
1443 aStream, aPrefix, aDumpHtml, TextureDumpMode::DoNotCompress);
1444 if (aDumpHtml) {
1445 aStream << R"(";</script>)";
1446 }
1447 }
1448 #endif
1449
1450 if (aDumpHtml) {
1451 aStream << "</a>";
1452 #ifdef MOZ_DUMP_PAINTING
1453 if (dumpClientTexture) {
1454 aStream << nsPrintfCString("<br><img id=\"%s\">\n",
1455 layerId.BeginReading())
1456 .get();
1457 }
1458 #endif
1459 }
1460
1461 if (Layer* mask = GetMaskLayer()) {
1462 aStream << nsPrintfCString("%s Mask layer:\n", aPrefix).get();
1463 nsAutoCString pfx(aPrefix);
1464 pfx += " ";
1465 mask->Dump(aStream, pfx.get(), aDumpHtml);
1466 }
1467
1468 for (size_t i = 0; i < GetAncestorMaskLayerCount(); i++) {
1469 aStream << nsPrintfCString("%s Ancestor mask layer %d:\n", aPrefix,
1470 uint32_t(i))
1471 .get();
1472 nsAutoCString pfx(aPrefix);
1473 pfx += " ";
1474 GetAncestorMaskLayerAt(i)->Dump(aStream, pfx.get(), aDumpHtml);
1475 }
1476
1477 #ifdef MOZ_DUMP_PAINTING
1478 for (size_t i = 0; i < mExtraDumpInfo.Length(); i++) {
1479 const nsCString& str = mExtraDumpInfo[i];
1480 aStream << aPrefix << " Info:\n" << str.get();
1481 }
1482 #endif
1483
1484 if (ContainerLayer* container = AsContainerLayer()) {
1485 nsTArray<LayerPolygon> children;
1486 if (aSorted) {
1487 children = container->SortChildrenBy3DZOrder(
1488 ContainerLayer::SortMode::WITH_GEOMETRY);
1489 } else {
1490 for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
1491 children.AppendElement(LayerPolygon(l));
1492 }
1493 }
1494 nsAutoCString pfx(aPrefix);
1495 pfx += " ";
1496 if (aDumpHtml) {
1497 aStream << "<ul>";
1498 }
1499
1500 for (LayerPolygon& child : children) {
1501 child.layer->Dump(aStream, pfx.get(), aDumpHtml, aSorted, child.geometry);
1502 }
1503
1504 if (aDumpHtml) {
1505 aStream << "</ul>";
1506 }
1507 }
1508
1509 if (aDumpHtml) {
1510 aStream << "</li>";
1511 }
1512 }
1513
1514 static void DumpGeometry(std::stringstream& aStream,
1515 const Maybe<gfx::Polygon>& aGeometry) {
1516 aStream << " [geometry=[";
1517
1518 const nsTArray<gfx::Point4D>& points = aGeometry->GetPoints();
1519 for (size_t i = 0; i < points.Length(); ++i) {
1520 const gfx::IntPoint point = TruncatedToInt(points[i].As2DPoint());
1521 const char* sfx = (i != points.Length() - 1) ? "," : "";
1522 AppendToString(aStream, point, "", sfx);
1523 }
1524
1525 aStream << "]]";
1526 }
1527
1528 void Layer::DumpSelf(std::stringstream& aStream, const char* aPrefix,
1529 const Maybe<gfx::Polygon>& aGeometry) {
1530 PrintInfo(aStream, aPrefix);
1531
1532 if (aGeometry) {
1533 DumpGeometry(aStream, aGeometry);
1534 }
1535
1536 aStream << "\n";
1537 }
1538
1539 void Layer::Dump(layerscope::LayersPacket* aPacket, const void* aParent) {
1540 DumpPacket(aPacket, aParent);
1541
1542 if (Layer* kid = GetFirstChild()) {
1543 kid->Dump(aPacket, this);
1544 }
1545
1546 if (Layer* next = GetNextSibling()) {
1547 next->Dump(aPacket, aParent);
1548 }
1549 }
1550
1551 void Layer::SetDisplayListLog(const char* log) {
1552 if (gfxUtils::DumpDisplayList()) {
1553 mDisplayListLog = log;
1554 }
1555 }
1556
1557 void Layer::GetDisplayListLog(nsCString& log) {
1558 log.SetLength(0);
1559
1560 if (gfxUtils::DumpDisplayList()) {
1561 // This function returns a plain text string which consists of two things
1562 // 1. DisplayList log.
1563 // 2. Memory address of this layer.
1564 // We know the target layer of each display item by information in #1.
1565 // Here is an example of a Text display item line log in #1
1566 // Text p=0xa9850c00 f=0x0xaa405b00(.....
1567 // f keeps the address of the target client layer of a display item.
1568 // For LayerScope, display-item-to-client-layer mapping is not enough since
1569 // LayerScope, which lives in the chrome process, knows only composite
1570 // layers. As so, we need display-item-to-client-layer-to-layer-composite
1571 // mapping. That's the reason we insert #2 into the log
1572 log.AppendPrintf("0x%p\n%s", (void*)this, mDisplayListLog.get());
1573 }
1574 }
1575
1576 void Layer::Log(const char* aPrefix) {
1577 if (!IsLogEnabled()) return;
1578
1579 LogSelf(aPrefix);
1580
1581 if (Layer* kid = GetFirstChild()) {
1582 nsAutoCString pfx(aPrefix);
1583 pfx += " ";
1584 kid->Log(pfx.get());
1585 }
1586
1587 if (Layer* next = GetNextSibling()) next->Log(aPrefix);
1588 }
1589
1590 void Layer::LogSelf(const char* aPrefix) {
1591 if (!IsLogEnabled()) return;
1592
1593 std::stringstream ss;
1594 PrintInfo(ss, aPrefix);
1595 MOZ_LAYERS_LOG(("%s", ss.str().c_str()));
1596
1597 if (mMaskLayer) {
1598 nsAutoCString pfx(aPrefix);
1599 pfx += R"( \ MaskLayer )";
1600 mMaskLayer->LogSelf(pfx.get());
1601 }
1602 }
1603
1604 void Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
1605 aStream << aPrefix;
1606 aStream
1607 << nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this).get();
1608
1609 layers::PrintInfo(aStream, AsHostLayer());
1610
1611 if (mClipRect) {
1612 AppendToString(aStream, *mClipRect, " [clip=", "]");
1613 }
1614 if (mSimpleAttrs.ScrolledClip()) {
1615 AppendToString(aStream, mSimpleAttrs.ScrolledClip()->GetClipRect(),
1616 " [scrolled-clip=", "]");
1617 if (const Maybe<size_t>& ix =
1618 mSimpleAttrs.ScrolledClip()->GetMaskLayerIndex()) {
1619 AppendToString(aStream, ix.value(), " [scrolled-mask=", "]");
1620 }
1621 }
1622 if (1.0 != mSimpleAttrs.PostXScale() || 1.0 != mSimpleAttrs.PostYScale()) {
1623 aStream << nsPrintfCString(" [postScale=%g, %g]", mSimpleAttrs.PostXScale(),
1624 mSimpleAttrs.PostYScale())
1625 .get();
1626 }
1627 if (!GetBaseTransform().IsIdentity()) {
1628 AppendToString(aStream, GetBaseTransform(), " [transform=", "]");
1629 }
1630 if (!GetEffectiveTransform().IsIdentity()) {
1631 AppendToString(aStream, GetEffectiveTransform(),
1632 " [effective-transform=", "]");
1633 }
1634 if (GetTransformIsPerspective()) {
1635 aStream << " [perspective]";
1636 }
1637 if (!mVisibleRegion.IsEmpty()) {
1638 AppendToString(aStream, mVisibleRegion.ToUnknownRegion(),
1639 " [visible=", "]");
1640 } else {
1641 aStream << " [not visible]";
1642 }
1643 if (!mEventRegions.IsEmpty()) {
1644 AppendToString(aStream, mEventRegions, " ", "");
1645 }
1646 if (1.0 != GetOpacity()) {
1647 aStream << nsPrintfCString(" [opacity=%g]", GetOpacity()).get();
1648 }
1649 if (IsOpaque()) {
1650 aStream << " [opaqueContent]";
1651 }
1652 if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
1653 aStream << " [componentAlpha]";
1654 }
1655 if (GetContentFlags() & CONTENT_BACKFACE_HIDDEN) {
1656 aStream << " [backfaceHidden]";
1657 }
1658 if (Extend3DContext()) {
1659 aStream << " [extend3DContext]";
1660 }
1661 if (Combines3DTransformWithAncestors()) {
1662 aStream << " [combines3DTransformWithAncestors]";
1663 }
1664 if (Is3DContextLeaf()) {
1665 aStream << " [is3DContextLeaf]";
1666 }
1667 if (GetScrollbarContainerDirection().isSome()) {
1668 aStream << " [scrollbar]";
1669 }
1670 if (Maybe<ScrollDirection> thumbDirection = GetScrollThumbData().mDirection) {
1671 if (*thumbDirection == ScrollDirection::eVertical) {
1672 aStream << nsPrintfCString(" [vscrollbar=%" PRIu64 "]",
1673 GetScrollbarTargetContainerId())
1674 .get();
1675 }
1676 if (*thumbDirection == ScrollDirection::eHorizontal) {
1677 aStream << nsPrintfCString(" [hscrollbar=%" PRIu64 "]",
1678 GetScrollbarTargetContainerId())
1679 .get();
1680 }
1681 }
1682 if (GetIsFixedPosition()) {
1683 LayerPoint anchor = GetFixedPositionAnchor();
1684 aStream << nsPrintfCString(" [isFixedPosition scrollId=%" PRIu64
1685 " sides=0x%x anchor=%s]",
1686 GetFixedPositionScrollContainerId(),
1687 GetFixedPositionSides(),
1688 ToString(anchor).c_str())
1689 .get();
1690 }
1691 if (GetIsStickyPosition()) {
1692 aStream << nsPrintfCString(" [isStickyPosition scrollId=%" PRIu64
1693 " outer=(%.3f,%.3f)-(%.3f,%.3f) "
1694 "inner=(%.3f,%.3f)-(%.3f,%.3f)]",
1695 GetStickyScrollContainerId(),
1696 GetStickyScrollRangeOuter().X(),
1697 GetStickyScrollRangeOuter().Y(),
1698 GetStickyScrollRangeOuter().XMost(),
1699 GetStickyScrollRangeOuter().YMost(),
1700 GetStickyScrollRangeInner().X(),
1701 GetStickyScrollRangeInner().Y(),
1702 GetStickyScrollRangeInner().XMost(),
1703 GetStickyScrollRangeInner().YMost())
1704 .get();
1705 }
1706 if (mMaskLayer) {
1707 aStream << nsPrintfCString(" [mMaskLayer=%p]", mMaskLayer.get()).get();
1708 }
1709 for (uint32_t i = 0; i < mScrollMetadata.Length(); i++) {
1710 if (!mScrollMetadata[i].IsDefault()) {
1711 aStream << nsPrintfCString(" [metrics%d=", i).get();
1712 AppendToString(aStream, mScrollMetadata[i], "", "]");
1713 }
1714 }
1715 if (!mAnimationInfo.GetAnimations().IsEmpty()) {
1716 aStream << nsPrintfCString(" [%d animations with id=%" PRIu64 " ]",
1717 (int)mAnimationInfo.GetAnimations().Length(),
1718 mAnimationInfo.GetCompositorAnimationsId())
1719 .get();
1720 }
1721 }
1722
1723 // The static helper function sets the transform matrix into the packet
1724 static void DumpTransform(layerscope::LayersPacket::Layer::Matrix* aLayerMatrix,
1725 const Matrix4x4& aMatrix) {
1726 aLayerMatrix->set_is2d(aMatrix.Is2D());
1727 if (aMatrix.Is2D()) {
1728 Matrix m = aMatrix.As2D();
1729 aLayerMatrix->set_isid(m.IsIdentity());
1730 if (!m.IsIdentity()) {
1731 aLayerMatrix->add_m(m._11);
1732 aLayerMatrix->add_m(m._12);
1733 aLayerMatrix->add_m(m._21);
1734 aLayerMatrix->add_m(m._22);
1735 aLayerMatrix->add_m(m._31);
1736 aLayerMatrix->add_m(m._32);
1737 }
1738 } else {
1739 aLayerMatrix->add_m(aMatrix._11);
1740 aLayerMatrix->add_m(aMatrix._12);
1741 aLayerMatrix->add_m(aMatrix._13);
1742 aLayerMatrix->add_m(aMatrix._14);
1743 aLayerMatrix->add_m(aMatrix._21);
1744 aLayerMatrix->add_m(aMatrix._22);
1745 aLayerMatrix->add_m(aMatrix._23);
1746 aLayerMatrix->add_m(aMatrix._24);
1747 aLayerMatrix->add_m(aMatrix._31);
1748 aLayerMatrix->add_m(aMatrix._32);
1749 aLayerMatrix->add_m(aMatrix._33);
1750 aLayerMatrix->add_m(aMatrix._34);
1751 aLayerMatrix->add_m(aMatrix._41);
1752 aLayerMatrix->add_m(aMatrix._42);
1753 aLayerMatrix->add_m(aMatrix._43);
1754 aLayerMatrix->add_m(aMatrix._44);
1755 }
1756 }
1757
1758 // The static helper function sets the IntRect into the packet
1759 template <typename T, typename Sub, typename Point, typename SizeT,
1760 typename MarginT>
1761 static void DumpRect(layerscope::LayersPacket::Layer::Rect* aLayerRect,
1762 const BaseRect<T, Sub, Point, SizeT, MarginT>& aRect) {
1763 aLayerRect->set_x(aRect.X());
1764 aLayerRect->set_y(aRect.Y());
1765 aLayerRect->set_w(aRect.Width());
1766 aLayerRect->set_h(aRect.Height());
1767 }
1768
1769 // The static helper function sets the nsIntRegion into the packet
1770 static void DumpRegion(layerscope::LayersPacket::Layer::Region* aLayerRegion,
1771 const nsIntRegion& aRegion) {
1772 for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
1773 DumpRect(aLayerRegion->add_r(), iter.Get());
1774 }
1775 }
1776
1777 void Layer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) {
1778 // Add a new layer (UnknownLayer)
1779 using namespace layerscope;
1780 LayersPacket::Layer* layer = aPacket->add_layer();
1781 // Basic information
1782 layer->set_type(LayersPacket::Layer::UnknownLayer);
1783 layer->set_ptr(reinterpret_cast<uint64_t>(this));
1784 layer->set_parentptr(reinterpret_cast<uint64_t>(aParent));
1785 // Shadow
1786 if (HostLayer* lc = AsHostLayer()) {
1787 LayersPacket::Layer::Shadow* s = layer->mutable_shadow();
1788 if (const Maybe<ParentLayerIntRect>& clipRect = lc->GetShadowClipRect()) {
1789 DumpRect(s->mutable_clip(), *clipRect);
1790 }
1791 if (!lc->GetShadowBaseTransform().IsIdentity()) {
1792 DumpTransform(s->mutable_transform(), lc->GetShadowBaseTransform());
1793 }
1794 if (!lc->GetShadowVisibleRegion().IsEmpty()) {
1795 DumpRegion(s->mutable_vregion(),
1796 lc->GetShadowVisibleRegion().ToUnknownRegion());
1797 }
1798 }
1799 // Clip
1800 if (mClipRect) {
1801 DumpRect(layer->mutable_clip(), *mClipRect);
1802 }
1803 // Transform
1804 if (!GetBaseTransform().IsIdentity()) {
1805 DumpTransform(layer->mutable_transform(), GetBaseTransform());
1806 }
1807 // Visible region
1808 if (!mVisibleRegion.ToUnknownRegion().IsEmpty()) {
1809 DumpRegion(layer->mutable_vregion(), mVisibleRegion.ToUnknownRegion());
1810 }
1811 // EventRegions
1812 if (!mEventRegions.IsEmpty()) {
1813 const EventRegions& e = mEventRegions;
1814 if (!e.mHitRegion.IsEmpty()) {
1815 DumpRegion(layer->mutable_hitregion(), e.mHitRegion);
1816 }
1817 if (!e.mDispatchToContentHitRegion.IsEmpty()) {
1818 DumpRegion(layer->mutable_dispatchregion(),
1819 e.mDispatchToContentHitRegion);
1820 }
1821 if (!e.mNoActionRegion.IsEmpty()) {
1822 DumpRegion(layer->mutable_noactionregion(), e.mNoActionRegion);
1823 }
1824 if (!e.mHorizontalPanRegion.IsEmpty()) {
1825 DumpRegion(layer->mutable_hpanregion(), e.mHorizontalPanRegion);
1826 }
1827 if (!e.mVerticalPanRegion.IsEmpty()) {
1828 DumpRegion(layer->mutable_vpanregion(), e.mVerticalPanRegion);
1829 }
1830 }
1831 // Opacity
1832 layer->set_opacity(GetOpacity());
1833 // Content opaque
1834 layer->set_copaque(static_cast<bool>(GetContentFlags() & CONTENT_OPAQUE));
1835 // Component alpha
1836 layer->set_calpha(
1837 static_cast<bool>(GetContentFlags() & CONTENT_COMPONENT_ALPHA));
1838 // Vertical or horizontal bar
1839 if (Maybe<ScrollDirection> thumbDirection = GetScrollThumbData().mDirection) {
1840 layer->set_direct(*thumbDirection == ScrollDirection::eVertical
1841 ? LayersPacket::Layer::VERTICAL
1842 : LayersPacket::Layer::HORIZONTAL);
1843 layer->set_barid(GetScrollbarTargetContainerId());
1844 }
1845
1846 // Mask layer
1847 if (mMaskLayer) {
1848 layer->set_mask(reinterpret_cast<uint64_t>(mMaskLayer.get()));
1849 }
1850
1851 // DisplayList log.
1852 if (mDisplayListLog.Length() > 0) {
1853 layer->set_displaylistloglength(mDisplayListLog.Length());
1854 auto compressedData =
1855 MakeUnique<char[]>(LZ4::maxCompressedSize(mDisplayListLog.Length()));
1856 int compressedSize =
1857 LZ4::compress((char*)mDisplayListLog.get(), mDisplayListLog.Length(),
1858 compressedData.get());
1859 layer->set_displaylistlog(compressedData.get(), compressedSize);
1860 }
1861 }
1862
1863 bool Layer::IsBackfaceHidden() {
1864 if (GetContentFlags() & CONTENT_BACKFACE_HIDDEN) {
1865 Layer* container = AsContainerLayer() ? this : GetParent();
1866 if (container) {
1867 // The effective transform can include non-preserve-3d parent
1868 // transforms, since we don't always require an intermediate.
1869 if (container->Extend3DContext() || container->Is3DContextLeaf()) {
1870 return container->GetEffectiveTransform().IsBackfaceVisible();
1871 }
1872 return container->GetBaseTransform().IsBackfaceVisible();
1873 }
1874 }
1875 return false;
1876 }
1877
1878 UniquePtr<LayerUserData> Layer::RemoveUserData(void* aKey) {
1879 UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(
1880 mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
1881 return d;
1882 }
1883
1884 void Layer::SetManager(LayerManager* aManager, HostLayer* aSelf) {
1885 // No one should be calling this for weird reasons.
1886 MOZ_ASSERT(aSelf);
1887 MOZ_ASSERT(aSelf->GetLayer() == this);
1888 mManager = aManager;
1889 }
1890
1891 void PaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
1892 Layer::PrintInfo(aStream, aPrefix);
1893 nsIntRegion validRegion = GetValidRegion();
1894 if (!validRegion.IsEmpty()) {
1895 AppendToString(aStream, validRegion, " [valid=", "]");
1896 }
1897 }
1898
1899 void PaintedLayer::DumpPacket(layerscope::LayersPacket* aPacket,
1900 const void* aParent) {
1901 Layer::DumpPacket(aPacket, aParent);
1902 // get this layer data
1903 using namespace layerscope;
1904 LayersPacket::Layer* layer =
1905 aPacket->mutable_layer(aPacket->layer_size() - 1);
1906 layer->set_type(LayersPacket::Layer::PaintedLayer);
1907 nsIntRegion validRegion = GetValidRegion();
1908 if (!validRegion.IsEmpty()) {
1909 DumpRegion(layer->mutable_valid(), validRegion);
1910 }
1911 }
1912
1913 void ContainerLayer::PrintInfo(std::stringstream& aStream,
1914 const char* aPrefix) {
1915 Layer::PrintInfo(aStream, aPrefix);
1916 if (UseIntermediateSurface()) {
1917 aStream << " [usesTmpSurf]";
1918 }
1919 if (1.0 != mPreXScale || 1.0 != mPreYScale) {
1920 aStream
1921 << nsPrintfCString(" [preScale=%g, %g]", mPreXScale, mPreYScale).get();
1922 }
1923 if (mScaleToResolution) {
1924 aStream << nsPrintfCString(" [presShellResolution=%g]",
1925 mPresShellResolution)
1926 .get();
1927 }
1928 }
1929
1930 void ContainerLayer::DumpPacket(layerscope::LayersPacket* aPacket,
1931 const void* aParent) {
1932 Layer::DumpPacket(aPacket, aParent);
1933 // Get this layer data
1934 using namespace layerscope;
1935 LayersPacket::Layer* layer =
1936 aPacket->mutable_layer(aPacket->layer_size() - 1);
1937 layer->set_type(LayersPacket::Layer::ContainerLayer);
1938 }
1939
1940 void DisplayItemLayer::EndTransaction() {
1941 mItem = nullptr;
1942 mBuilder = nullptr;
1943 }
1944
1945 void DisplayItemLayer::PrintInfo(std::stringstream& aStream,
1946 const char* aPrefix) {
1947 Layer::PrintInfo(aStream, aPrefix);
1948 const char* type = "TYPE_UNKNOWN";
1949 if (mItem) {
1950 type = mItem->Name();
1951 }
1952
1953 aStream << " [itype type=" << type << "]";
1954 }
1955
1956 void DisplayItemLayer::DumpPacket(layerscope::LayersPacket* aPacket,
1957 const void* aParent) {
1958 Layer::DumpPacket(aPacket, aParent);
1959 // Get this layer data
1960 using namespace layerscope;
1961 LayersPacket::Layer* layer =
1962 aPacket->mutable_layer(aPacket->layer_size() - 1);
1963 layer->set_type(LayersPacket::Layer::DisplayItemLayer);
1964 }
1965
1966 void ColorLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
1967 Layer::PrintInfo(aStream, aPrefix);
1968 AppendToString(aStream, mColor, " [color=", "]");
1969 AppendToString(aStream, mBounds, " [bounds=", "]");
1970 }
1971
1972 void ColorLayer::DumpPacket(layerscope::LayersPacket* aPacket,
1973 const void* aParent) {
1974 Layer::DumpPacket(aPacket, aParent);
1975 // Get this layer data
1976 using namespace layerscope;
1977 LayersPacket::Layer* layer =
1978 aPacket->mutable_layer(aPacket->layer_size() - 1);
1979 layer->set_type(LayersPacket::Layer::ColorLayer);
1980 layer->set_color(mColor.ToABGR());
1981 }
1982
1983 void BorderLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
1984 Layer::PrintInfo(aStream, aPrefix);
1985 }
1986
1987 void BorderLayer::DumpPacket(layerscope::LayersPacket* aPacket,
1988 const void* aParent) {
1989 Layer::DumpPacket(aPacket, aParent);
1990 }
1991
1992 CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData)
1993 : Layer(aManager, aImplData), mSamplingFilter(SamplingFilter::GOOD) {}
1994
1995 CanvasLayer::~CanvasLayer() = default;
1996
1997 void CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
1998 Layer::PrintInfo(aStream, aPrefix);
1999 if (mSamplingFilter != SamplingFilter::GOOD) {
2000 AppendToString(aStream, mSamplingFilter, " [filter=", "]");
2001 }
2002 }
2003
2004 // This help function is used to assign the correct enum value
2005 // to the packet
2006 static void DumpFilter(layerscope::LayersPacket::Layer* aLayer,
2007 const SamplingFilter& aSamplingFilter) {
2008 using namespace layerscope;
2009 switch (aSamplingFilter) {
2010 case SamplingFilter::GOOD:
2011 aLayer->set_filter(LayersPacket::Layer::FILTER_GOOD);
2012 break;
2013 case SamplingFilter::LINEAR:
2014 aLayer->set_filter(LayersPacket::Layer::FILTER_LINEAR);
2015 break;
2016 case SamplingFilter::POINT:
2017 aLayer->set_filter(LayersPacket::Layer::FILTER_POINT);
2018 break;
2019 default:
2020 // ignore it
2021 break;
2022 }
2023 }
2024
2025 void CanvasLayer::DumpPacket(layerscope::LayersPacket* aPacket,
2026 const void* aParent) {
2027 Layer::DumpPacket(aPacket, aParent);
2028 // Get this layer data
2029 using namespace layerscope;
2030 LayersPacket::Layer* layer =
2031 aPacket->mutable_layer(aPacket->layer_size() - 1);
2032 layer->set_type(LayersPacket::Layer::CanvasLayer);
2033 DumpFilter(layer, mSamplingFilter);
2034 }
2035
2036 CanvasRenderer* CanvasLayer::CreateOrGetCanvasRenderer() {
2037 if (!mCanvasRenderer) {
2038 mCanvasRenderer.reset(CreateCanvasRendererInternal());
2039 }
2040
2041 return mCanvasRenderer.get();
2042 }
2043
2044 void ImageLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
2045 Layer::PrintInfo(aStream, aPrefix);
2046 if (mSamplingFilter != SamplingFilter::GOOD) {
2047 AppendToString(aStream, mSamplingFilter, " [filter=", "]");
2048 }
2049 }
2050
2051 void ImageLayer::DumpPacket(layerscope::LayersPacket* aPacket,
2052 const void* aParent) {
2053 Layer::DumpPacket(aPacket, aParent);
2054 // Get this layer data
2055 using namespace layerscope;
2056 LayersPacket::Layer* layer =
2057 aPacket->mutable_layer(aPacket->layer_size() - 1);
2058 layer->set_type(LayersPacket::Layer::ImageLayer);
2059 DumpFilter(layer, mSamplingFilter);
2060 }
2061
2062 void RefLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
2063 ContainerLayer::PrintInfo(aStream, aPrefix);
2064 if (0 != mId) {
2065 AppendToString(aStream, mId, " [id=", "]");
2066 }
2067 if (mEventRegionsOverride & EventRegionsOverride::ForceDispatchToContent) {
2068 aStream << " [force-dtc]";
2069 }
2070 if (mEventRegionsOverride & EventRegionsOverride::ForceEmptyHitRegion) {
2071 aStream << " [force-ehr]";
2072 }
2073 }
2074
2075 void RefLayer::DumpPacket(layerscope::LayersPacket* aPacket,
2076 const void* aParent) {
2077 Layer::DumpPacket(aPacket, aParent);
2078 // Get this layer data
2079 using namespace layerscope;
2080 LayersPacket::Layer* layer =
2081 aPacket->mutable_layer(aPacket->layer_size() - 1);
2082 layer->set_type(LayersPacket::Layer::RefLayer);
2083 layer->set_refid(mId);
2084 }
2085
2086 void ReadbackLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
2087 Layer::PrintInfo(aStream, aPrefix);
2088 AppendToString(aStream, mSize, " [size=", "]");
2089 if (mBackgroundLayer) {
2090 AppendToString(aStream, mBackgroundLayer, " [backgroundLayer=", "]");
2091 AppendToString(aStream, mBackgroundLayerOffset, " [backgroundOffset=", "]");
2092 } else if (mBackgroundColor.a == 1.f) {
2093 AppendToString(aStream, mBackgroundColor, " [backgroundColor=", "]");
2094 } else {
2095 aStream << " [nobackground]";
2096 }
2097 }
2098
2099 void ReadbackLayer::DumpPacket(layerscope::LayersPacket* aPacket,
2100 const void* aParent) {
2101 Layer::DumpPacket(aPacket, aParent);
2102 // Get this layer data
2103 using namespace layerscope;
2104 LayersPacket::Layer* layer =
2105 aPacket->mutable_layer(aPacket->layer_size() - 1);
2106 layer->set_type(LayersPacket::Layer::ReadbackLayer);
2107 LayersPacket::Layer::Size* size = layer->mutable_size();
2108 size->set_w(mSize.width);
2109 size->set_h(mSize.height);
2110 }
2111
2112 //--------------------------------------------------
2113 // LayerManager
2114
2115 void LayerManager::Dump(std::stringstream& aStream, const char* aPrefix,
2116 bool aDumpHtml, bool aSorted) {
2117 #ifdef MOZ_DUMP_PAINTING
2118 if (aDumpHtml) {
2119 aStream << "<ul><li>";
2120 }
2121 #endif
2122 DumpSelf(aStream, aPrefix, aSorted);
2123
2124 nsAutoCString pfx(aPrefix);
2125 pfx += " ";
2126 if (!GetRoot()) {
2127 aStream << nsPrintfCString("%s(null)\n", pfx.get()).get();
2128 if (aDumpHtml) {
2129 aStream << "</li></ul>";
2130 }
2131 return;
2132 }
2133
2134 if (aDumpHtml) {
2135 aStream << "<ul>";
2136 }
2137 GetRoot()->Dump(aStream, pfx.get(), aDumpHtml, aSorted);
2138 if (aDumpHtml) {
2139 aStream << "</ul></li></ul>";
2140 }
2141 aStream << "\n";
2142 }
2143
2144 void LayerManager::DumpSelf(std::stringstream& aStream, const char* aPrefix,
2145 bool aSorted) {
2146 PrintInfo(aStream, aPrefix);
2147 aStream << " --- in "
2148 << (aSorted ? "3D-sorted rendering order" : "content order");
2149 aStream << "\n";
2150 }
2151
2152 void LayerManager::Dump(bool aSorted) {
2153 std::stringstream ss;
2154 Dump(ss, "", false, aSorted);
2155 print_stderr(ss);
2156 }
2157
2158 void LayerManager::Dump(layerscope::LayersPacket* aPacket) {
2159 DumpPacket(aPacket);
2160
2161 if (GetRoot()) {
2162 GetRoot()->Dump(aPacket, this);
2163 }
2164 }
2165
2166 void LayerManager::Log(const char* aPrefix) {
2167 if (!IsLogEnabled()) return;
2168
2169 LogSelf(aPrefix);
2170
2171 nsAutoCString pfx(aPrefix);
2172 pfx += " ";
2173 if (!GetRoot()) {
2174 MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
2175 return;
2176 }
2177
2178 GetRoot()->Log(pfx.get());
2179 }
2180
2181 void LayerManager::LogSelf(const char* aPrefix) {
2182 nsAutoCString str;
2183 std::stringstream ss;
2184 PrintInfo(ss, aPrefix);
2185 MOZ_LAYERS_LOG(("%s", ss.str().c_str()));
2186 }
2187
2188 void LayerManager::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
2189 aStream << aPrefix
2190 << nsPrintfCString("%sLayerManager (0x%p)", Name(), this).get();
2191 }
2192
2193 void LayerManager::DumpPacket(layerscope::LayersPacket* aPacket) {
2194 using namespace layerscope;
2195 // Add a new layer data (LayerManager)
2196 LayersPacket::Layer* layer = aPacket->add_layer();
2197 layer->set_type(LayersPacket::Layer::LayerManager);
2198 layer->set_ptr(reinterpret_cast<uint64_t>(this));
2199 // Layer Tree Root
2200 layer->set_parentptr(0);
2201 }
2202
2203 void LayerManager::TrackDisplayItemLayer(RefPtr<DisplayItemLayer> aLayer) {
2204 mDisplayItemLayers.AppendElement(aLayer);
2205 }
2206
2207 void LayerManager::ClearDisplayItemLayers() {
2208 for (uint32_t i = 0; i < mDisplayItemLayers.Length(); i++) {
2209 mDisplayItemLayers[i]->EndTransaction();
2210 }
2211
2212 mDisplayItemLayers.Clear();
2213 }
2214
2215 /*static*/ bool LayerManager::IsLogEnabled() {
2216 return MOZ_LOG_TEST(GetLog(), LogLevel::Debug);
2217 }
2218
2219 bool LayerManager::SetPendingScrollUpdateForNextTransaction(
2220 FrameMetrics::ViewID aScrollId, const ScrollUpdateInfo& aUpdateInfo) {
2221 Layer* withPendingTransform = DepthFirstSearch<ForwardIterator>(
2222 GetRoot(), [](Layer* aLayer) { return aLayer->HasPendingTransform(); });
2223 if (withPendingTransform) {
2224 return false;
2225 }
2226
2227 mPendingScrollUpdates[aScrollId] = aUpdateInfo;
2228 return true;
2229 }
2230
2231 Maybe<ScrollUpdateInfo> LayerManager::GetPendingScrollInfoUpdate(
2232 FrameMetrics::ViewID aScrollId) {
2233 auto it = mPendingScrollUpdates.find(aScrollId);
2234 if (it != mPendingScrollUpdates.end()) {
2235 return Some(it->second);
2236 }
2237 return Nothing();
2238 }
2239
2240 void LayerManager::ClearPendingScrollInfoUpdate() {
2241 mPendingScrollUpdates.clear();
2242 }
2243
2244 void PrintInfo(std::stringstream& aStream, HostLayer* aLayerComposite) {
2245 if (!aLayerComposite) {
2246 return;
2247 }
2248 if (const Maybe<ParentLayerIntRect>& clipRect =
2249 aLayerComposite->GetShadowClipRect()) {
2250 AppendToString(aStream, *clipRect, " [shadow-clip=", "]");
2251 }
2252 if (!aLayerComposite->GetShadowBaseTransform().IsIdentity()) {
2253 AppendToString(aStream, aLayerComposite->GetShadowBaseTransform(),
2254 " [shadow-transform=", "]");
2255 }
2256 if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
2257 AppendToString(aStream,
2258 aLayerComposite->GetShadowVisibleRegion().ToUnknownRegion(),
2259 " [shadow-visible=", "]");
2260 }
2261 }
2262
2263 void SetAntialiasingFlags(Layer* aLayer, DrawTarget* aTarget) {
2264 bool permitSubpixelAA =
2265 !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
2266 if (aTarget->IsCurrentGroupOpaque()) {
2267 aTarget->SetPermitSubpixelAA(permitSubpixelAA);
2268 return;
2269 }
2270
2271 const IntRect& bounds =
2272 aLayer->GetVisibleRegion().ToUnknownRegion().GetBounds();
2273 gfx::Rect transformedBounds = aTarget->GetTransform().TransformBounds(
2274 gfx::Rect(Float(bounds.X()), Float(bounds.Y()), Float(bounds.Width()),
2275 Float(bounds.Height())));
2276 transformedBounds.RoundOut();
2277 IntRect intTransformedBounds;
2278 transformedBounds.ToIntRect(&intTransformedBounds);
2279 permitSubpixelAA &=
2280 !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
2281 aTarget->GetOpaqueRect().Contains(intTransformedBounds);
2282 aTarget->SetPermitSubpixelAA(permitSubpixelAA);
2283 }
2284
2285 IntRect ToOutsideIntRect(const gfxRect& aRect) {
2286 return IntRect::RoundOut(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
2287 }
2288
2289 } // namespace layers
2290 } // namespace mozilla
2291