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