gfx/layers/Layers.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial