Bumping manifests a=b2g-bump
[gecko.git] / gfx / layers / Layers.cpp
blob23c194a3a44b55c37aa3fc07710d2a5cbb60e7f1
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "Layers.h"
9 #include <algorithm> // for max, min
10 #include "apz/src/AsyncPanZoomController.h"
11 #include "CompositableHost.h" // for CompositableHost
12 #include "ImageContainer.h" // for ImageContainer, etc
13 #include "ImageLayers.h" // for ImageLayer
14 #include "LayerSorter.h" // for SortLayersBy3DZOrder
15 #include "LayersLogging.h" // for AppendToString
16 #include "ReadbackLayer.h" // for ReadbackLayer
17 #include "gfxPlatform.h" // for gfxPlatform
18 #include "gfxPrefs.h"
19 #include "gfxUtils.h" // for gfxUtils, etc
20 #include "gfx2DGlue.h"
21 #include "mozilla/DebugOnly.h" // for DebugOnly
22 #include "mozilla/Telemetry.h" // for Accumulate
23 #include "mozilla/dom/AnimationPlayer.h" // for ComputedTimingFunction
24 #include "mozilla/gfx/2D.h" // for DrawTarget
25 #include "mozilla/gfx/BaseSize.h" // for BaseSize
26 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
27 #include "mozilla/layers/Compositor.h" // for Compositor
28 #include "mozilla/layers/CompositorTypes.h"
29 #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite
30 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
31 #include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
32 #include "nsAString.h"
33 #include "nsCSSValue.h" // for nsCSSValue::Array, etc
34 #include "nsPrintfCString.h" // for nsPrintfCString
35 #include "nsStyleStruct.h" // for nsTimingFunction, etc
36 #include "protobuf/LayerScopePacket.pb.h"
38 uint8_t gLayerManagerLayerBuilder;
40 namespace mozilla {
41 namespace layers {
43 FILE*
44 FILEOrDefault(FILE* aFile)
46 return aFile ? aFile : stderr;
49 typedef FrameMetrics::ViewID ViewID;
50 const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
51 const FrameMetrics FrameMetrics::sNullMetrics;
53 using namespace mozilla::gfx;
55 //--------------------------------------------------
56 // LayerManager
57 FrameMetrics::ViewID
58 LayerManager::GetRootScrollableLayerId()
60 if (!mRoot) {
61 return FrameMetrics::NULL_SCROLL_ID;
64 nsTArray<LayerMetricsWrapper> queue;
65 queue.AppendElement(LayerMetricsWrapper(mRoot));
66 while (queue.Length()) {
67 LayerMetricsWrapper layer = queue[0];
68 queue.RemoveElementAt(0);
70 const FrameMetrics& frameMetrics = layer.Metrics();
71 if (frameMetrics.IsScrollable()) {
72 return frameMetrics.GetScrollId();
75 LayerMetricsWrapper child = layer.GetFirstChild();
76 while (child) {
77 queue.AppendElement(child);
78 child = child.GetNextSibling();
82 return FrameMetrics::NULL_SCROLL_ID;
85 void
86 LayerManager::GetRootScrollableLayers(nsTArray<Layer*>& aArray)
88 if (!mRoot) {
89 return;
92 FrameMetrics::ViewID rootScrollableId = GetRootScrollableLayerId();
93 if (rootScrollableId == FrameMetrics::NULL_SCROLL_ID) {
94 aArray.AppendElement(mRoot);
95 return;
98 nsTArray<Layer*> queue;
99 queue.AppendElement(mRoot);
100 while (queue.Length()) {
101 Layer* layer = queue[0];
102 queue.RemoveElementAt(0);
104 if (LayerMetricsWrapper::TopmostScrollableMetrics(layer).GetScrollId() == rootScrollableId) {
105 aArray.AppendElement(layer);
106 continue;
109 for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
110 queue.AppendElement(child);
115 void
116 LayerManager::GetScrollableLayers(nsTArray<Layer*>& aArray)
118 if (!mRoot) {
119 return;
122 nsTArray<Layer*> queue;
123 queue.AppendElement(mRoot);
124 while (!queue.IsEmpty()) {
125 Layer* layer = queue.LastElement();
126 queue.RemoveElementAt(queue.Length() - 1);
128 if (layer->HasScrollableFrameMetrics()) {
129 aArray.AppendElement(layer);
130 continue;
133 for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
134 queue.AppendElement(child);
139 TemporaryRef<DrawTarget>
140 LayerManager::CreateOptimalDrawTarget(const gfx::IntSize &aSize,
141 SurfaceFormat aFormat)
143 return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aSize,
144 aFormat);
147 TemporaryRef<DrawTarget>
148 LayerManager::CreateOptimalMaskDrawTarget(const gfx::IntSize &aSize)
150 return CreateOptimalDrawTarget(aSize, SurfaceFormat::A8);
153 TemporaryRef<DrawTarget>
154 LayerManager::CreateDrawTarget(const IntSize &aSize,
155 SurfaceFormat aFormat)
157 return gfxPlatform::GetPlatform()->
158 CreateOffscreenCanvasDrawTarget(aSize, aFormat);
161 #ifdef DEBUG
162 void
163 LayerManager::Mutated(Layer* aLayer)
166 #endif // DEBUG
168 already_AddRefed<ImageContainer>
169 LayerManager::CreateImageContainer()
171 nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::DISABLE_ASYNC);
172 return container.forget();
175 already_AddRefed<ImageContainer>
176 LayerManager::CreateAsynchronousImageContainer()
178 nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::ENABLE_ASYNC);
179 return container.forget();
182 bool
183 LayerManager::AreComponentAlphaLayersEnabled()
185 return gfxPrefs::ComponentAlphaEnabled();
188 //--------------------------------------------------
189 // Layer
191 Layer::Layer(LayerManager* aManager, void* aImplData) :
192 mManager(aManager),
193 mParent(nullptr),
194 mNextSibling(nullptr),
195 mPrevSibling(nullptr),
196 mImplData(aImplData),
197 mMaskLayer(nullptr),
198 mPostXScale(1.0f),
199 mPostYScale(1.0f),
200 mOpacity(1.0),
201 mMixBlendMode(CompositionOp::OP_OVER),
202 mForceIsolatedGroup(false),
203 mContentFlags(0),
204 mUseClipRect(false),
205 mUseTileSourceRect(false),
206 mIsFixedPosition(false),
207 mMargins(0, 0, 0, 0),
208 mStickyPositionData(nullptr),
209 mScrollbarTargetId(FrameMetrics::NULL_SCROLL_ID),
210 mScrollbarDirection(ScrollDirection::NONE),
211 mDebugColorIndex(0),
212 mAnimationGeneration(0)
215 Layer::~Layer()
218 Animation*
219 Layer::AddAnimation()
221 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) AddAnimation", this));
223 MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
225 Animation* anim = mAnimations.AppendElement();
227 Mutated();
228 return anim;
231 void
232 Layer::ClearAnimations()
234 mPendingAnimations = nullptr;
236 if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
237 return;
240 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClearAnimations", this));
241 mAnimations.Clear();
242 mAnimationData.Clear();
243 Mutated();
246 Animation*
247 Layer::AddAnimationForNextTransaction()
249 MOZ_ASSERT(mPendingAnimations,
250 "should have called ClearAnimationsForNextTransaction first");
252 Animation* anim = mPendingAnimations->AppendElement();
254 return anim;
257 void
258 Layer::ClearAnimationsForNextTransaction()
260 // Ensure we have a non-null mPendingAnimations to mark a future clear.
261 if (!mPendingAnimations) {
262 mPendingAnimations = new AnimationArray;
265 mPendingAnimations->Clear();
268 static nsCSSValueSharedList*
269 CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
271 nsAutoPtr<nsCSSValueList> result;
272 nsCSSValueList** resultTail = getter_Transfers(result);
273 for (uint32_t i = 0; i < aFunctions.Length(); i++) {
274 nsRefPtr<nsCSSValue::Array> arr;
275 switch (aFunctions[i].type()) {
276 case TransformFunction::TRotationX:
278 float theta = aFunctions[i].get_RotationX().radians();
279 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatex,
280 resultTail);
281 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
282 break;
284 case TransformFunction::TRotationY:
286 float theta = aFunctions[i].get_RotationY().radians();
287 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatey,
288 resultTail);
289 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
290 break;
292 case TransformFunction::TRotationZ:
294 float theta = aFunctions[i].get_RotationZ().radians();
295 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatez,
296 resultTail);
297 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
298 break;
300 case TransformFunction::TRotation:
302 float theta = aFunctions[i].get_Rotation().radians();
303 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotate,
304 resultTail);
305 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
306 break;
308 case TransformFunction::TRotation3D:
310 float x = aFunctions[i].get_Rotation3D().x();
311 float y = aFunctions[i].get_Rotation3D().y();
312 float z = aFunctions[i].get_Rotation3D().z();
313 float theta = aFunctions[i].get_Rotation3D().radians();
314 arr =
315 StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotate3d,
316 resultTail);
317 arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
318 arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
319 arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
320 arr->Item(4).SetFloatValue(theta, eCSSUnit_Radian);
321 break;
323 case TransformFunction::TScale:
325 arr =
326 StyleAnimationValue::AppendTransformFunction(eCSSKeyword_scale3d,
327 resultTail);
328 arr->Item(1).SetFloatValue(aFunctions[i].get_Scale().x(), eCSSUnit_Number);
329 arr->Item(2).SetFloatValue(aFunctions[i].get_Scale().y(), eCSSUnit_Number);
330 arr->Item(3).SetFloatValue(aFunctions[i].get_Scale().z(), eCSSUnit_Number);
331 break;
333 case TransformFunction::TTranslation:
335 arr =
336 StyleAnimationValue::AppendTransformFunction(eCSSKeyword_translate3d,
337 resultTail);
338 arr->Item(1).SetFloatValue(aFunctions[i].get_Translation().x(), eCSSUnit_Pixel);
339 arr->Item(2).SetFloatValue(aFunctions[i].get_Translation().y(), eCSSUnit_Pixel);
340 arr->Item(3).SetFloatValue(aFunctions[i].get_Translation().z(), eCSSUnit_Pixel);
341 break;
343 case TransformFunction::TSkewX:
345 float x = aFunctions[i].get_SkewX().x();
346 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skewx,
347 resultTail);
348 arr->Item(1).SetFloatValue(x, eCSSUnit_Radian);
349 break;
351 case TransformFunction::TSkewY:
353 float y = aFunctions[i].get_SkewY().y();
354 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skewy,
355 resultTail);
356 arr->Item(1).SetFloatValue(y, eCSSUnit_Radian);
357 break;
359 case TransformFunction::TSkew:
361 arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skew,
362 resultTail);
363 arr->Item(1).SetFloatValue(aFunctions[i].get_Skew().x(), eCSSUnit_Radian);
364 arr->Item(2).SetFloatValue(aFunctions[i].get_Skew().y(), eCSSUnit_Radian);
365 break;
367 case TransformFunction::TTransformMatrix:
369 arr =
370 StyleAnimationValue::AppendTransformFunction(eCSSKeyword_matrix3d,
371 resultTail);
372 const gfx::Matrix4x4& matrix = aFunctions[i].get_TransformMatrix().value();
373 arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
374 arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
375 arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
376 arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number);
377 arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number);
378 arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number);
379 arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number);
380 arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number);
381 arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number);
382 arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number);
383 arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number);
384 arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number);
385 arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number);
386 arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number);
387 arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number);
388 arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number);
389 break;
391 case TransformFunction::TPerspective:
393 float perspective = aFunctions[i].get_Perspective().value();
394 arr =
395 StyleAnimationValue::AppendTransformFunction(eCSSKeyword_perspective,
396 resultTail);
397 arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel);
398 break;
400 default:
401 NS_ASSERTION(false, "All functions should be implemented?");
404 if (aFunctions.Length() == 0) {
405 result = new nsCSSValueList();
406 result->mValue.SetNoneValue();
408 return new nsCSSValueSharedList(result.forget());
411 void
412 Layer::SetAnimations(const AnimationArray& aAnimations)
414 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) SetAnimations", this));
416 mAnimations = aAnimations;
417 mAnimationData.Clear();
418 for (uint32_t i = 0; i < mAnimations.Length(); i++) {
419 AnimData* data = mAnimationData.AppendElement();
420 InfallibleTArray<nsAutoPtr<ComputedTimingFunction> >& functions =
421 data->mFunctions;
422 const InfallibleTArray<AnimationSegment>& segments =
423 mAnimations.ElementAt(i).segments();
424 for (uint32_t j = 0; j < segments.Length(); j++) {
425 TimingFunction tf = segments.ElementAt(j).sampleFn();
426 ComputedTimingFunction* ctf = new ComputedTimingFunction();
427 switch (tf.type()) {
428 case TimingFunction::TCubicBezierFunction: {
429 CubicBezierFunction cbf = tf.get_CubicBezierFunction();
430 ctf->Init(nsTimingFunction(cbf.x1(), cbf.y1(), cbf.x2(), cbf.y2()));
431 break;
433 default: {
434 NS_ASSERTION(tf.type() == TimingFunction::TStepFunction,
435 "Function must be bezier or step");
436 StepFunction sf = tf.get_StepFunction();
437 nsTimingFunction::Type type = sf.type() == 1 ? nsTimingFunction::StepStart
438 : nsTimingFunction::StepEnd;
439 ctf->Init(nsTimingFunction(type, sf.steps()));
440 break;
443 functions.AppendElement(ctf);
446 // Precompute the StyleAnimationValues that we need if this is a transform
447 // animation.
448 InfallibleTArray<StyleAnimationValue>& startValues = data->mStartValues;
449 InfallibleTArray<StyleAnimationValue>& endValues = data->mEndValues;
450 for (uint32_t j = 0; j < mAnimations[i].segments().Length(); j++) {
451 const AnimationSegment& segment = mAnimations[i].segments()[j];
452 StyleAnimationValue* startValue = startValues.AppendElement();
453 StyleAnimationValue* endValue = endValues.AppendElement();
454 if (segment.endState().type() == Animatable::TArrayOfTransformFunction) {
455 const InfallibleTArray<TransformFunction>& startFunctions =
456 segment.startState().get_ArrayOfTransformFunction();
457 startValue->SetTransformValue(CreateCSSValueList(startFunctions));
459 const InfallibleTArray<TransformFunction>& endFunctions =
460 segment.endState().get_ArrayOfTransformFunction();
461 endValue->SetTransformValue(CreateCSSValueList(endFunctions));
462 } else {
463 NS_ASSERTION(segment.endState().type() == Animatable::Tfloat,
464 "Unknown Animatable type");
465 startValue->SetFloatValue(segment.startState().get_float());
466 endValue->SetFloatValue(segment.endState().get_float());
471 Mutated();
474 void
475 Layer::StartPendingAnimations(const TimeStamp& aReadyTime)
477 bool updated = false;
478 for (size_t animIdx = 0, animEnd = mAnimations.Length();
479 animIdx < animEnd; animIdx++) {
480 Animation& anim = mAnimations[animIdx];
481 if (anim.startTime().IsNull()) {
482 anim.startTime() = aReadyTime - anim.initialCurrentTime();
483 updated = true;
487 if (updated) {
488 Mutated();
491 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
492 child->StartPendingAnimations(aReadyTime);
496 void
497 Layer::SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller)
499 MOZ_ASSERT(aIndex < GetFrameMetricsCount());
500 mApzcs[aIndex] = controller;
503 AsyncPanZoomController*
504 Layer::GetAsyncPanZoomController(uint32_t aIndex) const
506 MOZ_ASSERT(aIndex < GetFrameMetricsCount());
507 #ifdef DEBUG
508 if (mApzcs[aIndex]) {
509 MOZ_ASSERT(GetFrameMetrics(aIndex).IsScrollable());
511 #endif
512 return mApzcs[aIndex];
515 void
516 Layer::FrameMetricsChanged()
518 mApzcs.SetLength(GetFrameMetricsCount());
521 void
522 Layer::ApplyPendingUpdatesToSubtree()
524 ApplyPendingUpdatesForThisTransaction();
525 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
526 child->ApplyPendingUpdatesToSubtree();
530 bool
531 Layer::CanUseOpaqueSurface()
533 // If the visible content in the layer is opaque, there is no need
534 // for an alpha channel.
535 if (GetContentFlags() & CONTENT_OPAQUE)
536 return true;
537 // Also, if this layer is the bottommost layer in a container which
538 // doesn't need an alpha channel, we can use an opaque surface for this
539 // layer too. Any transparent areas must be covered by something else
540 // in the container.
541 ContainerLayer* parent = GetParent();
542 return parent && parent->GetFirstChild() == this &&
543 parent->CanUseOpaqueSurface();
546 // NB: eventually these methods will be defined unconditionally, and
547 // can be moved into Layers.h
548 const nsIntRect*
549 Layer::GetEffectiveClipRect()
551 if (LayerComposite* shadow = AsLayerComposite()) {
552 return shadow->GetShadowClipRect();
554 return GetClipRect();
557 const nsIntRegion&
558 Layer::GetEffectiveVisibleRegion()
560 if (LayerComposite* shadow = AsLayerComposite()) {
561 return shadow->GetShadowVisibleRegion();
563 return GetVisibleRegion();
566 Matrix4x4
567 Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
568 Matrix* aResidualTransform)
570 if (aResidualTransform) {
571 *aResidualTransform = Matrix();
574 Matrix matrix2D;
575 Matrix4x4 result;
576 if (mManager->IsSnappingEffectiveTransforms() &&
577 aTransform.Is2D(&matrix2D) &&
578 !matrix2D.HasNonTranslation() &&
579 matrix2D.HasNonIntegerTranslation()) {
580 IntPoint snappedTranslation = RoundedToInt(matrix2D.GetTranslation());
581 Matrix snappedMatrix = Matrix::Translation(snappedTranslation.x,
582 snappedTranslation.y);
583 result = Matrix4x4::From2D(snappedMatrix);
584 if (aResidualTransform) {
585 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
586 // (I.e., appying snappedMatrix after aResidualTransform gives the
587 // ideal transform.)
588 *aResidualTransform =
589 Matrix::Translation(matrix2D._31 - snappedTranslation.x,
590 matrix2D._32 - snappedTranslation.y);
592 } else {
593 result = aTransform;
595 return result;
598 Matrix4x4
599 Layer::SnapTransform(const Matrix4x4& aTransform,
600 const gfxRect& aSnapRect,
601 Matrix* aResidualTransform)
603 if (aResidualTransform) {
604 *aResidualTransform = Matrix();
607 Matrix matrix2D;
608 Matrix4x4 result;
609 if (mManager->IsSnappingEffectiveTransforms() &&
610 aTransform.Is2D(&matrix2D) &&
611 gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) &&
612 matrix2D.PreservesAxisAlignedRectangles()) {
613 IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft()));
614 IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight()));
615 IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight()));
617 Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
618 transformedTopLeft, transformedTopRight, transformedBottomRight);
620 result = Matrix4x4::From2D(snappedMatrix);
621 if (aResidualTransform && !snappedMatrix.IsSingular()) {
622 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
623 // (i.e., appying snappedMatrix after aResidualTransform gives the
624 // ideal transform.
625 Matrix snappedMatrixInverse = snappedMatrix;
626 snappedMatrixInverse.Invert();
627 *aResidualTransform = matrix2D * snappedMatrixInverse;
629 } else {
630 result = aTransform;
632 return result;
635 static bool
636 AncestorLayerMayChangeTransform(Layer* aLayer)
638 for (Layer* l = aLayer; l; l = l->GetParent()) {
639 if (l->GetContentFlags() & Layer::CONTENT_MAY_CHANGE_TRANSFORM) {
640 return true;
643 return false;
646 bool
647 Layer::MayResample()
649 Matrix transform2d;
650 return !GetEffectiveTransform().Is2D(&transform2d) ||
651 ThebesMatrix(transform2d).HasNonIntegerTranslation() ||
652 AncestorLayerMayChangeTransform(this);
655 RenderTargetIntRect
656 Layer::CalculateScissorRect(const RenderTargetIntRect& aCurrentScissorRect)
658 ContainerLayer* container = GetParent();
659 NS_ASSERTION(container, "This can't be called on the root!");
661 // Establish initial clip rect: it's either the one passed in, or
662 // if the parent has an intermediate surface, it's the extents of that surface.
663 RenderTargetIntRect currentClip;
664 if (container->UseIntermediateSurface()) {
665 currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
666 } else {
667 currentClip = aCurrentScissorRect;
670 if (!GetEffectiveClipRect()) {
671 return currentClip;
674 const RenderTargetIntRect clipRect = RenderTargetPixel::FromUntyped(*GetEffectiveClipRect());
675 if (clipRect.IsEmpty()) {
676 // We might have a non-translation transform in the container so we can't
677 // use the code path below.
678 return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
681 RenderTargetIntRect scissor = clipRect;
682 if (!container->UseIntermediateSurface()) {
683 gfx::Matrix matrix;
684 DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
685 // See DefaultComputeEffectiveTransforms below
686 NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
687 "Non preserves axis aligned transform with clipped child should have forced intermediate surface");
688 gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
689 gfxRect trScissor = gfx::ThebesRect(matrix.TransformBounds(r));
690 trScissor.Round();
691 nsIntRect tmp;
692 if (!gfxUtils::GfxRectToIntRect(trScissor, &tmp)) {
693 return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
695 scissor = RenderTargetPixel::FromUntyped(tmp);
697 // Find the nearest ancestor with an intermediate surface
698 do {
699 container = container->GetParent();
700 } while (container && !container->UseIntermediateSurface());
703 if (container) {
704 scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
706 return currentClip.Intersect(scissor);
709 const FrameMetrics&
710 Layer::GetFrameMetrics(uint32_t aIndex) const
712 MOZ_ASSERT(aIndex < GetFrameMetricsCount());
713 return mFrameMetrics[aIndex];
716 bool
717 Layer::HasScrollableFrameMetrics() const
719 for (uint32_t i = 0; i < GetFrameMetricsCount(); i++) {
720 if (GetFrameMetrics(i).IsScrollable()) {
721 return true;
724 return false;
727 bool
728 Layer::IsScrollInfoLayer() const
730 // A scrollable container layer with no children
731 return AsContainerLayer()
732 && HasScrollableFrameMetrics()
733 && !GetFirstChild();
736 const Matrix4x4
737 Layer::GetTransform() const
739 Matrix4x4 transform = mTransform;
740 transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f);
741 if (const ContainerLayer* c = AsContainerLayer()) {
742 transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
744 return transform;
747 const Matrix4x4
748 Layer::GetLocalTransform()
750 Matrix4x4 transform;
751 if (LayerComposite* shadow = AsLayerComposite())
752 transform = shadow->GetShadowTransform();
753 else
754 transform = mTransform;
756 transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f);
757 if (ContainerLayer* c = AsContainerLayer()) {
758 transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
761 return transform;
764 bool
765 Layer::HasTransformAnimation() const
767 for (uint32_t i = 0; i < mAnimations.Length(); i++) {
768 if (mAnimations[i].property() == eCSSProperty_transform) {
769 return true;
772 return false;
775 void
776 Layer::ApplyPendingUpdatesForThisTransaction()
778 if (mPendingTransform && *mPendingTransform != mTransform) {
779 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
780 mTransform = *mPendingTransform;
781 Mutated();
783 mPendingTransform = nullptr;
785 if (mPendingAnimations) {
786 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
787 mPendingAnimations->SwapElements(mAnimations);
788 mPendingAnimations = nullptr;
789 Mutated();
793 const float
794 Layer::GetLocalOpacity()
796 if (LayerComposite* shadow = AsLayerComposite())
797 return shadow->GetShadowOpacity();
798 return mOpacity;
801 float
802 Layer::GetEffectiveOpacity()
804 float opacity = GetLocalOpacity();
805 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
806 c = c->GetParent()) {
807 opacity *= c->GetLocalOpacity();
809 return opacity;
812 CompositionOp
813 Layer::GetEffectiveMixBlendMode()
815 if(mMixBlendMode != CompositionOp::OP_OVER)
816 return mMixBlendMode;
817 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
818 c = c->GetParent()) {
819 if(c->mMixBlendMode != CompositionOp::OP_OVER)
820 return c->mMixBlendMode;
823 return mMixBlendMode;
826 gfxContext::GraphicsOperator
827 Layer::DeprecatedGetEffectiveMixBlendMode()
829 return ThebesOp(GetEffectiveMixBlendMode());
832 void
833 Layer::ComputeEffectiveTransformForMaskLayer(const Matrix4x4& aTransformToSurface)
835 if (mMaskLayer) {
836 mMaskLayer->mEffectiveTransform = aTransformToSurface;
838 #ifdef DEBUG
839 bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D();
840 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
841 #endif
842 // The mask layer can have an async transform applied to it in some
843 // situations, so be sure to use its GetLocalTransform() rather than
844 // its GetTransform().
845 mMaskLayer->mEffectiveTransform = mMaskLayer->GetLocalTransform() *
846 mMaskLayer->mEffectiveTransform;
850 RenderTargetRect
851 Layer::TransformRectToRenderTarget(const LayerIntRect& aRect)
853 LayerRect rect(aRect);
854 RenderTargetRect quad = RenderTargetRect::FromUnknown(
855 GetEffectiveTransform().TransformBounds(
856 LayerPixel::ToUnknown(rect)));
857 return quad;
860 ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
861 : Layer(aManager, aImplData),
862 mFirstChild(nullptr),
863 mLastChild(nullptr),
864 mPreXScale(1.0f),
865 mPreYScale(1.0f),
866 mInheritedXScale(1.0f),
867 mInheritedYScale(1.0f),
868 mPresShellResolution(1.0f),
869 mScaleToResolution(false),
870 mUseIntermediateSurface(false),
871 mSupportsComponentAlphaChildren(false),
872 mMayHaveReadbackChild(false),
873 mChildrenChanged(false),
874 mEventRegionsOverride(EventRegionsOverride::NoOverride)
876 mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
879 ContainerLayer::~ContainerLayer() {}
881 bool
882 ContainerLayer::InsertAfter(Layer* aChild, Layer* aAfter)
884 if(aChild->Manager() != Manager()) {
885 NS_ERROR("Child has wrong manager");
886 return false;
888 if(aChild->GetParent()) {
889 NS_ERROR("aChild already in the tree");
890 return false;
892 if (aChild->GetNextSibling() || aChild->GetPrevSibling()) {
893 NS_ERROR("aChild already has siblings?");
894 return false;
896 if (aAfter && (aAfter->Manager() != Manager() ||
897 aAfter->GetParent() != this))
899 NS_ERROR("aAfter is not our child");
900 return false;
903 aChild->SetParent(this);
904 if (aAfter == mLastChild) {
905 mLastChild = aChild;
907 if (!aAfter) {
908 aChild->SetNextSibling(mFirstChild);
909 if (mFirstChild) {
910 mFirstChild->SetPrevSibling(aChild);
912 mFirstChild = aChild;
913 NS_ADDREF(aChild);
914 DidInsertChild(aChild);
915 return true;
918 Layer* next = aAfter->GetNextSibling();
919 aChild->SetNextSibling(next);
920 aChild->SetPrevSibling(aAfter);
921 if (next) {
922 next->SetPrevSibling(aChild);
924 aAfter->SetNextSibling(aChild);
925 NS_ADDREF(aChild);
926 DidInsertChild(aChild);
927 return true;
930 bool
931 ContainerLayer::RemoveChild(Layer *aChild)
933 if (aChild->Manager() != Manager()) {
934 NS_ERROR("Child has wrong manager");
935 return false;
937 if (aChild->GetParent() != this) {
938 NS_ERROR("aChild not our child");
939 return false;
942 Layer* prev = aChild->GetPrevSibling();
943 Layer* next = aChild->GetNextSibling();
944 if (prev) {
945 prev->SetNextSibling(next);
946 } else {
947 this->mFirstChild = next;
949 if (next) {
950 next->SetPrevSibling(prev);
951 } else {
952 this->mLastChild = prev;
955 aChild->SetNextSibling(nullptr);
956 aChild->SetPrevSibling(nullptr);
957 aChild->SetParent(nullptr);
959 this->DidRemoveChild(aChild);
960 NS_RELEASE(aChild);
961 return true;
965 bool
966 ContainerLayer::RepositionChild(Layer* aChild, Layer* aAfter)
968 if (aChild->Manager() != Manager()) {
969 NS_ERROR("Child has wrong manager");
970 return false;
972 if (aChild->GetParent() != this) {
973 NS_ERROR("aChild not our child");
974 return false;
976 if (aAfter && (aAfter->Manager() != Manager() ||
977 aAfter->GetParent() != this))
979 NS_ERROR("aAfter is not our child");
980 return false;
982 if (aChild == aAfter) {
983 NS_ERROR("aChild cannot be the same as aAfter");
984 return false;
987 Layer* prev = aChild->GetPrevSibling();
988 Layer* next = aChild->GetNextSibling();
989 if (prev == aAfter) {
990 // aChild is already in the correct position, nothing to do.
991 return true;
993 if (prev) {
994 prev->SetNextSibling(next);
995 } else {
996 mFirstChild = next;
998 if (next) {
999 next->SetPrevSibling(prev);
1000 } else {
1001 mLastChild = prev;
1003 if (!aAfter) {
1004 aChild->SetPrevSibling(nullptr);
1005 aChild->SetNextSibling(mFirstChild);
1006 if (mFirstChild) {
1007 mFirstChild->SetPrevSibling(aChild);
1009 mFirstChild = aChild;
1010 return true;
1013 Layer* afterNext = aAfter->GetNextSibling();
1014 if (afterNext) {
1015 afterNext->SetPrevSibling(aChild);
1016 } else {
1017 mLastChild = aChild;
1019 aAfter->SetNextSibling(aChild);
1020 aChild->SetPrevSibling(aAfter);
1021 aChild->SetNextSibling(afterNext);
1022 return true;
1025 void
1026 ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
1028 aAttrs = ContainerLayerAttributes(mPreXScale, mPreYScale,
1029 mInheritedXScale, mInheritedYScale,
1030 mPresShellResolution, mScaleToResolution,
1031 mEventRegionsOverride,
1032 reinterpret_cast<uint64_t>(mHMDInfo.get()));
1035 bool
1036 ContainerLayer::HasMultipleChildren()
1038 uint32_t count = 0;
1039 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
1040 const nsIntRect *clipRect = child->GetEffectiveClipRect();
1041 if (clipRect && clipRect->IsEmpty())
1042 continue;
1043 if (child->GetVisibleRegion().IsEmpty())
1044 continue;
1045 ++count;
1046 if (count > 1)
1047 return true;
1050 return false;
1053 void
1054 ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
1056 nsAutoTArray<Layer*, 10> toSort;
1058 for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
1059 ContainerLayer* container = l->AsContainerLayer();
1060 if (container && container->GetContentFlags() & CONTENT_PRESERVE_3D) {
1061 toSort.AppendElement(l);
1062 } else {
1063 if (toSort.Length() > 0) {
1064 SortLayersBy3DZOrder(toSort);
1065 aArray.MoveElementsFrom(toSort);
1067 aArray.AppendElement(l);
1070 if (toSort.Length() > 0) {
1071 SortLayersBy3DZOrder(toSort);
1072 aArray.MoveElementsFrom(toSort);
1076 void
1077 ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
1079 Matrix residual;
1080 Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
1081 idealTransform.ProjectTo2D();
1082 mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
1084 bool useIntermediateSurface;
1085 if (GetMaskLayer() ||
1086 GetForceIsolatedGroup()) {
1087 useIntermediateSurface = true;
1088 #ifdef MOZ_DUMP_PAINTING
1089 } else if (gfxUtils::sDumpPainting) {
1090 useIntermediateSurface = true;
1091 #endif
1092 } else {
1093 float opacity = GetEffectiveOpacity();
1094 CompositionOp blendMode = GetEffectiveMixBlendMode();
1095 if ((opacity != 1.0f || blendMode != CompositionOp::OP_OVER) && HasMultipleChildren()) {
1096 useIntermediateSurface = true;
1097 } else {
1098 useIntermediateSurface = false;
1099 gfx::Matrix contTransform;
1100 if (!mEffectiveTransform.Is2D(&contTransform) ||
1101 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
1102 !contTransform.PreservesAxisAlignedRectangles()) {
1103 #else
1104 gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) {
1105 #endif
1106 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
1107 const nsIntRect *clipRect = child->GetEffectiveClipRect();
1108 /* We can't (easily) forward our transform to children with a non-empty clip
1109 * rect since it would need to be adjusted for the transform. See
1110 * the calculations performed by CalculateScissorRect above.
1111 * Nor for a child with a mask layer.
1113 if ((clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) ||
1114 child->GetMaskLayer()) {
1115 useIntermediateSurface = true;
1116 break;
1123 mUseIntermediateSurface = useIntermediateSurface && !GetEffectiveVisibleRegion().IsEmpty();
1124 if (useIntermediateSurface) {
1125 ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual));
1126 } else {
1127 ComputeEffectiveTransformsForChildren(idealTransform);
1130 if (idealTransform.CanDraw2D()) {
1131 ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
1132 } else {
1133 ComputeEffectiveTransformForMaskLayer(Matrix4x4());
1137 void
1138 ContainerLayer::DefaultComputeSupportsComponentAlphaChildren(bool* aNeedsSurfaceCopy)
1140 if (!(GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT) ||
1141 !Manager()->AreComponentAlphaLayersEnabled()) {
1142 mSupportsComponentAlphaChildren = false;
1143 if (aNeedsSurfaceCopy) {
1144 *aNeedsSurfaceCopy = false;
1146 return;
1149 mSupportsComponentAlphaChildren = false;
1150 bool needsSurfaceCopy = false;
1151 CompositionOp blendMode = GetEffectiveMixBlendMode();
1152 if (UseIntermediateSurface()) {
1153 if (GetEffectiveVisibleRegion().GetNumRects() == 1 &&
1154 (GetContentFlags() & Layer::CONTENT_OPAQUE))
1156 mSupportsComponentAlphaChildren = true;
1157 } else {
1158 gfx::Matrix transform;
1159 if (HasOpaqueAncestorLayer(this) &&
1160 GetEffectiveTransform().Is2D(&transform) &&
1161 !gfx::ThebesMatrix(transform).HasNonIntegerTranslation() &&
1162 blendMode == gfx::CompositionOp::OP_OVER) {
1163 mSupportsComponentAlphaChildren = true;
1164 needsSurfaceCopy = true;
1167 } else if (blendMode == gfx::CompositionOp::OP_OVER) {
1168 mSupportsComponentAlphaChildren =
1169 (GetContentFlags() & Layer::CONTENT_OPAQUE) ||
1170 (GetParent() && GetParent()->SupportsComponentAlphaChildren());
1173 if (aNeedsSurfaceCopy) {
1174 *aNeedsSurfaceCopy = mSupportsComponentAlphaChildren && needsSurfaceCopy;
1178 void
1179 ContainerLayer::ComputeEffectiveTransformsForChildren(const Matrix4x4& aTransformToSurface)
1181 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
1182 l->ComputeEffectiveTransforms(aTransformToSurface);
1186 /* static */ bool
1187 ContainerLayer::HasOpaqueAncestorLayer(Layer* aLayer)
1189 for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
1190 if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
1191 return true;
1193 return false;
1196 void
1197 ContainerLayer::DidRemoveChild(Layer* aLayer)
1199 PaintedLayer* tl = aLayer->AsPaintedLayer();
1200 if (tl && tl->UsedForReadback()) {
1201 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
1202 if (l->GetType() == TYPE_READBACK) {
1203 static_cast<ReadbackLayer*>(l)->NotifyPaintedLayerRemoved(tl);
1207 if (aLayer->GetType() == TYPE_READBACK) {
1208 static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
1212 void
1213 ContainerLayer::DidInsertChild(Layer* aLayer)
1215 if (aLayer->GetType() == TYPE_READBACK) {
1216 mMayHaveReadbackChild = true;
1220 void
1221 RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
1223 aAttrs = RefLayerAttributes(GetReferentId(), mEventRegionsOverride);
1226 /**
1227 * StartFrameTimeRecording, together with StopFrameTimeRecording
1228 * enable recording of frame intervals.
1230 * To allow concurrent consumers, a cyclic array is used which serves all
1231 * consumers, practically stateless with regard to consumers.
1233 * To save resources, the buffer is allocated on first call to StartFrameTimeRecording
1234 * and recording is paused if no consumer which called StartFrameTimeRecording is able
1235 * to get valid results (because the cyclic buffer was overwritten since that call).
1237 * To determine availability of the data upon StopFrameTimeRecording:
1238 * - mRecording.mNextIndex increases on each PostPresent, and never resets.
1239 * - Cyclic buffer position is realized as mNextIndex % bufferSize.
1240 * - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is called,
1241 * the required start index is passed as an arg, and we're able to calculate the required
1242 * length. If this length is bigger than bufferSize, it means data was overwritten.
1243 * otherwise, we can return the entire sequence.
1244 * - To determine if we need to pause, mLatestStartIndex is updated to mNextIndex
1245 * on each call to StartFrameTimeRecording. If this index gets overwritten,
1246 * it means that all earlier start indices obtained via StartFrameTimeRecording
1247 * were also overwritten, hence, no point in recording, so pause.
1248 * - mCurrentRunStartIndex indicates the oldest index of the recording after which
1249 * the recording was not paused. If StopFrameTimeRecording is invoked with a start index
1250 * older than this, it means that some frames were not recorded, so data is invalid.
1252 uint32_t
1253 LayerManager::StartFrameTimeRecording(int32_t aBufferSize)
1255 if (mRecording.mIsPaused) {
1256 mRecording.mIsPaused = false;
1258 if (!mRecording.mIntervals.Length()) { // Initialize recording buffers
1259 mRecording.mIntervals.SetLength(aBufferSize);
1262 // After being paused, recent values got invalid. Update them to now.
1263 mRecording.mLastFrameTime = TimeStamp::Now();
1265 // Any recording which started before this is invalid, since we were paused.
1266 mRecording.mCurrentRunStartIndex = mRecording.mNextIndex;
1269 // If we'll overwrite this index, there are no more consumers with aStartIndex
1270 // for which we're able to provide the full recording, so no point in keep recording.
1271 mRecording.mLatestStartIndex = mRecording.mNextIndex;
1272 return mRecording.mNextIndex;
1275 void
1276 LayerManager::RecordFrame()
1278 if (!mRecording.mIsPaused) {
1279 TimeStamp now = TimeStamp::Now();
1280 uint32_t i = mRecording.mNextIndex % mRecording.mIntervals.Length();
1281 mRecording.mIntervals[i] = static_cast<float>((now - mRecording.mLastFrameTime)
1282 .ToMilliseconds());
1283 mRecording.mNextIndex++;
1284 mRecording.mLastFrameTime = now;
1286 if (mRecording.mNextIndex > (mRecording.mLatestStartIndex + mRecording.mIntervals.Length())) {
1287 // We've just overwritten the most recent recording start -> pause.
1288 mRecording.mIsPaused = true;
1293 void
1294 LayerManager::PostPresent()
1296 if (!mTabSwitchStart.IsNull()) {
1297 Telemetry::Accumulate(Telemetry::FX_TAB_SWITCH_TOTAL_MS,
1298 uint32_t((TimeStamp::Now() - mTabSwitchStart).ToMilliseconds()));
1299 mTabSwitchStart = TimeStamp();
1303 void
1304 LayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
1305 nsTArray<float>& aFrameIntervals)
1307 uint32_t bufferSize = mRecording.mIntervals.Length();
1308 uint32_t length = mRecording.mNextIndex - aStartIndex;
1309 if (mRecording.mIsPaused || length > bufferSize || aStartIndex < mRecording.mCurrentRunStartIndex) {
1310 // aStartIndex is too old. Also if aStartIndex was issued before mRecordingNextIndex overflowed (uint32_t)
1311 // and stopped after the overflow (would happen once every 828 days of constant 60fps).
1312 length = 0;
1315 if (!length) {
1316 aFrameIntervals.Clear();
1317 return; // empty recording, return empty arrays.
1319 // Set length in advance to avoid possibly repeated reallocations
1320 aFrameIntervals.SetLength(length);
1322 uint32_t cyclicPos = aStartIndex % bufferSize;
1323 for (uint32_t i = 0; i < length; i++, cyclicPos++) {
1324 if (cyclicPos == bufferSize) {
1325 cyclicPos = 0;
1327 aFrameIntervals[i] = mRecording.mIntervals[cyclicPos];
1331 void
1332 LayerManager::BeginTabSwitch()
1334 mTabSwitchStart = TimeStamp::Now();
1337 static void PrintInfo(std::stringstream& aStream, LayerComposite* aLayerComposite);
1339 #ifdef MOZ_DUMP_PAINTING
1340 template <typename T>
1341 void WriteSnapshotLinkToDumpFile(T* aObj, std::stringstream& aStream)
1343 if (!aObj) {
1344 return;
1346 nsCString string(aObj->Name());
1347 string.Append('-');
1348 string.AppendInt((uint64_t)aObj);
1349 aStream << nsPrintfCString("href=\"javascript:ViewImage('%s')\"", string.BeginReading()).get();
1352 template <typename T>
1353 void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
1355 nsCString string(aObj->Name());
1356 string.Append('-');
1357 string.AppendInt((uint64_t)aObj);
1358 if (gfxUtils::sDumpPaintFile) {
1359 fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
1361 gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile);
1362 if (gfxUtils::sDumpPaintFile) {
1363 fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
1367 void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf)
1369 WriteSnapshotToDumpFile_internal(aLayer, aSurf);
1372 void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf)
1374 WriteSnapshotToDumpFile_internal(aManager, aSurf);
1377 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
1379 RefPtr<SourceSurface> surf = aTarget->Snapshot();
1380 RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
1381 WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
1383 #endif
1385 void
1386 Layer::Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml)
1388 if (aDumpHtml) {
1389 aStream << nsPrintfCString("<li><a id=\"%p\" ", this).get();
1390 #ifdef MOZ_DUMP_PAINTING
1391 if (GetType() == TYPE_CONTAINER || GetType() == TYPE_PAINTED) {
1392 WriteSnapshotLinkToDumpFile(this, aStream);
1394 #endif
1395 aStream << ">";
1397 DumpSelf(aStream, aPrefix);
1399 #ifdef MOZ_DUMP_PAINTING
1400 if (gfxUtils::sDumpPainting && AsLayerComposite() && AsLayerComposite()->GetCompositableHost()) {
1401 AsLayerComposite()->GetCompositableHost()->Dump(aStream, aPrefix, aDumpHtml);
1403 #endif
1405 if (aDumpHtml) {
1406 aStream << "</a>";
1409 if (Layer* mask = GetMaskLayer()) {
1410 aStream << nsPrintfCString("%s Mask layer:\n", aPrefix).get();
1411 nsAutoCString pfx(aPrefix);
1412 pfx += " ";
1413 mask->Dump(aStream, pfx.get(), aDumpHtml);
1416 #ifdef MOZ_DUMP_PAINTING
1417 for (size_t i = 0; i < mExtraDumpInfo.Length(); i++) {
1418 const nsCString& str = mExtraDumpInfo[i];
1419 aStream << aPrefix << " Info:\n" << str.get();
1421 #endif
1423 if (Layer* kid = GetFirstChild()) {
1424 nsAutoCString pfx(aPrefix);
1425 pfx += " ";
1426 if (aDumpHtml) {
1427 aStream << "<ul>";
1429 kid->Dump(aStream, pfx.get(), aDumpHtml);
1430 if (aDumpHtml) {
1431 aStream << "</ul>";
1435 if (aDumpHtml) {
1436 aStream << "</li>";
1438 if (Layer* next = GetNextSibling())
1439 next->Dump(aStream, aPrefix, aDumpHtml);
1442 void
1443 Layer::DumpSelf(std::stringstream& aStream, const char* aPrefix)
1445 PrintInfo(aStream, aPrefix);
1446 aStream << "\n";
1449 void
1450 Layer::Dump(layerscope::LayersPacket* aPacket, const void* aParent)
1452 DumpPacket(aPacket, aParent);
1454 if (Layer* kid = GetFirstChild()) {
1455 kid->Dump(aPacket, this);
1458 if (Layer* next = GetNextSibling()) {
1459 next->Dump(aPacket, aParent);
1463 void
1464 Layer::Log(const char* aPrefix)
1466 if (!IsLogEnabled())
1467 return;
1469 LogSelf(aPrefix);
1471 if (Layer* kid = GetFirstChild()) {
1472 nsAutoCString pfx(aPrefix);
1473 pfx += " ";
1474 kid->Log(pfx.get());
1477 if (Layer* next = GetNextSibling())
1478 next->Log(aPrefix);
1481 void
1482 Layer::LogSelf(const char* aPrefix)
1484 if (!IsLogEnabled())
1485 return;
1487 std::stringstream ss;
1488 PrintInfo(ss, aPrefix);
1489 MOZ_LAYERS_LOG(("%s", ss.str().c_str()));
1491 if (mMaskLayer) {
1492 nsAutoCString pfx(aPrefix);
1493 pfx += " \\ MaskLayer ";
1494 mMaskLayer->LogSelf(pfx.get());
1498 void
1499 Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1501 aStream << aPrefix;
1502 aStream << nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this).get();
1504 layers::PrintInfo(aStream, AsLayerComposite());
1506 if (mUseClipRect) {
1507 AppendToString(aStream, mClipRect, " [clip=", "]");
1509 if (1.0 != mPostXScale || 1.0 != mPostYScale) {
1510 aStream << nsPrintfCString(" [postScale=%g, %g]", mPostXScale, mPostYScale).get();
1512 if (!mTransform.IsIdentity()) {
1513 AppendToString(aStream, mTransform, " [transform=", "]");
1515 if (!mLayerBounds.IsEmpty()) {
1516 AppendToString(aStream, mLayerBounds, " [bounds=", "]");
1518 if (!mVisibleRegion.IsEmpty()) {
1519 AppendToString(aStream, mVisibleRegion, " [visible=", "]");
1520 } else {
1521 aStream << " [not visible]";
1523 if (!mEventRegions.IsEmpty()) {
1524 AppendToString(aStream, mEventRegions, " ", "");
1526 if (1.0 != mOpacity) {
1527 aStream << nsPrintfCString(" [opacity=%g]", mOpacity).get();
1529 if (GetContentFlags() & CONTENT_OPAQUE) {
1530 aStream << " [opaqueContent]";
1532 if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
1533 aStream << " [componentAlpha]";
1535 if (GetScrollbarDirection() == VERTICAL) {
1536 aStream << nsPrintfCString(" [vscrollbar=%lld]", GetScrollbarTargetContainerId()).get();
1538 if (GetScrollbarDirection() == HORIZONTAL) {
1539 aStream << nsPrintfCString(" [hscrollbar=%lld]", GetScrollbarTargetContainerId()).get();
1541 if (GetIsFixedPosition()) {
1542 aStream << nsPrintfCString(" [isFixedPosition anchor=%s margin=%f,%f,%f,%f]",
1543 ToString(mAnchor).c_str(),
1544 mMargins.top, mMargins.right, mMargins.bottom, mMargins.left).get();
1546 if (GetIsStickyPosition()) {
1547 aStream << nsPrintfCString(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f "
1548 "inner=%f,%f %fx%f]", mStickyPositionData->mScrollId,
1549 mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y,
1550 mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height,
1551 mStickyPositionData->mInner.x, mStickyPositionData->mInner.y,
1552 mStickyPositionData->mInner.width, mStickyPositionData->mInner.height).get();
1554 if (mMaskLayer) {
1555 aStream << nsPrintfCString(" [mMaskLayer=%p]", mMaskLayer.get()).get();
1557 for (uint32_t i = 0; i < mFrameMetrics.Length(); i++) {
1558 if (!mFrameMetrics[i].IsDefault()) {
1559 aStream << nsPrintfCString(" [metrics%d=", i).get();
1560 AppendToString(aStream, mFrameMetrics[i], "", "]");
1565 // The static helper function sets the transform matrix into the packet
1566 static void
1567 DumpTransform(layerscope::LayersPacket::Layer::Matrix* aLayerMatrix, const Matrix4x4& aMatrix)
1569 aLayerMatrix->set_is2d(aMatrix.Is2D());
1570 if (aMatrix.Is2D()) {
1571 Matrix m = aMatrix.As2D();
1572 aLayerMatrix->set_isid(m.IsIdentity());
1573 if (!m.IsIdentity()) {
1574 aLayerMatrix->add_m(m._11), aLayerMatrix->add_m(m._12);
1575 aLayerMatrix->add_m(m._21), aLayerMatrix->add_m(m._22);
1576 aLayerMatrix->add_m(m._31), aLayerMatrix->add_m(m._32);
1578 } else {
1579 aLayerMatrix->add_m(aMatrix._11), aLayerMatrix->add_m(aMatrix._12);
1580 aLayerMatrix->add_m(aMatrix._13), aLayerMatrix->add_m(aMatrix._14);
1581 aLayerMatrix->add_m(aMatrix._21), aLayerMatrix->add_m(aMatrix._22);
1582 aLayerMatrix->add_m(aMatrix._23), aLayerMatrix->add_m(aMatrix._24);
1583 aLayerMatrix->add_m(aMatrix._31), aLayerMatrix->add_m(aMatrix._32);
1584 aLayerMatrix->add_m(aMatrix._33), aLayerMatrix->add_m(aMatrix._34);
1585 aLayerMatrix->add_m(aMatrix._41), aLayerMatrix->add_m(aMatrix._42);
1586 aLayerMatrix->add_m(aMatrix._43), aLayerMatrix->add_m(aMatrix._44);
1590 // The static helper function sets the nsIntRect into the packet
1591 static void
1592 DumpRect(layerscope::LayersPacket::Layer::Rect* aLayerRect, const nsIntRect& aRect)
1594 aLayerRect->set_x(aRect.x);
1595 aLayerRect->set_y(aRect.y);
1596 aLayerRect->set_w(aRect.width);
1597 aLayerRect->set_h(aRect.height);
1600 // The static helper function sets the nsIntRegion into the packet
1601 static void
1602 DumpRegion(layerscope::LayersPacket::Layer::Region* aLayerRegion, const nsIntRegion& aRegion)
1604 nsIntRegionRectIterator it(aRegion);
1605 while (const nsIntRect* sr = it.Next()) {
1606 DumpRect(aLayerRegion->add_r(), *sr);
1610 void
1611 Layer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1613 // Add a new layer (UnknownLayer)
1614 using namespace layerscope;
1615 LayersPacket::Layer* layer = aPacket->add_layer();
1616 // Basic information
1617 layer->set_type(LayersPacket::Layer::UnknownLayer);
1618 layer->set_ptr(reinterpret_cast<uint64_t>(this));
1619 layer->set_parentptr(reinterpret_cast<uint64_t>(aParent));
1620 // Shadow
1621 if (LayerComposite* lc = AsLayerComposite()) {
1622 LayersPacket::Layer::Shadow* s = layer->mutable_shadow();
1623 if (const nsIntRect* clipRect = lc->GetShadowClipRect()) {
1624 DumpRect(s->mutable_clip(), *clipRect);
1626 if (!lc->GetShadowTransform().IsIdentity()) {
1627 DumpTransform(s->mutable_transform(), lc->GetShadowTransform());
1629 if (!lc->GetShadowVisibleRegion().IsEmpty()) {
1630 DumpRegion(s->mutable_vregion(), lc->GetShadowVisibleRegion());
1633 // Clip
1634 if (mUseClipRect) {
1635 DumpRect(layer->mutable_clip(), mClipRect);
1637 // Transform
1638 if (!mTransform.IsIdentity()) {
1639 DumpTransform(layer->mutable_transform(), mTransform);
1641 // Visible region
1642 if (!mVisibleRegion.IsEmpty()) {
1643 DumpRegion(layer->mutable_vregion(), mVisibleRegion);
1645 // Opacity
1646 layer->set_opacity(mOpacity);
1647 // Content opaque
1648 layer->set_copaque(static_cast<bool>(GetContentFlags() & CONTENT_OPAQUE));
1649 // Component alpha
1650 layer->set_calpha(static_cast<bool>(GetContentFlags() & CONTENT_COMPONENT_ALPHA));
1651 // Vertical or horizontal bar
1652 if (GetScrollbarDirection() != NONE) {
1653 layer->set_direct(GetScrollbarDirection() == VERTICAL ?
1654 LayersPacket::Layer::VERTICAL :
1655 LayersPacket::Layer::HORIZONTAL);
1656 layer->set_barid(GetScrollbarTargetContainerId());
1658 // Mask layer
1659 if (mMaskLayer) {
1660 layer->set_mask(reinterpret_cast<uint64_t>(mMaskLayer.get()));
1664 void
1665 PaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1667 Layer::PrintInfo(aStream, aPrefix);
1668 if (!mValidRegion.IsEmpty()) {
1669 AppendToString(aStream, mValidRegion, " [valid=", "]");
1673 void
1674 PaintedLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1676 Layer::DumpPacket(aPacket, aParent);
1677 // get this layer data
1678 using namespace layerscope;
1679 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1680 layer->set_type(LayersPacket::Layer::PaintedLayer);
1681 if (!mValidRegion.IsEmpty()) {
1682 DumpRegion(layer->mutable_valid(), mValidRegion);
1686 void
1687 ContainerLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1689 Layer::PrintInfo(aStream, aPrefix);
1690 if (UseIntermediateSurface()) {
1691 aStream << " [usesTmpSurf]";
1693 if (1.0 != mPreXScale || 1.0 != mPreYScale) {
1694 aStream << nsPrintfCString(" [preScale=%g, %g]", mPreXScale, mPreYScale).get();
1696 if (mScaleToResolution) {
1697 aStream << nsPrintfCString(" [presShellResolution=%g]", mPresShellResolution).get();
1699 if (mEventRegionsOverride & EventRegionsOverride::ForceDispatchToContent) {
1700 aStream << " [force-dtc]";
1702 if (mEventRegionsOverride & EventRegionsOverride::ForceEmptyHitRegion) {
1703 aStream << " [force-ehr]";
1705 if (mHMDInfo) {
1706 aStream << nsPrintfCString(" [hmd=%p]", mHMDInfo.get()).get();
1710 void
1711 ContainerLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1713 Layer::DumpPacket(aPacket, aParent);
1714 // Get this layer data
1715 using namespace layerscope;
1716 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1717 layer->set_type(LayersPacket::Layer::ContainerLayer);
1720 void
1721 ColorLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1723 Layer::PrintInfo(aStream, aPrefix);
1724 AppendToString(aStream, mColor, " [color=", "]");
1727 void
1728 ColorLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1730 Layer::DumpPacket(aPacket, aParent);
1731 // Get this layer data
1732 using namespace layerscope;
1733 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1734 layer->set_type(LayersPacket::Layer::ColorLayer);
1735 layer->set_color(mColor.Packed());
1738 void
1739 CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1741 Layer::PrintInfo(aStream, aPrefix);
1742 if (mFilter != GraphicsFilter::FILTER_GOOD) {
1743 AppendToString(aStream, mFilter, " [filter=", "]");
1747 // This help function is used to assign the correct enum value
1748 // to the packet
1749 static void
1750 DumpFilter(layerscope::LayersPacket::Layer* aLayer, const GraphicsFilter& aFilter)
1752 using namespace layerscope;
1753 switch (aFilter) {
1754 case GraphicsFilter::FILTER_FAST:
1755 aLayer->set_filter(LayersPacket::Layer::FILTER_FAST);
1756 break;
1757 case GraphicsFilter::FILTER_GOOD:
1758 aLayer->set_filter(LayersPacket::Layer::FILTER_GOOD);
1759 break;
1760 case GraphicsFilter::FILTER_BEST:
1761 aLayer->set_filter(LayersPacket::Layer::FILTER_BEST);
1762 break;
1763 case GraphicsFilter::FILTER_NEAREST:
1764 aLayer->set_filter(LayersPacket::Layer::FILTER_NEAREST);
1765 break;
1766 case GraphicsFilter::FILTER_BILINEAR:
1767 aLayer->set_filter(LayersPacket::Layer::FILTER_BILINEAR);
1768 break;
1769 case GraphicsFilter::FILTER_GAUSSIAN:
1770 aLayer->set_filter(LayersPacket::Layer::FILTER_GAUSSIAN);
1771 break;
1772 default:
1773 // ignore it
1774 break;
1778 void
1779 CanvasLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1781 Layer::DumpPacket(aPacket, aParent);
1782 // Get this layer data
1783 using namespace layerscope;
1784 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1785 layer->set_type(LayersPacket::Layer::CanvasLayer);
1786 DumpFilter(layer, mFilter);
1789 void
1790 ImageLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1792 Layer::PrintInfo(aStream, aPrefix);
1793 if (mFilter != GraphicsFilter::FILTER_GOOD) {
1794 AppendToString(aStream, mFilter, " [filter=", "]");
1798 void
1799 ImageLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1801 Layer::DumpPacket(aPacket, aParent);
1802 // Get this layer data
1803 using namespace layerscope;
1804 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1805 layer->set_type(LayersPacket::Layer::ImageLayer);
1806 DumpFilter(layer, mFilter);
1809 void
1810 RefLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1812 ContainerLayer::PrintInfo(aStream, aPrefix);
1813 if (0 != mId) {
1814 AppendToString(aStream, mId, " [id=", "]");
1818 void
1819 RefLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1821 Layer::DumpPacket(aPacket, aParent);
1822 // Get this layer data
1823 using namespace layerscope;
1824 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1825 layer->set_type(LayersPacket::Layer::RefLayer);
1826 layer->set_refid(mId);
1829 void
1830 ReadbackLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1832 Layer::PrintInfo(aStream, aPrefix);
1833 AppendToString(aStream, mSize, " [size=", "]");
1834 if (mBackgroundLayer) {
1835 AppendToString(aStream, mBackgroundLayer, " [backgroundLayer=", "]");
1836 AppendToString(aStream, mBackgroundLayerOffset, " [backgroundOffset=", "]");
1837 } else if (mBackgroundColor.a == 1.0) {
1838 AppendToString(aStream, mBackgroundColor, " [backgroundColor=", "]");
1839 } else {
1840 aStream << " [nobackground]";
1844 void
1845 ReadbackLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
1847 Layer::DumpPacket(aPacket, aParent);
1848 // Get this layer data
1849 using namespace layerscope;
1850 LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
1851 layer->set_type(LayersPacket::Layer::ReadbackLayer);
1852 LayersPacket::Layer::Size* size = layer->mutable_size();
1853 size->set_w(mSize.width);
1854 size->set_h(mSize.height);
1857 //--------------------------------------------------
1858 // LayerManager
1860 void
1861 LayerManager::Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml)
1863 #ifdef MOZ_DUMP_PAINTING
1864 if (aDumpHtml) {
1865 aStream << "<ul><li><a ";
1866 WriteSnapshotLinkToDumpFile(this, aStream);
1867 aStream << ">";
1869 #endif
1870 DumpSelf(aStream, aPrefix);
1871 #ifdef MOZ_DUMP_PAINTING
1872 if (aDumpHtml) {
1873 aStream << "</a>";
1875 #endif
1877 nsAutoCString pfx(aPrefix);
1878 pfx += " ";
1879 if (!GetRoot()) {
1880 aStream << nsPrintfCString("%s(null)", pfx.get()).get();
1881 if (aDumpHtml) {
1882 aStream << "</li></ul>";
1884 return;
1887 if (aDumpHtml) {
1888 aStream << "<ul>";
1890 GetRoot()->Dump(aStream, pfx.get(), aDumpHtml);
1891 if (aDumpHtml) {
1892 aStream << "</ul></li></ul>";
1894 aStream << "\n";
1897 void
1898 LayerManager::DumpSelf(std::stringstream& aStream, const char* aPrefix)
1900 PrintInfo(aStream, aPrefix);
1901 aStream << "\n";
1904 void
1905 LayerManager::Dump()
1907 std::stringstream ss;
1908 Dump(ss);
1909 print_stderr(ss);
1912 void
1913 LayerManager::Dump(layerscope::LayersPacket* aPacket)
1915 DumpPacket(aPacket);
1917 if (GetRoot()) {
1918 GetRoot()->Dump(aPacket, this);
1922 void
1923 LayerManager::Log(const char* aPrefix)
1925 if (!IsLogEnabled())
1926 return;
1928 LogSelf(aPrefix);
1930 nsAutoCString pfx(aPrefix);
1931 pfx += " ";
1932 if (!GetRoot()) {
1933 MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
1934 return;
1937 GetRoot()->Log(pfx.get());
1940 void
1941 LayerManager::LogSelf(const char* aPrefix)
1943 nsAutoCString str;
1944 std::stringstream ss;
1945 PrintInfo(ss, aPrefix);
1946 MOZ_LAYERS_LOG(("%s", ss.str().c_str()));
1949 void
1950 LayerManager::PrintInfo(std::stringstream& aStream, const char* aPrefix)
1952 aStream << aPrefix << nsPrintfCString("%sLayerManager (0x%p)", Name(), this).get();
1955 void
1956 LayerManager::DumpPacket(layerscope::LayersPacket* aPacket)
1958 using namespace layerscope;
1959 // Add a new layer data (LayerManager)
1960 LayersPacket::Layer* layer = aPacket->add_layer();
1961 layer->set_type(LayersPacket::Layer::LayerManager);
1962 layer->set_ptr(reinterpret_cast<uint64_t>(this));
1963 // Layer Tree Root
1964 layer->set_parentptr(0);
1967 /*static*/ void
1968 LayerManager::InitLog()
1970 if (!sLog)
1971 sLog = PR_NewLogModule("Layers");
1974 /*static*/ bool
1975 LayerManager::IsLogEnabled()
1977 NS_ABORT_IF_FALSE(!!sLog,
1978 "layer manager must be created before logging is allowed");
1979 return PR_LOG_TEST(sLog, PR_LOG_DEBUG);
1982 void
1983 PrintInfo(std::stringstream& aStream, LayerComposite* aLayerComposite)
1985 if (!aLayerComposite) {
1986 return;
1988 if (const nsIntRect* clipRect = aLayerComposite->GetShadowClipRect()) {
1989 AppendToString(aStream, *clipRect, " [shadow-clip=", "]");
1991 if (!aLayerComposite->GetShadowTransform().IsIdentity()) {
1992 AppendToString(aStream, aLayerComposite->GetShadowTransform(), " [shadow-transform=", "]");
1994 if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
1995 AppendToString(aStream, aLayerComposite->GetShadowVisibleRegion(), " [shadow-visible=", "]");
1999 void
2000 SetAntialiasingFlags(Layer* aLayer, DrawTarget* aTarget)
2002 bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
2003 if (aTarget->GetFormat() != SurfaceFormat::B8G8R8A8) {
2004 aTarget->SetPermitSubpixelAA(permitSubpixelAA);
2005 return;
2008 const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
2009 gfx::Rect transformedBounds = aTarget->GetTransform().TransformBounds(gfx::Rect(Float(bounds.x), Float(bounds.y),
2010 Float(bounds.width), Float(bounds.height)));
2011 transformedBounds.RoundOut();
2012 IntRect intTransformedBounds;
2013 transformedBounds.ToIntRect(&intTransformedBounds);
2014 permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
2015 aTarget->GetOpaqueRect().Contains(intTransformedBounds);
2016 aTarget->SetPermitSubpixelAA(permitSubpixelAA);
2019 nsIntRect
2020 ToOutsideIntRect(const gfxRect &aRect)
2022 gfxRect r = aRect;
2023 r.RoundOut();
2024 return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
2027 PRLogModuleInfo* LayerManager::sLog;
2029 } // namespace layers
2030 } // namespace mozilla