gfx/layers/Layers.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/Layers.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1614 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * vim: sw=2 ts=8 et :
     1.6 + */
     1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +#include "Layers.h"
    1.12 +#include <algorithm>                    // for max, min
    1.13 +#include "AnimationCommon.h"            // for ComputedTimingFunction
    1.14 +#include "CompositableHost.h"           // for CompositableHost
    1.15 +#include "ImageContainer.h"             // for ImageContainer, etc
    1.16 +#include "ImageLayers.h"                // for ImageLayer
    1.17 +#include "LayerSorter.h"                // for SortLayersBy3DZOrder
    1.18 +#include "LayersLogging.h"              // for AppendToString
    1.19 +#include "ReadbackLayer.h"              // for ReadbackLayer
    1.20 +#include "gfxPlatform.h"                // for gfxPlatform
    1.21 +#include "gfxUtils.h"                   // for gfxUtils, etc
    1.22 +#include "gfx2DGlue.h"
    1.23 +#include "mozilla/DebugOnly.h"          // for DebugOnly
    1.24 +#include "mozilla/Telemetry.h"          // for Accumulate
    1.25 +#include "mozilla/gfx/2D.h"             // for DrawTarget
    1.26 +#include "mozilla/gfx/BaseSize.h"       // for BaseSize
    1.27 +#include "mozilla/gfx/Matrix.h"         // for Matrix4x4
    1.28 +#include "mozilla/layers/AsyncPanZoomController.h"
    1.29 +#include "mozilla/layers/Compositor.h"  // for Compositor
    1.30 +#include "mozilla/layers/CompositorTypes.h"
    1.31 +#include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite
    1.32 +#include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
    1.33 +#include "nsAString.h"
    1.34 +#include "nsCSSValue.h"                 // for nsCSSValue::Array, etc
    1.35 +#include "nsPrintfCString.h"            // for nsPrintfCString
    1.36 +#include "nsStyleStruct.h"              // for nsTimingFunction, etc
    1.37 +
    1.38 +using namespace mozilla::layers;
    1.39 +using namespace mozilla::gfx;
    1.40 +
    1.41 +typedef FrameMetrics::ViewID ViewID;
    1.42 +const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
    1.43 +
    1.44 +uint8_t gLayerManagerLayerBuilder;
    1.45 +
    1.46 +FILE*
    1.47 +FILEOrDefault(FILE* aFile)
    1.48 +{
    1.49 +  return aFile ? aFile : stderr;
    1.50 +}
    1.51 +
    1.52 +namespace mozilla {
    1.53 +namespace layers {
    1.54 +
    1.55 +//--------------------------------------------------
    1.56 +// LayerManager
    1.57 +Layer*
    1.58 +LayerManager::GetPrimaryScrollableLayer()
    1.59 +{
    1.60 +  if (!mRoot) {
    1.61 +    return nullptr;
    1.62 +  }
    1.63 +
    1.64 +  nsTArray<Layer*> queue;
    1.65 +  queue.AppendElement(mRoot);
    1.66 +  while (queue.Length()) {
    1.67 +    ContainerLayer* containerLayer = queue[0]->AsContainerLayer();
    1.68 +    queue.RemoveElementAt(0);
    1.69 +    if (!containerLayer) {
    1.70 +      continue;
    1.71 +    }
    1.72 +
    1.73 +    const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
    1.74 +    if (frameMetrics.IsScrollable()) {
    1.75 +      return containerLayer;
    1.76 +    }
    1.77 +
    1.78 +    Layer* child = containerLayer->GetFirstChild();
    1.79 +    while (child) {
    1.80 +      queue.AppendElement(child);
    1.81 +      child = child->GetNextSibling();
    1.82 +    }
    1.83 +  }
    1.84 +
    1.85 +  return mRoot;
    1.86 +}
    1.87 +
    1.88 +void
    1.89 +LayerManager::GetScrollableLayers(nsTArray<Layer*>& aArray)
    1.90 +{
    1.91 +  if (!mRoot) {
    1.92 +    return;
    1.93 +  }
    1.94 +
    1.95 +  nsTArray<Layer*> queue;
    1.96 +  queue.AppendElement(mRoot);
    1.97 +  while (!queue.IsEmpty()) {
    1.98 +    ContainerLayer* containerLayer = queue.LastElement()->AsContainerLayer();
    1.99 +    queue.RemoveElementAt(queue.Length() - 1);
   1.100 +    if (!containerLayer) {
   1.101 +      continue;
   1.102 +    }
   1.103 +
   1.104 +    const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
   1.105 +    if (frameMetrics.IsScrollable()) {
   1.106 +      aArray.AppendElement(containerLayer);
   1.107 +      continue;
   1.108 +    }
   1.109 +
   1.110 +    Layer* child = containerLayer->GetFirstChild();
   1.111 +    while (child) {
   1.112 +      queue.AppendElement(child);
   1.113 +      child = child->GetNextSibling();
   1.114 +    }
   1.115 +  }
   1.116 +}
   1.117 +
   1.118 +TemporaryRef<DrawTarget>
   1.119 +LayerManager::CreateOptimalDrawTarget(const gfx::IntSize &aSize,
   1.120 +                                      SurfaceFormat aFormat)
   1.121 +{
   1.122 +  return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aSize,
   1.123 +                                                                      aFormat);
   1.124 +}
   1.125 +
   1.126 +TemporaryRef<DrawTarget>
   1.127 +LayerManager::CreateOptimalMaskDrawTarget(const gfx::IntSize &aSize)
   1.128 +{
   1.129 +  return CreateOptimalDrawTarget(aSize, SurfaceFormat::A8);
   1.130 +}
   1.131 +
   1.132 +TemporaryRef<DrawTarget>
   1.133 +LayerManager::CreateDrawTarget(const IntSize &aSize,
   1.134 +                               SurfaceFormat aFormat)
   1.135 +{
   1.136 +  return gfxPlatform::GetPlatform()->
   1.137 +    CreateOffscreenCanvasDrawTarget(aSize, aFormat);
   1.138 +}
   1.139 +
   1.140 +#ifdef DEBUG
   1.141 +void
   1.142 +LayerManager::Mutated(Layer* aLayer)
   1.143 +{
   1.144 +}
   1.145 +#endif  // DEBUG
   1.146 +
   1.147 +already_AddRefed<ImageContainer>
   1.148 +LayerManager::CreateImageContainer()
   1.149 +{
   1.150 +  nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::DISABLE_ASYNC);
   1.151 +  return container.forget();
   1.152 +}
   1.153 +
   1.154 +already_AddRefed<ImageContainer>
   1.155 +LayerManager::CreateAsynchronousImageContainer()
   1.156 +{
   1.157 +  nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::ENABLE_ASYNC);
   1.158 +  return container.forget();
   1.159 +}
   1.160 +
   1.161 +//--------------------------------------------------
   1.162 +// Layer
   1.163 +
   1.164 +Layer::Layer(LayerManager* aManager, void* aImplData) :
   1.165 +  mManager(aManager),
   1.166 +  mParent(nullptr),
   1.167 +  mNextSibling(nullptr),
   1.168 +  mPrevSibling(nullptr),
   1.169 +  mImplData(aImplData),
   1.170 +  mMaskLayer(nullptr),
   1.171 +  mPostXScale(1.0f),
   1.172 +  mPostYScale(1.0f),
   1.173 +  mOpacity(1.0),
   1.174 +  mMixBlendMode(CompositionOp::OP_OVER),
   1.175 +  mForceIsolatedGroup(false),
   1.176 +  mContentFlags(0),
   1.177 +  mUseClipRect(false),
   1.178 +  mUseTileSourceRect(false),
   1.179 +  mIsFixedPosition(false),
   1.180 +  mMargins(0, 0, 0, 0),
   1.181 +  mStickyPositionData(nullptr),
   1.182 +  mScrollbarTargetId(FrameMetrics::NULL_SCROLL_ID),
   1.183 +  mScrollbarDirection(ScrollDirection::NONE),
   1.184 +  mDebugColorIndex(0),
   1.185 +  mAnimationGeneration(0)
   1.186 +{}
   1.187 +
   1.188 +Layer::~Layer()
   1.189 +{}
   1.190 +
   1.191 +Animation*
   1.192 +Layer::AddAnimation()
   1.193 +{
   1.194 +  MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) AddAnimation", this));
   1.195 +
   1.196 +  MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
   1.197 +
   1.198 +  Animation* anim = mAnimations.AppendElement();
   1.199 +
   1.200 +  Mutated();
   1.201 +  return anim;
   1.202 +}
   1.203 +
   1.204 +void
   1.205 +Layer::ClearAnimations()
   1.206 +{
   1.207 +  mPendingAnimations = nullptr;
   1.208 +
   1.209 +  if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
   1.210 +    return;
   1.211 +  }
   1.212 +
   1.213 +  MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClearAnimations", this));
   1.214 +  mAnimations.Clear();
   1.215 +  mAnimationData.Clear();
   1.216 +  Mutated();
   1.217 +}
   1.218 +
   1.219 +Animation*
   1.220 +Layer::AddAnimationForNextTransaction()
   1.221 +{
   1.222 +  MOZ_ASSERT(mPendingAnimations,
   1.223 +             "should have called ClearAnimationsForNextTransaction first");
   1.224 +
   1.225 +  Animation* anim = mPendingAnimations->AppendElement();
   1.226 +
   1.227 +  return anim;
   1.228 +}
   1.229 +
   1.230 +void
   1.231 +Layer::ClearAnimationsForNextTransaction()
   1.232 +{
   1.233 +  // Ensure we have a non-null mPendingAnimations to mark a future clear.
   1.234 +  if (!mPendingAnimations) {
   1.235 +    mPendingAnimations = new AnimationArray;
   1.236 +  }
   1.237 +
   1.238 +  mPendingAnimations->Clear();
   1.239 +}
   1.240 +
   1.241 +static nsCSSValueSharedList*
   1.242 +CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
   1.243 +{
   1.244 +  nsAutoPtr<nsCSSValueList> result;
   1.245 +  nsCSSValueList** resultTail = getter_Transfers(result);
   1.246 +  for (uint32_t i = 0; i < aFunctions.Length(); i++) {
   1.247 +    nsRefPtr<nsCSSValue::Array> arr;
   1.248 +    switch (aFunctions[i].type()) {
   1.249 +      case TransformFunction::TRotationX:
   1.250 +      {
   1.251 +        float theta = aFunctions[i].get_RotationX().radians();
   1.252 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatex, resultTail);
   1.253 +        arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
   1.254 +        break;
   1.255 +      }
   1.256 +      case TransformFunction::TRotationY:
   1.257 +      {
   1.258 +        float theta = aFunctions[i].get_RotationY().radians();
   1.259 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatey, resultTail);
   1.260 +        arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
   1.261 +        break;
   1.262 +      }
   1.263 +      case TransformFunction::TRotationZ:
   1.264 +      {
   1.265 +        float theta = aFunctions[i].get_RotationZ().radians();
   1.266 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotatez, resultTail);
   1.267 +        arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
   1.268 +        break;
   1.269 +      }
   1.270 +      case TransformFunction::TRotation:
   1.271 +      {
   1.272 +        float theta = aFunctions[i].get_Rotation().radians();
   1.273 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotate, resultTail);
   1.274 +        arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
   1.275 +        break;
   1.276 +      }
   1.277 +      case TransformFunction::TRotation3D:
   1.278 +      {
   1.279 +        float x = aFunctions[i].get_Rotation3D().x();
   1.280 +        float y = aFunctions[i].get_Rotation3D().y();
   1.281 +        float z = aFunctions[i].get_Rotation3D().z();
   1.282 +        float theta = aFunctions[i].get_Rotation3D().radians();
   1.283 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_rotate3d, resultTail);
   1.284 +        arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
   1.285 +        arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
   1.286 +        arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
   1.287 +        arr->Item(4).SetFloatValue(theta, eCSSUnit_Radian);
   1.288 +        break;
   1.289 +      }
   1.290 +      case TransformFunction::TScale:
   1.291 +      {
   1.292 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_scale3d, resultTail);
   1.293 +        arr->Item(1).SetFloatValue(aFunctions[i].get_Scale().x(), eCSSUnit_Number);
   1.294 +        arr->Item(2).SetFloatValue(aFunctions[i].get_Scale().y(), eCSSUnit_Number);
   1.295 +        arr->Item(3).SetFloatValue(aFunctions[i].get_Scale().z(), eCSSUnit_Number);
   1.296 +        break;
   1.297 +      }
   1.298 +      case TransformFunction::TTranslation:
   1.299 +      {
   1.300 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_translate3d, resultTail);
   1.301 +        arr->Item(1).SetFloatValue(aFunctions[i].get_Translation().x(), eCSSUnit_Pixel);
   1.302 +        arr->Item(2).SetFloatValue(aFunctions[i].get_Translation().y(), eCSSUnit_Pixel);
   1.303 +        arr->Item(3).SetFloatValue(aFunctions[i].get_Translation().z(), eCSSUnit_Pixel);
   1.304 +        break;
   1.305 +      }
   1.306 +      case TransformFunction::TSkewX:
   1.307 +      {
   1.308 +        float x = aFunctions[i].get_SkewX().x();
   1.309 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skewx, resultTail);
   1.310 +        arr->Item(1).SetFloatValue(x, eCSSUnit_Radian);
   1.311 +        break;
   1.312 +      }
   1.313 +      case TransformFunction::TSkewY:
   1.314 +      {
   1.315 +        float y = aFunctions[i].get_SkewY().y();
   1.316 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skewy, resultTail);
   1.317 +        arr->Item(1).SetFloatValue(y, eCSSUnit_Radian);
   1.318 +        break;
   1.319 +      }
   1.320 +      case TransformFunction::TSkew:
   1.321 +      {
   1.322 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_skew, resultTail);
   1.323 +        arr->Item(1).SetFloatValue(aFunctions[i].get_Skew().x(), eCSSUnit_Radian);
   1.324 +        arr->Item(2).SetFloatValue(aFunctions[i].get_Skew().y(), eCSSUnit_Radian);
   1.325 +        break;
   1.326 +      }
   1.327 +      case TransformFunction::TTransformMatrix:
   1.328 +      {
   1.329 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_matrix3d, resultTail);
   1.330 +        const gfx::Matrix4x4& matrix = aFunctions[i].get_TransformMatrix().value();
   1.331 +        arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
   1.332 +        arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
   1.333 +        arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
   1.334 +        arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number);
   1.335 +        arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number);
   1.336 +        arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number);
   1.337 +        arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number);
   1.338 +        arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number);
   1.339 +        arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number);
   1.340 +        arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number);
   1.341 +        arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number);
   1.342 +        arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number);
   1.343 +        arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number);
   1.344 +        arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number);
   1.345 +        arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number);
   1.346 +        arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number);
   1.347 +        break;
   1.348 +      }
   1.349 +      case TransformFunction::TPerspective:
   1.350 +      {
   1.351 +        float perspective = aFunctions[i].get_Perspective().value();
   1.352 +        arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_perspective, resultTail);
   1.353 +        arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel);
   1.354 +        break;
   1.355 +      }
   1.356 +      default:
   1.357 +        NS_ASSERTION(false, "All functions should be implemented?");
   1.358 +    }
   1.359 +  }
   1.360 +  if (aFunctions.Length() == 0) {
   1.361 +    result = new nsCSSValueList();
   1.362 +    result->mValue.SetNoneValue();
   1.363 +  }
   1.364 +  return new nsCSSValueSharedList(result.forget());
   1.365 +}
   1.366 +
   1.367 +void
   1.368 +Layer::SetAnimations(const AnimationArray& aAnimations)
   1.369 +{
   1.370 +  MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) SetAnimations", this));
   1.371 +
   1.372 +  mAnimations = aAnimations;
   1.373 +  mAnimationData.Clear();
   1.374 +  for (uint32_t i = 0; i < mAnimations.Length(); i++) {
   1.375 +    AnimData* data = mAnimationData.AppendElement();
   1.376 +    InfallibleTArray<nsAutoPtr<css::ComputedTimingFunction> >& functions = data->mFunctions;
   1.377 +    const InfallibleTArray<AnimationSegment>& segments =
   1.378 +      mAnimations.ElementAt(i).segments();
   1.379 +    for (uint32_t j = 0; j < segments.Length(); j++) {
   1.380 +      TimingFunction tf = segments.ElementAt(j).sampleFn();
   1.381 +      css::ComputedTimingFunction* ctf = new css::ComputedTimingFunction();
   1.382 +      switch (tf.type()) {
   1.383 +        case TimingFunction::TCubicBezierFunction: {
   1.384 +          CubicBezierFunction cbf = tf.get_CubicBezierFunction();
   1.385 +          ctf->Init(nsTimingFunction(cbf.x1(), cbf.y1(), cbf.x2(), cbf.y2()));
   1.386 +          break;
   1.387 +        }
   1.388 +        default: {
   1.389 +          NS_ASSERTION(tf.type() == TimingFunction::TStepFunction,
   1.390 +                       "Function must be bezier or step");
   1.391 +          StepFunction sf = tf.get_StepFunction();
   1.392 +          nsTimingFunction::Type type = sf.type() == 1 ? nsTimingFunction::StepStart
   1.393 +                                                       : nsTimingFunction::StepEnd;
   1.394 +          ctf->Init(nsTimingFunction(type, sf.steps()));
   1.395 +          break;
   1.396 +        }
   1.397 +      }
   1.398 +      functions.AppendElement(ctf);
   1.399 +    }
   1.400 +
   1.401 +    // Precompute the nsStyleAnimation::Values that we need if this is a transform
   1.402 +    // animation.
   1.403 +    InfallibleTArray<nsStyleAnimation::Value>& startValues = data->mStartValues;
   1.404 +    InfallibleTArray<nsStyleAnimation::Value>& endValues = data->mEndValues;
   1.405 +    for (uint32_t j = 0; j < mAnimations[i].segments().Length(); j++) {
   1.406 +      const AnimationSegment& segment = mAnimations[i].segments()[j];
   1.407 +      nsStyleAnimation::Value* startValue = startValues.AppendElement();
   1.408 +      nsStyleAnimation::Value* endValue = endValues.AppendElement();
   1.409 +      if (segment.endState().type() == Animatable::TArrayOfTransformFunction) {
   1.410 +        const InfallibleTArray<TransformFunction>& startFunctions =
   1.411 +          segment.startState().get_ArrayOfTransformFunction();
   1.412 +        startValue->SetTransformValue(CreateCSSValueList(startFunctions));
   1.413 +
   1.414 +        const InfallibleTArray<TransformFunction>& endFunctions =
   1.415 +          segment.endState().get_ArrayOfTransformFunction();
   1.416 +        endValue->SetTransformValue(CreateCSSValueList(endFunctions));
   1.417 +      } else {
   1.418 +        NS_ASSERTION(segment.endState().type() == Animatable::Tfloat,
   1.419 +                     "Unknown Animatable type");
   1.420 +        startValue->SetFloatValue(segment.startState().get_float());
   1.421 +        endValue->SetFloatValue(segment.endState().get_float());
   1.422 +      }
   1.423 +    }
   1.424 +  }
   1.425 +
   1.426 +  Mutated();
   1.427 +}
   1.428 +
   1.429 +void
   1.430 +ContainerLayer::SetAsyncPanZoomController(AsyncPanZoomController *controller)
   1.431 +{
   1.432 +  mAPZC = controller;
   1.433 +}
   1.434 +
   1.435 +AsyncPanZoomController*
   1.436 +ContainerLayer::GetAsyncPanZoomController() const
   1.437 +{
   1.438 +#ifdef DEBUG
   1.439 +  if (mAPZC) {
   1.440 +    MOZ_ASSERT(GetFrameMetrics().IsScrollable());
   1.441 +  }
   1.442 +#endif
   1.443 +  return mAPZC;
   1.444 +}
   1.445 +
   1.446 +void
   1.447 +Layer::ApplyPendingUpdatesToSubtree()
   1.448 +{
   1.449 +  ApplyPendingUpdatesForThisTransaction();
   1.450 +  for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
   1.451 +    child->ApplyPendingUpdatesToSubtree();
   1.452 +  }
   1.453 +}
   1.454 +
   1.455 +bool
   1.456 +Layer::CanUseOpaqueSurface()
   1.457 +{
   1.458 +  // If the visible content in the layer is opaque, there is no need
   1.459 +  // for an alpha channel.
   1.460 +  if (GetContentFlags() & CONTENT_OPAQUE)
   1.461 +    return true;
   1.462 +  // Also, if this layer is the bottommost layer in a container which
   1.463 +  // doesn't need an alpha channel, we can use an opaque surface for this
   1.464 +  // layer too. Any transparent areas must be covered by something else
   1.465 +  // in the container.
   1.466 +  ContainerLayer* parent = GetParent();
   1.467 +  return parent && parent->GetFirstChild() == this &&
   1.468 +    parent->CanUseOpaqueSurface();
   1.469 +}
   1.470 +
   1.471 +// NB: eventually these methods will be defined unconditionally, and
   1.472 +// can be moved into Layers.h
   1.473 +const nsIntRect*
   1.474 +Layer::GetEffectiveClipRect()
   1.475 +{
   1.476 +  if (LayerComposite* shadow = AsLayerComposite()) {
   1.477 +    return shadow->GetShadowClipRect();
   1.478 +  }
   1.479 +  return GetClipRect();
   1.480 +}
   1.481 +
   1.482 +const nsIntRegion&
   1.483 +Layer::GetEffectiveVisibleRegion()
   1.484 +{
   1.485 +  if (LayerComposite* shadow = AsLayerComposite()) {
   1.486 +    return shadow->GetShadowVisibleRegion();
   1.487 +  }
   1.488 +  return GetVisibleRegion();
   1.489 +}
   1.490 +
   1.491 +Matrix4x4
   1.492 +Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
   1.493 +                                Matrix* aResidualTransform)
   1.494 +{
   1.495 +  if (aResidualTransform) {
   1.496 +    *aResidualTransform = Matrix();
   1.497 +  }
   1.498 +
   1.499 +  Matrix matrix2D;
   1.500 +  Matrix4x4 result;
   1.501 +  if (mManager->IsSnappingEffectiveTransforms() &&
   1.502 +      aTransform.Is2D(&matrix2D) &&
   1.503 +      !matrix2D.HasNonTranslation() &&
   1.504 +      matrix2D.HasNonIntegerTranslation()) {
   1.505 +    IntPoint snappedTranslation = RoundedToInt(matrix2D.GetTranslation());
   1.506 +    Matrix snappedMatrix = Matrix::Translation(snappedTranslation.x,
   1.507 +                                               snappedTranslation.y);
   1.508 +    result = Matrix4x4::From2D(snappedMatrix);
   1.509 +    if (aResidualTransform) {
   1.510 +      // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
   1.511 +      // (I.e., appying snappedMatrix after aResidualTransform gives the
   1.512 +      // ideal transform.)
   1.513 +      *aResidualTransform =
   1.514 +        Matrix::Translation(matrix2D._31 - snappedTranslation.x,
   1.515 +                            matrix2D._32 - snappedTranslation.y);
   1.516 +    }
   1.517 +  } else {
   1.518 +    result = aTransform;
   1.519 +  }
   1.520 +  return result;
   1.521 +}
   1.522 +
   1.523 +Matrix4x4
   1.524 +Layer::SnapTransform(const Matrix4x4& aTransform,
   1.525 +                     const gfxRect& aSnapRect,
   1.526 +                     Matrix* aResidualTransform)
   1.527 +{
   1.528 +  if (aResidualTransform) {
   1.529 +    *aResidualTransform = Matrix();
   1.530 +  }
   1.531 +
   1.532 +  Matrix matrix2D;
   1.533 +  Matrix4x4 result;
   1.534 +  if (mManager->IsSnappingEffectiveTransforms() &&
   1.535 +      aTransform.Is2D(&matrix2D) &&
   1.536 +      gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) &&
   1.537 +      matrix2D.PreservesAxisAlignedRectangles()) {
   1.538 +    IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft()));
   1.539 +    IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight()));
   1.540 +    IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight()));
   1.541 +
   1.542 +    Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
   1.543 +      transformedTopLeft, transformedTopRight, transformedBottomRight);
   1.544 +
   1.545 +    result = Matrix4x4::From2D(snappedMatrix);
   1.546 +    if (aResidualTransform && !snappedMatrix.IsSingular()) {
   1.547 +      // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
   1.548 +      // (i.e., appying snappedMatrix after aResidualTransform gives the
   1.549 +      // ideal transform.
   1.550 +      Matrix snappedMatrixInverse = snappedMatrix;
   1.551 +      snappedMatrixInverse.Invert();
   1.552 +      *aResidualTransform = matrix2D * snappedMatrixInverse;
   1.553 +    }
   1.554 +  } else {
   1.555 +    result = aTransform;
   1.556 +  }
   1.557 +  return result;
   1.558 +}
   1.559 +
   1.560 +static bool
   1.561 +AncestorLayerMayChangeTransform(Layer* aLayer)
   1.562 +{
   1.563 +  for (Layer* l = aLayer; l; l = l->GetParent()) {
   1.564 +    if (l->GetContentFlags() & Layer::CONTENT_MAY_CHANGE_TRANSFORM) {
   1.565 +      return true;
   1.566 +    }
   1.567 +  }
   1.568 +  return false;
   1.569 +}
   1.570 +
   1.571 +bool
   1.572 +Layer::MayResample()
   1.573 +{
   1.574 +  Matrix transform2d;
   1.575 +  return !GetEffectiveTransform().Is2D(&transform2d) ||
   1.576 +         ThebesMatrix(transform2d).HasNonIntegerTranslation() ||
   1.577 +         AncestorLayerMayChangeTransform(this);
   1.578 +}
   1.579 +
   1.580 +nsIntRect
   1.581 +Layer::CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
   1.582 +                            const gfx::Matrix* aWorldTransform)
   1.583 +{
   1.584 +  ContainerLayer* container = GetParent();
   1.585 +  NS_ASSERTION(container, "This can't be called on the root!");
   1.586 +
   1.587 +  // Establish initial clip rect: it's either the one passed in, or
   1.588 +  // if the parent has an intermediate surface, it's the extents of that surface.
   1.589 +  nsIntRect currentClip;
   1.590 +  if (container->UseIntermediateSurface()) {
   1.591 +    currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
   1.592 +  } else {
   1.593 +    currentClip = aCurrentScissorRect;
   1.594 +  }
   1.595 +
   1.596 +  const nsIntRect *clipRect = GetEffectiveClipRect();
   1.597 +  if (!clipRect)
   1.598 +    return currentClip;
   1.599 +
   1.600 +  if (clipRect->IsEmpty()) {
   1.601 +    // We might have a non-translation transform in the container so we can't
   1.602 +    // use the code path below.
   1.603 +    return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
   1.604 +  }
   1.605 +
   1.606 +  nsIntRect scissor = *clipRect;
   1.607 +  if (!container->UseIntermediateSurface()) {
   1.608 +    gfx::Matrix matrix;
   1.609 +    DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
   1.610 +    // See DefaultComputeEffectiveTransforms below
   1.611 +    NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
   1.612 +                 "Non preserves axis aligned transform with clipped child should have forced intermediate surface");
   1.613 +    gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
   1.614 +    gfxRect trScissor = gfx::ThebesRect(matrix.TransformBounds(r));
   1.615 +    trScissor.Round();
   1.616 +    if (!gfxUtils::GfxRectToIntRect(trScissor, &scissor)) {
   1.617 +      return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
   1.618 +    }
   1.619 +
   1.620 +    // Find the nearest ancestor with an intermediate surface
   1.621 +    do {
   1.622 +      container = container->GetParent();
   1.623 +    } while (container && !container->UseIntermediateSurface());
   1.624 +  }
   1.625 +  if (container) {
   1.626 +    scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
   1.627 +  } else if (aWorldTransform) {
   1.628 +    gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
   1.629 +    gfx::Rect trScissor = aWorldTransform->TransformBounds(r);
   1.630 +    trScissor.Round();
   1.631 +    if (!gfxUtils::GfxRectToIntRect(ThebesRect(trScissor), &scissor))
   1.632 +      return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
   1.633 +  }
   1.634 +  return currentClip.Intersect(scissor);
   1.635 +}
   1.636 +
   1.637 +const Matrix4x4
   1.638 +Layer::GetTransform() const
   1.639 +{
   1.640 +  Matrix4x4 transform = mTransform;
   1.641 +  if (const ContainerLayer* c = AsContainerLayer()) {
   1.642 +    transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   1.643 +  }
   1.644 +  transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
   1.645 +  return transform;
   1.646 +}
   1.647 +
   1.648 +const Matrix4x4
   1.649 +Layer::GetLocalTransform()
   1.650 +{
   1.651 +  Matrix4x4 transform;
   1.652 +  if (LayerComposite* shadow = AsLayerComposite())
   1.653 +    transform = shadow->GetShadowTransform();
   1.654 +  else
   1.655 +    transform = mTransform;
   1.656 +  if (ContainerLayer* c = AsContainerLayer()) {
   1.657 +    transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
   1.658 +  }
   1.659 +  transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
   1.660 +
   1.661 +  return transform;
   1.662 +}
   1.663 +
   1.664 +void
   1.665 +Layer::ApplyPendingUpdatesForThisTransaction()
   1.666 +{
   1.667 +  if (mPendingTransform && *mPendingTransform != mTransform) {
   1.668 +    MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
   1.669 +    mTransform = *mPendingTransform;
   1.670 +    Mutated();
   1.671 +  }
   1.672 +  mPendingTransform = nullptr;
   1.673 +
   1.674 +  if (mPendingAnimations) {
   1.675 +    MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
   1.676 +    mPendingAnimations->SwapElements(mAnimations);
   1.677 +    mPendingAnimations = nullptr;
   1.678 +    Mutated();
   1.679 +  }
   1.680 +}
   1.681 +
   1.682 +const float
   1.683 +Layer::GetLocalOpacity()
   1.684 +{
   1.685 +   if (LayerComposite* shadow = AsLayerComposite())
   1.686 +    return shadow->GetShadowOpacity();
   1.687 +  return mOpacity;
   1.688 +}
   1.689 +
   1.690 +float
   1.691 +Layer::GetEffectiveOpacity()
   1.692 +{
   1.693 +  float opacity = GetLocalOpacity();
   1.694 +  for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
   1.695 +       c = c->GetParent()) {
   1.696 +    opacity *= c->GetLocalOpacity();
   1.697 +  }
   1.698 +  return opacity;
   1.699 +}
   1.700 +  
   1.701 +CompositionOp
   1.702 +Layer::GetEffectiveMixBlendMode()
   1.703 +{
   1.704 +  if(mMixBlendMode != CompositionOp::OP_OVER)
   1.705 +    return mMixBlendMode;
   1.706 +  for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
   1.707 +    c = c->GetParent()) {
   1.708 +    if(c->mMixBlendMode != CompositionOp::OP_OVER)
   1.709 +      return c->mMixBlendMode;
   1.710 +  }
   1.711 +
   1.712 +  return mMixBlendMode;
   1.713 +}
   1.714 +
   1.715 +gfxContext::GraphicsOperator
   1.716 +Layer::DeprecatedGetEffectiveMixBlendMode()
   1.717 +{
   1.718 +  return ThebesOp(GetEffectiveMixBlendMode());
   1.719 +}
   1.720 +
   1.721 +void
   1.722 +Layer::ComputeEffectiveTransformForMaskLayer(const Matrix4x4& aTransformToSurface)
   1.723 +{
   1.724 +  if (mMaskLayer) {
   1.725 +    mMaskLayer->mEffectiveTransform = aTransformToSurface;
   1.726 +
   1.727 +#ifdef DEBUG
   1.728 +    bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D();
   1.729 +    NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
   1.730 +#endif
   1.731 +    mMaskLayer->mEffectiveTransform = mMaskLayer->GetTransform() * mMaskLayer->mEffectiveTransform;
   1.732 +  }
   1.733 +}
   1.734 +
   1.735 +ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
   1.736 +  : Layer(aManager, aImplData),
   1.737 +    mFirstChild(nullptr),
   1.738 +    mLastChild(nullptr),
   1.739 +    mScrollHandoffParentId(FrameMetrics::NULL_SCROLL_ID),
   1.740 +    mPreXScale(1.0f),
   1.741 +    mPreYScale(1.0f),
   1.742 +    mInheritedXScale(1.0f),
   1.743 +    mInheritedYScale(1.0f),
   1.744 +    mUseIntermediateSurface(false),
   1.745 +    mSupportsComponentAlphaChildren(false),
   1.746 +    mMayHaveReadbackChild(false)
   1.747 +{
   1.748 +  mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
   1.749 +}
   1.750 +
   1.751 +ContainerLayer::~ContainerLayer() {}
   1.752 +
   1.753 +bool
   1.754 +ContainerLayer::InsertAfter(Layer* aChild, Layer* aAfter)
   1.755 +{
   1.756 +  if(aChild->Manager() != Manager()) {
   1.757 +    NS_ERROR("Child has wrong manager");
   1.758 +    return false;
   1.759 +  }
   1.760 +  if(aChild->GetParent()) {
   1.761 +    NS_ERROR("aChild already in the tree");
   1.762 +    return false;
   1.763 +  }
   1.764 +  if (aChild->GetNextSibling() || aChild->GetPrevSibling()) {
   1.765 +    NS_ERROR("aChild already has siblings?");
   1.766 +    return false;
   1.767 +  }
   1.768 +  if (aAfter && (aAfter->Manager() != Manager() ||
   1.769 +                 aAfter->GetParent() != this))
   1.770 +  {
   1.771 +    NS_ERROR("aAfter is not our child");
   1.772 +    return false;
   1.773 +  }
   1.774 +
   1.775 +  aChild->SetParent(this);
   1.776 +  if (aAfter == mLastChild) {
   1.777 +    mLastChild = aChild;
   1.778 +  }
   1.779 +  if (!aAfter) {
   1.780 +    aChild->SetNextSibling(mFirstChild);
   1.781 +    if (mFirstChild) {
   1.782 +      mFirstChild->SetPrevSibling(aChild);
   1.783 +    }
   1.784 +    mFirstChild = aChild;
   1.785 +    NS_ADDREF(aChild);
   1.786 +    DidInsertChild(aChild);
   1.787 +    return true;
   1.788 +  }
   1.789 +
   1.790 +  Layer* next = aAfter->GetNextSibling();
   1.791 +  aChild->SetNextSibling(next);
   1.792 +  aChild->SetPrevSibling(aAfter);
   1.793 +  if (next) {
   1.794 +    next->SetPrevSibling(aChild);
   1.795 +  }
   1.796 +  aAfter->SetNextSibling(aChild);
   1.797 +  NS_ADDREF(aChild);
   1.798 +  DidInsertChild(aChild);
   1.799 +  return true;
   1.800 +}
   1.801 +
   1.802 +bool
   1.803 +ContainerLayer::RemoveChild(Layer *aChild)
   1.804 +{
   1.805 +  if (aChild->Manager() != Manager()) {
   1.806 +    NS_ERROR("Child has wrong manager");
   1.807 +    return false;
   1.808 +  }
   1.809 +  if (aChild->GetParent() != this) {
   1.810 +    NS_ERROR("aChild not our child");
   1.811 +    return false;
   1.812 +  }
   1.813 +
   1.814 +  Layer* prev = aChild->GetPrevSibling();
   1.815 +  Layer* next = aChild->GetNextSibling();
   1.816 +  if (prev) {
   1.817 +    prev->SetNextSibling(next);
   1.818 +  } else {
   1.819 +    this->mFirstChild = next;
   1.820 +  }
   1.821 +  if (next) {
   1.822 +    next->SetPrevSibling(prev);
   1.823 +  } else {
   1.824 +    this->mLastChild = prev;
   1.825 +  }
   1.826 +
   1.827 +  aChild->SetNextSibling(nullptr);
   1.828 +  aChild->SetPrevSibling(nullptr);
   1.829 +  aChild->SetParent(nullptr);
   1.830 +
   1.831 +  this->DidRemoveChild(aChild);
   1.832 +  NS_RELEASE(aChild);
   1.833 +  return true;
   1.834 +}
   1.835 +
   1.836 +
   1.837 +bool
   1.838 +ContainerLayer::RepositionChild(Layer* aChild, Layer* aAfter)
   1.839 +{
   1.840 +  if (aChild->Manager() != Manager()) {
   1.841 +    NS_ERROR("Child has wrong manager");
   1.842 +    return false;
   1.843 +  }
   1.844 +  if (aChild->GetParent() != this) {
   1.845 +    NS_ERROR("aChild not our child");
   1.846 +    return false;
   1.847 +  }
   1.848 +  if (aAfter && (aAfter->Manager() != Manager() ||
   1.849 +                 aAfter->GetParent() != this))
   1.850 +  {
   1.851 +    NS_ERROR("aAfter is not our child");
   1.852 +    return false;
   1.853 +  }
   1.854 +  if (aChild == aAfter) {
   1.855 +    NS_ERROR("aChild cannot be the same as aAfter");
   1.856 +    return false;
   1.857 +  }
   1.858 +
   1.859 +  Layer* prev = aChild->GetPrevSibling();
   1.860 +  Layer* next = aChild->GetNextSibling();
   1.861 +  if (prev == aAfter) {
   1.862 +    // aChild is already in the correct position, nothing to do.
   1.863 +    return true;
   1.864 +  }
   1.865 +  if (prev) {
   1.866 +    prev->SetNextSibling(next);
   1.867 +  } else {
   1.868 +    mFirstChild = next;
   1.869 +  }
   1.870 +  if (next) {
   1.871 +    next->SetPrevSibling(prev);
   1.872 +  } else {
   1.873 +    mLastChild = prev;
   1.874 +  }
   1.875 +  if (!aAfter) {
   1.876 +    aChild->SetPrevSibling(nullptr);
   1.877 +    aChild->SetNextSibling(mFirstChild);
   1.878 +    if (mFirstChild) {
   1.879 +      mFirstChild->SetPrevSibling(aChild);
   1.880 +    }
   1.881 +    mFirstChild = aChild;
   1.882 +    return true;
   1.883 +  }
   1.884 +
   1.885 +  Layer* afterNext = aAfter->GetNextSibling();
   1.886 +  if (afterNext) {
   1.887 +    afterNext->SetPrevSibling(aChild);
   1.888 +  } else {
   1.889 +    mLastChild = aChild;
   1.890 +  }
   1.891 +  aAfter->SetNextSibling(aChild);
   1.892 +  aChild->SetPrevSibling(aAfter);
   1.893 +  aChild->SetNextSibling(afterNext);
   1.894 +  return true;
   1.895 +}
   1.896 +
   1.897 +void
   1.898 +ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
   1.899 +{
   1.900 +  aAttrs = ContainerLayerAttributes(GetFrameMetrics(), mScrollHandoffParentId,
   1.901 +                                    mPreXScale, mPreYScale,
   1.902 +                                    mInheritedXScale, mInheritedYScale);
   1.903 +}
   1.904 +
   1.905 +bool
   1.906 +ContainerLayer::HasMultipleChildren()
   1.907 +{
   1.908 +  uint32_t count = 0;
   1.909 +  for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
   1.910 +    const nsIntRect *clipRect = child->GetEffectiveClipRect();
   1.911 +    if (clipRect && clipRect->IsEmpty())
   1.912 +      continue;
   1.913 +    if (child->GetVisibleRegion().IsEmpty())
   1.914 +      continue;
   1.915 +    ++count;
   1.916 +    if (count > 1)
   1.917 +      return true;
   1.918 +  }
   1.919 +
   1.920 +  return false;
   1.921 +}
   1.922 +
   1.923 +void
   1.924 +ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
   1.925 +{
   1.926 +  nsAutoTArray<Layer*, 10> toSort;
   1.927 +
   1.928 +  for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
   1.929 +    ContainerLayer* container = l->AsContainerLayer();
   1.930 +    if (container && container->GetContentFlags() & CONTENT_PRESERVE_3D) {
   1.931 +      toSort.AppendElement(l);
   1.932 +    } else {
   1.933 +      if (toSort.Length() > 0) {
   1.934 +        SortLayersBy3DZOrder(toSort);
   1.935 +        aArray.MoveElementsFrom(toSort);
   1.936 +      }
   1.937 +      aArray.AppendElement(l);
   1.938 +    }
   1.939 +  }
   1.940 +  if (toSort.Length() > 0) {
   1.941 +    SortLayersBy3DZOrder(toSort);
   1.942 +    aArray.MoveElementsFrom(toSort);
   1.943 +  }
   1.944 +}
   1.945 +
   1.946 +void
   1.947 +ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
   1.948 +{
   1.949 +  Matrix residual;
   1.950 +  Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
   1.951 +  idealTransform.ProjectTo2D();
   1.952 +  mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
   1.953 +
   1.954 +  bool useIntermediateSurface;
   1.955 +  if (GetMaskLayer()) {
   1.956 +    useIntermediateSurface = true;
   1.957 +#ifdef MOZ_DUMP_PAINTING
   1.958 +  } else if (gfxUtils::sDumpPainting) {
   1.959 +    useIntermediateSurface = true;
   1.960 +#endif
   1.961 +  } else {
   1.962 +    float opacity = GetEffectiveOpacity();
   1.963 +    if (opacity != 1.0f && HasMultipleChildren()) {
   1.964 +      useIntermediateSurface = true;
   1.965 +    } else {
   1.966 +      useIntermediateSurface = false;
   1.967 +      gfx::Matrix contTransform;
   1.968 +      if (!mEffectiveTransform.Is2D(&contTransform) ||
   1.969 +#ifdef MOZ_GFX_OPTIMIZE_MOBILE
   1.970 +        !contTransform.PreservesAxisAlignedRectangles()) {
   1.971 +#else
   1.972 +        gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) {
   1.973 +#endif
   1.974 +        for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
   1.975 +          const nsIntRect *clipRect = child->GetEffectiveClipRect();
   1.976 +          /* We can't (easily) forward our transform to children with a non-empty clip
   1.977 +           * rect since it would need to be adjusted for the transform. See
   1.978 +           * the calculations performed by CalculateScissorRect above.
   1.979 +           * Nor for a child with a mask layer.
   1.980 +           */
   1.981 +          if ((clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) ||
   1.982 +              child->GetMaskLayer()) {
   1.983 +            useIntermediateSurface = true;
   1.984 +            break;
   1.985 +          }
   1.986 +        }
   1.987 +      }
   1.988 +    }
   1.989 +  }
   1.990 +
   1.991 +  mUseIntermediateSurface = useIntermediateSurface;
   1.992 +  if (useIntermediateSurface) {
   1.993 +    ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual));
   1.994 +  } else {
   1.995 +    ComputeEffectiveTransformsForChildren(idealTransform);
   1.996 +  }
   1.997 +
   1.998 +  if (idealTransform.CanDraw2D()) {
   1.999 +    ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
  1.1000 +  } else {
  1.1001 +    ComputeEffectiveTransformForMaskLayer(Matrix4x4());
  1.1002 +  }
  1.1003 +}
  1.1004 +
  1.1005 +void
  1.1006 +ContainerLayer::ComputeEffectiveTransformsForChildren(const Matrix4x4& aTransformToSurface)
  1.1007 +{
  1.1008 +  for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
  1.1009 +    l->ComputeEffectiveTransforms(aTransformToSurface);
  1.1010 +  }
  1.1011 +}
  1.1012 +
  1.1013 +/* static */ bool
  1.1014 +ContainerLayer::HasOpaqueAncestorLayer(Layer* aLayer)
  1.1015 +{
  1.1016 +  for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
  1.1017 +    if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
  1.1018 +      return true;
  1.1019 +  }
  1.1020 +  return false;
  1.1021 +}
  1.1022 +
  1.1023 +void
  1.1024 +ContainerLayer::DidRemoveChild(Layer* aLayer)
  1.1025 +{
  1.1026 +  ThebesLayer* tl = aLayer->AsThebesLayer();
  1.1027 +  if (tl && tl->UsedForReadback()) {
  1.1028 +    for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
  1.1029 +      if (l->GetType() == TYPE_READBACK) {
  1.1030 +        static_cast<ReadbackLayer*>(l)->NotifyThebesLayerRemoved(tl);
  1.1031 +      }
  1.1032 +    }
  1.1033 +  }
  1.1034 +  if (aLayer->GetType() == TYPE_READBACK) {
  1.1035 +    static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
  1.1036 +  }
  1.1037 +}
  1.1038 +
  1.1039 +void
  1.1040 +ContainerLayer::DidInsertChild(Layer* aLayer)
  1.1041 +{
  1.1042 +  if (aLayer->GetType() == TYPE_READBACK) {
  1.1043 +    mMayHaveReadbackChild = true;
  1.1044 +  }
  1.1045 +}
  1.1046 +
  1.1047 +void
  1.1048 +RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
  1.1049 +{
  1.1050 +  aAttrs = RefLayerAttributes(GetReferentId());
  1.1051 +}
  1.1052 +
  1.1053 +/** 
  1.1054 + * StartFrameTimeRecording, together with StopFrameTimeRecording
  1.1055 + * enable recording of frame intervals.
  1.1056 + *
  1.1057 + * To allow concurrent consumers, a cyclic array is used which serves all
  1.1058 + * consumers, practically stateless with regard to consumers.
  1.1059 + *
  1.1060 + * To save resources, the buffer is allocated on first call to StartFrameTimeRecording
  1.1061 + * and recording is paused if no consumer which called StartFrameTimeRecording is able
  1.1062 + * to get valid results (because the cyclic buffer was overwritten since that call).
  1.1063 + *
  1.1064 + * To determine availability of the data upon StopFrameTimeRecording:
  1.1065 + * - mRecording.mNextIndex increases on each PostPresent, and never resets.
  1.1066 + * - Cyclic buffer position is realized as mNextIndex % bufferSize.
  1.1067 + * - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is called,
  1.1068 + *   the required start index is passed as an arg, and we're able to calculate the required
  1.1069 + *   length. If this length is bigger than bufferSize, it means data was overwritten.
  1.1070 + *   otherwise, we can return the entire sequence.
  1.1071 + * - To determine if we need to pause, mLatestStartIndex is updated to mNextIndex
  1.1072 + *   on each call to StartFrameTimeRecording. If this index gets overwritten,
  1.1073 + *   it means that all earlier start indices obtained via StartFrameTimeRecording
  1.1074 + *   were also overwritten, hence, no point in recording, so pause.
  1.1075 + * - mCurrentRunStartIndex indicates the oldest index of the recording after which
  1.1076 + *   the recording was not paused. If StopFrameTimeRecording is invoked with a start index
  1.1077 + *   older than this, it means that some frames were not recorded, so data is invalid.
  1.1078 + */
  1.1079 +uint32_t
  1.1080 +LayerManager::StartFrameTimeRecording(int32_t aBufferSize)
  1.1081 +{
  1.1082 +  if (mRecording.mIsPaused) {
  1.1083 +    mRecording.mIsPaused = false;
  1.1084 +
  1.1085 +    if (!mRecording.mIntervals.Length()) { // Initialize recording buffers
  1.1086 +      mRecording.mIntervals.SetLength(aBufferSize);
  1.1087 +    }
  1.1088 +
  1.1089 +    // After being paused, recent values got invalid. Update them to now.
  1.1090 +    mRecording.mLastFrameTime = TimeStamp::Now();
  1.1091 +
  1.1092 +    // Any recording which started before this is invalid, since we were paused.
  1.1093 +    mRecording.mCurrentRunStartIndex = mRecording.mNextIndex;
  1.1094 +  }
  1.1095 +
  1.1096 +  // If we'll overwrite this index, there are no more consumers with aStartIndex
  1.1097 +  // for which we're able to provide the full recording, so no point in keep recording.
  1.1098 +  mRecording.mLatestStartIndex = mRecording.mNextIndex;
  1.1099 +  return mRecording.mNextIndex;
  1.1100 +}
  1.1101 +
  1.1102 +void
  1.1103 +LayerManager::RecordFrame()
  1.1104 +{
  1.1105 +  if (!mRecording.mIsPaused) {
  1.1106 +    TimeStamp now = TimeStamp::Now();
  1.1107 +    uint32_t i = mRecording.mNextIndex % mRecording.mIntervals.Length();
  1.1108 +    mRecording.mIntervals[i] = static_cast<float>((now - mRecording.mLastFrameTime)
  1.1109 +                                                  .ToMilliseconds());
  1.1110 +    mRecording.mNextIndex++;
  1.1111 +    mRecording.mLastFrameTime = now;
  1.1112 +
  1.1113 +    if (mRecording.mNextIndex > (mRecording.mLatestStartIndex + mRecording.mIntervals.Length())) {
  1.1114 +      // We've just overwritten the most recent recording start -> pause.
  1.1115 +      mRecording.mIsPaused = true;
  1.1116 +    }
  1.1117 +  }
  1.1118 +}
  1.1119 +
  1.1120 +void
  1.1121 +LayerManager::PostPresent()
  1.1122 +{
  1.1123 +  if (!mTabSwitchStart.IsNull()) {
  1.1124 +    Telemetry::Accumulate(Telemetry::FX_TAB_SWITCH_TOTAL_MS,
  1.1125 +                          uint32_t((TimeStamp::Now() - mTabSwitchStart).ToMilliseconds()));
  1.1126 +    mTabSwitchStart = TimeStamp();
  1.1127 +  }
  1.1128 +}
  1.1129 +
  1.1130 +void
  1.1131 +LayerManager::StopFrameTimeRecording(uint32_t         aStartIndex,
  1.1132 +                                     nsTArray<float>& aFrameIntervals)
  1.1133 +{
  1.1134 +  uint32_t bufferSize = mRecording.mIntervals.Length();
  1.1135 +  uint32_t length = mRecording.mNextIndex - aStartIndex;
  1.1136 +  if (mRecording.mIsPaused || length > bufferSize || aStartIndex < mRecording.mCurrentRunStartIndex) {
  1.1137 +    // aStartIndex is too old. Also if aStartIndex was issued before mRecordingNextIndex overflowed (uint32_t)
  1.1138 +    //   and stopped after the overflow (would happen once every 828 days of constant 60fps).
  1.1139 +    length = 0;
  1.1140 +  }
  1.1141 +
  1.1142 +  if (!length) {
  1.1143 +    aFrameIntervals.Clear();
  1.1144 +    return; // empty recording, return empty arrays.
  1.1145 +  }
  1.1146 +  // Set length in advance to avoid possibly repeated reallocations
  1.1147 +  aFrameIntervals.SetLength(length);
  1.1148 +
  1.1149 +  uint32_t cyclicPos = aStartIndex % bufferSize;
  1.1150 +  for (uint32_t i = 0; i < length; i++, cyclicPos++) {
  1.1151 +    if (cyclicPos == bufferSize) {
  1.1152 +      cyclicPos = 0;
  1.1153 +    }
  1.1154 +    aFrameIntervals[i] = mRecording.mIntervals[cyclicPos];
  1.1155 +  }
  1.1156 +}
  1.1157 +
  1.1158 +void
  1.1159 +LayerManager::BeginTabSwitch()
  1.1160 +{
  1.1161 +  mTabSwitchStart = TimeStamp::Now();
  1.1162 +}
  1.1163 +
  1.1164 +static nsACString& PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite);
  1.1165 +
  1.1166 +#ifdef MOZ_DUMP_PAINTING
  1.1167 +template <typename T>
  1.1168 +void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
  1.1169 +{
  1.1170 +  if (!aObj) {
  1.1171 +    return;
  1.1172 +  }
  1.1173 +  nsCString string(aObj->Name());
  1.1174 +  string.Append("-");
  1.1175 +  string.AppendInt((uint64_t)aObj);
  1.1176 +  fprintf_stderr(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
  1.1177 +}
  1.1178 +
  1.1179 +template <typename T>
  1.1180 +void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
  1.1181 +{
  1.1182 +  nsRefPtr<gfxImageSurface> deprecatedSurf =
  1.1183 +    new gfxImageSurface(aSurf->GetData(),
  1.1184 +                        ThebesIntSize(aSurf->GetSize()),
  1.1185 +                        aSurf->Stride(),
  1.1186 +                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
  1.1187 +  nsCString string(aObj->Name());
  1.1188 +  string.Append("-");
  1.1189 +  string.AppendInt((uint64_t)aObj);
  1.1190 +  if (gfxUtils::sDumpPaintFile) {
  1.1191 +    fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
  1.1192 +  }
  1.1193 +  deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
  1.1194 +  if (gfxUtils::sDumpPaintFile) {
  1.1195 +    fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
  1.1196 +  }
  1.1197 +}
  1.1198 +
  1.1199 +void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf)
  1.1200 +{
  1.1201 +  WriteSnapshotToDumpFile_internal(aLayer, aSurf);
  1.1202 +}
  1.1203 +
  1.1204 +void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf)
  1.1205 +{
  1.1206 +  WriteSnapshotToDumpFile_internal(aManager, aSurf);
  1.1207 +}
  1.1208 +
  1.1209 +void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
  1.1210 +{
  1.1211 +  RefPtr<SourceSurface> surf = aTarget->Snapshot();
  1.1212 +  RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
  1.1213 +  WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
  1.1214 +}
  1.1215 +#endif
  1.1216 +
  1.1217 +void
  1.1218 +Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
  1.1219 +{
  1.1220 +  if (aDumpHtml) {
  1.1221 +    fprintf_stderr(aFile, "<li><a id=\"%p\" ", this);
  1.1222 +#ifdef MOZ_DUMP_PAINTING
  1.1223 +    if (GetType() == TYPE_CONTAINER || GetType() == TYPE_THEBES) {
  1.1224 +      WriteSnapshotLinkToDumpFile(this, aFile);
  1.1225 +    }
  1.1226 +#endif
  1.1227 +    fprintf_stderr(aFile, ">");
  1.1228 +  }
  1.1229 +  DumpSelf(aFile, aPrefix);
  1.1230 +
  1.1231 +#ifdef MOZ_DUMP_PAINTING
  1.1232 +  if (AsLayerComposite() && AsLayerComposite()->GetCompositableHost()) {
  1.1233 +    AsLayerComposite()->GetCompositableHost()->Dump(aFile, aPrefix, aDumpHtml);
  1.1234 +  }
  1.1235 +#endif
  1.1236 +
  1.1237 +  if (aDumpHtml) {
  1.1238 +    fprintf_stderr(aFile, "</a>");
  1.1239 +  }
  1.1240 +
  1.1241 +  if (Layer* mask = GetMaskLayer()) {
  1.1242 +    fprintf_stderr(aFile, "%s  Mask layer:\n", aPrefix);
  1.1243 +    nsAutoCString pfx(aPrefix);
  1.1244 +    pfx += "    ";
  1.1245 +    mask->Dump(aFile, pfx.get(), aDumpHtml);
  1.1246 +  }
  1.1247 +
  1.1248 +  if (Layer* kid = GetFirstChild()) {
  1.1249 +    nsAutoCString pfx(aPrefix);
  1.1250 +    pfx += "  ";
  1.1251 +    if (aDumpHtml) {
  1.1252 +      fprintf_stderr(aFile, "<ul>");
  1.1253 +    }
  1.1254 +    kid->Dump(aFile, pfx.get(), aDumpHtml);
  1.1255 +    if (aDumpHtml) {
  1.1256 +      fprintf_stderr(aFile, "</ul>");
  1.1257 +    }
  1.1258 +  }
  1.1259 +
  1.1260 +  if (aDumpHtml) {
  1.1261 +    fprintf_stderr(aFile, "</li>");
  1.1262 +  }
  1.1263 +  if (Layer* next = GetNextSibling())
  1.1264 +    next->Dump(aFile, aPrefix, aDumpHtml);
  1.1265 +}
  1.1266 +
  1.1267 +void
  1.1268 +Layer::DumpSelf(FILE* aFile, const char* aPrefix)
  1.1269 +{
  1.1270 +  nsAutoCString str;
  1.1271 +  PrintInfo(str, aPrefix);
  1.1272 +  fprintf_stderr(aFile, "%s\n", str.get());
  1.1273 +}
  1.1274 +
  1.1275 +void
  1.1276 +Layer::Log(const char* aPrefix)
  1.1277 +{
  1.1278 +  if (!IsLogEnabled())
  1.1279 +    return;
  1.1280 +
  1.1281 +  LogSelf(aPrefix);
  1.1282 +
  1.1283 +  if (Layer* kid = GetFirstChild()) {
  1.1284 +    nsAutoCString pfx(aPrefix);
  1.1285 +    pfx += "  ";
  1.1286 +    kid->Log(pfx.get());
  1.1287 +  }
  1.1288 +
  1.1289 +  if (Layer* next = GetNextSibling())
  1.1290 +    next->Log(aPrefix);
  1.1291 +}
  1.1292 +
  1.1293 +void
  1.1294 +Layer::LogSelf(const char* aPrefix)
  1.1295 +{
  1.1296 +  if (!IsLogEnabled())
  1.1297 +    return;
  1.1298 +
  1.1299 +  nsAutoCString str;
  1.1300 +  PrintInfo(str, aPrefix);
  1.1301 +  MOZ_LAYERS_LOG(("%s", str.get()));
  1.1302 +
  1.1303 +  if (mMaskLayer) {
  1.1304 +    nsAutoCString pfx(aPrefix);
  1.1305 +    pfx += "   \\ MaskLayer ";
  1.1306 +    mMaskLayer->LogSelf(pfx.get());
  1.1307 +  }
  1.1308 +}
  1.1309 +
  1.1310 +nsACString&
  1.1311 +Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1312 +{
  1.1313 +  aTo += aPrefix;
  1.1314 +  aTo += nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this);
  1.1315 +
  1.1316 +  ::PrintInfo(aTo, AsLayerComposite());
  1.1317 +
  1.1318 +  if (mUseClipRect) {
  1.1319 +    AppendToString(aTo, mClipRect, " [clip=", "]");
  1.1320 +  }
  1.1321 +  if (1.0 != mPostXScale || 1.0 != mPostYScale) {
  1.1322 +    aTo.AppendPrintf(" [postScale=%g, %g]", mPostXScale, mPostYScale);
  1.1323 +  }
  1.1324 +  if (!mTransform.IsIdentity()) {
  1.1325 +    AppendToString(aTo, mTransform, " [transform=", "]");
  1.1326 +  }
  1.1327 +  if (!mVisibleRegion.IsEmpty()) {
  1.1328 +    AppendToString(aTo, mVisibleRegion, " [visible=", "]");
  1.1329 +  } else {
  1.1330 +    aTo += " [not visible]";
  1.1331 +  }
  1.1332 +  if (!mEventRegions.mHitRegion.IsEmpty()) {
  1.1333 +    AppendToString(aTo, mEventRegions.mHitRegion, " [hitregion=", "]");
  1.1334 +  }
  1.1335 +  if (!mEventRegions.mDispatchToContentHitRegion.IsEmpty()) {
  1.1336 +    AppendToString(aTo, mEventRegions.mDispatchToContentHitRegion, " [dispatchtocontentregion=", "]");
  1.1337 +  }
  1.1338 +  if (1.0 != mOpacity) {
  1.1339 +    aTo.AppendPrintf(" [opacity=%g]", mOpacity);
  1.1340 +  }
  1.1341 +  if (GetContentFlags() & CONTENT_OPAQUE) {
  1.1342 +    aTo += " [opaqueContent]";
  1.1343 +  }
  1.1344 +  if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
  1.1345 +    aTo += " [componentAlpha]";
  1.1346 +  }
  1.1347 +  if (GetScrollbarDirection() == VERTICAL) {
  1.1348 +    aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId());
  1.1349 +  }
  1.1350 +  if (GetScrollbarDirection() == HORIZONTAL) {
  1.1351 +    aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId());
  1.1352 +  }
  1.1353 +  if (GetIsFixedPosition()) {
  1.1354 +    aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f margin=%f,%f,%f,%f]", mAnchor.x, mAnchor.y,
  1.1355 +                     mMargins.top, mMargins.right, mMargins.bottom, mMargins.left);
  1.1356 +  }
  1.1357 +  if (GetIsStickyPosition()) {
  1.1358 +    aTo.AppendPrintf(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f "
  1.1359 +                     "inner=%f,%f %fx%f]", mStickyPositionData->mScrollId,
  1.1360 +                     mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y,
  1.1361 +                     mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height,
  1.1362 +                     mStickyPositionData->mInner.x, mStickyPositionData->mInner.y,
  1.1363 +                     mStickyPositionData->mInner.width, mStickyPositionData->mInner.height);
  1.1364 +  }
  1.1365 +  if (mMaskLayer) {
  1.1366 +    aTo.AppendPrintf(" [mMaskLayer=%p]", mMaskLayer.get());
  1.1367 +  }
  1.1368 +
  1.1369 +  return aTo;
  1.1370 +}
  1.1371 +
  1.1372 +nsACString&
  1.1373 +ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1374 +{
  1.1375 +  Layer::PrintInfo(aTo, aPrefix);
  1.1376 +  if (!mValidRegion.IsEmpty()) {
  1.1377 +    AppendToString(aTo, mValidRegion, " [valid=", "]");
  1.1378 +  }
  1.1379 +  return aTo;
  1.1380 +}
  1.1381 +
  1.1382 +nsACString&
  1.1383 +ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1384 +{
  1.1385 +  Layer::PrintInfo(aTo, aPrefix);
  1.1386 +  if (!mFrameMetrics.IsDefault()) {
  1.1387 +    AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
  1.1388 +  }
  1.1389 +  if (mScrollHandoffParentId != FrameMetrics::NULL_SCROLL_ID) {
  1.1390 +    aTo.AppendPrintf(" [scrollParent=%llu]", mScrollHandoffParentId);
  1.1391 +  }
  1.1392 +  if (UseIntermediateSurface()) {
  1.1393 +    aTo += " [usesTmpSurf]";
  1.1394 +  }
  1.1395 +  if (1.0 != mPreXScale || 1.0 != mPreYScale) {
  1.1396 +    aTo.AppendPrintf(" [preScale=%g, %g]", mPreXScale, mPreYScale);
  1.1397 +  }
  1.1398 +  return aTo;
  1.1399 +}
  1.1400 +
  1.1401 +nsACString&
  1.1402 +ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1403 +{
  1.1404 +  Layer::PrintInfo(aTo, aPrefix);
  1.1405 +  AppendToString(aTo, mColor, " [color=", "]");
  1.1406 +  return aTo;
  1.1407 +}
  1.1408 +
  1.1409 +nsACString&
  1.1410 +CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1411 +{
  1.1412 +  Layer::PrintInfo(aTo, aPrefix);
  1.1413 +  if (mFilter != GraphicsFilter::FILTER_GOOD) {
  1.1414 +    AppendToString(aTo, mFilter, " [filter=", "]");
  1.1415 +  }
  1.1416 +  return aTo;
  1.1417 +}
  1.1418 +
  1.1419 +nsACString&
  1.1420 +ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1421 +{
  1.1422 +  Layer::PrintInfo(aTo, aPrefix);
  1.1423 +  if (mFilter != GraphicsFilter::FILTER_GOOD) {
  1.1424 +    AppendToString(aTo, mFilter, " [filter=", "]");
  1.1425 +  }
  1.1426 +  return aTo;
  1.1427 +}
  1.1428 +
  1.1429 +nsACString&
  1.1430 +RefLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1431 +{
  1.1432 +  ContainerLayer::PrintInfo(aTo, aPrefix);
  1.1433 +  if (0 != mId) {
  1.1434 +    AppendToString(aTo, mId, " [id=", "]");
  1.1435 +  }
  1.1436 +  return aTo;
  1.1437 +}
  1.1438 +
  1.1439 +nsACString&
  1.1440 +ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1441 +{
  1.1442 +  Layer::PrintInfo(aTo, aPrefix);
  1.1443 +  AppendToString(aTo, mSize, " [size=", "]");
  1.1444 +  if (mBackgroundLayer) {
  1.1445 +    AppendToString(aTo, mBackgroundLayer, " [backgroundLayer=", "]");
  1.1446 +    AppendToString(aTo, mBackgroundLayerOffset, " [backgroundOffset=", "]");
  1.1447 +  } else if (mBackgroundColor.a == 1.0) {
  1.1448 +    AppendToString(aTo, mBackgroundColor, " [backgroundColor=", "]");
  1.1449 +  } else {
  1.1450 +    aTo += " [nobackground]";
  1.1451 +  }
  1.1452 +  return aTo;
  1.1453 +}
  1.1454 +
  1.1455 +//--------------------------------------------------
  1.1456 +// LayerManager
  1.1457 +
  1.1458 +void
  1.1459 +LayerManager::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
  1.1460 +{
  1.1461 +  FILE* file = FILEOrDefault(aFile);
  1.1462 +
  1.1463 +#ifdef MOZ_DUMP_PAINTING
  1.1464 +  if (aDumpHtml) {
  1.1465 +    fprintf_stderr(file, "<ul><li><a ");
  1.1466 +    WriteSnapshotLinkToDumpFile(this, file);
  1.1467 +    fprintf_stderr(file, ">");
  1.1468 +  }
  1.1469 +#endif
  1.1470 +  DumpSelf(file, aPrefix);
  1.1471 +#ifdef MOZ_DUMP_PAINTING
  1.1472 +  if (aDumpHtml) {
  1.1473 +    fprintf_stderr(file, "</a>");
  1.1474 +  }
  1.1475 +#endif
  1.1476 +
  1.1477 +  nsAutoCString pfx(aPrefix);
  1.1478 +  pfx += "  ";
  1.1479 +  if (!GetRoot()) {
  1.1480 +    fprintf_stderr(file, "%s(null)", pfx.get());
  1.1481 +    if (aDumpHtml) {
  1.1482 +      fprintf_stderr(file, "</li></ul>");
  1.1483 +    }
  1.1484 +    return;
  1.1485 +  }
  1.1486 +
  1.1487 +  if (aDumpHtml) {
  1.1488 +    fprintf_stderr(file, "<ul>");
  1.1489 +  }
  1.1490 +  GetRoot()->Dump(file, pfx.get(), aDumpHtml);
  1.1491 +  if (aDumpHtml) {
  1.1492 +    fprintf_stderr(file, "</ul></li></ul>");
  1.1493 +  }
  1.1494 +  fprintf_stderr(file, "\n");
  1.1495 +}
  1.1496 +
  1.1497 +void
  1.1498 +LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
  1.1499 +{
  1.1500 +  nsAutoCString str;
  1.1501 +  PrintInfo(str, aPrefix);
  1.1502 +  fprintf_stderr(FILEOrDefault(aFile), "%s\n", str.get());
  1.1503 +}
  1.1504 +
  1.1505 +void
  1.1506 +LayerManager::Log(const char* aPrefix)
  1.1507 +{
  1.1508 +  if (!IsLogEnabled())
  1.1509 +    return;
  1.1510 +
  1.1511 +  LogSelf(aPrefix);
  1.1512 +
  1.1513 +  nsAutoCString pfx(aPrefix);
  1.1514 +  pfx += "  ";
  1.1515 +  if (!GetRoot()) {
  1.1516 +    MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
  1.1517 +    return;
  1.1518 +  }
  1.1519 +
  1.1520 +  GetRoot()->Log(pfx.get());
  1.1521 +}
  1.1522 +
  1.1523 +void
  1.1524 +LayerManager::LogSelf(const char* aPrefix)
  1.1525 +{
  1.1526 +  nsAutoCString str;
  1.1527 +  PrintInfo(str, aPrefix);
  1.1528 +  MOZ_LAYERS_LOG(("%s", str.get()));
  1.1529 +}
  1.1530 +
  1.1531 +nsACString&
  1.1532 +LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
  1.1533 +{
  1.1534 +  aTo += aPrefix;
  1.1535 +  return aTo += nsPrintfCString("%sLayerManager (0x%p)", Name(), this);
  1.1536 +}
  1.1537 +
  1.1538 +/*static*/ void
  1.1539 +LayerManager::InitLog()
  1.1540 +{
  1.1541 +  if (!sLog)
  1.1542 +    sLog = PR_NewLogModule("Layers");
  1.1543 +}
  1.1544 +
  1.1545 +/*static*/ bool
  1.1546 +LayerManager::IsLogEnabled()
  1.1547 +{
  1.1548 +  NS_ABORT_IF_FALSE(!!sLog,
  1.1549 +                    "layer manager must be created before logging is allowed");
  1.1550 +  return PR_LOG_TEST(sLog, PR_LOG_DEBUG);
  1.1551 +}
  1.1552 +
  1.1553 +static nsACString&
  1.1554 +PrintInfo(nsACString& aTo, LayerComposite* aLayerComposite)
  1.1555 +{
  1.1556 +  if (!aLayerComposite) {
  1.1557 +    return aTo;
  1.1558 +  }
  1.1559 +  if (const nsIntRect* clipRect = aLayerComposite->GetShadowClipRect()) {
  1.1560 +    AppendToString(aTo, *clipRect, " [shadow-clip=", "]");
  1.1561 +  }
  1.1562 +  if (!aLayerComposite->GetShadowTransform().IsIdentity()) {
  1.1563 +    AppendToString(aTo, aLayerComposite->GetShadowTransform(), " [shadow-transform=", "]");
  1.1564 +  }
  1.1565 +  if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
  1.1566 +    AppendToString(aTo, aLayerComposite->GetShadowVisibleRegion(), " [shadow-visible=", "]");
  1.1567 +  }
  1.1568 +  return aTo;
  1.1569 +}
  1.1570 +
  1.1571 +void
  1.1572 +SetAntialiasingFlags(Layer* aLayer, DrawTarget* aTarget)
  1.1573 +{
  1.1574 +  bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
  1.1575 +  if (aTarget->GetFormat() != SurfaceFormat::B8G8R8A8) {
  1.1576 +    aTarget->SetPermitSubpixelAA(permitSubpixelAA);
  1.1577 +    return;
  1.1578 +  }
  1.1579 +
  1.1580 +  const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
  1.1581 +  gfx::Rect transformedBounds = aTarget->GetTransform().TransformBounds(gfx::Rect(Float(bounds.x), Float(bounds.y),
  1.1582 +                                                                                  Float(bounds.width), Float(bounds.height)));
  1.1583 +  transformedBounds.RoundOut();
  1.1584 +  IntRect intTransformedBounds;
  1.1585 +  transformedBounds.ToIntRect(&intTransformedBounds);
  1.1586 +  permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
  1.1587 +                      aTarget->GetOpaqueRect().Contains(intTransformedBounds);
  1.1588 +  aTarget->SetPermitSubpixelAA(permitSubpixelAA);
  1.1589 +}
  1.1590 +
  1.1591 +void
  1.1592 +SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget)
  1.1593 +{
  1.1594 +  if (!aTarget->IsCairo()) {
  1.1595 +    SetAntialiasingFlags(aLayer, aTarget->GetDrawTarget());
  1.1596 +    return;
  1.1597 +  }
  1.1598 +
  1.1599 +  bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
  1.1600 +  nsRefPtr<gfxASurface> surface = aTarget->CurrentSurface();
  1.1601 +  if (surface->GetContentType() != gfxContentType::COLOR_ALPHA) {
  1.1602 +    // Destination doesn't have alpha channel; no need to set any special flags
  1.1603 +    surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
  1.1604 +    return;
  1.1605 +  }
  1.1606 +
  1.1607 +  const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
  1.1608 +  permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
  1.1609 +      surface->GetOpaqueRect().Contains(
  1.1610 +      aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
  1.1611 +  surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
  1.1612 +}
  1.1613 +
  1.1614 +PRLogModuleInfo* LayerManager::sLog;
  1.1615 +
  1.1616 +} // namespace layers
  1.1617 +} // namespace mozilla

mercurial