backout 29799f914cab, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / gfx / layers / Layers.cpp
blobab16c665a0de39177784f2997b7f58ffea368d73
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 "AnimationCommon.h" // for ComputedTimingFunction
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 "gfxUtils.h" // for gfxUtils, etc
19 #include "mozilla/DebugOnly.h" // for DebugOnly
20 #include "mozilla/Preferences.h" // for Preferences
21 #include "mozilla/Telemetry.h" // for Accumulate
22 #include "mozilla/TelemetryHistogramEnums.h"
23 #include "mozilla/gfx/2D.h" // for DrawTarget
24 #include "mozilla/gfx/BaseSize.h" // for BaseSize
25 #include "mozilla/layers/AsyncPanZoomController.h"
26 #include "mozilla/layers/Compositor.h" // for Compositor
27 #include "mozilla/layers/CompositorTypes.h"
28 #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite
29 #include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
30 #include "nsAString.h"
31 #include "nsCSSValue.h" // for nsCSSValue::Array, etc
32 #include "nsPrintfCString.h" // for nsPrintfCString
33 #include "nsStyleStruct.h" // for nsTimingFunction, etc
35 using namespace mozilla::layers;
36 using namespace mozilla::gfx;
38 typedef FrameMetrics::ViewID ViewID;
39 const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
40 const ViewID FrameMetrics::ROOT_SCROLL_ID = 1;
41 const ViewID FrameMetrics::START_SCROLL_ID = 2;
43 uint8_t gLayerManagerLayerBuilder;
45 #ifdef MOZ_LAYERS_HAVE_LOG
46 FILE*
47 FILEOrDefault(FILE* aFile)
49 return aFile ? aFile : stderr;
51 #endif // MOZ_LAYERS_HAVE_LOG
53 namespace mozilla {
54 namespace layers {
56 //--------------------------------------------------
57 // LayerManager
58 Layer*
59 LayerManager::GetPrimaryScrollableLayer()
61 if (!mRoot) {
62 return nullptr;
65 nsTArray<Layer*> queue;
66 queue.AppendElement(mRoot);
67 while (queue.Length()) {
68 ContainerLayer* containerLayer = queue[0]->AsContainerLayer();
69 queue.RemoveElementAt(0);
70 if (!containerLayer) {
71 continue;
74 const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
75 if (frameMetrics.IsScrollable()) {
76 return containerLayer;
79 Layer* child = containerLayer->GetFirstChild();
80 while (child) {
81 queue.AppendElement(child);
82 child = child->GetNextSibling();
86 return mRoot;
89 void
90 LayerManager::GetScrollableLayers(nsTArray<Layer*>& aArray)
92 if (!mRoot) {
93 return;
96 nsTArray<Layer*> queue;
97 queue.AppendElement(mRoot);
98 while (!queue.IsEmpty()) {
99 ContainerLayer* containerLayer = queue.LastElement()->AsContainerLayer();
100 queue.RemoveElementAt(queue.Length() - 1);
101 if (!containerLayer) {
102 continue;
105 const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
106 if (frameMetrics.IsScrollable()) {
107 aArray.AppendElement(containerLayer);
108 continue;
111 Layer* child = containerLayer->GetFirstChild();
112 while (child) {
113 queue.AppendElement(child);
114 child = child->GetNextSibling();
119 already_AddRefed<gfxASurface>
120 LayerManager::CreateOptimalSurface(const gfxIntSize &aSize,
121 gfxImageFormat aFormat)
123 return gfxPlatform::GetPlatform()->
124 CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFormat));
127 already_AddRefed<gfxASurface>
128 LayerManager::CreateOptimalMaskSurface(const gfxIntSize &aSize)
130 return CreateOptimalSurface(aSize, gfxImageFormatA8);
133 TemporaryRef<DrawTarget>
134 LayerManager::CreateDrawTarget(const IntSize &aSize,
135 SurfaceFormat aFormat)
137 return gfxPlatform::GetPlatform()->
138 CreateOffscreenCanvasDrawTarget(aSize, aFormat);
141 TextureFactoryIdentifier
142 LayerManager::GetTextureFactoryIdentifier()
144 //TODO[nrc] make pure virtual when all layer managers use Compositor
145 NS_ERROR("Should have been overridden");
146 return TextureFactoryIdentifier();
150 #ifdef DEBUG
151 void
152 LayerManager::Mutated(Layer* aLayer)
155 #endif // DEBUG
157 already_AddRefed<ImageContainer>
158 LayerManager::CreateImageContainer()
160 nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::DISABLE_ASYNC);
161 return container.forget();
164 already_AddRefed<ImageContainer>
165 LayerManager::CreateAsynchronousImageContainer()
167 nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::ENABLE_ASYNC);
168 return container.forget();
171 //--------------------------------------------------
172 // Layer
174 Layer::Layer(LayerManager* aManager, void* aImplData) :
175 mManager(aManager),
176 mParent(nullptr),
177 mNextSibling(nullptr),
178 mPrevSibling(nullptr),
179 mImplData(aImplData),
180 mMaskLayer(nullptr),
181 mPostXScale(1.0f),
182 mPostYScale(1.0f),
183 mOpacity(1.0),
184 mMixBlendMode(gfxContext::OPERATOR_OVER),
185 mForceIsolatedGroup(false),
186 mContentFlags(0),
187 mUseClipRect(false),
188 mUseTileSourceRect(false),
189 mIsFixedPosition(false),
190 mMargins(0, 0, 0, 0),
191 mStickyPositionData(nullptr),
192 mDebugColorIndex(0),
193 mAnimationGeneration(0)
196 Layer::~Layer()
199 Animation*
200 Layer::AddAnimation(TimeStamp aStart, TimeDuration aDuration, float aIterations,
201 int aDirection, nsCSSProperty aProperty, const AnimationData& aData)
203 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) AddAnimation", this));
205 Animation* anim = mAnimations.AppendElement();
206 anim->startTime() = aStart;
207 anim->duration() = aDuration;
208 anim->numIterations() = aIterations;
209 anim->direction() = aDirection;
210 anim->property() = aProperty;
211 anim->data() = aData;
213 Mutated();
214 return anim;
217 void
218 Layer::ClearAnimations()
220 if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
221 return;
224 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClearAnimations", this));
225 mAnimations.Clear();
226 mAnimationData.Clear();
227 Mutated();
230 static nsCSSValueList*
231 CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
233 nsAutoPtr<nsCSSValueList> result;
234 nsCSSValueList** resultTail = getter_Transfers(result);
235 for (uint32_t i = 0; i < aFunctions.Length(); i++) {
236 nsRefPtr<nsCSSValue::Array> arr;
237 switch (aFunctions[i].type()) {
238 case TransformFunction::TRotationX:
240 float theta = aFunctions[i].get_RotationX().radians();
241 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatex, resultTail);
242 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
243 break;
245 case TransformFunction::TRotationY:
247 float theta = aFunctions[i].get_RotationY().radians();
248 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatey, resultTail);
249 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
250 break;
252 case TransformFunction::TRotationZ:
254 float theta = aFunctions[i].get_RotationZ().radians();
255 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatez, resultTail);
256 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
257 break;
259 case TransformFunction::TRotation:
261 float theta = aFunctions[i].get_Rotation().radians();
262 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotate, resultTail);
263 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
264 break;
266 case TransformFunction::TRotation3D:
268 float x = aFunctions[i].get_Rotation3D().x();
269 float y = aFunctions[i].get_Rotation3D().y();
270 float z = aFunctions[i].get_Rotation3D().z();
271 float theta = aFunctions[i].get_Rotation3D().radians();
272 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotate3d, resultTail);
273 arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
274 arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
275 arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
276 arr->Item(4).SetFloatValue(theta, eCSSUnit_Radian);
277 break;
279 case TransformFunction::TScale:
281 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_scale3d, resultTail);
282 arr->Item(1).SetFloatValue(aFunctions[i].get_Scale().x(), eCSSUnit_Number);
283 arr->Item(2).SetFloatValue(aFunctions[i].get_Scale().y(), eCSSUnit_Number);
284 arr->Item(3).SetFloatValue(aFunctions[i].get_Scale().z(), eCSSUnit_Number);
285 break;
287 case TransformFunction::TTranslation:
289 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_translate3d, resultTail);
290 arr->Item(1).SetFloatValue(aFunctions[i].get_Translation().x(), eCSSUnit_Pixel);
291 arr->Item(2).SetFloatValue(aFunctions[i].get_Translation().y(), eCSSUnit_Pixel);
292 arr->Item(3).SetFloatValue(aFunctions[i].get_Translation().z(), eCSSUnit_Pixel);
293 break;
295 case TransformFunction::TSkewX:
297 float x = aFunctions[i].get_SkewX().x();
298 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skewx, resultTail);
299 arr->Item(1).SetFloatValue(x, eCSSUnit_Radian);
300 break;
302 case TransformFunction::TSkewY:
304 float y = aFunctions[i].get_SkewY().y();
305 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skewy, resultTail);
306 arr->Item(1).SetFloatValue(y, eCSSUnit_Radian);
307 break;
309 case TransformFunction::TSkew:
311 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skew, resultTail);
312 arr->Item(1).SetFloatValue(aFunctions[i].get_Skew().x(), eCSSUnit_Radian);
313 arr->Item(2).SetFloatValue(aFunctions[i].get_Skew().y(), eCSSUnit_Radian);
314 break;
316 case TransformFunction::TTransformMatrix:
318 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_matrix3d, resultTail);
319 const gfx3DMatrix& matrix = aFunctions[i].get_TransformMatrix().value();
320 arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
321 arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
322 arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
323 arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number);
324 arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number);
325 arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number);
326 arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number);
327 arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number);
328 arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number);
329 arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number);
330 arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number);
331 arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number);
332 arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number);
333 arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number);
334 arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number);
335 arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number);
336 break;
338 case TransformFunction::TPerspective:
340 float perspective = aFunctions[i].get_Perspective().value();
341 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_perspective, resultTail);
342 arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel);
343 break;
345 default:
346 NS_ASSERTION(false, "All functions should be implemented?");
349 if (aFunctions.Length() == 0) {
350 result = new nsCSSValueList();
351 result->mValue.SetNoneValue();
353 return result.forget();
356 void
357 Layer::SetAnimations(const AnimationArray& aAnimations)
359 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) SetAnimations", this));
361 mAnimations = aAnimations;
362 mAnimationData.Clear();
363 for (uint32_t i = 0; i < mAnimations.Length(); i++) {
364 AnimData* data = mAnimationData.AppendElement();
365 InfallibleTArray<nsAutoPtr<css::ComputedTimingFunction> >& functions = data->mFunctions;
366 const InfallibleTArray<AnimationSegment>& segments =
367 mAnimations.ElementAt(i).segments();
368 for (uint32_t j = 0; j < segments.Length(); j++) {
369 TimingFunction tf = segments.ElementAt(j).sampleFn();
370 css::ComputedTimingFunction* ctf = new css::ComputedTimingFunction();
371 switch (tf.type()) {
372 case TimingFunction::TCubicBezierFunction: {
373 CubicBezierFunction cbf = tf.get_CubicBezierFunction();
374 ctf->Init(nsTimingFunction(cbf.x1(), cbf.y1(), cbf.x2(), cbf.y2()));
375 break;
377 default: {
378 NS_ASSERTION(tf.type() == TimingFunction::TStepFunction,
379 "Function must be bezier or step");
380 StepFunction sf = tf.get_StepFunction();
381 nsTimingFunction::Type type = sf.type() == 1 ? nsTimingFunction::StepStart
382 : nsTimingFunction::StepEnd;
383 ctf->Init(nsTimingFunction(type, sf.steps()));
384 break;
387 functions.AppendElement(ctf);
390 // Precompute the nsStyleAnimation::Values that we need if this is a transform
391 // animation.
392 InfallibleTArray<nsStyleAnimation::Value>& startValues = data->mStartValues;
393 InfallibleTArray<nsStyleAnimation::Value>& endValues = data->mEndValues;
394 for (uint32_t j = 0; j < mAnimations[i].segments().Length(); j++) {
395 const AnimationSegment& segment = mAnimations[i].segments()[j];
396 nsStyleAnimation::Value* startValue = startValues.AppendElement();
397 nsStyleAnimation::Value* endValue = endValues.AppendElement();
398 if (segment.endState().type() == Animatable::TArrayOfTransformFunction) {
399 const InfallibleTArray<TransformFunction>& startFunctions =
400 segment.startState().get_ArrayOfTransformFunction();
401 startValue->SetAndAdoptCSSValueListValue(CreateCSSValueList(startFunctions),
402 nsStyleAnimation::eUnit_Transform);
404 const InfallibleTArray<TransformFunction>& endFunctions =
405 segment.endState().get_ArrayOfTransformFunction();
406 endValue->SetAndAdoptCSSValueListValue(CreateCSSValueList(endFunctions),
407 nsStyleAnimation::eUnit_Transform);
408 } else {
409 NS_ASSERTION(segment.endState().type() == Animatable::Tfloat,
410 "Unknown Animatable type");
411 startValue->SetFloatValue(segment.startState().get_float());
412 endValue->SetFloatValue(segment.endState().get_float());
417 Mutated();
420 void
421 ContainerLayer::SetAsyncPanZoomController(AsyncPanZoomController *controller)
423 mAPZC = controller;
426 AsyncPanZoomController*
427 ContainerLayer::GetAsyncPanZoomController() const
429 #ifdef DEBUG
430 if (mAPZC) {
431 MOZ_ASSERT(GetFrameMetrics().IsScrollable());
433 #endif
434 return mAPZC;
437 void
438 Layer::ApplyPendingUpdatesToSubtree()
440 ApplyPendingUpdatesForThisTransaction();
441 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
442 child->ApplyPendingUpdatesToSubtree();
446 bool
447 Layer::CanUseOpaqueSurface()
449 // If the visible content in the layer is opaque, there is no need
450 // for an alpha channel.
451 if (GetContentFlags() & CONTENT_OPAQUE)
452 return true;
453 // Also, if this layer is the bottommost layer in a container which
454 // doesn't need an alpha channel, we can use an opaque surface for this
455 // layer too. Any transparent areas must be covered by something else
456 // in the container.
457 ContainerLayer* parent = GetParent();
458 return parent && parent->GetFirstChild() == this &&
459 parent->CanUseOpaqueSurface();
462 // NB: eventually these methods will be defined unconditionally, and
463 // can be moved into Layers.h
464 const nsIntRect*
465 Layer::GetEffectiveClipRect()
467 if (LayerComposite* shadow = AsLayerComposite()) {
468 return shadow->GetShadowClipRect();
470 return GetClipRect();
473 const nsIntRegion&
474 Layer::GetEffectiveVisibleRegion()
476 if (LayerComposite* shadow = AsLayerComposite()) {
477 return shadow->GetShadowVisibleRegion();
479 return GetVisibleRegion();
482 gfx3DMatrix
483 Layer::SnapTransformTranslation(const gfx3DMatrix& aTransform,
484 gfxMatrix* aResidualTransform)
486 if (aResidualTransform) {
487 *aResidualTransform = gfxMatrix();
490 gfxMatrix matrix2D;
491 gfx3DMatrix result;
492 if (mManager->IsSnappingEffectiveTransforms() &&
493 aTransform.Is2D(&matrix2D) &&
494 !matrix2D.HasNonTranslation() &&
495 matrix2D.HasNonIntegerTranslation()) {
496 gfxPoint snappedTranslation(matrix2D.GetTranslation());
497 snappedTranslation.Round();
498 gfxMatrix snappedMatrix = gfxMatrix().Translate(snappedTranslation);
499 result = gfx3DMatrix::From2D(snappedMatrix);
500 if (aResidualTransform) {
501 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
502 // (I.e., appying snappedMatrix after aResidualTransform gives the
503 // ideal transform.)
504 *aResidualTransform =
505 gfxMatrix().Translate(matrix2D.GetTranslation() - snappedTranslation);
507 } else {
508 result = aTransform;
510 return result;
513 gfx3DMatrix
514 Layer::SnapTransform(const gfx3DMatrix& aTransform,
515 const gfxRect& aSnapRect,
516 gfxMatrix* aResidualTransform)
518 if (aResidualTransform) {
519 *aResidualTransform = gfxMatrix();
522 gfxMatrix matrix2D;
523 gfx3DMatrix result;
524 if (mManager->IsSnappingEffectiveTransforms() &&
525 aTransform.Is2D(&matrix2D) &&
526 gfxSize(1.0, 1.0) <= aSnapRect.Size() &&
527 matrix2D.PreservesAxisAlignedRectangles()) {
528 gfxPoint transformedTopLeft = matrix2D.Transform(aSnapRect.TopLeft());
529 transformedTopLeft.Round();
530 gfxPoint transformedTopRight = matrix2D.Transform(aSnapRect.TopRight());
531 transformedTopRight.Round();
532 gfxPoint transformedBottomRight = matrix2D.Transform(aSnapRect.BottomRight());
533 transformedBottomRight.Round();
535 gfxMatrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
536 transformedTopLeft, transformedTopRight, transformedBottomRight);
538 result = gfx3DMatrix::From2D(snappedMatrix);
539 if (aResidualTransform && !snappedMatrix.IsSingular()) {
540 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
541 // (i.e., appying snappedMatrix after aResidualTransform gives the
542 // ideal transform.
543 gfxMatrix snappedMatrixInverse = snappedMatrix;
544 snappedMatrixInverse.Invert();
545 *aResidualTransform = matrix2D * snappedMatrixInverse;
547 } else {
548 result = aTransform;
550 return result;
553 static bool
554 AncestorLayerMayChangeTransform(Layer* aLayer)
556 for (Layer* l = aLayer; l; l = l->GetParent()) {
557 if (l->GetContentFlags() & Layer::CONTENT_MAY_CHANGE_TRANSFORM) {
558 return true;
561 return false;
564 bool
565 Layer::MayResample()
567 gfxMatrix transform2d;
568 return !GetEffectiveTransform().Is2D(&transform2d) ||
569 transform2d.HasNonIntegerTranslation() ||
570 AncestorLayerMayChangeTransform(this);
573 nsIntRect
574 Layer::CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
575 const gfxMatrix* aWorldTransform)
577 ContainerLayer* container = GetParent();
578 NS_ASSERTION(container, "This can't be called on the root!");
580 // Establish initial clip rect: it's either the one passed in, or
581 // if the parent has an intermediate surface, it's the extents of that surface.
582 nsIntRect currentClip;
583 if (container->UseIntermediateSurface()) {
584 currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
585 } else {
586 currentClip = aCurrentScissorRect;
589 const nsIntRect *clipRect = GetEffectiveClipRect();
590 if (!clipRect)
591 return currentClip;
593 if (clipRect->IsEmpty()) {
594 // We might have a non-translation transform in the container so we can't
595 // use the code path below.
596 return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
599 nsIntRect scissor = *clipRect;
600 if (!container->UseIntermediateSurface()) {
601 gfxMatrix matrix;
602 DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
603 // See DefaultComputeEffectiveTransforms below
604 NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
605 "Non preserves axis aligned transform with clipped child should have forced intermediate surface");
606 gfxRect r(scissor.x, scissor.y, scissor.width, scissor.height);
607 gfxRect trScissor = matrix.TransformBounds(r);
608 trScissor.Round();
609 if (!gfxUtils::GfxRectToIntRect(trScissor, &scissor)) {
610 return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
613 // Find the nearest ancestor with an intermediate surface
614 do {
615 container = container->GetParent();
616 } while (container && !container->UseIntermediateSurface());
618 if (container) {
619 scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
620 } else if (aWorldTransform) {
621 gfxRect r(scissor.x, scissor.y, scissor.width, scissor.height);
622 gfxRect trScissor = aWorldTransform->TransformBounds(r);
623 trScissor.Round();
624 if (!gfxUtils::GfxRectToIntRect(trScissor, &scissor))
625 return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
627 return currentClip.Intersect(scissor);
630 const gfx3DMatrix
631 Layer::GetTransform() const
633 gfx3DMatrix transform = mTransform;
634 if (const ContainerLayer* c = AsContainerLayer()) {
635 transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
637 transform.ScalePost(mPostXScale, mPostYScale, 1.0f);
638 return transform;
641 const gfx3DMatrix
642 Layer::GetLocalTransform()
644 gfx3DMatrix transform;
645 if (LayerComposite* shadow = AsLayerComposite())
646 transform = shadow->GetShadowTransform();
647 else
648 transform = mTransform;
649 if (ContainerLayer* c = AsContainerLayer()) {
650 transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
652 transform.ScalePost(mPostXScale, mPostYScale, 1.0f);
653 return transform;
656 void
657 Layer::ApplyPendingUpdatesForThisTransaction()
659 if (mPendingTransform && *mPendingTransform != mTransform) {
660 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
661 mTransform = *mPendingTransform;
662 Mutated();
664 mPendingTransform = nullptr;
667 const float
668 Layer::GetLocalOpacity()
670 if (LayerComposite* shadow = AsLayerComposite())
671 return shadow->GetShadowOpacity();
672 return mOpacity;
675 float
676 Layer::GetEffectiveOpacity()
678 float opacity = GetLocalOpacity();
679 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
680 c = c->GetParent()) {
681 opacity *= c->GetLocalOpacity();
683 return opacity;
686 gfxContext::GraphicsOperator
687 Layer::GetEffectiveMixBlendMode()
689 if(mMixBlendMode != gfxContext::OPERATOR_OVER)
690 return mMixBlendMode;
691 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
692 c = c->GetParent()) {
693 if(c->mMixBlendMode != gfxContext::OPERATOR_OVER)
694 return c->mMixBlendMode;
697 return mMixBlendMode;
700 void
701 Layer::ComputeEffectiveTransformForMaskLayer(const gfx3DMatrix& aTransformToSurface)
703 if (mMaskLayer) {
704 mMaskLayer->mEffectiveTransform = aTransformToSurface;
706 #ifdef DEBUG
707 gfxMatrix maskTranslation;
708 bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D(&maskTranslation);
709 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
710 #endif
711 mMaskLayer->mEffectiveTransform.PreMultiply(mMaskLayer->GetTransform());
715 ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
716 : Layer(aManager, aImplData),
717 mFirstChild(nullptr),
718 mLastChild(nullptr),
719 mPreXScale(1.0f),
720 mPreYScale(1.0f),
721 mInheritedXScale(1.0f),
722 mInheritedYScale(1.0f),
723 mUseIntermediateSurface(false),
724 mSupportsComponentAlphaChildren(false),
725 mMayHaveReadbackChild(false)
727 mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
730 ContainerLayer::~ContainerLayer() {}
732 void
733 ContainerLayer::InsertAfter(Layer* aChild, Layer* aAfter)
735 NS_ASSERTION(aChild->Manager() == Manager(),
736 "Child has wrong manager");
737 NS_ASSERTION(!aChild->GetParent(),
738 "aChild already in the tree");
739 NS_ASSERTION(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
740 "aChild already has siblings?");
741 NS_ASSERTION(!aAfter ||
742 (aAfter->Manager() == Manager() &&
743 aAfter->GetParent() == this),
744 "aAfter is not our child");
746 aChild->SetParent(this);
747 if (aAfter == mLastChild) {
748 mLastChild = aChild;
750 if (!aAfter) {
751 aChild->SetNextSibling(mFirstChild);
752 if (mFirstChild) {
753 mFirstChild->SetPrevSibling(aChild);
755 mFirstChild = aChild;
756 NS_ADDREF(aChild);
757 DidInsertChild(aChild);
758 return;
761 Layer* next = aAfter->GetNextSibling();
762 aChild->SetNextSibling(next);
763 aChild->SetPrevSibling(aAfter);
764 if (next) {
765 next->SetPrevSibling(aChild);
767 aAfter->SetNextSibling(aChild);
768 NS_ADDREF(aChild);
769 DidInsertChild(aChild);
772 void
773 ContainerLayer::RemoveChild(Layer *aChild)
775 NS_ASSERTION(aChild->Manager() == Manager(),
776 "Child has wrong manager");
777 NS_ASSERTION(aChild->GetParent() == this,
778 "aChild not our child");
780 Layer* prev = aChild->GetPrevSibling();
781 Layer* next = aChild->GetNextSibling();
782 if (prev) {
783 prev->SetNextSibling(next);
784 } else {
785 this->mFirstChild = next;
787 if (next) {
788 next->SetPrevSibling(prev);
789 } else {
790 this->mLastChild = prev;
793 aChild->SetNextSibling(nullptr);
794 aChild->SetPrevSibling(nullptr);
795 aChild->SetParent(nullptr);
797 this->DidRemoveChild(aChild);
798 NS_RELEASE(aChild);
802 void
803 ContainerLayer::RepositionChild(Layer* aChild, Layer* aAfter)
805 NS_ASSERTION(aChild->Manager() == Manager(),
806 "Child has wrong manager");
807 NS_ASSERTION(aChild->GetParent() == this,
808 "aChild not our child");
809 NS_ASSERTION(!aAfter ||
810 (aAfter->Manager() == Manager() &&
811 aAfter->GetParent() == this),
812 "aAfter is not our child");
814 Layer* prev = aChild->GetPrevSibling();
815 Layer* next = aChild->GetNextSibling();
816 if (prev == aAfter) {
817 // aChild is already in the correct position, nothing to do.
818 return;
820 if (prev) {
821 prev->SetNextSibling(next);
823 if (next) {
824 next->SetPrevSibling(prev);
826 if (!aAfter) {
827 aChild->SetPrevSibling(nullptr);
828 aChild->SetNextSibling(mFirstChild);
829 if (mFirstChild) {
830 mFirstChild->SetPrevSibling(aChild);
832 mFirstChild = aChild;
833 return;
836 Layer* afterNext = aAfter->GetNextSibling();
837 if (afterNext) {
838 afterNext->SetPrevSibling(aChild);
839 } else {
840 mLastChild = aChild;
842 aAfter->SetNextSibling(aChild);
843 aChild->SetPrevSibling(aAfter);
844 aChild->SetNextSibling(afterNext);
847 void
848 ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
850 aAttrs = ContainerLayerAttributes(GetFrameMetrics(), mPreXScale, mPreYScale,
851 mInheritedXScale, mInheritedYScale);
854 bool
855 ContainerLayer::HasMultipleChildren()
857 uint32_t count = 0;
858 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
859 const nsIntRect *clipRect = child->GetEffectiveClipRect();
860 if (clipRect && clipRect->IsEmpty())
861 continue;
862 if (child->GetVisibleRegion().IsEmpty())
863 continue;
864 ++count;
865 if (count > 1)
866 return true;
869 return false;
872 void
873 ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
875 nsAutoTArray<Layer*, 10> toSort;
877 for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
878 ContainerLayer* container = l->AsContainerLayer();
879 if (container && container->GetContentFlags() & CONTENT_PRESERVE_3D) {
880 toSort.AppendElement(l);
881 } else {
882 if (toSort.Length() > 0) {
883 SortLayersBy3DZOrder(toSort);
884 aArray.MoveElementsFrom(toSort);
886 aArray.AppendElement(l);
889 if (toSort.Length() > 0) {
890 SortLayersBy3DZOrder(toSort);
891 aArray.MoveElementsFrom(toSort);
895 void
896 ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
898 gfxMatrix residual;
899 gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
900 idealTransform.ProjectTo2D();
901 mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
903 bool useIntermediateSurface;
904 if (GetMaskLayer()) {
905 useIntermediateSurface = true;
906 #ifdef MOZ_DUMP_PAINTING
907 } else if (gfxUtils::sDumpPainting) {
908 useIntermediateSurface = true;
909 #endif
910 } else {
911 float opacity = GetEffectiveOpacity();
912 if (opacity != 1.0f && HasMultipleChildren()) {
913 useIntermediateSurface = true;
914 } else {
915 useIntermediateSurface = false;
916 gfxMatrix contTransform;
917 if (!mEffectiveTransform.Is2D(&contTransform) ||
918 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
919 !contTransform.PreservesAxisAlignedRectangles()) {
920 #else
921 contTransform.HasNonIntegerTranslation()) {
922 #endif
923 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
924 const nsIntRect *clipRect = child->GetEffectiveClipRect();
925 /* We can't (easily) forward our transform to children with a non-empty clip
926 * rect since it would need to be adjusted for the transform. See
927 * the calculations performed by CalculateScissorRect above.
928 * Nor for a child with a mask layer.
930 if ((clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) ||
931 child->GetMaskLayer()) {
932 useIntermediateSurface = true;
933 break;
940 mUseIntermediateSurface = useIntermediateSurface;
941 if (useIntermediateSurface) {
942 ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual));
943 } else {
944 ComputeEffectiveTransformsForChildren(idealTransform);
947 if (idealTransform.CanDraw2D()) {
948 ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
949 } else {
950 ComputeEffectiveTransformForMaskLayer(gfx3DMatrix());
954 void
955 ContainerLayer::ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface)
957 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
958 l->ComputeEffectiveTransforms(aTransformToSurface);
962 /* static */ bool
963 ContainerLayer::HasOpaqueAncestorLayer(Layer* aLayer)
965 for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
966 if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
967 return true;
969 return false;
972 void
973 ContainerLayer::DidRemoveChild(Layer* aLayer)
975 ThebesLayer* tl = aLayer->AsThebesLayer();
976 if (tl && tl->UsedForReadback()) {
977 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
978 if (l->GetType() == TYPE_READBACK) {
979 static_cast<ReadbackLayer*>(l)->NotifyThebesLayerRemoved(tl);
983 if (aLayer->GetType() == TYPE_READBACK) {
984 static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
988 void
989 ContainerLayer::DidInsertChild(Layer* aLayer)
991 if (aLayer->GetType() == TYPE_READBACK) {
992 mMayHaveReadbackChild = true;
996 void
997 RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
999 aAttrs = RefLayerAttributes(GetReferentId());
1002 /**
1003 * StartFrameTimeRecording, together with StopFrameTimeRecording
1004 * enable recording of frame intrvals and paint times.
1005 * (Paint start time is set from the refresh driver right before starting
1006 * flush/paint and ends at PostPresent. Intervals are measured at PostPresent).
1008 * To allow concurrent consumers, 2 cyclic arrays are used (for intervals, paints)
1009 * which serve all consumers, practically stateless with regard to consumers.
1011 * To save resources, the buffers are allocated on first call to StartFrameTimeRecording
1012 * and recording is paused if no consumer which called StartFrameTimeRecording is able
1013 * to get valid results (because the cyclic buffers were overwritten since that call).
1015 * To determine availability of the data upon StopFrameTimeRecording:
1016 * - mRecording.mNextIndex increases on each PostPresent, and never resets.
1017 * - Cyclic buffer position is realized as mNextIndex % bufferSize.
1018 * - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is called,
1019 * the required start index is passed as an arg, and we're able to calculate the required
1020 * length. If this length is bigger than bufferSize, it means data was overwritten.
1021 * otherwise, we can return the entire sequence.
1022 * - To determine if we need to pause, mLatestStartIndex is updated to mNextIndex
1023 * on each call to StartFrameTimeRecording. If this index gets overwritten,
1024 * it means that all earlier start indices obtained via StartFrameTimeRecording
1025 * were also overwritten, hence, no point in recording, so pause.
1026 * - mCurrentRunStartIndex indicates the oldest index of the recording after which
1027 * the recording was not paused. If StopFrameTimeRecording is invoked with a start index
1028 * older than this, it means that some frames were not recorded, so data is invalid.
1030 uint32_t
1031 LayerManager::StartFrameTimeRecording()
1033 if (mRecording.mIsPaused) {
1034 mRecording.mIsPaused = false;
1036 if (!mRecording.mIntervals.Length()) { // Initialize recording buffers
1037 const uint32_t kRecordingMinSize = 60 * 10; // 10 seconds @60 fps.
1038 const uint32_t kRecordingMaxSize = 60 * 60 * 60; // One hour
1039 uint32_t bufferSize = Preferences::GetUint("toolkit.framesRecording.bufferSize",
1040 kRecordingMinSize);
1041 bufferSize = std::min(bufferSize, kRecordingMaxSize);
1042 bufferSize = std::max(bufferSize, kRecordingMinSize);
1044 if (!mRecording.mIntervals.SetLength(bufferSize) || !mRecording.mPaints.SetLength(bufferSize)) {
1045 mRecording.mIsPaused = true; // OOM
1046 mRecording.mIntervals.Clear();
1047 mRecording.mPaints.Clear();
1051 // After being paused, recent values got invalid. Update them to now.
1052 mRecording.mLastFrameTime = TimeStamp::Now();
1053 mRecording.mPaintStartTime = mRecording.mLastFrameTime;
1055 // Any recording which started before this is invalid, since we were paused.
1056 mRecording.mCurrentRunStartIndex = mRecording.mNextIndex;
1059 // If we'll overwrite this index, there are no more consumers with aStartIndex
1060 // for which we're able to provide the full recording, so no point in keep recording.
1061 mRecording.mLatestStartIndex = mRecording.mNextIndex;
1062 return mRecording.mNextIndex;
1065 void
1066 LayerManager::SetPaintStartTime(TimeStamp& aTime)
1068 if (!mRecording.mIsPaused) {
1069 mRecording.mPaintStartTime = aTime;
1073 void
1074 LayerManager::PostPresent()
1076 if (!mRecording.mIsPaused) {
1077 TimeStamp now = TimeStamp::Now();
1078 uint32_t i = mRecording.mNextIndex % mRecording.mIntervals.Length();
1079 mRecording.mIntervals[i] = static_cast<float>((now - mRecording.mLastFrameTime)
1080 .ToMilliseconds());
1081 mRecording.mPaints[i] = static_cast<float>((now - mRecording.mPaintStartTime)
1082 .ToMilliseconds());
1083 mRecording.mNextIndex++;
1084 mRecording.mLastFrameTime = now;
1086 if (mRecording.mNextIndex > (mRecording.mLatestStartIndex + mRecording.mIntervals.Length())) {
1087 // We've just overwritten the most recent recording start -> pause.
1088 mRecording.mIsPaused = true;
1091 if (!mTabSwitchStart.IsNull()) {
1092 Telemetry::Accumulate(Telemetry::FX_TAB_SWITCH_TOTAL_MS,
1093 uint32_t((TimeStamp::Now() - mTabSwitchStart).ToMilliseconds()));
1094 mTabSwitchStart = TimeStamp();
1098 void
1099 LayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
1100 nsTArray<float>& aFrameIntervals,
1101 nsTArray<float>& aPaintTimes)
1103 uint32_t bufferSize = mRecording.mIntervals.Length();
1104 uint32_t length = mRecording.mNextIndex - aStartIndex;
1105 if (mRecording.mIsPaused || length > bufferSize || aStartIndex < mRecording.mCurrentRunStartIndex) {
1106 // aStartIndex is too old. Also if aStartIndex was issued before mRecordingNextIndex overflowed (uint32_t)
1107 // and stopped after the overflow (would happen once every 828 days of constant 60fps).
1108 length = 0;
1111 // Set length in advance to avoid possibly repeated reallocations (and OOM checks).
1112 if (!length || !aFrameIntervals.SetLength(length) || !aPaintTimes.SetLength(length)) {
1113 aFrameIntervals.Clear();
1114 aPaintTimes.Clear();
1115 return; // empty recording or OOM, return empty arrays.
1118 uint32_t cyclicPos = aStartIndex % bufferSize;
1119 for (uint32_t i = 0; i < length; i++, cyclicPos++) {
1120 if (cyclicPos == bufferSize) {
1121 cyclicPos = 0;
1123 aFrameIntervals[i] = mRecording.mIntervals[cyclicPos];
1124 aPaintTimes[i] = mRecording.mPaints[cyclicPos];
1128 void
1129 LayerManager::BeginTabSwitch()
1131 mTabSwitchStart = TimeStamp::Now();
1134 #ifdef MOZ_LAYERS_HAVE_LOG
1136 static nsACString& PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite);
1138 #ifdef MOZ_DUMP_PAINTING
1139 template <typename T>
1140 void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
1142 if (!aObj) {
1143 return;
1145 nsCString string(aObj->Name());
1146 string.Append("-");
1147 string.AppendInt((uint64_t)aObj);
1148 fprintf(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
1151 template <typename T>
1152 void WriteSnapshotToDumpFile_internal(T* aObj, gfxASurface* aSurf)
1154 nsCString string(aObj->Name());
1155 string.Append("-");
1156 string.AppendInt((uint64_t)aObj);
1157 if (gfxUtils::sDumpPaintFile)
1158 fprintf(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
1159 aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
1160 if (gfxUtils::sDumpPaintFile)
1161 fprintf(gfxUtils::sDumpPaintFile, "\";");
1164 void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf)
1166 WriteSnapshotToDumpFile_internal(aLayer, aSurf);
1169 void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf)
1171 WriteSnapshotToDumpFile_internal(aManager, aSurf);
1174 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
1176 nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aTarget);
1177 WriteSnapshotToDumpFile_internal(aCompositor, surf);
1179 #endif
1181 void
1182 Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
1184 if (aDumpHtml) {
1185 fprintf(aFile, "<li><a id=\"%p\" ", this);
1186 #ifdef MOZ_DUMP_PAINTING
1187 if (GetType() == TYPE_CONTAINER || GetType() == TYPE_THEBES) {
1188 WriteSnapshotLinkToDumpFile(this, aFile);
1190 #endif
1191 fprintf(aFile, ">");
1193 DumpSelf(aFile, aPrefix);
1195 #ifdef MOZ_DUMP_PAINTING
1196 if (AsLayerComposite() && AsLayerComposite()->GetCompositableHost()) {
1197 AsLayerComposite()->GetCompositableHost()->Dump(aFile, aPrefix, aDumpHtml);
1199 #endif
1201 if (aDumpHtml) {
1202 fprintf(aFile, "</a>");
1205 if (Layer* mask = GetMaskLayer()) {
1206 nsAutoCString pfx(aPrefix);
1207 pfx += " Mask layer: ";
1208 mask->Dump(aFile, pfx.get(), aDumpHtml);
1211 if (Layer* kid = GetFirstChild()) {
1212 nsAutoCString pfx(aPrefix);
1213 pfx += " ";
1214 if (aDumpHtml) {
1215 fprintf(aFile, "<ul>");
1217 kid->Dump(aFile, pfx.get(), aDumpHtml);
1218 if (aDumpHtml) {
1219 fprintf(aFile, "</ul>");
1223 if (aDumpHtml) {
1224 fprintf(aFile, "</li>");
1226 if (Layer* next = GetNextSibling())
1227 next->Dump(aFile, aPrefix, aDumpHtml);
1230 void
1231 Layer::DumpSelf(FILE* aFile, const char* aPrefix)
1233 nsAutoCString str;
1234 PrintInfo(str, aPrefix);
1235 if (!aFile || aFile == stderr) {
1236 printf_stderr("%s\n", str.get());
1237 } else {
1238 fprintf(aFile, "%s\n", str.get());
1242 void
1243 Layer::Log(const char* aPrefix)
1245 if (!IsLogEnabled())
1246 return;
1248 LogSelf(aPrefix);
1250 if (Layer* kid = GetFirstChild()) {
1251 nsAutoCString pfx(aPrefix);
1252 pfx += " ";
1253 kid->Log(pfx.get());
1256 if (Layer* next = GetNextSibling())
1257 next->Log(aPrefix);
1260 void
1261 Layer::LogSelf(const char* aPrefix)
1263 if (!IsLogEnabled())
1264 return;
1266 nsAutoCString str;
1267 PrintInfo(str, aPrefix);
1268 MOZ_LAYERS_LOG(("%s", str.get()));
1271 nsACString&
1272 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
1274 aTo += aPrefix;
1275 aTo += nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this);
1277 ::PrintInfo(aTo, AsLayerComposite());
1279 if (mUseClipRect) {
1280 AppendToString(aTo, mClipRect, " [clip=", "]");
1282 if (1.0 != mPostXScale || 1.0 != mPostYScale) {
1283 aTo.AppendPrintf(" [postScale=%g, %g]", mPostXScale, mPostYScale);
1285 if (!mTransform.IsIdentity()) {
1286 AppendToString(aTo, mTransform, " [transform=", "]");
1288 if (!mVisibleRegion.IsEmpty()) {
1289 AppendToString(aTo, mVisibleRegion, " [visible=", "]");
1290 } else {
1291 aTo += " [not visible]";
1293 if (1.0 != mOpacity) {
1294 aTo.AppendPrintf(" [opacity=%g]", mOpacity);
1296 if (GetContentFlags() & CONTENT_OPAQUE) {
1297 aTo += " [opaqueContent]";
1299 if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
1300 aTo += " [componentAlpha]";
1302 if (GetIsFixedPosition()) {
1303 aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f]", mAnchor.x, mAnchor.y);
1305 if (GetIsStickyPosition()) {
1306 aTo.AppendPrintf(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f "
1307 "inner=%f,%f %fx%f]", mStickyPositionData->mScrollId,
1308 mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y,
1309 mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height,
1310 mStickyPositionData->mInner.x, mStickyPositionData->mInner.y,
1311 mStickyPositionData->mInner.width, mStickyPositionData->mInner.height);
1314 return aTo;
1317 nsACString&
1318 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1320 Layer::PrintInfo(aTo, aPrefix);
1321 if (!mValidRegion.IsEmpty()) {
1322 AppendToString(aTo, mValidRegion, " [valid=", "]");
1324 return aTo;
1327 nsACString&
1328 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1330 Layer::PrintInfo(aTo, aPrefix);
1331 if (!mFrameMetrics.IsDefault()) {
1332 AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
1334 if (UseIntermediateSurface()) {
1335 aTo += " [usesTmpSurf]";
1337 if (1.0 != mPreXScale || 1.0 != mPreYScale) {
1338 aTo.AppendPrintf(" [preScale=%g, %g]", mPreXScale, mPreYScale);
1340 return aTo;
1343 nsACString&
1344 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1346 Layer::PrintInfo(aTo, aPrefix);
1347 AppendToString(aTo, mColor, " [color=", "]");
1348 return aTo;
1351 nsACString&
1352 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1354 Layer::PrintInfo(aTo, aPrefix);
1355 if (mFilter != GraphicsFilter::FILTER_GOOD) {
1356 AppendToString(aTo, mFilter, " [filter=", "]");
1358 return aTo;
1361 nsACString&
1362 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1364 Layer::PrintInfo(aTo, aPrefix);
1365 if (mFilter != GraphicsFilter::FILTER_GOOD) {
1366 AppendToString(aTo, mFilter, " [filter=", "]");
1368 return aTo;
1371 nsACString&
1372 RefLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1374 ContainerLayer::PrintInfo(aTo, aPrefix);
1375 if (0 != mId) {
1376 AppendToString(aTo, mId, " [id=", "]");
1378 return aTo;
1381 nsACString&
1382 ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1384 Layer::PrintInfo(aTo, aPrefix);
1385 AppendToString(aTo, mSize, " [size=", "]");
1386 if (mBackgroundLayer) {
1387 AppendToString(aTo, mBackgroundLayer, " [backgroundLayer=", "]");
1388 AppendToString(aTo, mBackgroundLayerOffset, " [backgroundOffset=", "]");
1389 } else if (mBackgroundColor.a == 1.0) {
1390 AppendToString(aTo, mBackgroundColor, " [backgroundColor=", "]");
1391 } else {
1392 aTo += " [nobackground]";
1394 return aTo;
1397 //--------------------------------------------------
1398 // LayerManager
1400 void
1401 LayerManager::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
1403 FILE* file = FILEOrDefault(aFile);
1405 #ifdef MOZ_DUMP_PAINTING
1406 if (aDumpHtml) {
1407 fprintf(file, "<ul><li><a ");
1408 WriteSnapshotLinkToDumpFile(this, file);
1409 fprintf(file, ">");
1411 #endif
1412 DumpSelf(file, aPrefix);
1413 #ifdef MOZ_DUMP_PAINTING
1414 if (aDumpHtml) {
1415 fprintf(file, "</a>");
1417 #endif
1419 nsAutoCString pfx(aPrefix);
1420 pfx += " ";
1421 if (!GetRoot()) {
1422 fprintf(file, "%s(null)", pfx.get());
1423 if (aDumpHtml) {
1424 fprintf(file, "</li></ul>");
1426 return;
1429 if (aDumpHtml) {
1430 fprintf(file, "<ul>");
1432 GetRoot()->Dump(file, pfx.get(), aDumpHtml);
1433 if (aDumpHtml) {
1434 fprintf(file, "</ul></li></ul>");
1436 fputc('\n', file);
1439 void
1440 LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
1442 nsAutoCString str;
1443 PrintInfo(str, aPrefix);
1444 fprintf(FILEOrDefault(aFile), "%s\n", str.get());
1447 void
1448 LayerManager::Log(const char* aPrefix)
1450 if (!IsLogEnabled())
1451 return;
1453 LogSelf(aPrefix);
1455 nsAutoCString pfx(aPrefix);
1456 pfx += " ";
1457 if (!GetRoot()) {
1458 MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
1459 return;
1462 GetRoot()->Log(pfx.get());
1465 void
1466 LayerManager::LogSelf(const char* aPrefix)
1468 nsAutoCString str;
1469 PrintInfo(str, aPrefix);
1470 MOZ_LAYERS_LOG(("%s", str.get()));
1473 nsACString&
1474 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
1476 aTo += aPrefix;
1477 return aTo += nsPrintfCString("%sLayerManager (0x%p)", Name(), this);
1480 /*static*/ void
1481 LayerManager::InitLog()
1483 if (!sLog)
1484 sLog = PR_NewLogModule("Layers");
1487 /*static*/ bool
1488 LayerManager::IsLogEnabled()
1490 NS_ABORT_IF_FALSE(!!sLog,
1491 "layer manager must be created before logging is allowed");
1492 return PR_LOG_TEST(sLog, PR_LOG_DEBUG);
1495 static nsACString&
1496 PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite)
1498 if (!aLayerComposite) {
1499 return aTo;
1501 if (const nsIntRect* clipRect = aLayerComposite->GetShadowClipRect()) {
1502 AppendToString(aTo, *clipRect, " [shadow-clip=", "]");
1504 if (!aLayerComposite->GetShadowTransform().IsIdentity()) {
1505 AppendToString(aTo, aLayerComposite->GetShadowTransform(), " [shadow-transform=", "]");
1507 if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
1508 AppendToString(aTo, aLayerComposite->GetShadowVisibleRegion(), " [shadow-visible=", "]");
1510 return aTo;
1513 #else // !MOZ_LAYERS_HAVE_LOG
1515 void Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml) {}
1516 void Layer::DumpSelf(FILE* aFile, const char* aPrefix) {}
1517 void Layer::Log(const char* aPrefix) {}
1518 void Layer::LogSelf(const char* aPrefix) {}
1519 nsACString&
1520 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
1521 { return aTo; }
1523 nsACString&
1524 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1525 { return aTo; }
1527 nsACString&
1528 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1529 { return aTo; }
1531 nsACString&
1532 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1533 { return aTo; }
1535 nsACString&
1536 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1537 { return aTo; }
1539 nsACString&
1540 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1541 { return aTo; }
1543 nsACString&
1544 RefLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1545 { return aTo; }
1547 nsACString&
1548 ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1549 { return aTo; }
1551 void LayerManager::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml) {}
1552 void LayerManager::DumpSelf(FILE* aFile, const char* aPrefix) {}
1553 void LayerManager::Log(const char* aPrefix) {}
1554 void LayerManager::LogSelf(const char* aPrefix) {}
1556 nsACString&
1557 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
1558 { return aTo; }
1560 /*static*/ void LayerManager::InitLog() {}
1561 /*static*/ bool LayerManager::IsLogEnabled() { return false; }
1563 #endif // MOZ_LAYERS_HAVE_LOG
1565 PRLogModuleInfo* LayerManager::sLog;
1567 } // namespace layers
1568 } // namespace mozilla