Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "Layers.h"
9 #include <algorithm> // for max, min
10 #include "AnimationCommon.h" // for ComputedTimingFunction
11 #include "CompositableHost.h" // for CompositableHost
12 #include "ImageContainer.h" // for ImageContainer, etc
13 #include "ImageLayers.h" // for ImageLayer
14 #include "LayerSorter.h" // for SortLayersBy3DZOrder
15 #include "LayersLogging.h" // for AppendToString
16 #include "ReadbackLayer.h" // for ReadbackLayer
17 #include "gfxPlatform.h" // for gfxPlatform
18 #include "gfxUtils.h" // for gfxUtils, etc
19 #include "gfx2DGlue.h"
20 #include "mozilla/DebugOnly.h" // for DebugOnly
21 #include "mozilla/Telemetry.h" // for Accumulate
22 #include "mozilla/gfx/2D.h" // for DrawTarget
23 #include "mozilla/gfx/BaseSize.h" // for BaseSize
24 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
25 #include "mozilla/layers/AsyncPanZoomController.h"
26 #include "mozilla/layers/Compositor.h" // for Compositor
27 #include "mozilla/layers/CompositorTypes.h"
28 #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite
29 #include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
30 #include "nsAString.h"
31 #include "nsCSSValue.h" // for nsCSSValue::Array, etc
32 #include "nsPrintfCString.h" // for nsPrintfCString
33 #include "nsStyleStruct.h" // for nsTimingFunction, etc
35 using namespace mozilla::layers;
36 using namespace mozilla::gfx;
38 typedef FrameMetrics::ViewID ViewID;
39 const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
41 uint8_t gLayerManagerLayerBuilder;
43 FILE*
44 FILEOrDefault(FILE* aFile)
45 {
46 return aFile ? aFile : stderr;
47 }
49 namespace mozilla {
50 namespace layers {
52 //--------------------------------------------------
53 // LayerManager
54 Layer*
55 LayerManager::GetPrimaryScrollableLayer()
56 {
57 if (!mRoot) {
58 return nullptr;
59 }
61 nsTArray<Layer*> queue;
62 queue.AppendElement(mRoot);
63 while (queue.Length()) {
64 ContainerLayer* containerLayer = queue[0]->AsContainerLayer();
65 queue.RemoveElementAt(0);
66 if (!containerLayer) {
67 continue;
68 }
70 const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
71 if (frameMetrics.IsScrollable()) {
72 return containerLayer;
73 }
75 Layer* child = containerLayer->GetFirstChild();
76 while (child) {
77 queue.AppendElement(child);
78 child = child->GetNextSibling();
79 }
80 }
82 return mRoot;
83 }
85 void
86 LayerManager::GetScrollableLayers(nsTArray<Layer*>& aArray)
87 {
88 if (!mRoot) {
89 return;
90 }
92 nsTArray<Layer*> queue;
93 queue.AppendElement(mRoot);
94 while (!queue.IsEmpty()) {
95 ContainerLayer* containerLayer = queue.LastElement()->AsContainerLayer();
96 queue.RemoveElementAt(queue.Length() - 1);
97 if (!containerLayer) {
98 continue;
99 }
101 const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
102 if (frameMetrics.IsScrollable()) {
103 aArray.AppendElement(containerLayer);
104 continue;
105 }
107 Layer* child = containerLayer->GetFirstChild();
108 while (child) {
109 queue.AppendElement(child);
110 child = child->GetNextSibling();
111 }
112 }
113 }
115 TemporaryRef<DrawTarget>
116 LayerManager::CreateOptimalDrawTarget(const gfx::IntSize &aSize,
117 SurfaceFormat aFormat)
118 {
119 return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aSize,
120 aFormat);
121 }
123 TemporaryRef<DrawTarget>
124 LayerManager::CreateOptimalMaskDrawTarget(const gfx::IntSize &aSize)
125 {
126 return CreateOptimalDrawTarget(aSize, SurfaceFormat::A8);
127 }
129 TemporaryRef<DrawTarget>
130 LayerManager::CreateDrawTarget(const IntSize &aSize,
131 SurfaceFormat aFormat)
132 {
133 return gfxPlatform::GetPlatform()->
134 CreateOffscreenCanvasDrawTarget(aSize, aFormat);
135 }
137 #ifdef DEBUG
138 void
139 LayerManager::Mutated(Layer* aLayer)
140 {
141 }
142 #endif // DEBUG
144 already_AddRefed<ImageContainer>
145 LayerManager::CreateImageContainer()
146 {
147 nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::DISABLE_ASYNC);
148 return container.forget();
149 }
151 already_AddRefed<ImageContainer>
152 LayerManager::CreateAsynchronousImageContainer()
153 {
154 nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::ENABLE_ASYNC);
155 return container.forget();
156 }
158 //--------------------------------------------------
159 // Layer
161 Layer::Layer(LayerManager* aManager, void* aImplData) :
162 mManager(aManager),
163 mParent(nullptr),
164 mNextSibling(nullptr),
165 mPrevSibling(nullptr),
166 mImplData(aImplData),
167 mMaskLayer(nullptr),
168 mPostXScale(1.0f),
169 mPostYScale(1.0f),
170 mOpacity(1.0),
171 mMixBlendMode(CompositionOp::OP_OVER),
172 mForceIsolatedGroup(false),
173 mContentFlags(0),
174 mUseClipRect(false),
175 mUseTileSourceRect(false),
176 mIsFixedPosition(false),
177 mMargins(0, 0, 0, 0),
178 mStickyPositionData(nullptr),
179 mScrollbarTargetId(FrameMetrics::NULL_SCROLL_ID),
180 mScrollbarDirection(ScrollDirection::NONE),
181 mDebugColorIndex(0),
182 mAnimationGeneration(0)
183 {}
185 Layer::~Layer()
186 {}
188 Animation*
189 Layer::AddAnimation()
190 {
191 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) AddAnimation", this));
193 MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
195 Animation* anim = mAnimations.AppendElement();
197 Mutated();
198 return anim;
199 }
201 void
202 Layer::ClearAnimations()
203 {
204 mPendingAnimations = nullptr;
206 if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
207 return;
208 }
210 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClearAnimations", this));
211 mAnimations.Clear();
212 mAnimationData.Clear();
213 Mutated();
214 }
216 Animation*
217 Layer::AddAnimationForNextTransaction()
218 {
219 MOZ_ASSERT(mPendingAnimations,
220 "should have called ClearAnimationsForNextTransaction first");
222 Animation* anim = mPendingAnimations->AppendElement();
224 return anim;
225 }
227 void
228 Layer::ClearAnimationsForNextTransaction()
229 {
230 // Ensure we have a non-null mPendingAnimations to mark a future clear.
231 if (!mPendingAnimations) {
232 mPendingAnimations = new AnimationArray;
233 }
235 mPendingAnimations->Clear();
236 }
238 static nsCSSValueSharedList*
239 CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
240 {
241 nsAutoPtr<nsCSSValueList> result;
242 nsCSSValueList** resultTail = getter_Transfers(result);
243 for (uint32_t i = 0; i < aFunctions.Length(); i++) {
244 nsRefPtr<nsCSSValue::Array> arr;
245 switch (aFunctions[i].type()) {
246 case TransformFunction::TRotationX:
247 {
248 float theta = aFunctions[i].get_RotationX().radians();
249 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatex, resultTail);
250 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
251 break;
252 }
253 case TransformFunction::TRotationY:
254 {
255 float theta = aFunctions[i].get_RotationY().radians();
256 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatey, resultTail);
257 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
258 break;
259 }
260 case TransformFunction::TRotationZ:
261 {
262 float theta = aFunctions[i].get_RotationZ().radians();
263 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatez, resultTail);
264 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
265 break;
266 }
267 case TransformFunction::TRotation:
268 {
269 float theta = aFunctions[i].get_Rotation().radians();
270 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotate, resultTail);
271 arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
272 break;
273 }
274 case TransformFunction::TRotation3D:
275 {
276 float x = aFunctions[i].get_Rotation3D().x();
277 float y = aFunctions[i].get_Rotation3D().y();
278 float z = aFunctions[i].get_Rotation3D().z();
279 float theta = aFunctions[i].get_Rotation3D().radians();
280 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotate3d, resultTail);
281 arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
282 arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
283 arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
284 arr->Item(4).SetFloatValue(theta, eCSSUnit_Radian);
285 break;
286 }
287 case TransformFunction::TScale:
288 {
289 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_scale3d, resultTail);
290 arr->Item(1).SetFloatValue(aFunctions[i].get_Scale().x(), eCSSUnit_Number);
291 arr->Item(2).SetFloatValue(aFunctions[i].get_Scale().y(), eCSSUnit_Number);
292 arr->Item(3).SetFloatValue(aFunctions[i].get_Scale().z(), eCSSUnit_Number);
293 break;
294 }
295 case TransformFunction::TTranslation:
296 {
297 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_translate3d, resultTail);
298 arr->Item(1).SetFloatValue(aFunctions[i].get_Translation().x(), eCSSUnit_Pixel);
299 arr->Item(2).SetFloatValue(aFunctions[i].get_Translation().y(), eCSSUnit_Pixel);
300 arr->Item(3).SetFloatValue(aFunctions[i].get_Translation().z(), eCSSUnit_Pixel);
301 break;
302 }
303 case TransformFunction::TSkewX:
304 {
305 float x = aFunctions[i].get_SkewX().x();
306 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skewx, resultTail);
307 arr->Item(1).SetFloatValue(x, eCSSUnit_Radian);
308 break;
309 }
310 case TransformFunction::TSkewY:
311 {
312 float y = aFunctions[i].get_SkewY().y();
313 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skewy, resultTail);
314 arr->Item(1).SetFloatValue(y, eCSSUnit_Radian);
315 break;
316 }
317 case TransformFunction::TSkew:
318 {
319 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skew, resultTail);
320 arr->Item(1).SetFloatValue(aFunctions[i].get_Skew().x(), eCSSUnit_Radian);
321 arr->Item(2).SetFloatValue(aFunctions[i].get_Skew().y(), eCSSUnit_Radian);
322 break;
323 }
324 case TransformFunction::TTransformMatrix:
325 {
326 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_matrix3d, resultTail);
327 const gfx::Matrix4x4& matrix = aFunctions[i].get_TransformMatrix().value();
328 arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
329 arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
330 arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
331 arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number);
332 arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number);
333 arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number);
334 arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number);
335 arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number);
336 arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number);
337 arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number);
338 arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number);
339 arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number);
340 arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number);
341 arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number);
342 arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number);
343 arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number);
344 break;
345 }
346 case TransformFunction::TPerspective:
347 {
348 float perspective = aFunctions[i].get_Perspective().value();
349 arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_perspective, resultTail);
350 arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel);
351 break;
352 }
353 default:
354 NS_ASSERTION(false, "All functions should be implemented?");
355 }
356 }
357 if (aFunctions.Length() == 0) {
358 result = new nsCSSValueList();
359 result->mValue.SetNoneValue();
360 }
361 return new nsCSSValueSharedList(result.forget());
362 }
364 void
365 Layer::SetAnimations(const AnimationArray& aAnimations)
366 {
367 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) SetAnimations", this));
369 mAnimations = aAnimations;
370 mAnimationData.Clear();
371 for (uint32_t i = 0; i < mAnimations.Length(); i++) {
372 AnimData* data = mAnimationData.AppendElement();
373 InfallibleTArray<nsAutoPtr<css::ComputedTimingFunction> >& functions = data->mFunctions;
374 const InfallibleTArray<AnimationSegment>& segments =
375 mAnimations.ElementAt(i).segments();
376 for (uint32_t j = 0; j < segments.Length(); j++) {
377 TimingFunction tf = segments.ElementAt(j).sampleFn();
378 css::ComputedTimingFunction* ctf = new css::ComputedTimingFunction();
379 switch (tf.type()) {
380 case TimingFunction::TCubicBezierFunction: {
381 CubicBezierFunction cbf = tf.get_CubicBezierFunction();
382 ctf->Init(nsTimingFunction(cbf.x1(), cbf.y1(), cbf.x2(), cbf.y2()));
383 break;
384 }
385 default: {
386 NS_ASSERTION(tf.type() == TimingFunction::TStepFunction,
387 "Function must be bezier or step");
388 StepFunction sf = tf.get_StepFunction();
389 nsTimingFunction::Type type = sf.type() == 1 ? nsTimingFunction::StepStart
390 : nsTimingFunction::StepEnd;
391 ctf->Init(nsTimingFunction(type, sf.steps()));
392 break;
393 }
394 }
395 functions.AppendElement(ctf);
396 }
398 // Precompute the nsStyleAnimation::Values that we need if this is a transform
399 // animation.
400 InfallibleTArray<nsStyleAnimation::Value>& startValues = data->mStartValues;
401 InfallibleTArray<nsStyleAnimation::Value>& endValues = data->mEndValues;
402 for (uint32_t j = 0; j < mAnimations[i].segments().Length(); j++) {
403 const AnimationSegment& segment = mAnimations[i].segments()[j];
404 nsStyleAnimation::Value* startValue = startValues.AppendElement();
405 nsStyleAnimation::Value* endValue = endValues.AppendElement();
406 if (segment.endState().type() == Animatable::TArrayOfTransformFunction) {
407 const InfallibleTArray<TransformFunction>& startFunctions =
408 segment.startState().get_ArrayOfTransformFunction();
409 startValue->SetTransformValue(CreateCSSValueList(startFunctions));
411 const InfallibleTArray<TransformFunction>& endFunctions =
412 segment.endState().get_ArrayOfTransformFunction();
413 endValue->SetTransformValue(CreateCSSValueList(endFunctions));
414 } else {
415 NS_ASSERTION(segment.endState().type() == Animatable::Tfloat,
416 "Unknown Animatable type");
417 startValue->SetFloatValue(segment.startState().get_float());
418 endValue->SetFloatValue(segment.endState().get_float());
419 }
420 }
421 }
423 Mutated();
424 }
426 void
427 ContainerLayer::SetAsyncPanZoomController(AsyncPanZoomController *controller)
428 {
429 mAPZC = controller;
430 }
432 AsyncPanZoomController*
433 ContainerLayer::GetAsyncPanZoomController() const
434 {
435 #ifdef DEBUG
436 if (mAPZC) {
437 MOZ_ASSERT(GetFrameMetrics().IsScrollable());
438 }
439 #endif
440 return mAPZC;
441 }
443 void
444 Layer::ApplyPendingUpdatesToSubtree()
445 {
446 ApplyPendingUpdatesForThisTransaction();
447 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
448 child->ApplyPendingUpdatesToSubtree();
449 }
450 }
452 bool
453 Layer::CanUseOpaqueSurface()
454 {
455 // If the visible content in the layer is opaque, there is no need
456 // for an alpha channel.
457 if (GetContentFlags() & CONTENT_OPAQUE)
458 return true;
459 // Also, if this layer is the bottommost layer in a container which
460 // doesn't need an alpha channel, we can use an opaque surface for this
461 // layer too. Any transparent areas must be covered by something else
462 // in the container.
463 ContainerLayer* parent = GetParent();
464 return parent && parent->GetFirstChild() == this &&
465 parent->CanUseOpaqueSurface();
466 }
468 // NB: eventually these methods will be defined unconditionally, and
469 // can be moved into Layers.h
470 const nsIntRect*
471 Layer::GetEffectiveClipRect()
472 {
473 if (LayerComposite* shadow = AsLayerComposite()) {
474 return shadow->GetShadowClipRect();
475 }
476 return GetClipRect();
477 }
479 const nsIntRegion&
480 Layer::GetEffectiveVisibleRegion()
481 {
482 if (LayerComposite* shadow = AsLayerComposite()) {
483 return shadow->GetShadowVisibleRegion();
484 }
485 return GetVisibleRegion();
486 }
488 Matrix4x4
489 Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
490 Matrix* aResidualTransform)
491 {
492 if (aResidualTransform) {
493 *aResidualTransform = Matrix();
494 }
496 Matrix matrix2D;
497 Matrix4x4 result;
498 if (mManager->IsSnappingEffectiveTransforms() &&
499 aTransform.Is2D(&matrix2D) &&
500 !matrix2D.HasNonTranslation() &&
501 matrix2D.HasNonIntegerTranslation()) {
502 IntPoint snappedTranslation = RoundedToInt(matrix2D.GetTranslation());
503 Matrix snappedMatrix = Matrix::Translation(snappedTranslation.x,
504 snappedTranslation.y);
505 result = Matrix4x4::From2D(snappedMatrix);
506 if (aResidualTransform) {
507 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
508 // (I.e., appying snappedMatrix after aResidualTransform gives the
509 // ideal transform.)
510 *aResidualTransform =
511 Matrix::Translation(matrix2D._31 - snappedTranslation.x,
512 matrix2D._32 - snappedTranslation.y);
513 }
514 } else {
515 result = aTransform;
516 }
517 return result;
518 }
520 Matrix4x4
521 Layer::SnapTransform(const Matrix4x4& aTransform,
522 const gfxRect& aSnapRect,
523 Matrix* aResidualTransform)
524 {
525 if (aResidualTransform) {
526 *aResidualTransform = Matrix();
527 }
529 Matrix matrix2D;
530 Matrix4x4 result;
531 if (mManager->IsSnappingEffectiveTransforms() &&
532 aTransform.Is2D(&matrix2D) &&
533 gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) &&
534 matrix2D.PreservesAxisAlignedRectangles()) {
535 IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft()));
536 IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight()));
537 IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight()));
539 Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
540 transformedTopLeft, transformedTopRight, transformedBottomRight);
542 result = Matrix4x4::From2D(snappedMatrix);
543 if (aResidualTransform && !snappedMatrix.IsSingular()) {
544 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
545 // (i.e., appying snappedMatrix after aResidualTransform gives the
546 // ideal transform.
547 Matrix snappedMatrixInverse = snappedMatrix;
548 snappedMatrixInverse.Invert();
549 *aResidualTransform = matrix2D * snappedMatrixInverse;
550 }
551 } else {
552 result = aTransform;
553 }
554 return result;
555 }
557 static bool
558 AncestorLayerMayChangeTransform(Layer* aLayer)
559 {
560 for (Layer* l = aLayer; l; l = l->GetParent()) {
561 if (l->GetContentFlags() & Layer::CONTENT_MAY_CHANGE_TRANSFORM) {
562 return true;
563 }
564 }
565 return false;
566 }
568 bool
569 Layer::MayResample()
570 {
571 Matrix transform2d;
572 return !GetEffectiveTransform().Is2D(&transform2d) ||
573 ThebesMatrix(transform2d).HasNonIntegerTranslation() ||
574 AncestorLayerMayChangeTransform(this);
575 }
577 nsIntRect
578 Layer::CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
579 const gfx::Matrix* aWorldTransform)
580 {
581 ContainerLayer* container = GetParent();
582 NS_ASSERTION(container, "This can't be called on the root!");
584 // Establish initial clip rect: it's either the one passed in, or
585 // if the parent has an intermediate surface, it's the extents of that surface.
586 nsIntRect currentClip;
587 if (container->UseIntermediateSurface()) {
588 currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
589 } else {
590 currentClip = aCurrentScissorRect;
591 }
593 const nsIntRect *clipRect = GetEffectiveClipRect();
594 if (!clipRect)
595 return currentClip;
597 if (clipRect->IsEmpty()) {
598 // We might have a non-translation transform in the container so we can't
599 // use the code path below.
600 return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
601 }
603 nsIntRect scissor = *clipRect;
604 if (!container->UseIntermediateSurface()) {
605 gfx::Matrix matrix;
606 DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
607 // See DefaultComputeEffectiveTransforms below
608 NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
609 "Non preserves axis aligned transform with clipped child should have forced intermediate surface");
610 gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
611 gfxRect trScissor = gfx::ThebesRect(matrix.TransformBounds(r));
612 trScissor.Round();
613 if (!gfxUtils::GfxRectToIntRect(trScissor, &scissor)) {
614 return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
615 }
617 // Find the nearest ancestor with an intermediate surface
618 do {
619 container = container->GetParent();
620 } while (container && !container->UseIntermediateSurface());
621 }
622 if (container) {
623 scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
624 } else if (aWorldTransform) {
625 gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
626 gfx::Rect trScissor = aWorldTransform->TransformBounds(r);
627 trScissor.Round();
628 if (!gfxUtils::GfxRectToIntRect(ThebesRect(trScissor), &scissor))
629 return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
630 }
631 return currentClip.Intersect(scissor);
632 }
634 const Matrix4x4
635 Layer::GetTransform() const
636 {
637 Matrix4x4 transform = mTransform;
638 if (const ContainerLayer* c = AsContainerLayer()) {
639 transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
640 }
641 transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
642 return transform;
643 }
645 const Matrix4x4
646 Layer::GetLocalTransform()
647 {
648 Matrix4x4 transform;
649 if (LayerComposite* shadow = AsLayerComposite())
650 transform = shadow->GetShadowTransform();
651 else
652 transform = mTransform;
653 if (ContainerLayer* c = AsContainerLayer()) {
654 transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
655 }
656 transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
658 return transform;
659 }
661 void
662 Layer::ApplyPendingUpdatesForThisTransaction()
663 {
664 if (mPendingTransform && *mPendingTransform != mTransform) {
665 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
666 mTransform = *mPendingTransform;
667 Mutated();
668 }
669 mPendingTransform = nullptr;
671 if (mPendingAnimations) {
672 MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
673 mPendingAnimations->SwapElements(mAnimations);
674 mPendingAnimations = nullptr;
675 Mutated();
676 }
677 }
679 const float
680 Layer::GetLocalOpacity()
681 {
682 if (LayerComposite* shadow = AsLayerComposite())
683 return shadow->GetShadowOpacity();
684 return mOpacity;
685 }
687 float
688 Layer::GetEffectiveOpacity()
689 {
690 float opacity = GetLocalOpacity();
691 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
692 c = c->GetParent()) {
693 opacity *= c->GetLocalOpacity();
694 }
695 return opacity;
696 }
698 CompositionOp
699 Layer::GetEffectiveMixBlendMode()
700 {
701 if(mMixBlendMode != CompositionOp::OP_OVER)
702 return mMixBlendMode;
703 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
704 c = c->GetParent()) {
705 if(c->mMixBlendMode != CompositionOp::OP_OVER)
706 return c->mMixBlendMode;
707 }
709 return mMixBlendMode;
710 }
712 gfxContext::GraphicsOperator
713 Layer::DeprecatedGetEffectiveMixBlendMode()
714 {
715 return ThebesOp(GetEffectiveMixBlendMode());
716 }
718 void
719 Layer::ComputeEffectiveTransformForMaskLayer(const Matrix4x4& aTransformToSurface)
720 {
721 if (mMaskLayer) {
722 mMaskLayer->mEffectiveTransform = aTransformToSurface;
724 #ifdef DEBUG
725 bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D();
726 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
727 #endif
728 mMaskLayer->mEffectiveTransform = mMaskLayer->GetTransform() * mMaskLayer->mEffectiveTransform;
729 }
730 }
732 ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
733 : Layer(aManager, aImplData),
734 mFirstChild(nullptr),
735 mLastChild(nullptr),
736 mScrollHandoffParentId(FrameMetrics::NULL_SCROLL_ID),
737 mPreXScale(1.0f),
738 mPreYScale(1.0f),
739 mInheritedXScale(1.0f),
740 mInheritedYScale(1.0f),
741 mUseIntermediateSurface(false),
742 mSupportsComponentAlphaChildren(false),
743 mMayHaveReadbackChild(false)
744 {
745 mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
746 }
748 ContainerLayer::~ContainerLayer() {}
750 bool
751 ContainerLayer::InsertAfter(Layer* aChild, Layer* aAfter)
752 {
753 if(aChild->Manager() != Manager()) {
754 NS_ERROR("Child has wrong manager");
755 return false;
756 }
757 if(aChild->GetParent()) {
758 NS_ERROR("aChild already in the tree");
759 return false;
760 }
761 if (aChild->GetNextSibling() || aChild->GetPrevSibling()) {
762 NS_ERROR("aChild already has siblings?");
763 return false;
764 }
765 if (aAfter && (aAfter->Manager() != Manager() ||
766 aAfter->GetParent() != this))
767 {
768 NS_ERROR("aAfter is not our child");
769 return false;
770 }
772 aChild->SetParent(this);
773 if (aAfter == mLastChild) {
774 mLastChild = aChild;
775 }
776 if (!aAfter) {
777 aChild->SetNextSibling(mFirstChild);
778 if (mFirstChild) {
779 mFirstChild->SetPrevSibling(aChild);
780 }
781 mFirstChild = aChild;
782 NS_ADDREF(aChild);
783 DidInsertChild(aChild);
784 return true;
785 }
787 Layer* next = aAfter->GetNextSibling();
788 aChild->SetNextSibling(next);
789 aChild->SetPrevSibling(aAfter);
790 if (next) {
791 next->SetPrevSibling(aChild);
792 }
793 aAfter->SetNextSibling(aChild);
794 NS_ADDREF(aChild);
795 DidInsertChild(aChild);
796 return true;
797 }
799 bool
800 ContainerLayer::RemoveChild(Layer *aChild)
801 {
802 if (aChild->Manager() != Manager()) {
803 NS_ERROR("Child has wrong manager");
804 return false;
805 }
806 if (aChild->GetParent() != this) {
807 NS_ERROR("aChild not our child");
808 return false;
809 }
811 Layer* prev = aChild->GetPrevSibling();
812 Layer* next = aChild->GetNextSibling();
813 if (prev) {
814 prev->SetNextSibling(next);
815 } else {
816 this->mFirstChild = next;
817 }
818 if (next) {
819 next->SetPrevSibling(prev);
820 } else {
821 this->mLastChild = prev;
822 }
824 aChild->SetNextSibling(nullptr);
825 aChild->SetPrevSibling(nullptr);
826 aChild->SetParent(nullptr);
828 this->DidRemoveChild(aChild);
829 NS_RELEASE(aChild);
830 return true;
831 }
834 bool
835 ContainerLayer::RepositionChild(Layer* aChild, Layer* aAfter)
836 {
837 if (aChild->Manager() != Manager()) {
838 NS_ERROR("Child has wrong manager");
839 return false;
840 }
841 if (aChild->GetParent() != this) {
842 NS_ERROR("aChild not our child");
843 return false;
844 }
845 if (aAfter && (aAfter->Manager() != Manager() ||
846 aAfter->GetParent() != this))
847 {
848 NS_ERROR("aAfter is not our child");
849 return false;
850 }
851 if (aChild == aAfter) {
852 NS_ERROR("aChild cannot be the same as aAfter");
853 return false;
854 }
856 Layer* prev = aChild->GetPrevSibling();
857 Layer* next = aChild->GetNextSibling();
858 if (prev == aAfter) {
859 // aChild is already in the correct position, nothing to do.
860 return true;
861 }
862 if (prev) {
863 prev->SetNextSibling(next);
864 } else {
865 mFirstChild = next;
866 }
867 if (next) {
868 next->SetPrevSibling(prev);
869 } else {
870 mLastChild = prev;
871 }
872 if (!aAfter) {
873 aChild->SetPrevSibling(nullptr);
874 aChild->SetNextSibling(mFirstChild);
875 if (mFirstChild) {
876 mFirstChild->SetPrevSibling(aChild);
877 }
878 mFirstChild = aChild;
879 return true;
880 }
882 Layer* afterNext = aAfter->GetNextSibling();
883 if (afterNext) {
884 afterNext->SetPrevSibling(aChild);
885 } else {
886 mLastChild = aChild;
887 }
888 aAfter->SetNextSibling(aChild);
889 aChild->SetPrevSibling(aAfter);
890 aChild->SetNextSibling(afterNext);
891 return true;
892 }
894 void
895 ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
896 {
897 aAttrs = ContainerLayerAttributes(GetFrameMetrics(), mScrollHandoffParentId,
898 mPreXScale, mPreYScale,
899 mInheritedXScale, mInheritedYScale);
900 }
902 bool
903 ContainerLayer::HasMultipleChildren()
904 {
905 uint32_t count = 0;
906 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
907 const nsIntRect *clipRect = child->GetEffectiveClipRect();
908 if (clipRect && clipRect->IsEmpty())
909 continue;
910 if (child->GetVisibleRegion().IsEmpty())
911 continue;
912 ++count;
913 if (count > 1)
914 return true;
915 }
917 return false;
918 }
920 void
921 ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
922 {
923 nsAutoTArray<Layer*, 10> toSort;
925 for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
926 ContainerLayer* container = l->AsContainerLayer();
927 if (container && container->GetContentFlags() & CONTENT_PRESERVE_3D) {
928 toSort.AppendElement(l);
929 } else {
930 if (toSort.Length() > 0) {
931 SortLayersBy3DZOrder(toSort);
932 aArray.MoveElementsFrom(toSort);
933 }
934 aArray.AppendElement(l);
935 }
936 }
937 if (toSort.Length() > 0) {
938 SortLayersBy3DZOrder(toSort);
939 aArray.MoveElementsFrom(toSort);
940 }
941 }
943 void
944 ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
945 {
946 Matrix residual;
947 Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
948 idealTransform.ProjectTo2D();
949 mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
951 bool useIntermediateSurface;
952 if (GetMaskLayer()) {
953 useIntermediateSurface = true;
954 #ifdef MOZ_DUMP_PAINTING
955 } else if (gfxUtils::sDumpPainting) {
956 useIntermediateSurface = true;
957 #endif
958 } else {
959 float opacity = GetEffectiveOpacity();
960 if (opacity != 1.0f && HasMultipleChildren()) {
961 useIntermediateSurface = true;
962 } else {
963 useIntermediateSurface = false;
964 gfx::Matrix contTransform;
965 if (!mEffectiveTransform.Is2D(&contTransform) ||
966 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
967 !contTransform.PreservesAxisAlignedRectangles()) {
968 #else
969 gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) {
970 #endif
971 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
972 const nsIntRect *clipRect = child->GetEffectiveClipRect();
973 /* We can't (easily) forward our transform to children with a non-empty clip
974 * rect since it would need to be adjusted for the transform. See
975 * the calculations performed by CalculateScissorRect above.
976 * Nor for a child with a mask layer.
977 */
978 if ((clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) ||
979 child->GetMaskLayer()) {
980 useIntermediateSurface = true;
981 break;
982 }
983 }
984 }
985 }
986 }
988 mUseIntermediateSurface = useIntermediateSurface;
989 if (useIntermediateSurface) {
990 ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual));
991 } else {
992 ComputeEffectiveTransformsForChildren(idealTransform);
993 }
995 if (idealTransform.CanDraw2D()) {
996 ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
997 } else {
998 ComputeEffectiveTransformForMaskLayer(Matrix4x4());
999 }
1000 }
1002 void
1003 ContainerLayer::ComputeEffectiveTransformsForChildren(const Matrix4x4& aTransformToSurface)
1004 {
1005 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
1006 l->ComputeEffectiveTransforms(aTransformToSurface);
1007 }
1008 }
1010 /* static */ bool
1011 ContainerLayer::HasOpaqueAncestorLayer(Layer* aLayer)
1012 {
1013 for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
1014 if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
1015 return true;
1016 }
1017 return false;
1018 }
1020 void
1021 ContainerLayer::DidRemoveChild(Layer* aLayer)
1022 {
1023 ThebesLayer* tl = aLayer->AsThebesLayer();
1024 if (tl && tl->UsedForReadback()) {
1025 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
1026 if (l->GetType() == TYPE_READBACK) {
1027 static_cast<ReadbackLayer*>(l)->NotifyThebesLayerRemoved(tl);
1028 }
1029 }
1030 }
1031 if (aLayer->GetType() == TYPE_READBACK) {
1032 static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
1033 }
1034 }
1036 void
1037 ContainerLayer::DidInsertChild(Layer* aLayer)
1038 {
1039 if (aLayer->GetType() == TYPE_READBACK) {
1040 mMayHaveReadbackChild = true;
1041 }
1042 }
1044 void
1045 RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
1046 {
1047 aAttrs = RefLayerAttributes(GetReferentId());
1048 }
1050 /**
1051 * StartFrameTimeRecording, together with StopFrameTimeRecording
1052 * enable recording of frame intervals.
1053 *
1054 * To allow concurrent consumers, a cyclic array is used which serves all
1055 * consumers, practically stateless with regard to consumers.
1056 *
1057 * To save resources, the buffer is allocated on first call to StartFrameTimeRecording
1058 * and recording is paused if no consumer which called StartFrameTimeRecording is able
1059 * to get valid results (because the cyclic buffer was overwritten since that call).
1060 *
1061 * To determine availability of the data upon StopFrameTimeRecording:
1062 * - mRecording.mNextIndex increases on each PostPresent, and never resets.
1063 * - Cyclic buffer position is realized as mNextIndex % bufferSize.
1064 * - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is called,
1065 * the required start index is passed as an arg, and we're able to calculate the required
1066 * length. If this length is bigger than bufferSize, it means data was overwritten.
1067 * otherwise, we can return the entire sequence.
1068 * - To determine if we need to pause, mLatestStartIndex is updated to mNextIndex
1069 * on each call to StartFrameTimeRecording. If this index gets overwritten,
1070 * it means that all earlier start indices obtained via StartFrameTimeRecording
1071 * were also overwritten, hence, no point in recording, so pause.
1072 * - mCurrentRunStartIndex indicates the oldest index of the recording after which
1073 * the recording was not paused. If StopFrameTimeRecording is invoked with a start index
1074 * older than this, it means that some frames were not recorded, so data is invalid.
1075 */
1076 uint32_t
1077 LayerManager::StartFrameTimeRecording(int32_t aBufferSize)
1078 {
1079 if (mRecording.mIsPaused) {
1080 mRecording.mIsPaused = false;
1082 if (!mRecording.mIntervals.Length()) { // Initialize recording buffers
1083 mRecording.mIntervals.SetLength(aBufferSize);
1084 }
1086 // After being paused, recent values got invalid. Update them to now.
1087 mRecording.mLastFrameTime = TimeStamp::Now();
1089 // Any recording which started before this is invalid, since we were paused.
1090 mRecording.mCurrentRunStartIndex = mRecording.mNextIndex;
1091 }
1093 // If we'll overwrite this index, there are no more consumers with aStartIndex
1094 // for which we're able to provide the full recording, so no point in keep recording.
1095 mRecording.mLatestStartIndex = mRecording.mNextIndex;
1096 return mRecording.mNextIndex;
1097 }
1099 void
1100 LayerManager::RecordFrame()
1101 {
1102 if (!mRecording.mIsPaused) {
1103 TimeStamp now = TimeStamp::Now();
1104 uint32_t i = mRecording.mNextIndex % mRecording.mIntervals.Length();
1105 mRecording.mIntervals[i] = static_cast<float>((now - mRecording.mLastFrameTime)
1106 .ToMilliseconds());
1107 mRecording.mNextIndex++;
1108 mRecording.mLastFrameTime = now;
1110 if (mRecording.mNextIndex > (mRecording.mLatestStartIndex + mRecording.mIntervals.Length())) {
1111 // We've just overwritten the most recent recording start -> pause.
1112 mRecording.mIsPaused = true;
1113 }
1114 }
1115 }
1117 void
1118 LayerManager::PostPresent()
1119 {
1120 if (!mTabSwitchStart.IsNull()) {
1121 Telemetry::Accumulate(Telemetry::FX_TAB_SWITCH_TOTAL_MS,
1122 uint32_t((TimeStamp::Now() - mTabSwitchStart).ToMilliseconds()));
1123 mTabSwitchStart = TimeStamp();
1124 }
1125 }
1127 void
1128 LayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
1129 nsTArray<float>& aFrameIntervals)
1130 {
1131 uint32_t bufferSize = mRecording.mIntervals.Length();
1132 uint32_t length = mRecording.mNextIndex - aStartIndex;
1133 if (mRecording.mIsPaused || length > bufferSize || aStartIndex < mRecording.mCurrentRunStartIndex) {
1134 // aStartIndex is too old. Also if aStartIndex was issued before mRecordingNextIndex overflowed (uint32_t)
1135 // and stopped after the overflow (would happen once every 828 days of constant 60fps).
1136 length = 0;
1137 }
1139 if (!length) {
1140 aFrameIntervals.Clear();
1141 return; // empty recording, return empty arrays.
1142 }
1143 // Set length in advance to avoid possibly repeated reallocations
1144 aFrameIntervals.SetLength(length);
1146 uint32_t cyclicPos = aStartIndex % bufferSize;
1147 for (uint32_t i = 0; i < length; i++, cyclicPos++) {
1148 if (cyclicPos == bufferSize) {
1149 cyclicPos = 0;
1150 }
1151 aFrameIntervals[i] = mRecording.mIntervals[cyclicPos];
1152 }
1153 }
1155 void
1156 LayerManager::BeginTabSwitch()
1157 {
1158 mTabSwitchStart = TimeStamp::Now();
1159 }
1161 static nsACString& PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite);
1163 #ifdef MOZ_DUMP_PAINTING
1164 template <typename T>
1165 void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
1166 {
1167 if (!aObj) {
1168 return;
1169 }
1170 nsCString string(aObj->Name());
1171 string.Append("-");
1172 string.AppendInt((uint64_t)aObj);
1173 fprintf_stderr(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
1174 }
1176 template <typename T>
1177 void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
1178 {
1179 nsRefPtr<gfxImageSurface> deprecatedSurf =
1180 new gfxImageSurface(aSurf->GetData(),
1181 ThebesIntSize(aSurf->GetSize()),
1182 aSurf->Stride(),
1183 SurfaceFormatToImageFormat(aSurf->GetFormat()));
1184 nsCString string(aObj->Name());
1185 string.Append("-");
1186 string.AppendInt((uint64_t)aObj);
1187 if (gfxUtils::sDumpPaintFile) {
1188 fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
1189 }
1190 deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
1191 if (gfxUtils::sDumpPaintFile) {
1192 fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
1193 }
1194 }
1196 void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf)
1197 {
1198 WriteSnapshotToDumpFile_internal(aLayer, aSurf);
1199 }
1201 void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf)
1202 {
1203 WriteSnapshotToDumpFile_internal(aManager, aSurf);
1204 }
1206 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
1207 {
1208 RefPtr<SourceSurface> surf = aTarget->Snapshot();
1209 RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
1210 WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
1211 }
1212 #endif
1214 void
1215 Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
1216 {
1217 if (aDumpHtml) {
1218 fprintf_stderr(aFile, "<li><a id=\"%p\" ", this);
1219 #ifdef MOZ_DUMP_PAINTING
1220 if (GetType() == TYPE_CONTAINER || GetType() == TYPE_THEBES) {
1221 WriteSnapshotLinkToDumpFile(this, aFile);
1222 }
1223 #endif
1224 fprintf_stderr(aFile, ">");
1225 }
1226 DumpSelf(aFile, aPrefix);
1228 #ifdef MOZ_DUMP_PAINTING
1229 if (AsLayerComposite() && AsLayerComposite()->GetCompositableHost()) {
1230 AsLayerComposite()->GetCompositableHost()->Dump(aFile, aPrefix, aDumpHtml);
1231 }
1232 #endif
1234 if (aDumpHtml) {
1235 fprintf_stderr(aFile, "</a>");
1236 }
1238 if (Layer* mask = GetMaskLayer()) {
1239 fprintf_stderr(aFile, "%s Mask layer:\n", aPrefix);
1240 nsAutoCString pfx(aPrefix);
1241 pfx += " ";
1242 mask->Dump(aFile, pfx.get(), aDumpHtml);
1243 }
1245 if (Layer* kid = GetFirstChild()) {
1246 nsAutoCString pfx(aPrefix);
1247 pfx += " ";
1248 if (aDumpHtml) {
1249 fprintf_stderr(aFile, "<ul>");
1250 }
1251 kid->Dump(aFile, pfx.get(), aDumpHtml);
1252 if (aDumpHtml) {
1253 fprintf_stderr(aFile, "</ul>");
1254 }
1255 }
1257 if (aDumpHtml) {
1258 fprintf_stderr(aFile, "</li>");
1259 }
1260 if (Layer* next = GetNextSibling())
1261 next->Dump(aFile, aPrefix, aDumpHtml);
1262 }
1264 void
1265 Layer::DumpSelf(FILE* aFile, const char* aPrefix)
1266 {
1267 nsAutoCString str;
1268 PrintInfo(str, aPrefix);
1269 fprintf_stderr(aFile, "%s\n", str.get());
1270 }
1272 void
1273 Layer::Log(const char* aPrefix)
1274 {
1275 if (!IsLogEnabled())
1276 return;
1278 LogSelf(aPrefix);
1280 if (Layer* kid = GetFirstChild()) {
1281 nsAutoCString pfx(aPrefix);
1282 pfx += " ";
1283 kid->Log(pfx.get());
1284 }
1286 if (Layer* next = GetNextSibling())
1287 next->Log(aPrefix);
1288 }
1290 void
1291 Layer::LogSelf(const char* aPrefix)
1292 {
1293 if (!IsLogEnabled())
1294 return;
1296 nsAutoCString str;
1297 PrintInfo(str, aPrefix);
1298 MOZ_LAYERS_LOG(("%s", str.get()));
1300 if (mMaskLayer) {
1301 nsAutoCString pfx(aPrefix);
1302 pfx += " \\ MaskLayer ";
1303 mMaskLayer->LogSelf(pfx.get());
1304 }
1305 }
1307 nsACString&
1308 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
1309 {
1310 aTo += aPrefix;
1311 aTo += nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this);
1313 ::PrintInfo(aTo, AsLayerComposite());
1315 if (mUseClipRect) {
1316 AppendToString(aTo, mClipRect, " [clip=", "]");
1317 }
1318 if (1.0 != mPostXScale || 1.0 != mPostYScale) {
1319 aTo.AppendPrintf(" [postScale=%g, %g]", mPostXScale, mPostYScale);
1320 }
1321 if (!mTransform.IsIdentity()) {
1322 AppendToString(aTo, mTransform, " [transform=", "]");
1323 }
1324 if (!mVisibleRegion.IsEmpty()) {
1325 AppendToString(aTo, mVisibleRegion, " [visible=", "]");
1326 } else {
1327 aTo += " [not visible]";
1328 }
1329 if (!mEventRegions.mHitRegion.IsEmpty()) {
1330 AppendToString(aTo, mEventRegions.mHitRegion, " [hitregion=", "]");
1331 }
1332 if (!mEventRegions.mDispatchToContentHitRegion.IsEmpty()) {
1333 AppendToString(aTo, mEventRegions.mDispatchToContentHitRegion, " [dispatchtocontentregion=", "]");
1334 }
1335 if (1.0 != mOpacity) {
1336 aTo.AppendPrintf(" [opacity=%g]", mOpacity);
1337 }
1338 if (GetContentFlags() & CONTENT_OPAQUE) {
1339 aTo += " [opaqueContent]";
1340 }
1341 if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
1342 aTo += " [componentAlpha]";
1343 }
1344 if (GetScrollbarDirection() == VERTICAL) {
1345 aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId());
1346 }
1347 if (GetScrollbarDirection() == HORIZONTAL) {
1348 aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId());
1349 }
1350 if (GetIsFixedPosition()) {
1351 aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f margin=%f,%f,%f,%f]", mAnchor.x, mAnchor.y,
1352 mMargins.top, mMargins.right, mMargins.bottom, mMargins.left);
1353 }
1354 if (GetIsStickyPosition()) {
1355 aTo.AppendPrintf(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f "
1356 "inner=%f,%f %fx%f]", mStickyPositionData->mScrollId,
1357 mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y,
1358 mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height,
1359 mStickyPositionData->mInner.x, mStickyPositionData->mInner.y,
1360 mStickyPositionData->mInner.width, mStickyPositionData->mInner.height);
1361 }
1362 if (mMaskLayer) {
1363 aTo.AppendPrintf(" [mMaskLayer=%p]", mMaskLayer.get());
1364 }
1366 return aTo;
1367 }
1369 nsACString&
1370 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1371 {
1372 Layer::PrintInfo(aTo, aPrefix);
1373 if (!mValidRegion.IsEmpty()) {
1374 AppendToString(aTo, mValidRegion, " [valid=", "]");
1375 }
1376 return aTo;
1377 }
1379 nsACString&
1380 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1381 {
1382 Layer::PrintInfo(aTo, aPrefix);
1383 if (!mFrameMetrics.IsDefault()) {
1384 AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
1385 }
1386 if (mScrollHandoffParentId != FrameMetrics::NULL_SCROLL_ID) {
1387 aTo.AppendPrintf(" [scrollParent=%llu]", mScrollHandoffParentId);
1388 }
1389 if (UseIntermediateSurface()) {
1390 aTo += " [usesTmpSurf]";
1391 }
1392 if (1.0 != mPreXScale || 1.0 != mPreYScale) {
1393 aTo.AppendPrintf(" [preScale=%g, %g]", mPreXScale, mPreYScale);
1394 }
1395 return aTo;
1396 }
1398 nsACString&
1399 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1400 {
1401 Layer::PrintInfo(aTo, aPrefix);
1402 AppendToString(aTo, mColor, " [color=", "]");
1403 return aTo;
1404 }
1406 nsACString&
1407 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1408 {
1409 Layer::PrintInfo(aTo, aPrefix);
1410 if (mFilter != GraphicsFilter::FILTER_GOOD) {
1411 AppendToString(aTo, mFilter, " [filter=", "]");
1412 }
1413 return aTo;
1414 }
1416 nsACString&
1417 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1418 {
1419 Layer::PrintInfo(aTo, aPrefix);
1420 if (mFilter != GraphicsFilter::FILTER_GOOD) {
1421 AppendToString(aTo, mFilter, " [filter=", "]");
1422 }
1423 return aTo;
1424 }
1426 nsACString&
1427 RefLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1428 {
1429 ContainerLayer::PrintInfo(aTo, aPrefix);
1430 if (0 != mId) {
1431 AppendToString(aTo, mId, " [id=", "]");
1432 }
1433 return aTo;
1434 }
1436 nsACString&
1437 ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
1438 {
1439 Layer::PrintInfo(aTo, aPrefix);
1440 AppendToString(aTo, mSize, " [size=", "]");
1441 if (mBackgroundLayer) {
1442 AppendToString(aTo, mBackgroundLayer, " [backgroundLayer=", "]");
1443 AppendToString(aTo, mBackgroundLayerOffset, " [backgroundOffset=", "]");
1444 } else if (mBackgroundColor.a == 1.0) {
1445 AppendToString(aTo, mBackgroundColor, " [backgroundColor=", "]");
1446 } else {
1447 aTo += " [nobackground]";
1448 }
1449 return aTo;
1450 }
1452 //--------------------------------------------------
1453 // LayerManager
1455 void
1456 LayerManager::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
1457 {
1458 FILE* file = FILEOrDefault(aFile);
1460 #ifdef MOZ_DUMP_PAINTING
1461 if (aDumpHtml) {
1462 fprintf_stderr(file, "<ul><li><a ");
1463 WriteSnapshotLinkToDumpFile(this, file);
1464 fprintf_stderr(file, ">");
1465 }
1466 #endif
1467 DumpSelf(file, aPrefix);
1468 #ifdef MOZ_DUMP_PAINTING
1469 if (aDumpHtml) {
1470 fprintf_stderr(file, "</a>");
1471 }
1472 #endif
1474 nsAutoCString pfx(aPrefix);
1475 pfx += " ";
1476 if (!GetRoot()) {
1477 fprintf_stderr(file, "%s(null)", pfx.get());
1478 if (aDumpHtml) {
1479 fprintf_stderr(file, "</li></ul>");
1480 }
1481 return;
1482 }
1484 if (aDumpHtml) {
1485 fprintf_stderr(file, "<ul>");
1486 }
1487 GetRoot()->Dump(file, pfx.get(), aDumpHtml);
1488 if (aDumpHtml) {
1489 fprintf_stderr(file, "</ul></li></ul>");
1490 }
1491 fprintf_stderr(file, "\n");
1492 }
1494 void
1495 LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
1496 {
1497 nsAutoCString str;
1498 PrintInfo(str, aPrefix);
1499 fprintf_stderr(FILEOrDefault(aFile), "%s\n", str.get());
1500 }
1502 void
1503 LayerManager::Log(const char* aPrefix)
1504 {
1505 if (!IsLogEnabled())
1506 return;
1508 LogSelf(aPrefix);
1510 nsAutoCString pfx(aPrefix);
1511 pfx += " ";
1512 if (!GetRoot()) {
1513 MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
1514 return;
1515 }
1517 GetRoot()->Log(pfx.get());
1518 }
1520 void
1521 LayerManager::LogSelf(const char* aPrefix)
1522 {
1523 nsAutoCString str;
1524 PrintInfo(str, aPrefix);
1525 MOZ_LAYERS_LOG(("%s", str.get()));
1526 }
1528 nsACString&
1529 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
1530 {
1531 aTo += aPrefix;
1532 return aTo += nsPrintfCString("%sLayerManager (0x%p)", Name(), this);
1533 }
1535 /*static*/ void
1536 LayerManager::InitLog()
1537 {
1538 if (!sLog)
1539 sLog = PR_NewLogModule("Layers");
1540 }
1542 /*static*/ bool
1543 LayerManager::IsLogEnabled()
1544 {
1545 NS_ABORT_IF_FALSE(!!sLog,
1546 "layer manager must be created before logging is allowed");
1547 return PR_LOG_TEST(sLog, PR_LOG_DEBUG);
1548 }
1550 static nsACString&
1551 PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite)
1552 {
1553 if (!aLayerComposite) {
1554 return aTo;
1555 }
1556 if (const nsIntRect* clipRect = aLayerComposite->GetShadowClipRect()) {
1557 AppendToString(aTo, *clipRect, " [shadow-clip=", "]");
1558 }
1559 if (!aLayerComposite->GetShadowTransform().IsIdentity()) {
1560 AppendToString(aTo, aLayerComposite->GetShadowTransform(), " [shadow-transform=", "]");
1561 }
1562 if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
1563 AppendToString(aTo, aLayerComposite->GetShadowVisibleRegion(), " [shadow-visible=", "]");
1564 }
1565 return aTo;
1566 }
1568 void
1569 SetAntialiasingFlags(Layer* aLayer, DrawTarget* aTarget)
1570 {
1571 bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
1572 if (aTarget->GetFormat() != SurfaceFormat::B8G8R8A8) {
1573 aTarget->SetPermitSubpixelAA(permitSubpixelAA);
1574 return;
1575 }
1577 const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
1578 gfx::Rect transformedBounds = aTarget->GetTransform().TransformBounds(gfx::Rect(Float(bounds.x), Float(bounds.y),
1579 Float(bounds.width), Float(bounds.height)));
1580 transformedBounds.RoundOut();
1581 IntRect intTransformedBounds;
1582 transformedBounds.ToIntRect(&intTransformedBounds);
1583 permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
1584 aTarget->GetOpaqueRect().Contains(intTransformedBounds);
1585 aTarget->SetPermitSubpixelAA(permitSubpixelAA);
1586 }
1588 void
1589 SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget)
1590 {
1591 if (!aTarget->IsCairo()) {
1592 SetAntialiasingFlags(aLayer, aTarget->GetDrawTarget());
1593 return;
1594 }
1596 bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
1597 nsRefPtr<gfxASurface> surface = aTarget->CurrentSurface();
1598 if (surface->GetContentType() != gfxContentType::COLOR_ALPHA) {
1599 // Destination doesn't have alpha channel; no need to set any special flags
1600 surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
1601 return;
1602 }
1604 const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
1605 permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
1606 surface->GetOpaqueRect().Contains(
1607 aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
1608 surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
1609 }
1611 PRLogModuleInfo* LayerManager::sLog;
1613 } // namespace layers
1614 } // namespace mozilla