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