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