gfx/layers/Layers.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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   }
  1002 void
  1003 ContainerLayer::ComputeEffectiveTransformsForChildren(const Matrix4x4& aTransformToSurface)
  1005   for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
  1006     l->ComputeEffectiveTransforms(aTransformToSurface);
  1010 /* static */ bool
  1011 ContainerLayer::HasOpaqueAncestorLayer(Layer* aLayer)
  1013   for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
  1014     if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
  1015       return true;
  1017   return false;
  1020 void
  1021 ContainerLayer::DidRemoveChild(Layer* aLayer)
  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);
  1031   if (aLayer->GetType() == TYPE_READBACK) {
  1032     static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
  1036 void
  1037 ContainerLayer::DidInsertChild(Layer* aLayer)
  1039   if (aLayer->GetType() == TYPE_READBACK) {
  1040     mMayHaveReadbackChild = true;
  1044 void
  1045 RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
  1047   aAttrs = RefLayerAttributes(GetReferentId());
  1050 /** 
  1051  * StartFrameTimeRecording, together with StopFrameTimeRecording
  1052  * enable recording of frame intervals.
  1054  * To allow concurrent consumers, a cyclic array is used which serves all
  1055  * consumers, practically stateless with regard to consumers.
  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).
  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)
  1079   if (mRecording.mIsPaused) {
  1080     mRecording.mIsPaused = false;
  1082     if (!mRecording.mIntervals.Length()) { // Initialize recording buffers
  1083       mRecording.mIntervals.SetLength(aBufferSize);
  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;
  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;
  1099 void
  1100 LayerManager::RecordFrame()
  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;
  1117 void
  1118 LayerManager::PostPresent()
  1120   if (!mTabSwitchStart.IsNull()) {
  1121     Telemetry::Accumulate(Telemetry::FX_TAB_SWITCH_TOTAL_MS,
  1122                           uint32_t((TimeStamp::Now() - mTabSwitchStart).ToMilliseconds()));
  1123     mTabSwitchStart = TimeStamp();
  1127 void
  1128 LayerManager::StopFrameTimeRecording(uint32_t         aStartIndex,
  1129                                      nsTArray<float>& aFrameIntervals)
  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;
  1139   if (!length) {
  1140     aFrameIntervals.Clear();
  1141     return; // empty recording, return empty arrays.
  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;
  1151     aFrameIntervals[i] = mRecording.mIntervals[cyclicPos];
  1155 void
  1156 LayerManager::BeginTabSwitch()
  1158   mTabSwitchStart = TimeStamp::Now();
  1161 static nsACString& PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite);
  1163 #ifdef MOZ_DUMP_PAINTING
  1164 template <typename T>
  1165 void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
  1167   if (!aObj) {
  1168     return;
  1170   nsCString string(aObj->Name());
  1171   string.Append("-");
  1172   string.AppendInt((uint64_t)aObj);
  1173   fprintf_stderr(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
  1176 template <typename T>
  1177 void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
  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());
  1190   deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
  1191   if (gfxUtils::sDumpPaintFile) {
  1192     fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
  1196 void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf)
  1198   WriteSnapshotToDumpFile_internal(aLayer, aSurf);
  1201 void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf)
  1203   WriteSnapshotToDumpFile_internal(aManager, aSurf);
  1206 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
  1208   RefPtr<SourceSurface> surf = aTarget->Snapshot();
  1209   RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
  1210   WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
  1212 #endif
  1214 void
  1215 Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
  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);
  1223 #endif
  1224     fprintf_stderr(aFile, ">");
  1226   DumpSelf(aFile, aPrefix);
  1228 #ifdef MOZ_DUMP_PAINTING
  1229   if (AsLayerComposite() && AsLayerComposite()->GetCompositableHost()) {
  1230     AsLayerComposite()->GetCompositableHost()->Dump(aFile, aPrefix, aDumpHtml);
  1232 #endif
  1234   if (aDumpHtml) {
  1235     fprintf_stderr(aFile, "</a>");
  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);
  1245   if (Layer* kid = GetFirstChild()) {
  1246     nsAutoCString pfx(aPrefix);
  1247     pfx += "  ";
  1248     if (aDumpHtml) {
  1249       fprintf_stderr(aFile, "<ul>");
  1251     kid->Dump(aFile, pfx.get(), aDumpHtml);
  1252     if (aDumpHtml) {
  1253       fprintf_stderr(aFile, "</ul>");
  1257   if (aDumpHtml) {
  1258     fprintf_stderr(aFile, "</li>");
  1260   if (Layer* next = GetNextSibling())
  1261     next->Dump(aFile, aPrefix, aDumpHtml);
  1264 void
  1265 Layer::DumpSelf(FILE* aFile, const char* aPrefix)
  1267   nsAutoCString str;
  1268   PrintInfo(str, aPrefix);
  1269   fprintf_stderr(aFile, "%s\n", str.get());
  1272 void
  1273 Layer::Log(const char* aPrefix)
  1275   if (!IsLogEnabled())
  1276     return;
  1278   LogSelf(aPrefix);
  1280   if (Layer* kid = GetFirstChild()) {
  1281     nsAutoCString pfx(aPrefix);
  1282     pfx += "  ";
  1283     kid->Log(pfx.get());
  1286   if (Layer* next = GetNextSibling())
  1287     next->Log(aPrefix);
  1290 void
  1291 Layer::LogSelf(const char* aPrefix)
  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());
  1307 nsACString&
  1308 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
  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=", "]");
  1318   if (1.0 != mPostXScale || 1.0 != mPostYScale) {
  1319     aTo.AppendPrintf(" [postScale=%g, %g]", mPostXScale, mPostYScale);
  1321   if (!mTransform.IsIdentity()) {
  1322     AppendToString(aTo, mTransform, " [transform=", "]");
  1324   if (!mVisibleRegion.IsEmpty()) {
  1325     AppendToString(aTo, mVisibleRegion, " [visible=", "]");
  1326   } else {
  1327     aTo += " [not visible]";
  1329   if (!mEventRegions.mHitRegion.IsEmpty()) {
  1330     AppendToString(aTo, mEventRegions.mHitRegion, " [hitregion=", "]");
  1332   if (!mEventRegions.mDispatchToContentHitRegion.IsEmpty()) {
  1333     AppendToString(aTo, mEventRegions.mDispatchToContentHitRegion, " [dispatchtocontentregion=", "]");
  1335   if (1.0 != mOpacity) {
  1336     aTo.AppendPrintf(" [opacity=%g]", mOpacity);
  1338   if (GetContentFlags() & CONTENT_OPAQUE) {
  1339     aTo += " [opaqueContent]";
  1341   if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
  1342     aTo += " [componentAlpha]";
  1344   if (GetScrollbarDirection() == VERTICAL) {
  1345     aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId());
  1347   if (GetScrollbarDirection() == HORIZONTAL) {
  1348     aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId());
  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);
  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);
  1362   if (mMaskLayer) {
  1363     aTo.AppendPrintf(" [mMaskLayer=%p]", mMaskLayer.get());
  1366   return aTo;
  1369 nsACString&
  1370 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1372   Layer::PrintInfo(aTo, aPrefix);
  1373   if (!mValidRegion.IsEmpty()) {
  1374     AppendToString(aTo, mValidRegion, " [valid=", "]");
  1376   return aTo;
  1379 nsACString&
  1380 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1382   Layer::PrintInfo(aTo, aPrefix);
  1383   if (!mFrameMetrics.IsDefault()) {
  1384     AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
  1386   if (mScrollHandoffParentId != FrameMetrics::NULL_SCROLL_ID) {
  1387     aTo.AppendPrintf(" [scrollParent=%llu]", mScrollHandoffParentId);
  1389   if (UseIntermediateSurface()) {
  1390     aTo += " [usesTmpSurf]";
  1392   if (1.0 != mPreXScale || 1.0 != mPreYScale) {
  1393     aTo.AppendPrintf(" [preScale=%g, %g]", mPreXScale, mPreYScale);
  1395   return aTo;
  1398 nsACString&
  1399 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1401   Layer::PrintInfo(aTo, aPrefix);
  1402   AppendToString(aTo, mColor, " [color=", "]");
  1403   return aTo;
  1406 nsACString&
  1407 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1409   Layer::PrintInfo(aTo, aPrefix);
  1410   if (mFilter != GraphicsFilter::FILTER_GOOD) {
  1411     AppendToString(aTo, mFilter, " [filter=", "]");
  1413   return aTo;
  1416 nsACString&
  1417 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1419   Layer::PrintInfo(aTo, aPrefix);
  1420   if (mFilter != GraphicsFilter::FILTER_GOOD) {
  1421     AppendToString(aTo, mFilter, " [filter=", "]");
  1423   return aTo;
  1426 nsACString&
  1427 RefLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1429   ContainerLayer::PrintInfo(aTo, aPrefix);
  1430   if (0 != mId) {
  1431     AppendToString(aTo, mId, " [id=", "]");
  1433   return aTo;
  1436 nsACString&
  1437 ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  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]";
  1449   return aTo;
  1452 //--------------------------------------------------
  1453 // LayerManager
  1455 void
  1456 LayerManager::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
  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, ">");
  1466 #endif
  1467   DumpSelf(file, aPrefix);
  1468 #ifdef MOZ_DUMP_PAINTING
  1469   if (aDumpHtml) {
  1470     fprintf_stderr(file, "</a>");
  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>");
  1481     return;
  1484   if (aDumpHtml) {
  1485     fprintf_stderr(file, "<ul>");
  1487   GetRoot()->Dump(file, pfx.get(), aDumpHtml);
  1488   if (aDumpHtml) {
  1489     fprintf_stderr(file, "</ul></li></ul>");
  1491   fprintf_stderr(file, "\n");
  1494 void
  1495 LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
  1497   nsAutoCString str;
  1498   PrintInfo(str, aPrefix);
  1499   fprintf_stderr(FILEOrDefault(aFile), "%s\n", str.get());
  1502 void
  1503 LayerManager::Log(const char* aPrefix)
  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;
  1517   GetRoot()->Log(pfx.get());
  1520 void
  1521 LayerManager::LogSelf(const char* aPrefix)
  1523   nsAutoCString str;
  1524   PrintInfo(str, aPrefix);
  1525   MOZ_LAYERS_LOG(("%s", str.get()));
  1528 nsACString&
  1529 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
  1531   aTo += aPrefix;
  1532   return aTo += nsPrintfCString("%sLayerManager (0x%p)", Name(), this);
  1535 /*static*/ void
  1536 LayerManager::InitLog()
  1538   if (!sLog)
  1539     sLog = PR_NewLogModule("Layers");
  1542 /*static*/ bool
  1543 LayerManager::IsLogEnabled()
  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);
  1550 static nsACString&
  1551 PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite)
  1553   if (!aLayerComposite) {
  1554     return aTo;
  1556   if (const nsIntRect* clipRect = aLayerComposite->GetShadowClipRect()) {
  1557     AppendToString(aTo, *clipRect, " [shadow-clip=", "]");
  1559   if (!aLayerComposite->GetShadowTransform().IsIdentity()) {
  1560     AppendToString(aTo, aLayerComposite->GetShadowTransform(), " [shadow-transform=", "]");
  1562   if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
  1563     AppendToString(aTo, aLayerComposite->GetShadowVisibleRegion(), " [shadow-visible=", "]");
  1565   return aTo;
  1568 void
  1569 SetAntialiasingFlags(Layer* aLayer, DrawTarget* aTarget)
  1571   bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
  1572   if (aTarget->GetFormat() != SurfaceFormat::B8G8R8A8) {
  1573     aTarget->SetPermitSubpixelAA(permitSubpixelAA);
  1574     return;
  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);
  1588 void
  1589 SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget)
  1591   if (!aTarget->IsCairo()) {
  1592     SetAntialiasingFlags(aLayer, aTarget->GetDrawTarget());
  1593     return;
  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;
  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);
  1611 PRLogModuleInfo* LayerManager::sLog;
  1613 } // namespace layers
  1614 } // namespace mozilla

mercurial