Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 : */
7 :
8 : /*
9 : * structures that represent things to be painted (ordered in z-order),
10 : * used during painting and hit testing
11 : */
12 :
13 : #include "nsDisplayList.h"
14 :
15 : #include <stdint.h>
16 : #include <algorithm>
17 : #include <limits>
18 :
19 : #include "gfxContext.h"
20 : #include "gfxUtils.h"
21 : #include "mozilla/dom/TabChild.h"
22 : #include "mozilla/dom/KeyframeEffect.h"
23 : #include "mozilla/dom/Selection.h"
24 : #include "mozilla/gfx/2D.h"
25 : #include "mozilla/layers/PLayerTransaction.h"
26 : #include "nsCSSRendering.h"
27 : #include "nsCSSRenderingGradients.h"
28 : #include "nsISelectionController.h"
29 : #include "nsIPresShell.h"
30 : #include "nsRegion.h"
31 : #include "nsStyleStructInlines.h"
32 : #include "nsStyleTransformMatrix.h"
33 : #include "gfxMatrix.h"
34 : #include "gfxPrefs.h"
35 : #include "nsSVGIntegrationUtils.h"
36 : #include "nsSVGUtils.h"
37 : #include "nsLayoutUtils.h"
38 : #include "nsIScrollableFrame.h"
39 : #include "nsIFrameInlines.h"
40 : #include "nsThemeConstants.h"
41 : #include "BorderConsts.h"
42 : #include "LayerTreeInvalidation.h"
43 : #include "mozilla/MathAlgorithms.h"
44 :
45 : #include "imgIContainer.h"
46 : #include "BasicLayers.h"
47 : #include "nsBoxFrame.h"
48 : #include "nsImageFrame.h"
49 : #include "nsSubDocumentFrame.h"
50 : #include "SVGObserverUtils.h"
51 : #include "nsSVGElement.h"
52 : #include "nsSVGClipPathFrame.h"
53 : #include "GeckoProfiler.h"
54 : #include "nsViewManager.h"
55 : #include "ImageLayers.h"
56 : #include "ImageContainer.h"
57 : #include "nsCanvasFrame.h"
58 : #include "StickyScrollContainer.h"
59 : #include "mozilla/AnimationPerformanceWarning.h"
60 : #include "mozilla/AnimationUtils.h"
61 : #include "mozilla/EffectCompositor.h"
62 : #include "mozilla/EffectSet.h"
63 : #include "mozilla/EventStates.h"
64 : #include "mozilla/LookAndFeel.h"
65 : #include "mozilla/OperatorNewExtensions.h"
66 : #include "mozilla/PendingAnimationTracker.h"
67 : #include "mozilla/Preferences.h"
68 : #include "mozilla/StyleAnimationValue.h"
69 : #include "mozilla/ServoBindings.h"
70 : #include "mozilla/Telemetry.h"
71 : #include "mozilla/UniquePtr.h"
72 : #include "mozilla/Unused.h"
73 : #include "mozilla/ViewportFrame.h"
74 : #include "mozilla/gfx/gfxVars.h"
75 : #include "ActiveLayerTracker.h"
76 : #include "nsContentUtils.h"
77 : #include "nsPrintfCString.h"
78 : #include "UnitTransforms.h"
79 : #include "LayersLogging.h"
80 : #include "FrameLayerBuilder.h"
81 : #include "mozilla/EventStateManager.h"
82 : #include "nsCaret.h"
83 : #include "nsDOMTokenList.h"
84 : #include "nsCSSProps.h"
85 : #include "nsSVGMaskFrame.h"
86 : #include "nsTableCellFrame.h"
87 : #include "nsTableColFrame.h"
88 : #include "nsSliderFrame.h"
89 : #include "ClientLayerManager.h"
90 : #include "mozilla/layers/StackingContextHelper.h"
91 : #include "mozilla/layers/WebRenderBridgeChild.h"
92 : #include "mozilla/layers/WebRenderLayerManager.h"
93 : #include "mozilla/layers/WebRenderMessages.h"
94 : #include "mozilla/layers/WebRenderScrollData.h"
95 :
96 : // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
97 : // GetTickCount().
98 : #ifdef GetCurrentTime
99 : #undef GetCurrentTime
100 : #endif
101 :
102 : using namespace mozilla;
103 : using namespace mozilla::layers;
104 : using namespace mozilla::dom;
105 : using namespace mozilla::layout;
106 : using namespace mozilla::gfx;
107 :
108 : typedef FrameMetrics::ViewID ViewID;
109 : typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
110 :
111 : #ifdef DEBUG
112 : static bool
113 0 : SpammyLayoutWarningsEnabled()
114 : {
115 : static bool sValue = false;
116 : static bool sValueInitialized = false;
117 :
118 0 : if (!sValueInitialized) {
119 0 : Preferences::GetBool("layout.spammy_warnings.enabled", &sValue);
120 0 : sValueInitialized = true;
121 : }
122 :
123 0 : return sValue;
124 : }
125 : #endif
126 :
127 : #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
128 0 : void AssertUniqueItem(nsDisplayItem* aItem) {
129 0 : nsIFrame::DisplayItemArray* items = aItem->Frame()->GetProperty(nsIFrame::DisplayItems());
130 0 : if (!items) {
131 : return;
132 : }
133 0 : for (nsDisplayItem* i : *items) {
134 0 : if (i != aItem &&
135 0 : !i->HasDeletedFrame() &&
136 0 : i->Frame() == aItem->Frame() &&
137 0 : i->GetPerFrameKey() == aItem->GetPerFrameKey()) {
138 0 : if (i->mPreProcessedItem) {
139 : continue;
140 : }
141 0 : MOZ_DIAGNOSTIC_ASSERT(false, "Duplicate display item!");
142 : }
143 : }
144 : }
145 : #endif
146 :
147 : /* static */ bool
148 0 : ActiveScrolledRoot::IsAncestor(const ActiveScrolledRoot* aAncestor,
149 : const ActiveScrolledRoot* aDescendant)
150 : {
151 0 : if (!aAncestor) {
152 : // nullptr is the root
153 : return true;
154 : }
155 0 : if (Depth(aAncestor) > Depth(aDescendant)) {
156 : return false;
157 : }
158 : const ActiveScrolledRoot* asr = aDescendant;
159 0 : while (asr) {
160 0 : if (asr == aAncestor) {
161 : return true;
162 : }
163 0 : asr = asr->mParent;
164 : }
165 : return false;
166 : }
167 :
168 : /* static */ nsCString
169 0 : ActiveScrolledRoot::ToString(const ActiveScrolledRoot* aActiveScrolledRoot)
170 : {
171 0 : nsAutoCString str;
172 0 : for (auto* asr = aActiveScrolledRoot; asr; asr = asr->mParent) {
173 0 : str.AppendPrintf("<0x%p>", asr->mScrollableFrame);
174 0 : if (asr->mParent) {
175 0 : str.AppendLiteral(", ");
176 : }
177 : }
178 0 : return str;
179 : }
180 :
181 : static inline CSSAngle
182 0 : MakeCSSAngle(const nsCSSValue& aValue)
183 : {
184 0 : return CSSAngle(aValue.GetAngleValue(), aValue.GetUnit());
185 : }
186 :
187 0 : static void AddTransformFunctions(const nsCSSValueList* aList,
188 : mozilla::ComputedStyle* aStyle,
189 : nsPresContext* aPresContext,
190 : TransformReferenceBox& aRefBox,
191 : InfallibleTArray<TransformFunction>& aFunctions)
192 : {
193 0 : if (aList->mValue.GetUnit() == eCSSUnit_None) {
194 : return;
195 : }
196 :
197 0 : for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
198 0 : const nsCSSValue& currElem = curr->mValue;
199 0 : NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
200 : "Stream should consist solely of functions!");
201 0 : nsCSSValue::Array* array = currElem.GetArrayValue();
202 0 : switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
203 : case eCSSKeyword_rotatex:
204 : {
205 0 : CSSAngle theta = MakeCSSAngle(array->Item(1));
206 0 : aFunctions.AppendElement(RotationX(theta));
207 : break;
208 : }
209 : case eCSSKeyword_rotatey:
210 : {
211 0 : CSSAngle theta = MakeCSSAngle(array->Item(1));
212 0 : aFunctions.AppendElement(RotationY(theta));
213 : break;
214 : }
215 : case eCSSKeyword_rotatez:
216 : {
217 0 : CSSAngle theta = MakeCSSAngle(array->Item(1));
218 0 : aFunctions.AppendElement(RotationZ(theta));
219 : break;
220 : }
221 : case eCSSKeyword_rotate:
222 : {
223 0 : CSSAngle theta = MakeCSSAngle(array->Item(1));
224 0 : aFunctions.AppendElement(Rotation(theta));
225 : break;
226 : }
227 : case eCSSKeyword_rotate3d:
228 : {
229 0 : double x = array->Item(1).GetFloatValue();
230 0 : double y = array->Item(2).GetFloatValue();
231 0 : double z = array->Item(3).GetFloatValue();
232 0 : CSSAngle theta = MakeCSSAngle(array->Item(4));
233 0 : aFunctions.AppendElement(Rotation3D(x, y, z, theta));
234 : break;
235 : }
236 : case eCSSKeyword_scalex:
237 : {
238 0 : double x = array->Item(1).GetFloatValue();
239 0 : aFunctions.AppendElement(Scale(x, 1, 1));
240 : break;
241 : }
242 : case eCSSKeyword_scaley:
243 : {
244 0 : double y = array->Item(1).GetFloatValue();
245 0 : aFunctions.AppendElement(Scale(1, y, 1));
246 : break;
247 : }
248 : case eCSSKeyword_scalez:
249 : {
250 0 : double z = array->Item(1).GetFloatValue();
251 0 : aFunctions.AppendElement(Scale(1, 1, z));
252 : break;
253 : }
254 : case eCSSKeyword_scale:
255 : {
256 0 : double x = array->Item(1).GetFloatValue();
257 : // scale(x) is shorthand for scale(x, x);
258 0 : double y = array->Count() == 2 ? x : array->Item(2).GetFloatValue();
259 0 : aFunctions.AppendElement(Scale(x, y, 1));
260 : break;
261 : }
262 : case eCSSKeyword_scale3d:
263 : {
264 0 : double x = array->Item(1).GetFloatValue();
265 0 : double y = array->Item(2).GetFloatValue();
266 0 : double z = array->Item(3).GetFloatValue();
267 0 : aFunctions.AppendElement(Scale(x, y, z));
268 : break;
269 : }
270 : case eCSSKeyword_translatex:
271 : {
272 0 : double x = nsStyleTransformMatrix::ProcessTranslatePart(
273 0 : array->Item(1),
274 0 : &aRefBox, &TransformReferenceBox::Width);
275 0 : aFunctions.AppendElement(Translation(x, 0, 0));
276 : break;
277 : }
278 : case eCSSKeyword_translatey:
279 : {
280 0 : double y = nsStyleTransformMatrix::ProcessTranslatePart(
281 0 : array->Item(1),
282 0 : &aRefBox, &TransformReferenceBox::Height);
283 0 : aFunctions.AppendElement(Translation(0, y, 0));
284 : break;
285 : }
286 : case eCSSKeyword_translatez:
287 : {
288 0 : double z = nsStyleTransformMatrix::ProcessTranslatePart(
289 0 : array->Item(1),
290 0 : nullptr);
291 0 : aFunctions.AppendElement(Translation(0, 0, z));
292 : break;
293 : }
294 : case eCSSKeyword_translate:
295 : {
296 0 : double x = nsStyleTransformMatrix::ProcessTranslatePart(
297 0 : array->Item(1),
298 0 : &aRefBox, &TransformReferenceBox::Width);
299 : // translate(x) is shorthand for translate(x, 0)
300 0 : double y = 0;
301 0 : if (array->Count() == 3) {
302 0 : y = nsStyleTransformMatrix::ProcessTranslatePart(
303 0 : array->Item(2),
304 : &aRefBox, &TransformReferenceBox::Height);
305 : }
306 0 : aFunctions.AppendElement(Translation(x, y, 0));
307 : break;
308 : }
309 : case eCSSKeyword_translate3d:
310 : {
311 0 : double x = nsStyleTransformMatrix::ProcessTranslatePart(
312 0 : array->Item(1),
313 0 : &aRefBox, &TransformReferenceBox::Width);
314 0 : double y = nsStyleTransformMatrix::ProcessTranslatePart(
315 0 : array->Item(2),
316 0 : &aRefBox, &TransformReferenceBox::Height);
317 0 : double z = nsStyleTransformMatrix::ProcessTranslatePart(
318 0 : array->Item(3),
319 0 : nullptr);
320 :
321 0 : aFunctions.AppendElement(Translation(x, y, z));
322 : break;
323 : }
324 : case eCSSKeyword_skewx:
325 : {
326 0 : CSSAngle x = MakeCSSAngle(array->Item(1));
327 0 : aFunctions.AppendElement(SkewX(x));
328 : break;
329 : }
330 : case eCSSKeyword_skewy:
331 : {
332 0 : CSSAngle y = MakeCSSAngle(array->Item(1));
333 0 : aFunctions.AppendElement(SkewY(y));
334 : break;
335 : }
336 : case eCSSKeyword_skew:
337 : {
338 0 : CSSAngle x = MakeCSSAngle(array->Item(1));
339 : // skew(x) is shorthand for skew(x, 0)
340 0 : CSSAngle y(0.0f, eCSSUnit_Degree);
341 0 : if (array->Count() == 3) {
342 0 : y = MakeCSSAngle(array->Item(2));
343 : }
344 0 : aFunctions.AppendElement(Skew(x, y));
345 : break;
346 : }
347 : case eCSSKeyword_matrix:
348 : {
349 0 : gfx::Matrix4x4 matrix;
350 0 : matrix._11 = array->Item(1).GetFloatValue();
351 0 : matrix._12 = array->Item(2).GetFloatValue();
352 0 : matrix._13 = 0;
353 0 : matrix._14 = 0;
354 0 : matrix._21 = array->Item(3).GetFloatValue();
355 0 : matrix._22 = array->Item(4).GetFloatValue();
356 0 : matrix._23 = 0;
357 0 : matrix._24 = 0;
358 0 : matrix._31 = 0;
359 0 : matrix._32 = 0;
360 0 : matrix._33 = 1;
361 0 : matrix._34 = 0;
362 0 : matrix._41 = ProcessTranslatePart(array->Item(5),
363 : &aRefBox, &TransformReferenceBox::Width);
364 0 : matrix._42 = ProcessTranslatePart(array->Item(6),
365 : &aRefBox, &TransformReferenceBox::Height);
366 0 : matrix._43 = 0;
367 0 : matrix._44 = 1;
368 0 : aFunctions.AppendElement(TransformMatrix(matrix));
369 : break;
370 : }
371 : case eCSSKeyword_matrix3d:
372 : {
373 0 : gfx::Matrix4x4 matrix;
374 0 : matrix._11 = array->Item(1).GetFloatValue();
375 0 : matrix._12 = array->Item(2).GetFloatValue();
376 0 : matrix._13 = array->Item(3).GetFloatValue();
377 0 : matrix._14 = array->Item(4).GetFloatValue();
378 0 : matrix._21 = array->Item(5).GetFloatValue();
379 0 : matrix._22 = array->Item(6).GetFloatValue();
380 0 : matrix._23 = array->Item(7).GetFloatValue();
381 0 : matrix._24 = array->Item(8).GetFloatValue();
382 0 : matrix._31 = array->Item(9).GetFloatValue();
383 0 : matrix._32 = array->Item(10).GetFloatValue();
384 0 : matrix._33 = array->Item(11).GetFloatValue();
385 0 : matrix._34 = array->Item(12).GetFloatValue();
386 0 : matrix._41 = ProcessTranslatePart(array->Item(13),
387 : &aRefBox, &TransformReferenceBox::Width);
388 0 : matrix._42 = ProcessTranslatePart(array->Item(14),
389 : &aRefBox, &TransformReferenceBox::Height);
390 0 : matrix._43 = ProcessTranslatePart(array->Item(15),
391 : &aRefBox, nullptr);
392 0 : matrix._44 = array->Item(16).GetFloatValue();
393 0 : aFunctions.AppendElement(TransformMatrix(matrix));
394 : break;
395 : }
396 : case eCSSKeyword_interpolatematrix:
397 : {
398 : bool dummy;
399 0 : Matrix4x4 matrix;
400 : nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array,
401 : aRefBox,
402 0 : &dummy);
403 0 : aFunctions.AppendElement(TransformMatrix(matrix));
404 : break;
405 : }
406 : case eCSSKeyword_accumulatematrix:
407 : {
408 : bool dummy;
409 0 : Matrix4x4 matrix;
410 : nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, array,
411 : aRefBox,
412 0 : &dummy);
413 0 : aFunctions.AppendElement(TransformMatrix(matrix));
414 : break;
415 : }
416 : case eCSSKeyword_perspective:
417 : {
418 0 : aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
419 : break;
420 : }
421 : default:
422 0 : NS_ERROR("Function not handled yet!");
423 : }
424 : }
425 : }
426 :
427 : static void
428 0 : AddTransformFunctions(const nsCSSValueSharedList* aList,
429 : const nsIFrame* aFrame,
430 : TransformReferenceBox& aRefBox,
431 : layers::Animatable& aAnimatable)
432 : {
433 0 : MOZ_ASSERT(aList->mHead);
434 0 : AddTransformFunctions(aList->mHead,
435 : aFrame->Style(),
436 : aFrame->PresContext(),
437 : aRefBox,
438 0 : aAnimatable.get_ArrayOfTransformFunction());
439 0 : }
440 :
441 : static TimingFunction
442 0 : ToTimingFunction(const Maybe<ComputedTimingFunction>& aCTF)
443 : {
444 0 : if (aCTF.isNothing()) {
445 0 : return TimingFunction(null_t());
446 : }
447 :
448 0 : if (aCTF->HasSpline()) {
449 0 : const nsSMILKeySpline* spline = aCTF->GetFunction();
450 0 : return TimingFunction(CubicBezierFunction(spline->X1(), spline->Y1(),
451 0 : spline->X2(), spline->Y2()));
452 : }
453 :
454 0 : if (aCTF->GetType() == nsTimingFunction::Type::Frames) {
455 0 : return TimingFunction(FramesFunction(aCTF->GetFrames()));
456 : }
457 :
458 0 : uint32_t type = aCTF->GetType() == nsTimingFunction::Type::StepStart ? 1 : 2;
459 0 : return TimingFunction(StepFunction(aCTF->GetSteps(), type));
460 : }
461 :
462 : static void
463 0 : SetAnimatable(nsCSSPropertyID aProperty,
464 : const AnimationValue& aAnimationValue,
465 : nsIFrame* aFrame,
466 : TransformReferenceBox& aRefBox,
467 : layers::Animatable& aAnimatable)
468 : {
469 0 : MOZ_ASSERT(aFrame);
470 :
471 0 : if (aAnimationValue.IsNull()) {
472 0 : aAnimatable = null_t();
473 0 : return;
474 : }
475 :
476 0 : switch (aProperty) {
477 : case eCSSProperty_opacity:
478 0 : aAnimatable = aAnimationValue.GetOpacity();
479 0 : break;
480 : case eCSSProperty_transform: {
481 0 : aAnimatable = InfallibleTArray<TransformFunction>();
482 0 : if (aAnimationValue.mServo) {
483 0 : RefPtr<nsCSSValueSharedList> list;
484 0 : Servo_AnimationValue_GetTransform(aAnimationValue.mServo, &list);
485 0 : AddTransformFunctions(list, aFrame, aRefBox, aAnimatable);
486 : } else {
487 0 : MOZ_CRASH("old style system disabled");
488 : }
489 0 : break;
490 : }
491 : default:
492 0 : MOZ_ASSERT_UNREACHABLE("Unsupported property");
493 : }
494 : }
495 :
496 : static void
497 0 : AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
498 : dom::Animation* aAnimation, AnimationInfo& aAnimationInfo,
499 : AnimationData& aData, bool aPending)
500 : {
501 0 : MOZ_ASSERT(aAnimation->GetEffect(),
502 : "Should not be adding an animation without an effect");
503 0 : MOZ_ASSERT(!aAnimation->GetCurrentOrPendingStartTime().IsNull() ||
504 : !aAnimation->IsPlaying() ||
505 : (aAnimation->GetTimeline() &&
506 : aAnimation->GetTimeline()->TracksWallclockTime()),
507 : "If the animation has an unresolved start time it should either"
508 : " be static (so we don't need a start time) or else have a"
509 : " timeline capable of converting TimeStamps (so we can calculate"
510 : " one later");
511 :
512 : layers::Animation* animation =
513 0 : aPending ?
514 : aAnimationInfo.AddAnimationForNextTransaction() :
515 0 : aAnimationInfo.AddAnimation();
516 :
517 0 : const TimingParams& timing = aAnimation->GetEffect()->SpecifiedTiming();
518 :
519 : // If we are starting a new transition that replaces an existing transition
520 : // running on the compositor, it is possible that the animation on the
521 : // compositor will have advanced ahead of the main thread. If we use as
522 : // the starting point of the new transition, the current value of the
523 : // replaced transition as calculated on the main thread using the refresh
524 : // driver time, the new transition will jump when it starts. Instead, we
525 : // re-calculate the starting point of the new transition by applying the
526 : // current TimeStamp to the parameters of the replaced transition.
527 : //
528 : // We need to do this here, rather than when we generate the new transition,
529 : // since after generating the new transition other requestAnimationFrame
530 : // callbacks may run that introduce further lag between the main thread and
531 : // the compositor.
532 0 : if (aAnimation->AsCSSTransition() &&
533 0 : aAnimation->GetEffect() &&
534 0 : aAnimation->GetEffect()->AsTransition()) {
535 : // We update startValue from the replaced transition only if the effect is
536 : // an ElementPropertyTransition.
537 0 : aAnimation->GetEffect()->AsTransition()->
538 0 : UpdateStartValueFromReplacedTransition();
539 : }
540 :
541 0 : animation->originTime() = !aAnimation->GetTimeline()
542 0 : ? TimeStamp()
543 0 : : aAnimation->GetTimeline()->
544 0 : ToTimeStamp(TimeDuration());
545 :
546 0 : Nullable<TimeDuration> startTime = aAnimation->GetCurrentOrPendingStartTime();
547 0 : if (startTime.IsNull()) {
548 0 : animation->startTime() = null_t();
549 : } else {
550 0 : animation->startTime() = startTime.Value();
551 : }
552 :
553 0 : animation->holdTime() = aAnimation->GetCurrentTime().Value();
554 :
555 : const ComputedTiming computedTiming =
556 0 : aAnimation->GetEffect()->GetComputedTiming();
557 0 : animation->delay() = timing.Delay();
558 0 : animation->endDelay() = timing.EndDelay();
559 0 : animation->duration() = computedTiming.mDuration;
560 0 : animation->iterations() = computedTiming.mIterations;
561 0 : animation->iterationStart() = computedTiming.mIterationStart;
562 0 : animation->direction() = static_cast<uint8_t>(timing.Direction());
563 0 : animation->fillMode() = static_cast<uint8_t>(computedTiming.mFill);
564 0 : animation->property() = aProperty.mProperty;
565 0 : animation->playbackRate() = aAnimation->CurrentOrPendingPlaybackRate();
566 0 : animation->previousPlaybackRate() =
567 0 : aAnimation->HasPendingPlaybackRate()
568 0 : ? aAnimation->PlaybackRate()
569 : : std::numeric_limits<float>::quiet_NaN();
570 0 : animation->data() = aData;
571 0 : animation->easingFunction() = ToTimingFunction(timing.TimingFunction());
572 0 : animation->iterationComposite() =
573 0 : static_cast<uint8_t>(aAnimation->GetEffect()->
574 0 : AsKeyframeEffect()->IterationComposite());
575 0 : animation->isNotPlaying() = !aAnimation->IsPlaying();
576 :
577 0 : TransformReferenceBox refBox(aFrame);
578 :
579 : // If the animation is additive or accumulates, we need to pass its base value
580 : // to the compositor.
581 :
582 : AnimationValue baseStyle =
583 0 : aAnimation->GetEffect()->AsKeyframeEffect()->BaseStyle(aProperty.mProperty);
584 0 : if (!baseStyle.IsNull()) {
585 0 : SetAnimatable(aProperty.mProperty,
586 : baseStyle,
587 : aFrame, refBox,
588 0 : animation->baseStyle());
589 : } else {
590 0 : animation->baseStyle() = null_t();
591 : }
592 :
593 0 : for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) {
594 0 : const AnimationPropertySegment& segment = aProperty.mSegments[segIdx];
595 :
596 0 : AnimationSegment* animSegment = animation->segments().AppendElement();
597 0 : SetAnimatable(aProperty.mProperty,
598 : segment.mFromValue,
599 : aFrame, refBox,
600 0 : animSegment->startState());
601 0 : SetAnimatable(aProperty.mProperty,
602 : segment.mToValue,
603 : aFrame, refBox,
604 0 : animSegment->endState());
605 :
606 0 : animSegment->startPortion() = segment.mFromKey;
607 0 : animSegment->endPortion() = segment.mToKey;
608 0 : animSegment->startComposite() =
609 0 : static_cast<uint8_t>(segment.mFromComposite);
610 0 : animSegment->endComposite() =
611 0 : static_cast<uint8_t>(segment.mToComposite);
612 0 : animSegment->sampleFn() = ToTimingFunction(segment.mTimingFunction);
613 : }
614 0 : }
615 :
616 : static void
617 0 : AddAnimationsForProperty(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
618 : nsDisplayItem* aItem, nsCSSPropertyID aProperty,
619 : AnimationInfo& aAnimationInfo, bool aPending,
620 : bool aIsForWebRender)
621 : {
622 0 : if (aPending) {
623 0 : aAnimationInfo.ClearAnimationsForNextTransaction();
624 : } else {
625 0 : aAnimationInfo.ClearAnimations();
626 : }
627 :
628 0 : nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aFrame);
629 0 : if (!styleFrame) {
630 0 : return;
631 : }
632 :
633 : // Update the animation generation on the layer. We need to do this before
634 : // any early returns since even if we don't add any animations to the
635 : // layer, we still need to mark it as up-to-date with regards to animations.
636 : // Otherwise, in RestyleManager we'll notice the discrepancy between the
637 : // animation generation numbers and update the layer indefinitely.
638 : uint64_t animationGeneration =
639 : // Note that GetAnimationGenerationForFrame() calles EffectSet::GetEffectSet
640 : // that expects to work with the style frame instead of the primary frame.
641 0 : RestyleManager::GetAnimationGenerationForFrame(styleFrame);
642 0 : aAnimationInfo.SetAnimationGeneration(animationGeneration);
643 :
644 0 : EffectCompositor::ClearIsRunningOnCompositor(styleFrame, aProperty);
645 : nsTArray<RefPtr<dom::Animation>> compositorAnimations =
646 0 : EffectCompositor::GetAnimationsForCompositor(styleFrame, aProperty);
647 0 : if (compositorAnimations.IsEmpty()) {
648 : return;
649 : }
650 :
651 : // If the frame is not prerendered, bail out.
652 : // Do this check only during layer construction; during updating the
653 : // caller is required to check it appropriately.
654 0 : if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) {
655 : // EffectCompositor needs to know that we refused to run this animation
656 : // asynchronously so that it will not throttle the main thread
657 : // animation.
658 0 : aFrame->SetProperty(nsIFrame::RefusedAsyncAnimationProperty(), true);
659 :
660 : // We need to schedule another refresh driver run so that EffectCompositor
661 : // gets a chance to unthrottle the animation.
662 0 : aFrame->SchedulePaint();
663 0 : return;
664 : }
665 :
666 0 : AnimationData data;
667 0 : if (aProperty == eCSSProperty_transform) {
668 : // XXX Performance here isn't ideal for SVG. We'd prefer to avoid resolving
669 : // the dimensions of refBox. That said, we only get here if there are CSS
670 : // animations or transitions on this element, and that is likely to be a
671 : // lot rarer than transforms on SVG (the frequency of which drives the need
672 : // for TransformReferenceBox).
673 0 : TransformReferenceBox refBox(aFrame);
674 0 : nsRect bounds(0, 0, refBox.Width(), refBox.Height());
675 : // all data passed directly to the compositor should be in dev pixels
676 0 : int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
677 0 : float scale = devPixelsToAppUnits;
678 : Point3D offsetToTransformOrigin =
679 0 : nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
680 0 : nsPoint origin;
681 0 : float scaleX = 1.0f;
682 0 : float scaleY = 1.0f;
683 0 : bool hasPerspectiveParent = false;
684 0 : if (aIsForWebRender) {
685 : // leave origin empty, because we are sending it separately on the stacking
686 : // context that we are pushing to WR, and WR will automatically include
687 : // it when picking up the animated transform values
688 0 : } else if (aItem) {
689 : // This branch is for display items to leverage the cache of
690 : // nsDisplayListBuilder.
691 0 : origin = aItem->ToReferenceFrame();
692 : } else {
693 : // This branch is running for restyling.
694 : // Animations are animated at the coordination of the reference
695 : // frame outside, not the given frame itself. The given frame
696 : // is also reference frame too, so the parent's reference frame
697 : // are used.
698 : nsIFrame* referenceFrame =
699 0 : nsLayoutUtils::GetReferenceFrame(nsLayoutUtils::GetCrossDocParentFrame(aFrame));
700 0 : origin = aFrame->GetOffsetToCrossDoc(referenceFrame);
701 : }
702 :
703 0 : data = TransformData(origin, offsetToTransformOrigin,
704 : bounds, devPixelsToAppUnits,
705 0 : scaleX, scaleY, hasPerspectiveParent);
706 0 : } else if (aProperty == eCSSProperty_opacity) {
707 0 : data = null_t();
708 : }
709 :
710 0 : MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
711 : CSSPropFlags::CanAnimateOnCompositor),
712 : "inconsistent property flags");
713 :
714 : // Add from first to last (since last overrides)
715 0 : for (size_t animIdx = 0; animIdx < compositorAnimations.Length(); animIdx++) {
716 0 : dom::Animation* anim = compositorAnimations[animIdx];
717 0 : if (!anim->IsRelevant()) {
718 : continue;
719 : }
720 :
721 : dom::KeyframeEffect* keyframeEffect =
722 0 : anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
723 0 : MOZ_ASSERT(keyframeEffect,
724 : "A playing animation should have a keyframe effect");
725 : const AnimationProperty* property =
726 0 : keyframeEffect->GetEffectiveAnimationOfProperty(aProperty);
727 0 : if (!property) {
728 : continue;
729 : }
730 :
731 : // Note that if the property is overridden by !important rules,
732 : // GetEffectiveAnimationOfProperty returns null instead.
733 : // This is what we want, since if we have animations overridden by
734 : // !important rules, we don't want to send them to the compositor.
735 0 : MOZ_ASSERT(anim->CascadeLevel() !=
736 : EffectCompositor::CascadeLevel::Animations ||
737 : !EffectSet::GetEffectSet(styleFrame)->PropertiesWithImportantRules()
738 : .HasProperty(aProperty),
739 : "GetEffectiveAnimationOfProperty already tested the property "
740 : "is not overridden by !important rules");
741 :
742 : // Don't add animations that are pending if their timeline does not
743 : // track wallclock time. This is because any pending animations on layers
744 : // will have their start time updated with the current wallclock time.
745 : // If we can't convert that wallclock time back to an equivalent timeline
746 : // time, we won't be able to update the content animation and it will end
747 : // up being out of sync with the layer animation.
748 : //
749 : // Currently this only happens when the timeline is driven by a refresh
750 : // driver under test control. In this case, the next time the refresh
751 : // driver is advanced it will trigger any pending animations.
752 0 : if (anim->Pending() &&
753 0 : (anim->GetTimeline() && !anim->GetTimeline()->TracksWallclockTime())) {
754 : continue;
755 : }
756 :
757 0 : AddAnimationForProperty(aFrame, *property, anim, aAnimationInfo, data, aPending);
758 0 : keyframeEffect->SetIsRunningOnCompositor(aProperty, true);
759 : }
760 : }
761 :
762 : static bool
763 0 : GenerateAndPushTextMask(nsIFrame* aFrame, gfxContext* aContext,
764 : const nsRect& aFillRect, nsDisplayListBuilder* aBuilder)
765 : {
766 0 : if (aBuilder->IsForGenerateGlyphMask() ||
767 0 : aBuilder->IsForPaintingSelectionBG()) {
768 : return false;
769 : }
770 :
771 : // The main function of enabling background-clip:text property value.
772 : // When a nsDisplayBackgroundImage detects "text" bg-clip style, it will call
773 : // this function to
774 : // 1. Paint background color of the selection text if any.
775 : // 2. Generate a mask by all descendant text frames
776 : // 3. Push the generated mask into aContext.
777 : //
778 : // TBD: we actually generate display list of aFrame twice here. It's better
779 : // to reuse the same display list and paint that one twice, one for selection
780 : // background, one for generating text mask.
781 :
782 0 : gfxContext* sourceCtx = aContext;
783 : LayoutDeviceRect bounds =
784 : LayoutDeviceRect::FromAppUnits(aFillRect,
785 0 : aFrame->PresContext()->AppUnitsPerDevPixel());
786 :
787 : {
788 : // Paint text selection background into sourceCtx.
789 0 : gfxContextMatrixAutoSaveRestore save(sourceCtx);
790 0 : sourceCtx->SetMatrix(sourceCtx->CurrentMatrix().PreTranslate(bounds.TopLeft().ToUnknownPoint()));
791 :
792 0 : nsLayoutUtils::PaintFrame(aContext, aFrame,
793 0 : nsRect(nsPoint(0, 0), aFrame->GetSize()),
794 : NS_RGB(255, 255, 255),
795 0 : nsDisplayListBuilderMode::PAINTING_SELECTION_BACKGROUND);
796 : }
797 :
798 : // Evaluate required surface size.
799 : IntRect drawRect =
800 0 : RoundedOut(ToRect(sourceCtx->GetClipExtents(gfxContext::eDeviceSpace)));
801 :
802 0 : Matrix currentMatrix = sourceCtx->CurrentMatrix();
803 : Matrix maskTransform = currentMatrix *
804 0 : Matrix::Translation(-drawRect.x, -drawRect.y);
805 0 : maskTransform.Invert();
806 :
807 : // Create a mask surface.
808 0 : RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
809 : RefPtr<DrawTarget> maskDT =
810 0 : sourceTarget->CreateClippedDrawTarget(drawRect.Size(),
811 0 : maskTransform * currentMatrix,
812 0 : SurfaceFormat::A8);
813 0 : if (!maskDT || !maskDT->IsValid()) {
814 : return false;
815 : }
816 0 : RefPtr<gfxContext> maskCtx = gfxContext::CreatePreservingTransformOrNull(maskDT);
817 0 : MOZ_ASSERT(maskCtx);
818 0 : maskCtx->SetMatrix(Matrix::Translation(bounds.TopLeft().ToUnknownPoint()) *
819 0 : currentMatrix *
820 0 : Matrix::Translation(-drawRect.TopLeft()));
821 :
822 : // Shade text shape into mask A8 surface.
823 0 : nsLayoutUtils::PaintFrame(maskCtx, aFrame,
824 0 : nsRect(nsPoint(0, 0), aFrame->GetSize()),
825 : NS_RGB(255, 255, 255),
826 0 : nsDisplayListBuilderMode::GENERATE_GLYPH);
827 :
828 : // Push the generated mask into aContext, so that the caller can pop and
829 : // blend with it.
830 0 : RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
831 0 : sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0, maskSurface, maskTransform);
832 :
833 : return true;
834 : }
835 :
836 : /* static */ void
837 0 : nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
838 : nsDisplayListBuilder* aBuilder,
839 : nsDisplayItem* aItem,
840 : nsIFrame* aFrame,
841 : nsCSSPropertyID aProperty)
842 : {
843 0 : MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
844 : CSSPropFlags::CanAnimateOnCompositor),
845 : "inconsistent property flags");
846 :
847 : // This function can be called in two ways: from
848 : // nsDisplay*::BuildLayer while constructing a layer (with all
849 : // pointers non-null), or from RestyleManager's handling of
850 : // UpdateOpacityLayer/UpdateTransformLayer hints.
851 0 : MOZ_ASSERT(!aBuilder == !aItem,
852 : "should only be called in two configurations, with both "
853 : "aBuilder and aItem, or with neither");
854 0 : MOZ_ASSERT(!aItem || aFrame == aItem->Frame(), "frame mismatch");
855 :
856 : // Only send animations to a layer that is actually using
857 : // off-main-thread compositing.
858 0 : LayersBackend backend = aLayer->Manager()->GetBackendType();
859 0 : if (!(backend == layers::LayersBackend::LAYERS_CLIENT ||
860 : backend == layers::LayersBackend::LAYERS_WR)) {
861 : return;
862 : }
863 :
864 0 : bool pending = !aBuilder;
865 0 : AnimationInfo& animationInfo = aLayer->GetAnimationInfo();
866 : AddAnimationsForProperty(aFrame, aBuilder, aItem, aProperty,
867 0 : animationInfo, pending, false);
868 0 : animationInfo.TransferMutatedFlagToLayer(aLayer);
869 : }
870 :
871 : nsDisplayItem*
872 0 : nsDisplayListBuilder::MergeItems(nsTArray<nsDisplayItem*>& aMergedItems)
873 : {
874 : // For merging, we create a temporary item by cloning the last item of the
875 : // mergeable items list. This ensures that the temporary item will have the
876 : // correct frame and bounds.
877 0 : nsDisplayItem* merged = nullptr;
878 :
879 0 : for (nsDisplayItem* item : Reversed(aMergedItems)) {
880 0 : MOZ_ASSERT(item);
881 :
882 0 : if (!merged) {
883 : // Create the temporary item.
884 0 : merged = item->Clone(this);
885 0 : MOZ_ASSERT(merged);
886 :
887 0 : AddTemporaryItem(merged);
888 : } else {
889 : // Merge the item properties (frame/bounds/etc) with the previously
890 : // created temporary item.
891 0 : MOZ_ASSERT(merged->CanMerge(item));
892 0 : merged->Merge(item);
893 : }
894 :
895 : // Create nsDisplayWrapList that points to the internal display list of the
896 : // item we are merging. This nsDisplayWrapList is added to the display list
897 : // of the temporary item.
898 0 : merged->MergeDisplayListFromItem(this, item);
899 : }
900 :
901 0 : return merged;
902 : }
903 :
904 : void
905 0 : nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::SetCurrentActiveScrolledRoot(
906 : const ActiveScrolledRoot* aActiveScrolledRoot)
907 : {
908 0 : MOZ_ASSERT(!mUsed);
909 :
910 : // Set the builder's mCurrentActiveScrolledRoot.
911 0 : mBuilder->mCurrentActiveScrolledRoot = aActiveScrolledRoot;
912 :
913 : // We also need to adjust the builder's mCurrentContainerASR.
914 : // mCurrentContainerASR needs to be an ASR that all the container's
915 : // contents have finite bounds with respect to. If aActiveScrolledRoot
916 : // is an ancestor ASR of mCurrentContainerASR, that means we need to
917 : // set mCurrentContainerASR to aActiveScrolledRoot, because otherwise
918 : // the items that will be created with aActiveScrolledRoot wouldn't
919 : // have finite bounds with respect to mCurrentContainerASR. There's one
920 : // exception, in the case where there's a content clip on the builder
921 : // that is scrolled by a descendant ASR of aActiveScrolledRoot. This
922 : // content clip will clip all items that are created while this
923 : // AutoCurrentActiveScrolledRootSetter exists. This means that the items
924 : // created during our lifetime will have finite bounds with respect to
925 : // the content clip's ASR, even if the items' actual ASR is an ancestor
926 : // of that. And it also means that mCurrentContainerASR only needs to be
927 : // set to the content clip's ASR and not all the way to aActiveScrolledRoot.
928 : // This case is tested by fixed-pos-scrolled-clip-opacity-layerize.html
929 : // and fixed-pos-scrolled-clip-opacity-inside-layerize.html.
930 :
931 : // finiteBoundsASR is the leafmost ASR that all items created during
932 : // object's lifetime have finite bounds with respect to.
933 0 : const ActiveScrolledRoot* finiteBoundsASR = ActiveScrolledRoot::PickDescendant(
934 0 : mContentClipASR, aActiveScrolledRoot);
935 :
936 : // mCurrentContainerASR is adjusted so that it's still an ancestor of
937 : // finiteBoundsASR.
938 0 : mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor(
939 : mBuilder->mCurrentContainerASR, finiteBoundsASR);
940 :
941 : // If we are entering out-of-flow content inside a CSS filter, mark
942 : // scroll frames wrt. which the content is fixed as containing such content.
943 0 : if (mBuilder->mFilterASR &&
944 0 : ActiveScrolledRoot::IsAncestor(aActiveScrolledRoot, mBuilder->mFilterASR)) {
945 0 : for (const ActiveScrolledRoot* asr = mBuilder->mFilterASR;
946 0 : asr && asr != aActiveScrolledRoot;
947 0 : asr = asr->mParent) {
948 0 : asr->mScrollableFrame->SetHasOutOfFlowContentInsideFilter();
949 : }
950 : }
951 :
952 0 : mUsed = true;
953 0 : }
954 :
955 : void
956 0 : nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::InsertScrollFrame(nsIScrollableFrame* aScrollableFrame)
957 : {
958 0 : MOZ_ASSERT(!mUsed);
959 0 : size_t descendantsEndIndex = mBuilder->mActiveScrolledRoots.Length();
960 0 : const ActiveScrolledRoot* parentASR = mBuilder->mCurrentActiveScrolledRoot;
961 0 : const ActiveScrolledRoot* asr = mBuilder->AllocateActiveScrolledRoot(parentASR, aScrollableFrame);
962 0 : mBuilder->mCurrentActiveScrolledRoot = asr;
963 :
964 : // All child ASRs of parentASR that were created while this
965 : // AutoCurrentActiveScrolledRootSetter object was on the stack belong to us
966 : // now. Reparent them to asr.
967 0 : for (size_t i = mDescendantsStartIndex; i < descendantsEndIndex; i++) {
968 0 : ActiveScrolledRoot* descendantASR = mBuilder->mActiveScrolledRoots[i];
969 0 : if (ActiveScrolledRoot::IsAncestor(parentASR, descendantASR)) {
970 : descendantASR->IncrementDepth();
971 0 : if (descendantASR->mParent == parentASR) {
972 0 : descendantASR->mParent = asr;
973 : }
974 : }
975 : }
976 :
977 0 : mUsed = true;
978 0 : }
979 :
980 0 : nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
981 0 : nsDisplayListBuilderMode aMode, bool aBuildCaret, bool aRetainingDisplayList)
982 : : mReferenceFrame(aReferenceFrame),
983 : mIgnoreScrollFrame(nullptr),
984 : mCompositorHitTestInfo(nullptr),
985 : mCurrentTableItem(nullptr),
986 : mCurrentActiveScrolledRoot(nullptr),
987 : mCurrentContainerASR(nullptr),
988 : mCurrentFrame(aReferenceFrame),
989 : mCurrentReferenceFrame(aReferenceFrame),
990 38 : mRootAGR(AnimatedGeometryRoot::CreateAGRForFrame(aReferenceFrame, nullptr, true, aRetainingDisplayList)),
991 : mCurrentAGR(mRootAGR),
992 : mUsedAGRBudget(0),
993 : mDirtyRect(-1,-1,-1,-1),
994 : mGlassDisplayItem(nullptr),
995 : mScrollInfoItemsForHoisting(nullptr),
996 : mActiveScrolledRootForRootScrollframe(nullptr),
997 : mMode(aMode),
998 : mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
999 : mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
1000 : mSVGEffectsBuildingDepth(0),
1001 : mFilterASR(nullptr),
1002 : mContainsBlendMode(false),
1003 : mIsBuildingScrollbar(false),
1004 : mCurrentScrollbarWillHaveLayer(false),
1005 : mBuildCaret(aBuildCaret),
1006 : mRetainingDisplayList(aRetainingDisplayList),
1007 : mPartialUpdate(false),
1008 : mIgnoreSuppression(false),
1009 : mIsAtRootOfPseudoStackingContext(false),
1010 : mIncludeAllOutOfFlows(false),
1011 : mDescendIntoSubdocuments(true),
1012 : mSelectedFramesOnly(false),
1013 : mAllowMergingAndFlattening(true),
1014 : mWillComputePluginGeometry(false),
1015 : mInTransform(false),
1016 : mInPageSequence(false),
1017 : mIsInChromePresContext(false),
1018 : mSyncDecodeImages(false),
1019 : mIsPaintingToWindow(false),
1020 : mIsCompositingCheap(false),
1021 : mContainsPluginItem(false),
1022 : mAncestorHasApzAwareEventHandler(false),
1023 : mHaveScrollableDisplayPort(false),
1024 : mWindowDraggingAllowed(false),
1025 19 : mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
1026 : mForceLayerForScrollParent(false),
1027 19 : mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)),
1028 : mBuildingInvisibleItems(false),
1029 : mHitTestIsForVisibility(false),
1030 : mIsBuilding(false),
1031 : mInInvalidSubtree(false),
1032 : mDisablePartialUpdates(false),
1033 437 : mPartialBuildFailed(false)
1034 : {
1035 19 : MOZ_COUNT_CTOR(nsDisplayListBuilder);
1036 :
1037 19 : mBuildCompositorHitTestInfo = mAsyncPanZoomEnabled && IsForPainting();
1038 :
1039 0 : mLessEventRegionItems = gfxPrefs::LessEventRegionItems();
1040 :
1041 0 : nsPresContext* pc = aReferenceFrame->PresContext();
1042 0 : nsIPresShell *shell = pc->PresShell();
1043 19 : if (pc->IsRenderingOnlySelection()) {
1044 0 : nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
1045 0 : if (selcon) {
1046 : mBoundingSelection =
1047 0 : selcon->GetSelection(nsISelectionController::SELECTION_NORMAL);
1048 : }
1049 : }
1050 :
1051 : static_assert(static_cast<uint32_t>(DisplayItemType::TYPE_MAX) < (1 << TYPE_BITS),
1052 : "Check TYPE_MAX should not overflow");
1053 19 : }
1054 :
1055 : void
1056 19 : nsDisplayListBuilder::BeginFrame()
1057 : {
1058 0 : nsCSSRendering::BeginFrameTreesLocked();
1059 19 : mCurrentAGR = mRootAGR;
1060 19 : mFrameToAnimatedGeometryRootMap.Put(mReferenceFrame, mRootAGR);
1061 :
1062 19 : mIsPaintingToWindow = false;
1063 0 : mIgnoreSuppression = false;
1064 0 : mInTransform = false;
1065 0 : mSyncDecodeImages = false;
1066 19 : }
1067 :
1068 : void
1069 0 : nsDisplayListBuilder::EndFrame()
1070 : {
1071 0 : NS_ASSERTION(!mInInvalidSubtree, "Someone forgot to cleanup mInInvalidSubtree!");
1072 38 : mFrameToAnimatedGeometryRootMap.Clear();
1073 19 : mActiveScrolledRoots.Clear();
1074 0 : FreeClipChains();
1075 19 : FreeTemporaryItems();
1076 0 : nsCSSRendering::EndFrameTreesLocked();
1077 :
1078 0 : MOZ_ASSERT(!mCompositorHitTestInfo);
1079 0 : }
1080 :
1081 : void
1082 23 : nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
1083 : {
1084 0 : mFramesMarkedForDisplay.AppendElement(aFrame);
1085 0 : for (nsIFrame* f = aFrame; f;
1086 : f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
1087 442 : if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
1088 : return;
1089 211 : f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
1090 0 : if (f == aStopAtFrame) {
1091 : // we've reached a frame that we know will be painted, so we can stop.
1092 : break;
1093 : }
1094 : }
1095 : }
1096 :
1097 : void
1098 0 : nsDisplayListBuilder::AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame)
1099 : {
1100 0 : mFramesMarkedForDisplayIfVisible.AppendElement(aFrame);
1101 0 : }
1102 :
1103 : void
1104 0 : nsDisplayListBuilder::MarkFrameForDisplayIfVisible(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
1105 : {
1106 0 : AddFrameMarkedForDisplayIfVisible(aFrame);
1107 0 : for (nsIFrame* f = aFrame; f;
1108 : f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
1109 0 : if (f->ForceDescendIntoIfVisible())
1110 : return;
1111 0 : f->SetForceDescendIntoIfVisible(true);
1112 0 : if (f == aStopAtFrame) {
1113 : // we've reached a frame that we know will be painted, so we can stop.
1114 : break;
1115 : }
1116 : }
1117 : }
1118 :
1119 767 : bool nsDisplayListBuilder::NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem)
1120 : {
1121 767 : return aItem == mGlassDisplayItem || aItem->ClearsBackground();
1122 : }
1123 :
1124 : AnimatedGeometryRoot*
1125 0 : nsDisplayListBuilder::WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot,
1126 : bool aIsAsync,
1127 : AnimatedGeometryRoot* aParent /* = nullptr */)
1128 : {
1129 32 : DebugOnly<bool> dummy;
1130 16 : MOZ_ASSERT(IsAnimatedGeometryRoot(aAnimatedGeometryRoot, dummy) == AGR_YES);
1131 :
1132 32 : RefPtr<AnimatedGeometryRoot> result;
1133 16 : if (!mFrameToAnimatedGeometryRootMap.Get(aAnimatedGeometryRoot, &result)) {
1134 0 : MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), aAnimatedGeometryRoot));
1135 0 : RefPtr<AnimatedGeometryRoot> parent = aParent;
1136 0 : if (!parent) {
1137 0 : nsIFrame* parentFrame = nsLayoutUtils::GetCrossDocParentFrame(aAnimatedGeometryRoot);
1138 0 : if (parentFrame) {
1139 : bool isAsync;
1140 0 : nsIFrame* parentAGRFrame = FindAnimatedGeometryRootFrameFor(parentFrame, isAsync);
1141 0 : parent = WrapAGRForFrame(parentAGRFrame, isAsync);
1142 : }
1143 : }
1144 0 : result = AnimatedGeometryRoot::CreateAGRForFrame(aAnimatedGeometryRoot, parent, aIsAsync, IsRetainingDisplayList());
1145 0 : mFrameToAnimatedGeometryRootMap.Put(aAnimatedGeometryRoot, result);
1146 : }
1147 0 : MOZ_ASSERT(!aParent || result->mParentAGR == aParent);
1148 32 : return result;
1149 : }
1150 :
1151 : AnimatedGeometryRoot*
1152 0 : nsDisplayListBuilder::AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR)
1153 : {
1154 0 : if (!aASR) {
1155 0 : return GetRootAnimatedGeometryRoot();
1156 : }
1157 0 : nsIFrame* scrolledFrame = aASR->mScrollableFrame->GetScrolledFrame();
1158 0 : return FindAnimatedGeometryRootFor(scrolledFrame);
1159 : }
1160 :
1161 : AnimatedGeometryRoot*
1162 562 : nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame)
1163 : {
1164 0 : if (!IsPaintingToWindow()) {
1165 114 : return mRootAGR;
1166 : }
1167 505 : if (aFrame == mCurrentFrame) {
1168 0 : return mCurrentAGR;
1169 : }
1170 0 : RefPtr<AnimatedGeometryRoot> result;
1171 0 : if (mFrameToAnimatedGeometryRootMap.Get(aFrame, &result)) {
1172 0 : return result;
1173 : }
1174 :
1175 : bool isAsync;
1176 0 : nsIFrame* agrFrame = FindAnimatedGeometryRootFrameFor(aFrame, isAsync);
1177 0 : result = WrapAGRForFrame(agrFrame, isAsync);
1178 0 : mFrameToAnimatedGeometryRootMap.Put(aFrame, result);
1179 16 : return result;
1180 : }
1181 :
1182 : AnimatedGeometryRoot*
1183 0 : nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsDisplayItem* aItem)
1184 : {
1185 0 : if (aItem->ShouldFixToViewport(this)) {
1186 : // Make its active scrolled root be the active scrolled root of
1187 : // the enclosing viewport, since it shouldn't be scrolled by scrolled
1188 : // frames in its document. InvalidateFixedBackgroundFramesFromList in
1189 : // nsGfxScrollFrame will not repaint this item when scrolling occurs.
1190 0 : nsIFrame* viewportFrame = nsLayoutUtils::GetClosestFrameOfType(
1191 0 : aItem->Frame(), LayoutFrameType::Viewport, RootReferenceFrame());
1192 0 : if (viewportFrame) {
1193 0 : return FindAnimatedGeometryRootFor(viewportFrame);
1194 : }
1195 : }
1196 0 : return FindAnimatedGeometryRootFor(aItem->Frame());
1197 : }
1198 :
1199 0 : bool nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
1200 : nsIFrame* aFrame)
1201 : {
1202 1 : MOZ_ASSERT(aFrame->GetParent() == aDirtyFrame);
1203 36 : nsRect dirty;
1204 : nsRect visible =
1205 : OutOfFlowDisplayData::ComputeVisibleRectForFrame(this, aFrame, GetVisibleRect(),
1206 54 : GetDirtyRect(), &dirty);
1207 54 : if (!(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) &&
1208 0 : visible.IsEmpty()) {
1209 : return false;
1210 : }
1211 :
1212 : // Only MarkFrameForDisplay if we're dirty. If this is a nested out-of-flow frame, then it will
1213 : // also mark any outer frames to ensure that building reaches the dirty feame.
1214 0 : if (!dirty.IsEmpty() ||
1215 0 : aFrame->ForceDescendIntoIfVisible()) {
1216 18 : MarkFrameForDisplay(aFrame, aDirtyFrame);
1217 : }
1218 :
1219 : return true;
1220 : }
1221 :
1222 0 : static void UnmarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
1223 226 : for (nsIFrame* f = aFrame; f;
1224 : f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
1225 452 : if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
1226 : return;
1227 211 : f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
1228 0 : if (f == aStopAtFrame) {
1229 : // we've reached a frame that we know will be painted, so we can stop.
1230 : break;
1231 : }
1232 : }
1233 : }
1234 :
1235 0 : static void UnmarkFrameForDisplayIfVisible(nsIFrame* aFrame) {
1236 0 : for (nsIFrame* f = aFrame; f;
1237 : f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
1238 0 : if (!f->ForceDescendIntoIfVisible())
1239 : return;
1240 0 : f->SetForceDescendIntoIfVisible(false);
1241 : }
1242 : }
1243 :
1244 0 : nsDisplayListBuilder::~nsDisplayListBuilder() {
1245 38 : NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
1246 : "All frames should have been unmarked");
1247 38 : NS_ASSERTION(mFramesWithOOFData.Length() == 0,
1248 : "All OOF data should have been removed");
1249 38 : NS_ASSERTION(mPresShellStates.Length() == 0,
1250 : "All presshells should have been exited");
1251 0 : NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
1252 :
1253 0 : for (DisplayItemClipChain* c : mClipChainsToDestroy) {
1254 0 : c->DisplayItemClipChain::~DisplayItemClipChain();
1255 : }
1256 :
1257 0 : MOZ_COUNT_DTOR(nsDisplayListBuilder);
1258 19 : }
1259 :
1260 : uint32_t
1261 48 : nsDisplayListBuilder::GetBackgroundPaintFlags() {
1262 48 : uint32_t flags = 0;
1263 0 : if (mSyncDecodeImages) {
1264 0 : flags |= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES;
1265 : }
1266 48 : if (mIsPaintingToWindow) {
1267 0 : flags |= nsCSSRendering::PAINTBG_TO_WINDOW;
1268 : }
1269 0 : return flags;
1270 : }
1271 :
1272 : void
1273 0 : nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
1274 : const nsRegion& aRegion)
1275 : {
1276 103 : if (aRegion.IsEmpty())
1277 90 : return;
1278 :
1279 0 : nsRegion tmp;
1280 13 : tmp.Sub(*aVisibleRegion, aRegion);
1281 : // Don't let *aVisibleRegion get too complex, but don't let it fluff out
1282 : // to its bounds either, which can be very bad (see bug 516740).
1283 : // Do let aVisibleRegion get more complex if by doing so we reduce its
1284 : // area by at least half.
1285 0 : if (GetAccurateVisibleRegions() || tmp.GetNumRects() <= 15 ||
1286 0 : tmp.Area() <= aVisibleRegion->Area()/2) {
1287 : *aVisibleRegion = tmp;
1288 : }
1289 : }
1290 :
1291 : nsCaret *
1292 0 : nsDisplayListBuilder::GetCaret() {
1293 15 : RefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret();
1294 10 : return caret;
1295 : }
1296 :
1297 : void
1298 0 : nsDisplayListBuilder::IncrementPresShellPaintCount(nsIPresShell* aPresShell)
1299 : {
1300 0 : if (mIsPaintingToWindow) {
1301 8 : mReferenceFrame->AddPaintedPresShell(aPresShell);
1302 8 : aPresShell->IncrementPaintCount();
1303 : }
1304 0 : }
1305 :
1306 : void
1307 0 : nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
1308 : bool aPointerEventsNoneDoc)
1309 : {
1310 0 : PresShellState* state = mPresShellStates.AppendElement();
1311 19 : state->mPresShell = aReferenceFrame->PresShell();
1312 19 : state->mCaretFrame = nullptr;
1313 0 : state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
1314 38 : state->mFirstFrameWithOOFData = mFramesWithOOFData.Length();
1315 :
1316 0 : nsIScrollableFrame* sf = state->mPresShell->GetRootScrollFrameAsScrollable();
1317 0 : if (sf && IsInSubdocument()) {
1318 : // We are forcing a rebuild of nsDisplayCanvasBackgroundColor to make sure
1319 : // that the canvas background color will be set correctly, and that only one
1320 : // unscrollable item will be created.
1321 : // This is done to avoid, for example, a case where only scrollbar frames
1322 : // are invalidated - we would skip creating nsDisplayCanvasBackgroundColor
1323 : // and possibly end up with an extra nsDisplaySolidColor item.
1324 : // We skip this for the root document, since we don't want to use
1325 : // MarkFrameForDisplayIfVisible before ComputeRebuildRegion. We'll
1326 : // do it manually there.
1327 0 : nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
1328 0 : if (canvasFrame) {
1329 0 : MarkFrameForDisplayIfVisible(canvasFrame, aReferenceFrame);
1330 : }
1331 : }
1332 :
1333 : #ifdef DEBUG
1334 0 : state->mAutoLayoutPhase.emplace(aReferenceFrame->PresContext(), eLayoutPhase_DisplayListBuilding);
1335 : #endif
1336 :
1337 19 : state->mPresShell->UpdateCanvasBackground();
1338 :
1339 19 : bool buildCaret = mBuildCaret;
1340 0 : if (mIgnoreSuppression || !state->mPresShell->IsPaintingSuppressed()) {
1341 19 : state->mIsBackgroundOnly = false;
1342 : } else {
1343 0 : state->mIsBackgroundOnly = true;
1344 0 : buildCaret = false;
1345 : }
1346 :
1347 0 : bool pointerEventsNone = aPointerEventsNoneDoc;
1348 19 : if (IsInSubdocument()) {
1349 0 : pointerEventsNone |= mPresShellStates[mPresShellStates.Length() - 2].mInsidePointerEventsNoneDoc;
1350 : }
1351 19 : state->mInsidePointerEventsNoneDoc = pointerEventsNone;
1352 :
1353 0 : if (!buildCaret)
1354 0 : return;
1355 :
1356 24 : RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
1357 0 : state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
1358 8 : if (state->mCaretFrame) {
1359 0 : MarkFrameForDisplay(state->mCaretFrame, aReferenceFrame);
1360 : }
1361 :
1362 0 : nsPresContext* pc = aReferenceFrame->PresContext();
1363 0 : nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
1364 0 : if (docShell) {
1365 0 : docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
1366 : }
1367 8 : mIsInChromePresContext = pc->IsChrome();
1368 : }
1369 :
1370 : // A non-blank paint is a paint that does not just contain the canvas background.
1371 : static bool
1372 1 : DisplayListIsNonBlank(nsDisplayList* aList)
1373 : {
1374 1 : for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
1375 1 : switch (i->GetType()) {
1376 : case DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO:
1377 : case DisplayItemType::TYPE_CANVAS_BACKGROUND_COLOR:
1378 : case DisplayItemType::TYPE_CANVAS_BACKGROUND_IMAGE:
1379 : continue;
1380 : case DisplayItemType::TYPE_SOLID_COLOR:
1381 : case DisplayItemType::TYPE_BACKGROUND:
1382 : case DisplayItemType::TYPE_BACKGROUND_COLOR:
1383 1 : if (i->Frame()->IsCanvasFrame()) {
1384 : continue;
1385 : }
1386 : return true;
1387 : default:
1388 : return true;
1389 : }
1390 : }
1391 : return false;
1392 : }
1393 :
1394 : void
1395 19 : nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame, nsDisplayList* aPaintedContents)
1396 : {
1397 19 : NS_ASSERTION(CurrentPresShellState()->mPresShell ==
1398 : aReferenceFrame->PresShell(),
1399 : "Presshell mismatch");
1400 :
1401 19 : if (mIsPaintingToWindow) {
1402 0 : nsPresContext* pc = aReferenceFrame->PresContext();
1403 8 : if (!pc->HadNonBlankPaint()) {
1404 0 : if (!CurrentPresShellState()->mIsBackgroundOnly &&
1405 1 : DisplayListIsNonBlank(aPaintedContents)) {
1406 1 : pc->NotifyNonBlankPaint();
1407 : }
1408 : }
1409 : }
1410 :
1411 0 : ResetMarkedFramesForDisplayList(aReferenceFrame);
1412 0 : mPresShellStates.SetLength(mPresShellStates.Length() - 1);
1413 :
1414 38 : if (!mPresShellStates.IsEmpty()) {
1415 0 : nsPresContext* pc = CurrentPresContext();
1416 0 : nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
1417 0 : if (docShell) {
1418 0 : docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
1419 : }
1420 0 : mIsInChromePresContext = pc->IsChrome();
1421 : } else {
1422 0 : mCurrentAGR = mRootAGR;
1423 :
1424 0 : for (uint32_t i = 0;
1425 0 : i < mFramesMarkedForDisplayIfVisible.Length(); ++i) {
1426 0 : UnmarkFrameForDisplayIfVisible(mFramesMarkedForDisplayIfVisible[i]);
1427 : }
1428 19 : mFramesMarkedForDisplayIfVisible.SetLength(0);
1429 : }
1430 19 : }
1431 :
1432 : void
1433 0 : nsDisplayListBuilder::FreeClipChains()
1434 : {
1435 : // Iterate the clip chains from newest to oldest (forward
1436 : // iteration), so that we destroy descendants first which
1437 : // will drop the ref count on their ancestors.
1438 38 : auto it = mClipChainsToDestroy.begin();
1439 :
1440 0 : while(it != mClipChainsToDestroy.end()) {
1441 101 : DisplayItemClipChain* clip = *it;
1442 :
1443 101 : if (!clip->mRefCount) {
1444 101 : mClipDeduplicator.erase(clip);
1445 0 : it = mClipChainsToDestroy.erase(it);
1446 101 : clip->DisplayItemClipChain::~DisplayItemClipChain();
1447 0 : Destroy(DisplayItemType::TYPE_ZERO, clip);
1448 : } else {
1449 : ++it;
1450 : }
1451 : }
1452 0 : }
1453 :
1454 : void
1455 19 : nsDisplayListBuilder::FreeTemporaryItems()
1456 : {
1457 57 : for (nsDisplayItem* i : mTemporaryItems) {
1458 : // Temporary display items are not added to the frames.
1459 0 : MOZ_ASSERT(i->Frame());
1460 0 : i->RemoveFrame(i->Frame());
1461 0 : i->Destroy(this);
1462 : }
1463 :
1464 0 : mTemporaryItems.Clear();
1465 19 : }
1466 :
1467 : void
1468 0 : nsDisplayListBuilder::ResetMarkedFramesForDisplayList(nsIFrame* aReferenceFrame)
1469 : {
1470 : // Unmark and pop off the frames marked for display in this pres shell.
1471 0 : uint32_t firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
1472 0 : for (uint32_t i = firstFrameForShell;
1473 84 : i < mFramesMarkedForDisplay.Length(); ++i) {
1474 46 : UnmarkFrameForDisplay(mFramesMarkedForDisplay[i], aReferenceFrame);
1475 : }
1476 19 : mFramesMarkedForDisplay.SetLength(firstFrameForShell);
1477 :
1478 0 : firstFrameForShell = CurrentPresShellState()->mFirstFrameWithOOFData;
1479 0 : for (uint32_t i = firstFrameForShell; i < mFramesWithOOFData.Length(); ++i) {
1480 0 : mFramesWithOOFData[i]->DeleteProperty(OutOfFlowDisplayDataProperty());
1481 : }
1482 19 : mFramesWithOOFData.SetLength(firstFrameForShell);
1483 0 : }
1484 :
1485 : void
1486 0 : nsDisplayListBuilder::ClearFixedBackgroundDisplayData()
1487 : {
1488 0 : CurrentPresShellState()->mFixedBackgroundDisplayData = Nothing();
1489 0 : }
1490 :
1491 : void
1492 116 : nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
1493 : const nsFrameList& aFrames)
1494 : {
1495 1 : bool markedFrames = false;
1496 1 : for (nsIFrame* e : aFrames) {
1497 : // Skip the AccessibleCaret frame when building no caret.
1498 18 : if (!IsBuildingCaret()) {
1499 0 : nsIContent* content = e->GetContent();
1500 0 : if (content && content->IsInNativeAnonymousSubtree() && content->IsElement()) {
1501 0 : auto classList = content->AsElement()->ClassList();
1502 0 : if (classList->Contains(NS_LITERAL_STRING("moz-accessiblecaret"))) {
1503 : continue;
1504 : }
1505 : }
1506 : }
1507 0 : if (MarkOutOfFlowFrameForDisplay(aDirtyFrame, e)) {
1508 0 : markedFrames = true;
1509 : }
1510 : }
1511 :
1512 116 : if (markedFrames) {
1513 : // mClipState.GetClipChainForContainingBlockDescendants can return pointers
1514 : // to objects on the stack, so we need to clone the chain.
1515 : const DisplayItemClipChain* clipChain =
1516 18 : CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
1517 18 : const DisplayItemClipChain* combinedClipChain = mClipState.GetCurrentCombinedClipChain(this);
1518 18 : const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
1519 0 : OutOfFlowDisplayData* data = new OutOfFlowDisplayData(clipChain, combinedClipChain, asr, GetVisibleRect(), GetDirtyRect());
1520 18 : aDirtyFrame->SetProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
1521 18 : mFramesWithOOFData.AppendElement(aDirtyFrame);
1522 : }
1523 :
1524 0 : if (!aDirtyFrame->GetParent()) {
1525 : // This is the viewport frame of aDirtyFrame's presshell.
1526 : // Store the current display data so that it can be used for fixed
1527 : // background images.
1528 0 : NS_ASSERTION(CurrentPresShellState()->mPresShell ==
1529 : aDirtyFrame->PresShell(),
1530 : "Presshell mismatch");
1531 0 : MOZ_ASSERT(!CurrentPresShellState()->mFixedBackgroundDisplayData,
1532 : "already traversed this presshell's root frame?");
1533 :
1534 : const DisplayItemClipChain* clipChain =
1535 0 : CopyWholeChain(mClipState.GetClipChainForContainingBlockDescendants());
1536 19 : const DisplayItemClipChain* combinedClipChain = mClipState.GetCurrentCombinedClipChain(this);
1537 19 : const ActiveScrolledRoot* asr = mCurrentActiveScrolledRoot;
1538 0 : CurrentPresShellState()->mFixedBackgroundDisplayData.emplace(
1539 19 : clipChain, combinedClipChain, asr, GetVisibleRect(), GetDirtyRect());
1540 : }
1541 116 : }
1542 :
1543 : /**
1544 : * Mark all preserve-3d children with
1545 : * NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO to make sure
1546 : * nsFrame::BuildDisplayListForChild() would visit them. Also compute
1547 : * dirty rect for preserve-3d children.
1548 : *
1549 : * @param aDirtyFrame is the frame to mark children extending context.
1550 : */
1551 : void
1552 0 : nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame)
1553 : {
1554 0 : AutoTArray<nsIFrame::ChildList,4> childListArray;
1555 0 : aDirtyFrame->GetChildLists(&childListArray);
1556 : nsIFrame::ChildListArrayIterator lists(childListArray);
1557 0 : for (; !lists.IsDone(); lists.Next()) {
1558 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
1559 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
1560 0 : nsIFrame *child = childFrames.get();
1561 0 : if (child->Combines3DTransformWithAncestors()) {
1562 0 : MarkFrameForDisplay(child, aDirtyFrame);
1563 : }
1564 : }
1565 : }
1566 0 : }
1567 :
1568 : uint32_t gDisplayItemSizes[static_cast<uint32_t>(DisplayItemType::TYPE_MAX)] = { 0 };
1569 :
1570 : void*
1571 775 : nsDisplayListBuilder::Allocate(size_t aSize, DisplayItemType aType)
1572 : {
1573 0 : size_t roundedUpSize = RoundUpPow2(aSize);
1574 775 : uint_fast8_t type = FloorLog2Size(roundedUpSize);
1575 :
1576 775 : MOZ_RELEASE_ASSERT(gDisplayItemSizes[static_cast<uint32_t>(aType)] == type ||
1577 : gDisplayItemSizes[static_cast<uint32_t>(aType)] == 0);
1578 0 : gDisplayItemSizes[static_cast<uint32_t>(aType)] = type;
1579 1550 : return mPool.AllocateByCustomID(type, roundedUpSize);
1580 : }
1581 :
1582 : void
1583 0 : nsDisplayListBuilder::Destroy(DisplayItemType aType, void* aPtr)
1584 : {
1585 0 : mPool.FreeByCustomID(gDisplayItemSizes[static_cast<uint32_t>(aType)], aPtr);
1586 0 : }
1587 :
1588 : ActiveScrolledRoot*
1589 0 : nsDisplayListBuilder::AllocateActiveScrolledRoot(const ActiveScrolledRoot* aParent,
1590 : nsIScrollableFrame* aScrollableFrame)
1591 : {
1592 0 : RefPtr<ActiveScrolledRoot> asr = ActiveScrolledRoot::CreateASRForFrame(aParent, aScrollableFrame, IsRetainingDisplayList());
1593 0 : mActiveScrolledRoots.AppendElement(asr);
1594 0 : return asr;
1595 : }
1596 :
1597 : const DisplayItemClipChain*
1598 240 : nsDisplayListBuilder::AllocateDisplayItemClipChain(const DisplayItemClip& aClip,
1599 : const ActiveScrolledRoot* aASR,
1600 : const DisplayItemClipChain* aParent)
1601 : {
1602 240 : MOZ_ASSERT(!(aParent && aParent->mOnStack));
1603 240 : void* p = Allocate(sizeof(DisplayItemClipChain), DisplayItemType::TYPE_ZERO);
1604 240 : DisplayItemClipChain* c = new (KnownNotNull, p) DisplayItemClipChain(aClip, aASR, aParent);
1605 : #ifdef DEBUG
1606 240 : c->mOnStack = false;
1607 : #endif
1608 240 : auto result = mClipDeduplicator.insert(c);
1609 0 : if (!result.second) {
1610 : // An equivalent clip chain item was already created, so let's return that
1611 : // instead. Destroy the one we just created.
1612 : // Note that this can cause clip chains from different coordinate systems to
1613 : // collapse into the same clip chain object, because clip chains do not keep
1614 : // track of the reference frame that they were created in.
1615 0 : c->DisplayItemClipChain::~DisplayItemClipChain();
1616 0 : Destroy(DisplayItemType::TYPE_ZERO, c);
1617 139 : return *(result.first);
1618 : }
1619 101 : mClipChainsToDestroy.emplace_front(c);
1620 101 : return c;
1621 : }
1622 :
1623 0 : struct ClipChainItem {
1624 : DisplayItemClip clip;
1625 : const ActiveScrolledRoot* asr;
1626 : };
1627 :
1628 : const DisplayItemClipChain*
1629 256 : nsDisplayListBuilder::CreateClipChainIntersection(const DisplayItemClipChain* aAncestor,
1630 : const DisplayItemClipChain* aLeafClip1,
1631 : const DisplayItemClipChain* aLeafClip2)
1632 : {
1633 512 : AutoTArray<ClipChainItem,8> intersectedClips;
1634 :
1635 256 : const DisplayItemClipChain* clip1 = aLeafClip1;
1636 0 : const DisplayItemClipChain* clip2 = aLeafClip2;
1637 :
1638 : const ActiveScrolledRoot* asr =
1639 256 : ActiveScrolledRoot::PickDescendant(clip1 ? clip1->mASR : nullptr,
1640 0 : clip2 ? clip2->mASR : nullptr);
1641 :
1642 : // Build up the intersection from the leaf to the root and put it into
1643 : // intersectedClips. The loop below will convert intersectedClips into an
1644 : // actual DisplayItemClipChain.
1645 : // (We need to do this in two passes because we need the parent clip in order
1646 : // to create the DisplayItemClipChain object, but the parent clip has not
1647 : // been created at that point.)
1648 256 : while (!aAncestor || asr != aAncestor->mASR) {
1649 256 : if (clip1 && clip1->mASR == asr) {
1650 42 : if (clip2 && clip2->mASR == asr) {
1651 64 : DisplayItemClip intersection = clip1->mClip;
1652 32 : intersection.IntersectWith(clip2->mClip);
1653 64 : intersectedClips.AppendElement(ClipChainItem{ intersection, asr });
1654 96 : clip2 = clip2->mParent;
1655 : } else {
1656 0 : intersectedClips.AppendElement(ClipChainItem{ clip1->mClip, asr });
1657 : }
1658 0 : clip1 = clip1->mParent;
1659 0 : } else if (clip2 && clip2->mASR == asr) {
1660 0 : intersectedClips.AppendElement(ClipChainItem{ clip2->mClip, asr });
1661 0 : clip2 = clip2->mParent;
1662 : }
1663 0 : if (!asr) {
1664 256 : MOZ_ASSERT(!aAncestor, "We should have exited this loop earlier");
1665 : break;
1666 : }
1667 0 : asr = asr->mParent;
1668 : }
1669 :
1670 : // Convert intersectedClips into a DisplayItemClipChain.
1671 0 : const DisplayItemClipChain* parentSC = aAncestor;
1672 997 : for (auto& sc : Reversed(intersectedClips)) {
1673 229 : parentSC = AllocateDisplayItemClipChain(sc.clip, sc.asr, parentSC);
1674 : }
1675 512 : return parentSC;
1676 : }
1677 :
1678 : const DisplayItemClipChain*
1679 0 : nsDisplayListBuilder::CopyWholeChain(const DisplayItemClipChain* aClipChain)
1680 : {
1681 37 : return CreateClipChainIntersection(nullptr, aClipChain, nullptr);
1682 : }
1683 :
1684 : const nsIFrame*
1685 1900 : nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame *aFrame,
1686 : nsPoint* aOffset) const
1687 : {
1688 0 : if (aFrame == mCurrentFrame) {
1689 1819 : if (aOffset) {
1690 1688 : *aOffset = mCurrentOffsetToReferenceFrame;
1691 : }
1692 0 : return mCurrentReferenceFrame;
1693 : }
1694 577 : for (const nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f))
1695 : {
1696 0 : if (f == mReferenceFrame || f->IsTransformed()) {
1697 0 : if (aOffset) {
1698 70 : *aOffset = aFrame->GetOffsetToCrossDoc(f);
1699 : }
1700 : return f;
1701 : }
1702 : }
1703 0 : if (aOffset) {
1704 0 : *aOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
1705 : }
1706 0 : return mReferenceFrame;
1707 : }
1708 :
1709 : // Sticky frames are active if their nearest scrollable frame is also active.
1710 : static bool
1711 0 : IsStickyFrameActive(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aParent)
1712 : {
1713 0 : MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY);
1714 :
1715 : // Find the nearest scrollframe.
1716 0 : nsIFrame* cursor = aFrame;
1717 0 : nsIFrame* parent = aParent;
1718 0 : if (!parent) {
1719 0 : parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
1720 : }
1721 0 : while (!parent->IsScrollFrame()) {
1722 0 : cursor = parent;
1723 0 : if ((parent = nsLayoutUtils::GetCrossDocParentFrame(cursor)) == nullptr) {
1724 : return false;
1725 : }
1726 : }
1727 :
1728 0 : nsIScrollableFrame* sf = do_QueryFrame(parent);
1729 0 : return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor;
1730 : }
1731 :
1732 : nsDisplayListBuilder::AGRState
1733 947 : nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame,
1734 : bool& aIsAsync,
1735 : nsIFrame** aParent)
1736 : {
1737 947 : aIsAsync = false;
1738 947 : if (aFrame == mReferenceFrame) {
1739 54 : aIsAsync = true;
1740 0 : return AGR_YES;
1741 : }
1742 893 : if (!IsPaintingToWindow()) {
1743 79 : if (aParent) {
1744 0 : *aParent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
1745 : }
1746 : return AGR_NO;
1747 : }
1748 :
1749 0 : nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
1750 0 : if (!parent) {
1751 0 : aIsAsync = true;
1752 0 : return AGR_YES;
1753 : }
1754 :
1755 814 : AGRState result = AGR_NO; // Possible to transition from not being an AGR
1756 : // to being an AGR without a style change.
1757 :
1758 1 : LayoutFrameType parentType = parent->Type();
1759 :
1760 814 : if (aFrame->IsTransformed()) {
1761 0 : aIsAsync = EffectCompositor::HasAnimationsForCompositor(aFrame, eCSSProperty_transform);
1762 0 : result = AGR_YES;
1763 : }
1764 :
1765 0 : if (parentType == LayoutFrameType::Scroll ||
1766 814 : parentType == LayoutFrameType::ListControl) {
1767 0 : nsIScrollableFrame* sf = do_QueryFrame(parent);
1768 0 : if (sf->GetScrolledFrame() == aFrame) {
1769 0 : if (sf->IsScrollingActive(this)) {
1770 0 : aIsAsync = aIsAsync || sf->IsMaybeAsynchronouslyScrolled();
1771 0 : result = AGR_YES;
1772 : } else {
1773 : result = AGR_MAYBE;
1774 : }
1775 : }
1776 : }
1777 :
1778 : // Finished checking all conditions that might set aIsAsync, so we can
1779 : // early return now.
1780 814 : if (result == AGR_YES) {
1781 : return result;
1782 : }
1783 :
1784 814 : if (nsLayoutUtils::IsPopup(aFrame))
1785 : return AGR_YES;
1786 814 : if (ActiveLayerTracker::IsOffsetStyleAnimated(aFrame)) {
1787 0 : const bool inBudget = AddToAGRBudget(aFrame);
1788 0 : if (inBudget) {
1789 : return AGR_YES;
1790 : }
1791 : }
1792 814 : if (!aFrame->GetParent() &&
1793 0 : nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext())) {
1794 : // Viewport frames in a display port need to be animated geometry roots
1795 : // for background-attachment:fixed elements.
1796 : return AGR_YES;
1797 : }
1798 :
1799 :
1800 : // Treat the slider thumb as being as an active scrolled root when it wants
1801 : // its own layer so that it can move without repainting.
1802 814 : if (parentType == LayoutFrameType::Slider) {
1803 0 : nsIScrollableFrame* sf = static_cast<nsSliderFrame*>(parent)->GetScrollFrame();
1804 : // The word "Maybe" in IsMaybeScrollingActive might be confusing but we do
1805 : // indeed need to always consider scroll thumbs as AGRs if
1806 : // IsMaybeScrollingActive is true because that is the same condition we use
1807 : // in ScrollFrameHelper::AppendScrollPartsTo to layerize scroll thumbs.
1808 0 : if (sf && sf->IsMaybeScrollingActive()) {
1809 : return AGR_YES;
1810 : }
1811 : result = AGR_MAYBE;
1812 : }
1813 :
1814 814 : if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
1815 0 : if (IsStickyFrameActive(this, aFrame, parent)) {
1816 : return AGR_YES;
1817 : }
1818 : result = AGR_MAYBE;
1819 : }
1820 :
1821 :
1822 : // Fixed-pos frames are parented by the viewport frame, which has no parent.
1823 814 : if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
1824 : return AGR_YES;
1825 : }
1826 :
1827 1628 : if ((aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED) &&
1828 0 : aFrame->IsFrameOfType(nsIFrame::eSVG)) {
1829 : // For SVG containers, they always have
1830 : // NS_FRAME_MAY_BE_TRANSFORMED bit. However, they would be
1831 : // affected by the fragement identifiers in the svgView form at
1832 : // runtime without a new ComputedStyle.
1833 : // For example, layout/reftests/svg/fragmentIdentifier-01.xhtml
1834 : //
1835 : // see https://www.w3.org/TR/SVG/linking.html#SVGFragmentIdentifiers
1836 0 : result = AGR_MAYBE;
1837 : }
1838 :
1839 814 : if (aParent) {
1840 48 : *aParent = parent;
1841 : }
1842 : return result;
1843 : }
1844 :
1845 : nsIFrame*
1846 0 : nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame, bool& aIsAsync)
1847 : {
1848 16 : MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), aFrame));
1849 : nsIFrame* cursor = aFrame;
1850 112 : while (cursor != RootReferenceFrame()) {
1851 : nsIFrame* next;
1852 48 : if (IsAnimatedGeometryRoot(cursor, aIsAsync, &next) == AGR_YES)
1853 0 : return cursor;
1854 48 : cursor = next;
1855 : }
1856 : // Root frame is always an async agr.
1857 0 : aIsAsync = true;
1858 16 : return cursor;
1859 : }
1860 :
1861 : void
1862 0 : nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
1863 : {
1864 : bool isAsync;
1865 0 : if (*mCurrentAGR != mCurrentFrame &&
1866 0 : IsAnimatedGeometryRoot(const_cast<nsIFrame*>(mCurrentFrame), isAsync) == AGR_YES) {
1867 0 : AnimatedGeometryRoot* oldAGR = mCurrentAGR;
1868 0 : mCurrentAGR = WrapAGRForFrame(const_cast<nsIFrame*>(mCurrentFrame), isAsync, mCurrentAGR);
1869 :
1870 : // Iterate the AGR cache and look for any objects that reference the old AGR and check
1871 : // to see if they need to be updated. AGRs can be in the cache multiple times, so we may
1872 : // end up doing the work multiple times for AGRs that don't change.
1873 0 : for (auto iter = mFrameToAnimatedGeometryRootMap.Iter(); !iter.Done(); iter.Next()) {
1874 0 : RefPtr<AnimatedGeometryRoot> cached = iter.UserData();
1875 0 : if (cached->mParentAGR == oldAGR && cached != mCurrentAGR) {
1876 : // It's possible that this cached AGR struct that has the old AGR as a parent
1877 : // should instead have mCurrentFrame has a parent.
1878 0 : nsIFrame* parent = FindAnimatedGeometryRootFrameFor(*cached, isAsync);
1879 0 : MOZ_ASSERT(parent == mCurrentFrame || parent == *oldAGR);
1880 0 : if (parent == mCurrentFrame) {
1881 0 : cached->mParentAGR = mCurrentAGR;
1882 : }
1883 : }
1884 : }
1885 : }
1886 0 : }
1887 :
1888 : static nsRect
1889 104 : ApplyAllClipNonRoundedIntersection(const DisplayItemClipChain* aClipChain, const nsRect& aRect)
1890 : {
1891 104 : nsRect result = aRect;
1892 312 : while (aClipChain) {
1893 0 : result = aClipChain->mClip.ApplyNonRoundedIntersection(result);
1894 208 : aClipChain = aClipChain->mParent;
1895 : }
1896 0 : return result;
1897 : }
1898 :
1899 : void
1900 0 : nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
1901 : {
1902 688 : if (!mWindowDraggingAllowed || !IsForPainting()) {
1903 0 : return;
1904 : }
1905 :
1906 620 : const nsStyleUIReset* styleUI = aFrame->StyleUIReset();
1907 0 : if (styleUI->mWindowDragging == StyleWindowDragging::Default) {
1908 : // This frame has the default value and doesn't influence the window
1909 : // dragging region.
1910 : return;
1911 : }
1912 :
1913 0 : LayoutDeviceToLayoutDeviceMatrix4x4 referenceFrameToRootReferenceFrame;
1914 :
1915 : // The const_cast is for nsLayoutUtils::GetTransformToAncestor.
1916 104 : nsIFrame* referenceFrame = const_cast<nsIFrame*>(FindReferenceFrameFor(aFrame));
1917 :
1918 104 : if (IsInTransform()) {
1919 : // Only support 2d rectilinear transforms. Transform support is needed for
1920 : // the horizontal flip transform that's applied to the urlbar textbox in
1921 : // RTL mode - it should be able to exclude itself from the draggable region.
1922 0 : referenceFrameToRootReferenceFrame =
1923 0 : ViewAs<LayoutDeviceToLayoutDeviceMatrix4x4>(
1924 0 : nsLayoutUtils::GetTransformToAncestor(referenceFrame, mReferenceFrame).GetMatrix());
1925 0 : Matrix referenceFrameToRootReferenceFrame2d;
1926 0 : if (!referenceFrameToRootReferenceFrame.Is2D(&referenceFrameToRootReferenceFrame2d) ||
1927 0 : !referenceFrameToRootReferenceFrame2d.IsRectilinear()) {
1928 0 : return;
1929 : }
1930 : } else {
1931 0 : MOZ_ASSERT(referenceFrame == mReferenceFrame,
1932 : "referenceFrameToRootReferenceFrame needs to be adjusted");
1933 : }
1934 :
1935 : // We do some basic visibility checking on the frame's border box here.
1936 : // We intersect it both with the current dirty rect and with the current
1937 : // clip. Either one is just a conservative approximation on its own, but
1938 : // their intersection luckily works well enough for our purposes, so that
1939 : // we don't have to do full-blown visibility computations.
1940 : // The most important case we need to handle is the scrolled-off tab:
1941 : // If the tab bar overflows, tab parts that are clipped by the scrollbox
1942 : // should not be allowed to interfere with the window dragging region. Using
1943 : // just the current DisplayItemClip is not enough to cover this case
1944 : // completely because clips are reset while building stacking context
1945 : // contents, so for example we'd fail to clip frames that have a clip path
1946 : // applied to them. But the current dirty rect doesn't get reset in that
1947 : // case, so we use it to make this case work.
1948 104 : nsRect borderBox = aFrame->GetRectRelativeToSelf().Intersect(mVisibleRect);
1949 208 : borderBox += ToReferenceFrame(aFrame);
1950 104 : const DisplayItemClipChain* clip = ClipState().GetCurrentCombinedClipChain(this);
1951 104 : borderBox = ApplyAllClipNonRoundedIntersection(clip, borderBox);
1952 208 : if (borderBox.IsEmpty()) {
1953 104 : return;
1954 : }
1955 :
1956 : LayoutDeviceRect devPixelBorderBox =
1957 0 : LayoutDevicePixel::FromAppUnits(borderBox, aFrame->PresContext()->AppUnitsPerDevPixel());
1958 :
1959 : LayoutDeviceRect transformedDevPixelBorderBox =
1960 0 : TransformBy(referenceFrameToRootReferenceFrame, devPixelBorderBox);
1961 104 : transformedDevPixelBorderBox.Round();
1962 104 : LayoutDeviceIntRect transformedDevPixelBorderBoxInt;
1963 :
1964 0 : if (!transformedDevPixelBorderBox.ToIntRect(&transformedDevPixelBorderBoxInt)) {
1965 : return;
1966 : }
1967 :
1968 : LayoutDeviceIntRegion& region =
1969 0 : styleUI->mWindowDragging == StyleWindowDragging::Drag
1970 104 : ? mWindowDraggingRegion : mWindowNoDraggingRegion;
1971 :
1972 104 : if (!IsRetainingDisplayList()) {
1973 104 : region.OrWith(transformedDevPixelBorderBoxInt);
1974 104 : return;
1975 : }
1976 :
1977 0 : mozilla::gfx::IntRect rect(transformedDevPixelBorderBoxInt.ToUnknownRect());
1978 0 : if (styleUI->mWindowDragging == StyleWindowDragging::Drag) {
1979 0 : mRetainedWindowDraggingRegion.Add(aFrame, rect);
1980 : } else {
1981 0 : mRetainedWindowNoDraggingRegion.Add(aFrame, rect);
1982 : }
1983 : }
1984 :
1985 : LayoutDeviceIntRegion
1986 1 : nsDisplayListBuilder::GetWindowDraggingRegion() const
1987 : {
1988 1 : LayoutDeviceIntRegion result;
1989 8 : if (!IsRetainingDisplayList()) {
1990 8 : result.Sub(mWindowDraggingRegion, mWindowNoDraggingRegion);
1991 : return result;
1992 : }
1993 :
1994 : LayoutDeviceIntRegion dragRegion =
1995 0 : mRetainedWindowDraggingRegion.ToLayoutDeviceIntRegion();
1996 :
1997 : LayoutDeviceIntRegion noDragRegion =
1998 0 : mRetainedWindowNoDraggingRegion.ToLayoutDeviceIntRegion();
1999 :
2000 0 : result.Sub(dragRegion, noDragRegion);
2001 : return result;
2002 : }
2003 :
2004 : /**
2005 : * Removes modified frames and rects from |aRegion|.
2006 : */
2007 : static void
2008 0 : RemoveModifiedFramesAndRects(nsDisplayListBuilder::WeakFrameRegion& aRegion)
2009 : {
2010 0 : std::vector<WeakFrame>& frames = aRegion.mFrames;
2011 0 : nsTArray<pixman_box32_t>& rects = aRegion.mRects;
2012 :
2013 0 : MOZ_ASSERT(frames.size() == rects.Length());
2014 :
2015 0 : uint32_t i = 0;
2016 0 : uint32_t length = frames.size();
2017 :
2018 0 : while(i < length) {
2019 0 : WeakFrame& frame = frames[i];
2020 :
2021 0 : if (!frame.IsAlive() || frame->IsFrameModified()) {
2022 : // To avoid O(n) shifts in the array, move the last element of the array
2023 : // to the current position and decrease the array length. Moving WeakFrame
2024 : // inside of the array causes a new WeakFrame to be created and registered
2025 : // with PresShell. We could avoid this by, for example, using a wrapper
2026 : // class for WeakFrame, or by storing raw WeakFrame pointers.
2027 0 : frames[i] = frames[length - 1];
2028 0 : rects[i] = rects[length - 1];
2029 0 : length--;
2030 : } else {
2031 0 : i++;
2032 : }
2033 : }
2034 :
2035 0 : frames.resize(length);
2036 0 : rects.TruncateLength(length);
2037 0 : }
2038 :
2039 : void
2040 0 : nsDisplayListBuilder::RemoveModifiedWindowRegions()
2041 : {
2042 0 : RemoveModifiedFramesAndRects(mRetainedWindowDraggingRegion);
2043 0 : RemoveModifiedFramesAndRects(mRetainedWindowNoDraggingRegion);
2044 0 : RemoveModifiedFramesAndRects(mWindowExcludeGlassRegion);
2045 0 : }
2046 :
2047 : void
2048 19 : nsDisplayListBuilder::ClearRetainedWindowRegions()
2049 : {
2050 0 : mRetainedWindowDraggingRegion.Clear();
2051 0 : mRetainedWindowNoDraggingRegion.Clear();
2052 0 : mWindowExcludeGlassRegion.Clear();
2053 19 : }
2054 :
2055 : const uint32_t gWillChangeAreaMultiplier = 3;
2056 0 : static uint32_t GetLayerizationCost(const nsSize& aSize) {
2057 : // There's significant overhead for each layer created from Gecko
2058 : // (IPC+Shared Objects) and from the backend (like an OpenGL texture).
2059 : // Therefore we set a minimum cost threshold of a 64x64 area.
2060 0 : int minBudgetCost = 64 * 64;
2061 :
2062 : uint32_t budgetCost =
2063 0 : std::max(minBudgetCost,
2064 0 : nsPresContext::AppUnitsToIntCSSPixels(aSize.width) *
2065 0 : nsPresContext::AppUnitsToIntCSSPixels(aSize.height));
2066 :
2067 0 : return budgetCost;
2068 : }
2069 :
2070 : bool
2071 0 : nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
2072 : const nsSize& aSize) {
2073 0 : if (mWillChangeBudgetSet.Get(aFrame, nullptr)) {
2074 : return true; // Already accounted
2075 : }
2076 :
2077 0 : nsPresContext* key = aFrame->PresContext();
2078 0 : DocumentWillChangeBudget budget;
2079 0 : auto willChangeBudgetEntry = mWillChangeBudget.LookupForAdd(key);
2080 0 : if (willChangeBudgetEntry) {
2081 : // We have an existing entry.
2082 0 : budget = willChangeBudgetEntry.Data();
2083 : } else {
2084 0 : budget = DocumentWillChangeBudget();
2085 0 : willChangeBudgetEntry.OrInsert([&budget] () { return budget; });
2086 : }
2087 :
2088 0 : nsRect area = aFrame->PresContext()->GetVisibleArea();
2089 0 : uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
2090 0 : nsPresContext::AppUnitsToIntCSSPixels(area.height);
2091 :
2092 0 : uint32_t cost = GetLayerizationCost(aSize);
2093 0 : bool onBudget = (budget.mBudget + cost) /
2094 0 : gWillChangeAreaMultiplier < budgetLimit;
2095 :
2096 0 : if (onBudget) {
2097 0 : budget.mBudget += cost;
2098 0 : willChangeBudgetEntry.Data() = budget;
2099 0 : mWillChangeBudgetSet.Put(aFrame, cost);
2100 : aFrame->SetMayHaveWillChangeBudget(true);
2101 : }
2102 :
2103 : return onBudget;
2104 : }
2105 :
2106 : bool
2107 0 : nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame,
2108 : const nsSize& aSize) {
2109 0 : bool onBudget = AddToWillChangeBudget(aFrame, aSize);
2110 :
2111 0 : if (!onBudget) {
2112 0 : nsString usageStr;
2113 0 : usageStr.AppendInt(GetLayerizationCost(aSize));
2114 :
2115 0 : nsString multiplierStr;
2116 0 : multiplierStr.AppendInt(gWillChangeAreaMultiplier);
2117 :
2118 0 : nsString limitStr;
2119 0 : nsRect area = aFrame->PresContext()->GetVisibleArea();
2120 0 : uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
2121 0 : nsPresContext::AppUnitsToIntCSSPixels(area.height);
2122 0 : limitStr.AppendInt(budgetLimit);
2123 :
2124 0 : const char16_t* params[] = { multiplierStr.get(), limitStr.get() };
2125 0 : aFrame->PresContext()->Document()->WarnOnceAbout(
2126 : nsIDocument::eIgnoringWillChangeOverBudget, false,
2127 0 : params, ArrayLength(params));
2128 : }
2129 0 : return onBudget;
2130 : }
2131 :
2132 : void
2133 1225 : nsDisplayListBuilder::ClearWillChangeBudget(nsIFrame* aFrame)
2134 : {
2135 1225 : if (!aFrame->MayHaveWillChangeBudget()) {
2136 0 : return;
2137 : }
2138 0 : aFrame->SetMayHaveWillChangeBudget(false);
2139 :
2140 0 : uint32_t cost = 0;
2141 0 : if (!mWillChangeBudgetSet.Get(aFrame, &cost)) {
2142 : return;
2143 : }
2144 0 : mWillChangeBudgetSet.Remove(aFrame);
2145 :
2146 : DocumentWillChangeBudget& budget =
2147 0 : mWillChangeBudget.GetOrInsert(aFrame->PresContext());
2148 0 : MOZ_ASSERT(budget.mBudget >= cost);
2149 0 : budget.mBudget -= cost;
2150 : }
2151 :
2152 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
2153 : const float gAGRBudgetAreaMultiplier = 0.3;
2154 : #else
2155 : const float gAGRBudgetAreaMultiplier = 3.0;
2156 : #endif
2157 :
2158 : bool
2159 0 : nsDisplayListBuilder::AddToAGRBudget(nsIFrame* aFrame)
2160 : {
2161 0 : if (mAGRBudgetSet.Contains(aFrame)) {
2162 : return true;
2163 : }
2164 :
2165 0 : const nsPresContext* presContext = aFrame->PresContext()->GetRootPresContext();
2166 0 : if (!presContext) {
2167 : return false;
2168 : }
2169 :
2170 0 : const nsRect area = presContext->GetVisibleArea();
2171 0 : const uint32_t budgetLimit = gAGRBudgetAreaMultiplier *
2172 0 : nsPresContext::AppUnitsToIntCSSPixels(area.width) *
2173 0 : nsPresContext::AppUnitsToIntCSSPixels(area.height);
2174 :
2175 0 : const uint32_t cost = GetLayerizationCost(aFrame->GetSize());
2176 0 : const bool onBudget = mUsedAGRBudget + cost < budgetLimit;
2177 :
2178 0 : if (onBudget) {
2179 0 : mUsedAGRBudget += cost;
2180 0 : mAGRBudgetSet.PutEntry(aFrame);
2181 : }
2182 :
2183 : return onBudget;
2184 : }
2185 :
2186 : void
2187 0 : nsDisplayListBuilder::EnterSVGEffectsContents(nsDisplayList* aHoistedItemsStorage)
2188 : {
2189 0 : MOZ_ASSERT(mSVGEffectsBuildingDepth >= 0);
2190 0 : MOZ_ASSERT(aHoistedItemsStorage);
2191 0 : if (mSVGEffectsBuildingDepth == 0) {
2192 0 : MOZ_ASSERT(!mScrollInfoItemsForHoisting);
2193 0 : mScrollInfoItemsForHoisting = aHoistedItemsStorage;
2194 : }
2195 0 : mSVGEffectsBuildingDepth++;
2196 0 : }
2197 :
2198 : void
2199 0 : nsDisplayListBuilder::ExitSVGEffectsContents()
2200 : {
2201 0 : mSVGEffectsBuildingDepth--;
2202 0 : MOZ_ASSERT(mSVGEffectsBuildingDepth >= 0);
2203 0 : MOZ_ASSERT(mScrollInfoItemsForHoisting);
2204 0 : if (mSVGEffectsBuildingDepth == 0) {
2205 0 : mScrollInfoItemsForHoisting = nullptr;
2206 : }
2207 0 : }
2208 :
2209 : void
2210 0 : nsDisplayListBuilder::AppendNewScrollInfoItemForHoisting(nsDisplayScrollInfoLayer* aScrollInfoItem)
2211 : {
2212 0 : MOZ_ASSERT(ShouldBuildScrollInfoItemsForHoisting());
2213 0 : MOZ_ASSERT(mScrollInfoItemsForHoisting);
2214 0 : mScrollInfoItemsForHoisting->AppendToTop(aScrollInfoItem);
2215 0 : }
2216 :
2217 : static nsRect
2218 556 : GetFrameArea(const nsDisplayListBuilder* aBuilder, const nsIFrame* aFrame)
2219 : {
2220 0 : nsRect area;
2221 :
2222 0 : nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(aFrame);
2223 556 : if (scrollFrame) {
2224 : // If the frame is content of a scrollframe, then we need to pick up the
2225 : // area corresponding to the overflow rect as well. Otherwise the parts of
2226 : // the overflow that are not occupied by descendants get skipped and the
2227 : // APZ code sends touch events to the content underneath instead.
2228 : // See https://bugzilla.mozilla.org/show_bug.cgi?id=1127773#c15.
2229 0 : area = aFrame->GetScrollableOverflowRect();
2230 : } else {
2231 1028 : area = nsRect(nsPoint(0, 0), aFrame->GetSize());
2232 : }
2233 :
2234 1112 : if (!area.IsEmpty()) {
2235 548 : return area + aBuilder->ToReferenceFrame(aFrame);
2236 : }
2237 :
2238 0 : return area;
2239 : }
2240 :
2241 : void
2242 0 : nsDisplayListBuilder::BuildCompositorHitTestInfoIfNeeded(nsIFrame* aFrame,
2243 : nsDisplayList* aList,
2244 : const bool aBuildNew)
2245 : {
2246 688 : MOZ_ASSERT(aFrame);
2247 688 : MOZ_ASSERT(aList);
2248 :
2249 0 : if (!BuildCompositorHitTestInfo()) {
2250 574 : return;
2251 : }
2252 :
2253 0 : CompositorHitTestInfo info = aFrame->GetCompositorHitTestInfo(this);
2254 0 : if (!ShouldBuildCompositorHitTestInfo(aFrame, info, aBuildNew)) {
2255 : // Either the parent hit test info can be reused, or this frame has no hit
2256 : // test flags set.
2257 : return;
2258 : }
2259 :
2260 : nsDisplayCompositorHitTestInfo* item =
2261 0 : MakeDisplayItem<nsDisplayCompositorHitTestInfo>(this, aFrame, info);
2262 :
2263 228 : SetCompositorHitTestInfo(item);
2264 114 : aList->AppendToTop(item);
2265 : }
2266 :
2267 : bool
2268 0 : nsDisplayListBuilder::ShouldBuildCompositorHitTestInfo(const nsIFrame* aFrame,
2269 : const CompositorHitTestInfo& aInfo,
2270 : const bool aBuildNew) const
2271 : {
2272 620 : MOZ_ASSERT(mBuildCompositorHitTestInfo);
2273 :
2274 620 : if (aInfo == CompositorHitTestInfo::eInvisibleToHitTest) {
2275 : return false;
2276 : }
2277 :
2278 556 : if (!mCompositorHitTestInfo || !mLessEventRegionItems || aBuildNew) {
2279 : return true;
2280 : }
2281 :
2282 442 : if (mCompositorHitTestInfo->HitTestInfo() != aInfo) {
2283 : // Hit test flags are different.
2284 : return true;
2285 : }
2286 :
2287 : // Create a new item if the parent does not contain the child completely.
2288 442 : return !mCompositorHitTestInfo->Area().Contains(GetFrameArea(this, aFrame));
2289 : }
2290 :
2291 118 : void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const
2292 : {
2293 118 : aDestination.BorderBackground()->AppendToTop(BorderBackground());
2294 118 : aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
2295 0 : aDestination.Floats()->AppendToTop(Floats());
2296 118 : aDestination.Content()->AppendToTop(Content());
2297 118 : aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
2298 118 : aDestination.Outlines()->AppendToTop(Outlines());
2299 0 : }
2300 :
2301 : static void
2302 16 : MoveListTo(nsDisplayList* aList, nsTArray<nsDisplayItem*>* aElements) {
2303 : nsDisplayItem* item;
2304 96 : while ((item = aList->RemoveBottom()) != nullptr) {
2305 40 : aElements->AppendElement(item);
2306 : }
2307 0 : }
2308 :
2309 : nsRect
2310 16 : nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
2311 0 : nsRect bounds;
2312 0 : for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
2313 40 : bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
2314 : }
2315 16 : return bounds;
2316 : }
2317 :
2318 : nsRect
2319 166 : nsDisplayList::GetClippedBoundsWithRespectToASR(nsDisplayListBuilder* aBuilder,
2320 : const ActiveScrolledRoot* aASR,
2321 : nsRect* aBuildingRect) const {
2322 166 : nsRect bounds;
2323 0 : for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
2324 0 : nsRect r = i->GetClippedBounds(aBuilder);
2325 546 : if (aASR != i->GetActiveScrolledRoot() && !r.IsEmpty()) {
2326 0 : if (Maybe<nsRect> clip = i->GetClipWithRespectToASR(aBuilder, aASR)) {
2327 0 : r = clip.ref();
2328 : }
2329 : }
2330 0 : if (aBuildingRect) {
2331 0 : aBuildingRect->UnionRect(*aBuildingRect, i->GetBuildingRect());
2332 : }
2333 0 : bounds.UnionRect(bounds, r);
2334 : }
2335 0 : return bounds;
2336 : }
2337 :
2338 : nsRect
2339 0 : nsDisplayList::GetBuildingRect() const {
2340 0 : nsRect result;
2341 0 : for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
2342 0 : result.UnionRect(result, i->GetBuildingRect());
2343 : }
2344 0 : return result;
2345 : }
2346 :
2347 : bool
2348 0 : nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
2349 : nsRegion* aVisibleRegion) {
2350 0 : AUTO_PROFILER_LABEL("nsDisplayList::ComputeVisibilityForRoot", GRAPHICS);
2351 :
2352 0 : nsRegion r;
2353 0 : const ActiveScrolledRoot* rootASR = nullptr;
2354 0 : if (gfxPrefs::LayoutUseContainersForRootFrames()) {
2355 0 : rootASR = aBuilder->ActiveScrolledRootForRootScrollframe();
2356 : }
2357 0 : r.And(*aVisibleRegion, GetClippedBoundsWithRespectToASR(aBuilder, rootASR));
2358 0 : return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
2359 : }
2360 :
2361 : static nsRegion
2362 0 : TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
2363 : {
2364 : bool snap;
2365 174 : nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
2366 0 : if (aBuilder->IsForPluginGeometry() &&
2367 0 : aItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO)
2368 : {
2369 : // Treat all leaf chrome items as opaque, unless their frames are opacity:0.
2370 : // Since opacity:0 frames generate an nsDisplayOpacity, that item will
2371 : // not be treated as opaque here, so opacity:0 chrome content will be
2372 : // effectively ignored, as it should be.
2373 : // We treat leaf chrome items as opaque to ensure that they cover
2374 : // content plugins, for security reasons.
2375 : // Non-leaf chrome items don't render contents of their own so shouldn't
2376 : // be treated as opaque (and their bounds is just the union of their
2377 : // children, which might be a large area their contents don't really cover).
2378 0 : nsIFrame* f = aItem->Frame();
2379 0 : if (f->PresContext()->IsChrome() && !aItem->GetChildren() &&
2380 0 : f->StyleEffects()->mOpacity != 0.0) {
2381 0 : opaque = aItem->GetBounds(aBuilder, &snap);
2382 : }
2383 : }
2384 0 : if (opaque.IsEmpty()) {
2385 74 : return opaque;
2386 : }
2387 26 : nsRegion opaqueClipped;
2388 0 : for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
2389 : opaqueClipped.Or(opaqueClipped,
2390 0 : aItem->GetClip().ApproximateIntersectInward(iter.Get()));
2391 : }
2392 13 : return opaqueClipped;
2393 : }
2394 :
2395 : bool
2396 16 : nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
2397 : nsRegion* aVisibleRegion,
2398 : const nsRect& aListVisibleBounds)
2399 : {
2400 : #ifdef DEBUG
2401 0 : nsRegion r;
2402 0 : r.And(*aVisibleRegion, GetBounds(aBuilder));
2403 : // XXX this fails sometimes:
2404 0 : NS_WARNING_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
2405 : "bad aListVisibleBounds");
2406 : #endif
2407 :
2408 16 : bool anyVisible = false;
2409 :
2410 32 : AutoTArray<nsDisplayItem*, 512> elements;
2411 16 : MoveListTo(this, &elements);
2412 :
2413 56 : for (int32_t i = elements.Length() - 1; i >= 0; --i) {
2414 80 : nsDisplayItem* item = elements[i];
2415 :
2416 0 : if (item->ForceNotVisible() && !item->GetSameCoordinateSystemChildren()) {
2417 0 : NS_ASSERTION(item->GetBuildingRect().IsEmpty(),
2418 : "invisible items should have empty vis rect");
2419 0 : item->SetPaintRect(nsRect());
2420 : } else {
2421 0 : nsRect bounds = item->GetClippedBounds(aBuilder);
2422 :
2423 80 : nsRegion itemVisible;
2424 0 : itemVisible.And(*aVisibleRegion, bounds);
2425 0 : item->SetPaintRect(itemVisible.GetBounds());
2426 : }
2427 :
2428 40 : if (item->ComputeVisibility(aBuilder, aVisibleRegion)) {
2429 0 : anyVisible = true;
2430 :
2431 20 : nsRegion opaque = TreatAsOpaque(item, aBuilder);
2432 : // Subtract opaque item from the visible region
2433 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
2434 : }
2435 40 : AppendToBottom(item);
2436 : }
2437 :
2438 0 : mIsOpaque = !aVisibleRegion->Intersects(aListVisibleBounds);
2439 0 : return anyVisible;
2440 : }
2441 :
2442 : static bool
2443 16 : TriggerPendingAnimationsOnSubDocuments(nsIDocument* aDocument, void* aReadyTime)
2444 : {
2445 0 : PendingAnimationTracker* tracker = aDocument->GetPendingAnimationTracker();
2446 16 : if (tracker) {
2447 0 : nsIPresShell* shell = aDocument->GetShell();
2448 : // If paint-suppression is in effect then we haven't finished painting
2449 : // this document yet so we shouldn't start animations
2450 0 : if (!shell || !shell->IsPaintingSuppressed()) {
2451 0 : const TimeStamp& readyTime = *static_cast<TimeStamp*>(aReadyTime);
2452 8 : tracker->TriggerPendingAnimationsOnNextTick(readyTime);
2453 : }
2454 : }
2455 : aDocument->EnumerateSubDocuments(TriggerPendingAnimationsOnSubDocuments,
2456 1 : aReadyTime);
2457 16 : return true;
2458 : }
2459 :
2460 : static void
2461 0 : TriggerPendingAnimations(nsIDocument* aDocument,
2462 : const TimeStamp& aReadyTime) {
2463 8 : MOZ_ASSERT(!aReadyTime.IsNull(),
2464 : "Animation ready time is not set. Perhaps we're using a layer"
2465 : " manager that doesn't update it");
2466 : TriggerPendingAnimationsOnSubDocuments(aDocument,
2467 8 : const_cast<TimeStamp*>(&aReadyTime));
2468 0 : }
2469 :
2470 : LayerManager*
2471 30 : nsDisplayListBuilder::GetWidgetLayerManager(nsView** aView)
2472 : {
2473 30 : if (aView) {
2474 8 : *aView = RootReferenceFrame()->GetView();
2475 : }
2476 0 : if (RootReferenceFrame() != nsLayoutUtils::GetDisplayRootFrame(RootReferenceFrame())) {
2477 : return nullptr;
2478 : }
2479 30 : nsIWidget* window = RootReferenceFrame()->GetNearestWidget();
2480 0 : if (window) {
2481 8 : return window->GetLayerManager();
2482 : }
2483 : return nullptr;
2484 : }
2485 :
2486 : FrameLayerBuilder*
2487 0 : nsDisplayList::BuildLayers(nsDisplayListBuilder* aBuilder,
2488 : LayerManager* aLayerManager,
2489 : uint32_t aFlags,
2490 : bool aIsWidgetTransaction)
2491 : {
2492 19 : nsIFrame* frame = aBuilder->RootReferenceFrame();
2493 0 : nsPresContext* presContext = frame->PresContext();
2494 0 : nsIPresShell* presShell = presContext->PresShell();
2495 :
2496 19 : FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
2497 19 : layerBuilder->Init(aBuilder, aLayerManager);
2498 :
2499 19 : if (aFlags & PAINT_COMPRESSED) {
2500 0 : layerBuilder->SetLayerTreeCompressionMode();
2501 : }
2502 :
2503 38 : RefPtr<ContainerLayer> root;
2504 : {
2505 0 : AUTO_PROFILER_TRACING("Paint", "LayerBuilding");
2506 :
2507 19 : if (XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
2508 0 : FrameLayerBuilder::InvalidateAllLayers(aLayerManager);
2509 : }
2510 :
2511 0 : if (aIsWidgetTransaction) {
2512 8 : layerBuilder->DidBeginRetainedLayerTransaction(aLayerManager);
2513 : }
2514 :
2515 : // Clear any ScrollMetadata that may have been set on the root layer on a
2516 : // previous paint. This paint will set new metrics if necessary, and if we
2517 : // don't clear the old one here, we may be left with extra metrics.
2518 0 : if (Layer* rootLayer = aLayerManager->GetRoot()) {
2519 14 : rootLayer->SetScrollMetadata(nsTArray<ScrollMetadata>());
2520 : }
2521 :
2522 : ContainerLayerParameters containerParameters
2523 19 : (presShell->GetResolution(), presShell->GetResolution());
2524 :
2525 : {
2526 38 : PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
2527 :
2528 : root = layerBuilder->
2529 0 : BuildContainerLayerFor(aBuilder, aLayerManager, frame, nullptr, this,
2530 0 : containerParameters, nullptr);
2531 :
2532 19 : if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
2533 0 : if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(aLayerManager)) {
2534 0 : pt->flbMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
2535 : }
2536 : }
2537 : }
2538 :
2539 19 : if (!root) {
2540 0 : return nullptr;
2541 : }
2542 : // Root is being scaled up by the X/Y resolution. Scale it back down.
2543 19 : root->SetPostScale(1.0f/containerParameters.mXScale,
2544 0 : 1.0f/containerParameters.mYScale);
2545 1 : root->SetScaleToResolution(presShell->ScaleToResolution(),
2546 19 : containerParameters.mXScale);
2547 :
2548 0 : auto callback = [root](FrameMetrics::ViewID aScrollId) -> bool {
2549 0 : return nsLayoutUtils::ContainsMetricsWithId(root, aScrollId);
2550 38 : };
2551 19 : if (Maybe<ScrollMetadata> rootMetadata = nsLayoutUtils::GetRootMetadata(
2552 76 : aBuilder, root->Manager(), containerParameters, callback)) {
2553 8 : root->SetScrollMetadata(rootMetadata.value());
2554 : }
2555 :
2556 : // NS_WARNING is debug-only, so don't even bother checking the conditions in
2557 : // a release build.
2558 : #ifdef DEBUG
2559 19 : bool usingDisplayport = false;
2560 0 : if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
2561 11 : nsIContent* content = rootScrollFrame->GetContent();
2562 11 : if (content) {
2563 0 : usingDisplayport = nsLayoutUtils::HasDisplayPort(content);
2564 : }
2565 : }
2566 0 : if (usingDisplayport &&
2567 0 : !(root->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
2568 0 : SpammyLayoutWarningsEnabled()) {
2569 : // See bug 693938, attachment 567017
2570 0 : NS_WARNING("Transparent content with displayports can be expensive.");
2571 : }
2572 : #endif
2573 :
2574 38 : aLayerManager->SetRoot(root);
2575 19 : layerBuilder->WillEndTransaction();
2576 : }
2577 1 : return layerBuilder;
2578 : }
2579 :
2580 : /**
2581 : * We paint by executing a layer manager transaction, constructing a
2582 : * single layer representing the display list, and then making it the
2583 : * root of the layer manager, drawing into the PaintedLayers.
2584 : */
2585 0 : already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
2586 : gfxContext* aCtx,
2587 : uint32_t aFlags)
2588 : {
2589 0 : AUTO_PROFILER_LABEL("nsDisplayList::PaintRoot", GRAPHICS);
2590 :
2591 38 : RefPtr<LayerManager> layerManager;
2592 19 : bool widgetTransaction = false;
2593 19 : bool doBeginTransaction = true;
2594 19 : nsView *view = nullptr;
2595 19 : if (aFlags & PAINT_USE_WIDGET_LAYERS) {
2596 0 : layerManager = aBuilder->GetWidgetLayerManager(&view);
2597 0 : if (layerManager) {
2598 0 : doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
2599 0 : widgetTransaction = true;
2600 : }
2601 : }
2602 19 : if (!layerManager) {
2603 0 : if (!aCtx) {
2604 0 : NS_WARNING("Nowhere to paint into");
2605 : return nullptr;
2606 : }
2607 1 : layerManager = new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN);
2608 : }
2609 :
2610 19 : nsIFrame* frame = aBuilder->RootReferenceFrame();
2611 0 : nsPresContext* presContext = frame->PresContext();
2612 0 : nsIPresShell* presShell = presContext->PresShell();
2613 19 : nsIDocument* document = presShell->GetDocument();
2614 :
2615 19 : if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
2616 0 : if (doBeginTransaction) {
2617 0 : if (aCtx) {
2618 0 : if (!layerManager->BeginTransactionWithTarget(aCtx)) {
2619 : return nullptr;
2620 : }
2621 : } else {
2622 0 : if (!layerManager->BeginTransaction()) {
2623 : return nullptr;
2624 : }
2625 : }
2626 : }
2627 :
2628 : bool prevIsCompositingCheap =
2629 0 : aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
2630 0 : MaybeSetupTransactionIdAllocator(layerManager, presContext);
2631 :
2632 0 : bool sent = false;
2633 0 : if (aFlags & PAINT_IDENTICAL_DISPLAY_LIST) {
2634 0 : sent = layerManager->EndEmptyTransaction();
2635 : }
2636 :
2637 0 : if (!sent) {
2638 : // Windowed plugins are not supported with WebRender enabled.
2639 : // But PluginGeometry needs to be updated to show plugin.
2640 : // Windowed plugins are going to be removed by Bug 1296400.
2641 0 : nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
2642 0 : if (rootPresContext && XRE_IsContentProcess()) {
2643 0 : if (aBuilder->WillComputePluginGeometry()) {
2644 0 : rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
2645 : }
2646 : // This must be called even if PluginGeometryUpdates were not computed.
2647 0 : rootPresContext->CollectPluginGeometryUpdates(layerManager);
2648 : }
2649 :
2650 0 : WebRenderLayerManager* wrManager = static_cast<WebRenderLayerManager*>(layerManager.get());
2651 :
2652 0 : nsIDocShell* docShell = presContext->GetDocShell();
2653 0 : nsTArray<wr::WrFilterOp> wrFilters;
2654 0 : gfx::Matrix5x4* colorMatrix = nsDocShell::Cast(docShell)->GetColorMatrix();
2655 0 : if (colorMatrix) {
2656 : wr::WrFilterOp gs = {
2657 : wr::WrFilterOpType::ColorMatrix
2658 0 : };
2659 : MOZ_ASSERT(sizeof(gs.matrix) == sizeof(colorMatrix->components));
2660 0 : memcpy(&(gs.matrix), colorMatrix->components, sizeof(gs.matrix));
2661 0 : wrFilters.AppendElement(gs);
2662 : }
2663 :
2664 0 : wrManager->EndTransactionWithoutLayer(this, aBuilder, wrFilters);
2665 : }
2666 :
2667 : // For layers-free mode, we check the invalidation state bits in the EndTransaction.
2668 : // So we clear the invalidation state bits after EndTransaction.
2669 0 : if (widgetTransaction ||
2670 : // SVG-as-an-image docs don't paint as part of the retained layer tree,
2671 : // but they still need the invalidation state bits cleared in order for
2672 : // invalidation for CSS/SMIL animation to work properly.
2673 0 : (document && document->IsBeingUsedAsImage())) {
2674 0 : frame->ClearInvalidationStateBits();
2675 : }
2676 :
2677 0 : aBuilder->SetIsCompositingCheap(prevIsCompositingCheap);
2678 0 : if (document && widgetTransaction) {
2679 0 : TriggerPendingAnimations(document, layerManager->GetAnimationReadyTime());
2680 : }
2681 :
2682 0 : if (presContext->RefreshDriver()->HasScheduleFlush()) {
2683 0 : presContext->NotifyInvalidation(layerManager->GetLastTransactionId(), frame->GetRect());
2684 : }
2685 :
2686 : return layerManager.forget();
2687 : }
2688 :
2689 : NotifySubDocInvalidationFunc computeInvalidFunc =
2690 1 : presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
2691 :
2692 1 : UniquePtr<LayerProperties> props;
2693 :
2694 11 : bool computeInvalidRect = (computeInvalidFunc ||
2695 1 : (!layerManager->IsCompositingCheap() && layerManager->NeedsWidgetInvalidation())) &&
2696 19 : widgetTransaction;
2697 :
2698 1 : if (computeInvalidRect) {
2699 16 : props = LayerProperties::CloneFrom(layerManager->GetRoot());
2700 : }
2701 :
2702 19 : if (doBeginTransaction) {
2703 11 : if (aCtx) {
2704 11 : if (!layerManager->BeginTransactionWithTarget(aCtx)) {
2705 : return nullptr;
2706 : }
2707 : } else {
2708 0 : if (!layerManager->BeginTransaction()) {
2709 : return nullptr;
2710 : }
2711 : }
2712 : }
2713 :
2714 1 : bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
2715 1 : LayerManager::EndTransactionFlags flags = LayerManager::END_DEFAULT;
2716 1 : if (layerManager->NeedsWidgetInvalidation()) {
2717 11 : if (aFlags & PAINT_NO_COMPOSITE) {
2718 0 : flags = LayerManager::END_NO_COMPOSITE;
2719 : }
2720 : } else {
2721 : // Client layer managers never composite directly, so
2722 : // we don't need to worry about END_NO_COMPOSITE.
2723 8 : if (aBuilder->WillComputePluginGeometry()) {
2724 0 : flags = LayerManager::END_NO_REMOTE_COMPOSITE;
2725 : }
2726 : }
2727 :
2728 19 : MaybeSetupTransactionIdAllocator(layerManager, presContext);
2729 :
2730 : // Store the existing layer builder to reinstate it on return.
2731 0 : FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
2732 0 : FrameLayerBuilder *layerBuilder = nullptr;
2733 :
2734 19 : bool sent = false;
2735 0 : if (aFlags & PAINT_IDENTICAL_DISPLAY_LIST) {
2736 0 : sent = layerManager->EndEmptyTransaction(flags);
2737 : }
2738 :
2739 0 : if (!sent) {
2740 0 : layerBuilder = BuildLayers(aBuilder, layerManager,
2741 0 : aFlags, widgetTransaction);
2742 :
2743 19 : if (!layerBuilder) {
2744 0 : layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
2745 : return nullptr;
2746 : }
2747 :
2748 : // If this is the content process, we ship plugin geometry updates over with layer
2749 : // updates, so calculate that now before we call EndTransaction.
2750 19 : nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
2751 0 : if (rootPresContext && XRE_IsContentProcess()) {
2752 0 : if (aBuilder->WillComputePluginGeometry()) {
2753 0 : rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
2754 : }
2755 : // The layer system caches plugin configuration information for forwarding
2756 : // with layer updates which needs to get set during reflow. This must be
2757 : // called even if there are no windowed plugins in the page.
2758 0 : rootPresContext->CollectPluginGeometryUpdates(layerManager);
2759 : }
2760 :
2761 0 : layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
2762 19 : aBuilder, flags);
2763 19 : layerBuilder->DidEndTransaction();
2764 : }
2765 :
2766 38 : if (widgetTransaction ||
2767 : // SVG-as-an-image docs don't paint as part of the retained layer tree,
2768 : // but they still need the invalidation state bits cleared in order for
2769 : // invalidation for CSS/SMIL animation to work properly.
2770 11 : (document && document->IsBeingUsedAsImage())) {
2771 0 : frame->ClearInvalidationStateBits();
2772 : }
2773 :
2774 38 : aBuilder->SetIsCompositingCheap(temp);
2775 :
2776 0 : if (document && widgetTransaction) {
2777 0 : TriggerPendingAnimations(document, layerManager->GetAnimationReadyTime());
2778 : }
2779 :
2780 0 : nsIntRegion invalid;
2781 1 : bool areaOverflowed = false;
2782 19 : if (props) {
2783 16 : if (!props->ComputeDifferences(layerManager->GetRoot(), invalid, computeInvalidFunc)) {
2784 0 : areaOverflowed = true;
2785 : }
2786 11 : } else if (widgetTransaction) {
2787 0 : LayerProperties::ClearInvalidations(layerManager->GetRoot());
2788 : }
2789 :
2790 0 : bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
2791 19 : if (view) {
2792 8 : if (props && !areaOverflowed) {
2793 8 : if (!invalid.IsEmpty()) {
2794 4 : nsIntRect bounds = invalid.GetBounds();
2795 : nsRect rect(presContext->DevPixelsToAppUnits(bounds.x),
2796 : presContext->DevPixelsToAppUnits(bounds.y),
2797 : presContext->DevPixelsToAppUnits(bounds.width),
2798 0 : presContext->DevPixelsToAppUnits(bounds.height));
2799 0 : if (shouldInvalidate) {
2800 0 : view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
2801 : }
2802 4 : presContext->NotifyInvalidation(layerManager->GetLastTransactionId(), bounds);
2803 : }
2804 0 : } else if (shouldInvalidate) {
2805 0 : view->GetViewManager()->InvalidateView(view);
2806 : }
2807 : }
2808 :
2809 19 : layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
2810 19 : return layerManager.forget();
2811 : }
2812 :
2813 0 : nsDisplayItem* nsDisplayList::RemoveBottom() {
2814 0 : nsDisplayItem* item = mSentinel.mAbove;
2815 1102 : if (!item)
2816 : return nullptr;
2817 0 : mSentinel.mAbove = item->mAbove;
2818 0 : if (item == mTop) {
2819 : // must have been the only item
2820 0 : mTop = &mSentinel;
2821 : }
2822 692 : item->mAbove = nullptr;
2823 0 : mLength--;
2824 0 : return item;
2825 : }
2826 :
2827 0 : void nsDisplayList::DeleteAll(nsDisplayListBuilder* aBuilder) {
2828 : nsDisplayItem* item;
2829 0 : while ((item = RemoveBottom()) != nullptr) {
2830 0 : item->Destroy(aBuilder);
2831 : }
2832 174 : }
2833 :
2834 : static bool
2835 0 : GetMouseThrough(const nsIFrame* aFrame)
2836 : {
2837 0 : if (!aFrame->IsXULBoxFrame())
2838 : return false;
2839 :
2840 : const nsIFrame* frame = aFrame;
2841 0 : while (frame) {
2842 0 : if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS) {
2843 : return true;
2844 0 : } else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) {
2845 : return false;
2846 : }
2847 0 : frame = nsBox::GetParentXULBox(frame);
2848 : }
2849 : return false;
2850 : }
2851 :
2852 : static bool
2853 0 : IsFrameReceivingPointerEvents(nsIFrame* aFrame)
2854 : {
2855 : return NS_STYLE_POINTER_EVENTS_NONE !=
2856 0 : aFrame->StyleUserInterface()->GetEffectivePointerEvents(aFrame);
2857 : }
2858 :
2859 : // A list of frames, and their z depth. Used for sorting
2860 : // the results of hit testing.
2861 0 : struct FramesWithDepth
2862 : {
2863 0 : explicit FramesWithDepth(float aDepth) :
2864 0 : mDepth(aDepth)
2865 : {}
2866 :
2867 0 : bool operator<(const FramesWithDepth& aOther) const {
2868 0 : if (!FuzzyEqual(mDepth, aOther.mDepth, 0.1f)) {
2869 : // We want to sort so that the shallowest item (highest depth value) is first
2870 0 : return mDepth > aOther.mDepth;
2871 : }
2872 0 : return this < &aOther;
2873 : }
2874 : bool operator==(const FramesWithDepth& aOther) const {
2875 : return this == &aOther;
2876 : }
2877 :
2878 : float mDepth;
2879 : nsTArray<nsIFrame*> mFrames;
2880 : };
2881 :
2882 : // Sort the frames by depth and then moves all the contained frames to the destination
2883 : static void
2884 0 : FlushFramesArray(nsTArray<FramesWithDepth>& aSource, nsTArray<nsIFrame*>* aDest)
2885 : {
2886 0 : if (aSource.IsEmpty()) {
2887 : return;
2888 : }
2889 0 : aSource.Sort();
2890 0 : uint32_t length = aSource.Length();
2891 0 : for (uint32_t i = 0; i < length; i++) {
2892 0 : aDest->AppendElements(std::move(aSource[i].mFrames));
2893 : }
2894 0 : aSource.Clear();
2895 : }
2896 :
2897 0 : void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
2898 : nsDisplayItem::HitTestState* aState,
2899 : nsTArray<nsIFrame*> *aOutFrames) const {
2900 : nsDisplayItem* item;
2901 :
2902 0 : if (aState->mInPreserves3D) {
2903 : // Collect leaves of the current 3D rendering context.
2904 0 : for (item = GetBottom(); item; item = item->GetAbove()) {
2905 0 : auto itemType = item->GetType();
2906 0 : if (itemType != DisplayItemType::TYPE_TRANSFORM ||
2907 0 : !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
2908 0 : item->HitTest(aBuilder, aRect, aState, aOutFrames);
2909 : } else {
2910 : // One of leaves in the current 3D rendering context.
2911 0 : aState->mItemBuffer.AppendElement(item);
2912 : }
2913 : }
2914 0 : return;
2915 : }
2916 :
2917 0 : int32_t itemBufferStart = aState->mItemBuffer.Length();
2918 0 : for (item = GetBottom(); item; item = item->GetAbove()) {
2919 0 : aState->mItemBuffer.AppendElement(item);
2920 : }
2921 :
2922 0 : AutoTArray<FramesWithDepth, 16> temp;
2923 0 : for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) {
2924 : // Pop element off the end of the buffer. We want to shorten the buffer
2925 : // so that recursive calls to HitTest have more buffer space.
2926 0 : item = aState->mItemBuffer[i];
2927 0 : aState->mItemBuffer.SetLength(i);
2928 :
2929 : bool snap;
2930 0 : nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect);
2931 0 : auto itemType = item->GetType();
2932 : bool same3DContext =
2933 0 : (itemType == DisplayItemType::TYPE_TRANSFORM &&
2934 0 : static_cast<nsDisplayTransform*>(item)->IsParticipating3DContext()) ||
2935 0 : (itemType == DisplayItemType::TYPE_PERSPECTIVE &&
2936 0 : item->Frame()->Extend3DContext());
2937 0 : if (same3DContext &&
2938 0 : (itemType != DisplayItemType::TYPE_TRANSFORM ||
2939 0 : !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext())) {
2940 0 : if (!item->GetClip().MayIntersect(aRect)) {
2941 : continue;
2942 : }
2943 0 : AutoTArray<nsIFrame*, 1> neverUsed;
2944 : // Start gethering leaves of the 3D rendering context, and
2945 : // append leaves at the end of mItemBuffer. Leaves are
2946 : // processed at following iterations.
2947 0 : aState->mInPreserves3D = true;
2948 0 : item->HitTest(aBuilder, aRect, aState, &neverUsed);
2949 0 : aState->mInPreserves3D = false;
2950 0 : i = aState->mItemBuffer.Length();
2951 : continue;
2952 : }
2953 0 : if (same3DContext || item->GetClip().MayIntersect(r)) {
2954 0 : AutoTArray<nsIFrame*, 16> outFrames;
2955 0 : item->HitTest(aBuilder, aRect, aState, &outFrames);
2956 :
2957 : // For 3d transforms with preserve-3d we add hit frames into the temp list
2958 : // so we can sort them later, otherwise we add them directly to the output list.
2959 0 : nsTArray<nsIFrame*> *writeFrames = aOutFrames;
2960 0 : if (item->GetType() == DisplayItemType::TYPE_TRANSFORM &&
2961 0 : static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
2962 0 : if (outFrames.Length()) {
2963 0 : nsDisplayTransform *transform = static_cast<nsDisplayTransform*>(item);
2964 0 : nsPoint point = aRect.TopLeft();
2965 : // A 1x1 rect means a point, otherwise use the center of the rect
2966 0 : if (aRect.width != 1 || aRect.height != 1) {
2967 0 : point = aRect.Center();
2968 : }
2969 0 : temp.AppendElement(FramesWithDepth(transform->GetHitDepthAtPoint(aBuilder, point)));
2970 0 : writeFrames = &temp[temp.Length() - 1].mFrames;
2971 : }
2972 : } else {
2973 : // We may have just finished a run of consecutive preserve-3d transforms,
2974 : // so flush these into the destination array before processing our frame list.
2975 0 : FlushFramesArray(temp, aOutFrames);
2976 : }
2977 :
2978 0 : for (uint32_t j = 0; j < outFrames.Length(); j++) {
2979 0 : nsIFrame *f = outFrames.ElementAt(j);
2980 : // Filter out some frames depending on the type of hittest
2981 : // we are doing. For visibility tests, pass through all frames.
2982 : // For pointer tests, only pass through frames that are styled
2983 : // to receive pointer events.
2984 0 : if (aBuilder->HitTestIsForVisibility() ||
2985 0 : (!GetMouseThrough(f) && IsFrameReceivingPointerEvents(f))) {
2986 0 : writeFrames->AppendElement(f);
2987 : }
2988 : }
2989 :
2990 0 : if (aBuilder->HitTestIsForVisibility() &&
2991 0 : item->GetOpaqueRegion(aBuilder, &snap).Contains(aRect)) {
2992 : // We're exiting early, so pop the remaining items off the buffer.
2993 0 : aState->mItemBuffer.SetLength(itemBufferStart);
2994 0 : break;
2995 : }
2996 : }
2997 : }
2998 : // Clear any remaining preserve-3d transforms.
2999 0 : FlushFramesArray(temp, aOutFrames);
3000 0 : NS_ASSERTION(aState->mItemBuffer.Length() == uint32_t(itemBufferStart),
3001 : "How did we forget to pop some elements?");
3002 : }
3003 :
3004 0 : static nsIContent* FindContentInDocument(nsDisplayItem* aItem, nsIDocument* aDoc) {
3005 0 : nsIFrame* f = aItem->Frame();
3006 0 : while (f) {
3007 0 : nsPresContext* pc = f->PresContext();
3008 0 : if (pc->Document() == aDoc) {
3009 0 : return f->GetContent();
3010 : }
3011 0 : f = nsLayoutUtils::GetCrossDocParentFrame(pc->PresShell()->GetRootFrame());
3012 : }
3013 : return nullptr;
3014 : }
3015 :
3016 : struct ZSortItem {
3017 : nsDisplayItem* item;
3018 : int32_t zIndex;
3019 :
3020 74 : explicit ZSortItem(nsDisplayItem* aItem)
3021 0 : : item(aItem), zIndex(aItem->ZIndex()) {}
3022 :
3023 : operator nsDisplayItem*() {
3024 : return item;
3025 : }
3026 : };
3027 :
3028 : struct ZOrderComparator {
3029 : bool operator()(const ZSortItem& aLeft, const ZSortItem& aRight) const {
3030 : // Note that we can't just take the difference of the two
3031 : // z-indices here, because that might overflow a 32-bit int.
3032 168 : return aLeft.zIndex < aRight.zIndex;
3033 : }
3034 : };
3035 :
3036 0 : void nsDisplayList::SortByZOrder() {
3037 0 : Sort<ZSortItem>(ZOrderComparator());
3038 110 : }
3039 :
3040 : struct ContentComparator {
3041 : nsIContent* mCommonAncestor;
3042 :
3043 : explicit ContentComparator(nsIContent* aCommonAncestor)
3044 0 : : mCommonAncestor(aCommonAncestor) {}
3045 :
3046 0 : bool operator()(nsDisplayItem* aLeft, nsDisplayItem* aRight) const {
3047 : // It's possible that the nsIContent for aItem1 or aItem2 is in a subdocument
3048 : // of commonAncestor, because display items for subdocuments have been
3049 : // mixed into the same list. Ensure that we're looking at content
3050 : // in commonAncestor's document.
3051 0 : nsIDocument* commonAncestorDoc = mCommonAncestor->OwnerDoc();
3052 0 : nsIContent* content1 = FindContentInDocument(aLeft, commonAncestorDoc);
3053 0 : nsIContent* content2 = FindContentInDocument(aRight, commonAncestorDoc);
3054 0 : if (!content1 || !content2) {
3055 0 : NS_ERROR("Document trees are mixed up!");
3056 : // Something weird going on
3057 0 : return true;
3058 : }
3059 0 : return nsLayoutUtils::CompareTreePosition(content1, content2, mCommonAncestor) < 0;
3060 : }
3061 : };
3062 :
3063 110 : void nsDisplayList::SortByContentOrder(nsIContent* aCommonAncestor) {
3064 110 : Sort<nsDisplayItem*>(ContentComparator(aCommonAncestor));
3065 110 : }
3066 :
3067 410 : nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
3068 : : nsDisplayItem(aBuilder, aFrame,
3069 0 : aBuilder->CurrentActiveScrolledRoot())
3070 410 : {}
3071 :
3072 546 : nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3073 : const ActiveScrolledRoot* aActiveScrolledRoot,
3074 0 : bool aAnonymous)
3075 : : mFrame(aFrame)
3076 : , mActiveScrolledRoot(aActiveScrolledRoot)
3077 : , mAnimatedGeometryRoot(nullptr)
3078 546 : , mForceNotVisible(aBuilder->IsBuildingInvisibleItems())
3079 : , mDisableSubpixelAA(false)
3080 : , mReusedItem(false)
3081 0 : , mBackfaceHidden(mFrame->In3DContextAndBackfaceIsHidden())
3082 : , mPaintRectValid(false)
3083 : #ifdef MOZ_DUMP_PAINTING
3084 5460 : , mPainted(false)
3085 : #endif
3086 : {
3087 546 : MOZ_COUNT_CTOR(nsDisplayItem);
3088 0 : if (aBuilder->IsRetainingDisplayList() && !aAnonymous) {
3089 0 : mFrame->AddDisplayItem(this);
3090 : }
3091 0 : mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
3092 : // This can return the wrong result if the item override ShouldFixToViewport(),
3093 : // the item needs to set it again in its constructor.
3094 1 : mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(aFrame);
3095 546 : MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(),
3096 : *mAnimatedGeometryRoot), "Bad");
3097 546 : NS_ASSERTION(aBuilder->GetVisibleRect().width >= 0 ||
3098 : !aBuilder->IsForPainting(), "visible rect not set");
3099 :
3100 0 : SetClipChain(aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder), true);
3101 :
3102 : // The visible rect is for mCurrentFrame, so we have to use
3103 : // mCurrentOffsetToReferenceFrame
3104 : nsRect visible = aBuilder->GetVisibleRect() +
3105 1638 : aBuilder->GetCurrentFrameOffsetToReferenceFrame();
3106 0 : SetBuildingRect(visible);
3107 0 : }
3108 :
3109 : /* static */ bool
3110 248 : nsDisplayItem::ForceActiveLayers()
3111 : {
3112 : static bool sForce = false;
3113 : static bool sForceCached = false;
3114 :
3115 0 : if (!sForceCached) {
3116 1 : Preferences::AddBoolVarCache(&sForce, "layers.force-active", false);
3117 1 : sForceCached = true;
3118 : }
3119 :
3120 248 : return sForce;
3121 : }
3122 :
3123 92 : static int32_t ZIndexForFrame(nsIFrame* aFrame)
3124 : {
3125 0 : if (!aFrame->IsAbsPosContainingBlock() && !aFrame->IsFlexOrGridItem())
3126 : return 0;
3127 :
3128 0 : const nsStylePosition* position = aFrame->StylePosition();
3129 76 : if (position->mZIndex.GetUnit() == eStyleUnit_Integer)
3130 24 : return position->mZIndex.GetIntValue();
3131 :
3132 : // sort the auto and 0 elements together
3133 : return 0;
3134 : }
3135 :
3136 : int32_t
3137 0 : nsDisplayItem::ZIndex() const
3138 : {
3139 92 : return ZIndexForFrame(mFrame);
3140 : }
3141 :
3142 : bool
3143 0 : nsDisplayItem::ComputeVisibility(nsDisplayListBuilder* aBuilder,
3144 : nsRegion* aVisibleRegion)
3145 : {
3146 401 : return !GetPaintRect().IsEmpty() &&
3147 0 : !IsInvisibleInRect(aVisibleRegion->GetBounds());
3148 : }
3149 :
3150 : bool
3151 136 : nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
3152 : nsRegion* aVisibleRegion,
3153 : bool aUseClipBounds) {
3154 0 : if (mForceNotVisible && !GetSameCoordinateSystemChildren()) {
3155 : // mForceNotVisible wants to ensure that this display item doesn't render
3156 : // anything itself. If this item has contents, then we obviously want to
3157 : // render those, so we don't need this check in that case.
3158 0 : NS_ASSERTION(GetBuildingRect().IsEmpty(),
3159 : "invisible items without children should have empty vis rect");
3160 0 : SetPaintRect(nsRect());
3161 : } else {
3162 0 : nsRect bounds;
3163 136 : if (aUseClipBounds) {
3164 136 : bounds = GetClippedBounds(aBuilder);
3165 : } else {
3166 : bool snap;
3167 0 : bounds = GetBounds(aBuilder, &snap);
3168 : }
3169 :
3170 272 : nsRegion itemVisible;
3171 136 : itemVisible.And(*aVisibleRegion, bounds);
3172 272 : SetPaintRect(itemVisible.GetBounds());
3173 : }
3174 :
3175 : // When we recompute visibility within layers we don't need to
3176 : // expand the visible region for content behind plugins (the plugin
3177 : // is not in the layer).
3178 136 : if (!ComputeVisibility(aBuilder, aVisibleRegion)) {
3179 118 : SetPaintRect(nsRect());
3180 0 : return false;
3181 : }
3182 :
3183 0 : nsRegion opaque = TreatAsOpaque(this, aBuilder);
3184 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
3185 : return true;
3186 : }
3187 :
3188 : void
3189 671 : nsDisplayItem::SetClipChain(const DisplayItemClipChain* aClipChain,
3190 : bool aStore)
3191 : {
3192 1342 : mClipChain = aClipChain;
3193 1342 : mClip = DisplayItemClipChain::ClipForASR(aClipChain, mActiveScrolledRoot);
3194 :
3195 1 : if (aStore) {
3196 557 : mState.mClipChain = mClipChain;
3197 1 : mState.mClip = mClip;
3198 : }
3199 0 : }
3200 :
3201 : Maybe<nsRect>
3202 0 : nsDisplayItem::GetClipWithRespectToASR(nsDisplayListBuilder* aBuilder,
3203 : const ActiveScrolledRoot* aASR) const
3204 : {
3205 0 : if (const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(GetClipChain(), aASR)) {
3206 0 : return Some(clip->GetClipRect());
3207 : }
3208 : #ifdef DEBUG
3209 0 : if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
3210 0 : MOZ_ASSERT(false, "item should have finite clip with respect to aASR");
3211 : }
3212 : #endif
3213 : return Nothing();
3214 : }
3215 :
3216 : void
3217 0 : nsDisplayItem::FuseClipChainUpTo(nsDisplayListBuilder* aBuilder,
3218 : const ActiveScrolledRoot* aASR)
3219 : {
3220 0 : const DisplayItemClipChain* sc = mClipChain;
3221 0 : DisplayItemClip mergedClip;
3222 57 : while (sc && ActiveScrolledRoot::PickDescendant(aASR, sc->mASR) == sc->mASR) {
3223 11 : mergedClip.IntersectWith(sc->mClip);
3224 22 : sc = sc->mParent;
3225 : }
3226 0 : if (mergedClip.HasClip()) {
3227 22 : mClipChain = aBuilder->AllocateDisplayItemClipChain(mergedClip, aASR, sc);
3228 11 : mClip = &mClipChain->mClip;
3229 : } else {
3230 0 : mClipChain = nullptr;
3231 24 : mClip = nullptr;
3232 : }
3233 0 : }
3234 :
3235 : bool
3236 0 : nsDisplayItem::ShouldUseAdvancedLayer(LayerManager* aManager, PrefFunc aFunc) const
3237 : {
3238 56 : return CanUseAdvancedLayer(aManager) ? aFunc() : false;
3239 : }
3240 :
3241 : bool
3242 0 : nsDisplayItem::CanUseAdvancedLayer(LayerManager* aManager) const
3243 : {
3244 112 : return gfxPrefs::LayersAdvancedBasicLayerEnabled() ||
3245 112 : !aManager ||
3246 1 : aManager->GetBackendType() == layers::LayersBackend::LAYERS_WR;
3247 : }
3248 :
3249 : static const DisplayItemClipChain*
3250 0 : FindCommonAncestorClipForIntersection(const DisplayItemClipChain* aOne,
3251 : const DisplayItemClipChain* aTwo)
3252 : {
3253 0 : for (const ActiveScrolledRoot* asr =
3254 0 : ActiveScrolledRoot::PickDescendant(aOne->mASR, aTwo->mASR);
3255 0 : asr;
3256 0 : asr = asr->mParent) {
3257 0 : if (aOne == aTwo) {
3258 : return aOne;
3259 : }
3260 0 : if (aOne->mASR == asr) {
3261 0 : aOne = aOne->mParent;
3262 : }
3263 0 : if (aTwo->mASR == asr) {
3264 0 : aTwo = aTwo->mParent;
3265 : }
3266 0 : if (!aOne) {
3267 : return aTwo;
3268 : }
3269 0 : if (!aTwo) {
3270 : return aOne;
3271 : }
3272 : }
3273 : return nullptr;
3274 : }
3275 :
3276 : void
3277 8 : nsDisplayItem::IntersectClip(nsDisplayListBuilder* aBuilder,
3278 : const DisplayItemClipChain* aOther,
3279 : bool aStore)
3280 : {
3281 0 : if (!aOther || mClipChain == aOther) {
3282 : return;
3283 : }
3284 :
3285 : // aOther might be a reference to a clip on the stack. We need to make sure
3286 : // that CreateClipChainIntersection will allocate the actual intersected
3287 : // clip in the builder's arena, so for the mClipChain == nullptr case,
3288 : // we supply nullptr as the common ancestor so that CreateClipChainIntersection
3289 : // clones the whole chain.
3290 : const DisplayItemClipChain* ancestorClip =
3291 0 : mClipChain ? FindCommonAncestorClipForIntersection(mClipChain, aOther) : nullptr;
3292 :
3293 0 : SetClipChain(aBuilder->CreateClipChainIntersection(ancestorClip, mClipChain, aOther),
3294 0 : aStore);
3295 : }
3296 :
3297 : nsRect
3298 0 : nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder) const
3299 : {
3300 : bool snap;
3301 0 : nsRect r = GetBounds(aBuilder, &snap);
3302 1548 : return GetClip().ApplyNonRoundedIntersection(r);
3303 : }
3304 :
3305 : nsRect
3306 0 : nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder,
3307 : bool* aSnap) const
3308 : {
3309 46 : *aSnap = true;
3310 46 : return mBounds;
3311 : }
3312 :
3313 : LayerState
3314 0 : nsDisplaySolidColor::GetLayerState(nsDisplayListBuilder* aBuilder,
3315 : LayerManager* aManager,
3316 : const ContainerLayerParameters& aParameters)
3317 : {
3318 0 : if (ForceActiveLayers()) {
3319 : return LAYER_ACTIVE;
3320 : }
3321 8 : return LAYER_NONE;
3322 : }
3323 :
3324 : already_AddRefed<Layer>
3325 0 : nsDisplaySolidColor::BuildLayer(nsDisplayListBuilder* aBuilder,
3326 : LayerManager* aManager,
3327 : const ContainerLayerParameters& aContainerParameters)
3328 : {
3329 : RefPtr<ColorLayer> layer = static_cast<ColorLayer*>
3330 0 : (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
3331 0 : if (!layer) {
3332 0 : layer = aManager->CreateColorLayer();
3333 0 : if (!layer) {
3334 : return nullptr;
3335 : }
3336 : }
3337 0 : layer->SetColor(gfx::Color::FromABGR(mColor));
3338 :
3339 0 : const int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
3340 0 : layer->SetBounds(mBounds.ToNearestPixels(appUnitsPerDevPixel));
3341 0 : layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
3342 0 : aContainerParameters.mOffset.y, 0));
3343 :
3344 0 : return layer.forget();
3345 : }
3346 :
3347 : void
3348 2 : nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
3349 : gfxContext* aCtx)
3350 : {
3351 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
3352 2 : DrawTarget* drawTarget = aCtx->GetDrawTarget();
3353 : Rect rect =
3354 4 : NSRectToSnappedRect(GetPaintRect(), appUnitsPerDevPixel, *drawTarget);
3355 0 : drawTarget->FillRect(rect, ColorPattern(ToDeviceColor(mColor)));
3356 2 : }
3357 :
3358 : void
3359 0 : nsDisplaySolidColor::WriteDebugInfo(std::stringstream& aStream)
3360 : {
3361 0 : aStream << " (rgba "
3362 0 : << (int)NS_GET_R(mColor) << ","
3363 0 : << (int)NS_GET_G(mColor) << ","
3364 0 : << (int)NS_GET_B(mColor) << ","
3365 0 : << (int)NS_GET_A(mColor) << ")";
3366 0 : }
3367 :
3368 : bool
3369 0 : nsDisplaySolidColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
3370 : mozilla::wr::IpcResourceUpdateQueue& aResources,
3371 : const StackingContextHelper& aSc,
3372 : mozilla::layers::WebRenderLayerManager* aManager,
3373 : nsDisplayListBuilder* aDisplayListBuilder)
3374 : {
3375 : LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
3376 0 : GetPaintRect(), mFrame->PresContext()->AppUnitsPerDevPixel());
3377 0 : wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(bounds);
3378 :
3379 0 : aBuilder.PushRect(roundedRect,
3380 : roundedRect,
3381 0 : !BackfaceIsHidden(),
3382 0 : wr::ToColorF(ToDeviceColor(mColor)));
3383 :
3384 0 : return true;
3385 : }
3386 :
3387 : nsRect
3388 0 : nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder,
3389 : bool* aSnap) const
3390 : {
3391 0 : *aSnap = true;
3392 0 : return mRegion.GetBounds();
3393 : }
3394 :
3395 : void
3396 0 : nsDisplaySolidColorRegion::Paint(nsDisplayListBuilder* aBuilder,
3397 : gfxContext* aCtx)
3398 : {
3399 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
3400 0 : DrawTarget* drawTarget = aCtx->GetDrawTarget();
3401 0 : ColorPattern color(mColor);
3402 0 : for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
3403 : Rect rect =
3404 0 : NSRectToSnappedRect(iter.Get(), appUnitsPerDevPixel, *drawTarget);
3405 0 : drawTarget->FillRect(rect, color);
3406 : }
3407 0 : }
3408 :
3409 : void
3410 0 : nsDisplaySolidColorRegion::WriteDebugInfo(std::stringstream& aStream)
3411 : {
3412 0 : aStream << " (rgba "
3413 0 : << int(mColor.r * 255) << ","
3414 0 : << int(mColor.g * 255) << ","
3415 0 : << int(mColor.b * 255) << ","
3416 0 : << mColor.a << ")";
3417 0 : }
3418 :
3419 : bool
3420 0 : nsDisplaySolidColorRegion::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
3421 : mozilla::wr::IpcResourceUpdateQueue& aResources,
3422 : const StackingContextHelper& aSc,
3423 : mozilla::layers::WebRenderLayerManager* aManager,
3424 : nsDisplayListBuilder* aDisplayListBuilder)
3425 : {
3426 0 : for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
3427 0 : nsRect rect = iter.Get();
3428 : LayoutDeviceRect layerRects = LayoutDeviceRect::FromAppUnits(
3429 0 : rect, mFrame->PresContext()->AppUnitsPerDevPixel());
3430 0 : wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(layerRects);
3431 0 : aBuilder.PushRect(roundedRect,
3432 : roundedRect,
3433 0 : !BackfaceIsHidden(),
3434 0 : wr::ToColorF(ToDeviceColor(mColor)));
3435 : }
3436 :
3437 0 : return true;
3438 : }
3439 :
3440 : static void
3441 0 : RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
3442 : nsIFrame* aFrame, nsITheme::ThemeGeometryType aType)
3443 : {
3444 0 : if (aBuilder->IsInChromeDocumentOrPopup() && !aBuilder->IsInTransform()) {
3445 0 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
3446 0 : nsPoint offset = aBuilder->IsInSubdocument() ? aBuilder->ToReferenceFrame(aFrame)
3447 0 : : aFrame->GetOffsetTo(displayRoot);
3448 0 : nsRect borderBox = nsRect(offset, aFrame->GetSize());
3449 0 : aBuilder->RegisterThemeGeometry(aType, aItem,
3450 0 : LayoutDeviceIntRect::FromUnknownRect(
3451 0 : borderBox.ToNearestPixels(
3452 0 : aFrame->PresContext()->AppUnitsPerDevPixel())));
3453 : }
3454 0 : }
3455 :
3456 : // Return the bounds of the viewport relative to |aFrame|'s reference frame.
3457 : // Returns Nothing() if transforming into |aFrame|'s coordinate space fails.
3458 : static Maybe<nsRect>
3459 0 : GetViewportRectRelativeToReferenceFrame(nsDisplayListBuilder* aBuilder,
3460 : nsIFrame* aFrame)
3461 : {
3462 0 : nsIFrame* rootFrame = aFrame->PresShell()->GetRootFrame();
3463 0 : nsRect rootRect = rootFrame->GetRectRelativeToSelf();
3464 0 : if (nsLayoutUtils::TransformRect(rootFrame, aFrame, rootRect) == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
3465 0 : return Some(rootRect + aBuilder->ToReferenceFrame(aFrame));
3466 : }
3467 : return Nothing();
3468 : }
3469 :
3470 : /* static */ nsDisplayBackgroundImage::InitData
3471 1 : nsDisplayBackgroundImage::GetInitData(nsDisplayListBuilder* aBuilder,
3472 : nsIFrame* aFrame,
3473 : uint32_t aLayer,
3474 : const nsRect& aBackgroundRect,
3475 : ComputedStyle* aBackgroundStyle)
3476 : {
3477 16 : nsPresContext* presContext = aFrame->PresContext();
3478 1 : uint32_t flags = aBuilder->GetBackgroundPaintFlags();
3479 32 : const nsStyleImageLayers::Layer &layer = aBackgroundStyle->StyleBackground()->mImage.mLayers[aLayer];
3480 :
3481 : bool isTransformedFixed;
3482 : nsBackgroundLayerState state =
3483 : nsCSSRendering::PrepareImageLayer(presContext, aFrame, flags,
3484 : aBackgroundRect, aBackgroundRect, layer,
3485 1 : &isTransformedFixed);
3486 :
3487 : // background-attachment:fixed is treated as background-attachment:scroll
3488 : // if it's affected by a transform.
3489 : // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=17521.
3490 : bool shouldTreatAsFixed =
3491 1 : layer.mAttachment == StyleImageLayerAttachment::Fixed && !isTransformedFixed;
3492 :
3493 16 : bool shouldFixToViewport = shouldTreatAsFixed && !layer.mImage.IsEmpty();
3494 16 : bool isRasterImage = state.mImageRenderer.IsRasterImage();
3495 32 : nsCOMPtr<imgIContainer> image;
3496 0 : if (isRasterImage) {
3497 0 : image = state.mImageRenderer.GetImage();
3498 : }
3499 : return InitData{
3500 : aBuilder, aFrame, aBackgroundStyle, image, aBackgroundRect,
3501 : state.mFillArea, state.mDestArea, aLayer, isRasterImage,
3502 : shouldFixToViewport
3503 32 : };
3504 : }
3505 :
3506 16 : nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
3507 : const InitData& aInitData,
3508 0 : nsIFrame* aFrameForBounds)
3509 16 : : nsDisplayImageContainer(aBuilder, aInitData.frame)
3510 16 : , mBackgroundStyle(aInitData.backgroundStyle)
3511 : , mImage(aInitData.image)
3512 : , mDependentFrame(nullptr)
3513 : , mBackgroundRect(aInitData.backgroundRect)
3514 : , mFillRect(aInitData.fillArea)
3515 : , mDestRect(aInitData.destArea)
3516 0 : , mLayer(aInitData.layer)
3517 16 : , mIsRasterImage(aInitData.isRasterImage)
3518 16 : , mShouldFixToViewport(aInitData.shouldFixToViewport)
3519 80 : , mImageFlags(0)
3520 : {
3521 16 : MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
3522 :
3523 16 : mBounds = GetBoundsInternal(aInitData.builder, aFrameForBounds);
3524 16 : if (mShouldFixToViewport) {
3525 0 : mAnimatedGeometryRoot = aInitData.builder->FindAnimatedGeometryRootFor(this);
3526 :
3527 : // Expand the item's visible rect to cover the entire bounds, limited to the
3528 : // viewport rect. This is necessary because the background's clip can move
3529 : // asynchronously.
3530 0 : if (Maybe<nsRect> viewportRect = GetViewportRectRelativeToReferenceFrame(aInitData.builder, mFrame)) {
3531 0 : SetBuildingRect(mBounds.Intersect(*viewportRect));
3532 : }
3533 : }
3534 0 : }
3535 :
3536 32 : nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
3537 : {
3538 : #ifdef NS_BUILD_REFCNT_LOGGING
3539 16 : MOZ_COUNT_DTOR(nsDisplayBackgroundImage);
3540 : #endif
3541 16 : if (mDependentFrame) {
3542 0 : mDependentFrame->RemoveDisplayItem(this);
3543 : }
3544 16 : }
3545 :
3546 0 : static nsIFrame* GetBackgroundComputedStyleFrame(nsIFrame* aFrame)
3547 : {
3548 : nsIFrame* f;
3549 56 : if (!nsCSSRendering::FindBackgroundFrame(aFrame, &f)) {
3550 : // We don't want to bail out if moz-appearance is set on a root
3551 : // node. If it has a parent content node, bail because it's not
3552 : // a root, other wise keep going in order to let the theme stuff
3553 : // draw the background. The canvas really should be drawing the
3554 : // bg, but there's no way to hook that up via css.
3555 0 : if (!aFrame->StyleDisplay()->mAppearance) {
3556 : return nullptr;
3557 : }
3558 :
3559 0 : nsIContent* content = aFrame->GetContent();
3560 0 : if (!content || content->GetParent()) {
3561 : return nullptr;
3562 : }
3563 :
3564 0 : f = aFrame;
3565 : }
3566 56 : return f;
3567 : }
3568 :
3569 : static void
3570 16 : SetBackgroundClipRegion(DisplayListClipState::AutoSaveRestore& aClipState,
3571 : nsIFrame* aFrame, const nsPoint& aToReferenceFrame,
3572 : const nsStyleImageLayers::Layer& aLayer,
3573 : const nsRect& aBackgroundRect,
3574 : bool aWillPaintBorder)
3575 : {
3576 0 : nsCSSRendering::ImageLayerClipState clip;
3577 16 : nsCSSRendering::GetImageLayerClip(aLayer, aFrame, *aFrame->StyleBorder(),
3578 : aBackgroundRect, aBackgroundRect, aWillPaintBorder,
3579 : aFrame->PresContext()->AppUnitsPerDevPixel(),
3580 16 : &clip);
3581 :
3582 16 : if (clip.mHasAdditionalBGClipArea) {
3583 0 : aClipState.ClipContentDescendants(clip.mAdditionalBGClipArea, clip.mBGClipArea,
3584 0 : clip.mHasRoundedCorners ? clip.mRadii : nullptr);
3585 : } else {
3586 0 : aClipState.ClipContentDescendants(clip.mBGClipArea, clip.mHasRoundedCorners ? clip.mRadii : nullptr);
3587 : }
3588 16 : }
3589 :
3590 : /**
3591 : * This is used for the find bar highlighter overlay. It's only accessible
3592 : * through the AnonymousContent API, so it's not exposed to general web pages.
3593 : */
3594 : static bool
3595 72 : SpecialCutoutRegionCase(nsDisplayListBuilder* aBuilder,
3596 : nsIFrame* aFrame,
3597 : const nsRect& aBackgroundRect,
3598 : nsDisplayList* aList,
3599 : nscolor aColor)
3600 : {
3601 1 : nsIContent* content = aFrame->GetContent();
3602 72 : if (!content) {
3603 : return false;
3604 : }
3605 :
3606 72 : void* cutoutRegion = content->GetProperty(nsGkAtoms::cutoutregion);
3607 0 : if (!cutoutRegion) {
3608 : return false;
3609 : }
3610 :
3611 0 : if (NS_GET_A(aColor) == 0) {
3612 : return true;
3613 : }
3614 :
3615 0 : nsRegion region;
3616 0 : region.Sub(aBackgroundRect, *static_cast<nsRegion*>(cutoutRegion));
3617 0 : region.MoveBy(aBuilder->ToReferenceFrame(aFrame));
3618 : aList->AppendToTop(
3619 0 : MakeDisplayItem<nsDisplaySolidColorRegion>(aBuilder, aFrame, region, aColor));
3620 :
3621 : return true;
3622 : }
3623 :
3624 :
3625 : /*static*/ bool
3626 72 : nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
3627 : nsIFrame* aFrame,
3628 : const nsRect& aBackgroundRect,
3629 : nsDisplayList* aList,
3630 : bool aAllowWillPaintBorderOptimization,
3631 : ComputedStyle* aComputedStyle,
3632 : const nsRect& aBackgroundOriginRect,
3633 : nsIFrame* aSecondaryReferenceFrame)
3634 : {
3635 72 : ComputedStyle* bgSC = aComputedStyle;
3636 72 : const nsStyleBackground* bg = nullptr;
3637 144 : nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame);
3638 0 : nsRect bgOriginRect = bgRect;
3639 0 : if (!aBackgroundOriginRect.IsEmpty()) {
3640 0 : bgOriginRect = aBackgroundOriginRect + aBuilder->ToReferenceFrame(aFrame);
3641 : }
3642 144 : nsPresContext* presContext = aFrame->PresContext();
3643 0 : bool isThemed = aFrame->IsThemed();
3644 0 : nsIFrame* dependentFrame = nullptr;
3645 72 : if (!isThemed) {
3646 56 : if (!bgSC) {
3647 56 : dependentFrame = GetBackgroundComputedStyleFrame(aFrame);
3648 1 : if (dependentFrame) {
3649 56 : bgSC = dependentFrame->Style();
3650 56 : if (dependentFrame == aFrame) {
3651 48 : dependentFrame = nullptr;
3652 : }
3653 : }
3654 : }
3655 56 : if (bgSC) {
3656 1 : bg = bgSC->StyleBackground();
3657 : }
3658 : }
3659 :
3660 72 : bool drawBackgroundColor = false;
3661 : // Dummy initialisation to keep Valgrind/Memcheck happy.
3662 : // See bug 1122375 comment 1.
3663 0 : nscolor color = NS_RGBA(0,0,0,0);
3664 72 : if (!nsCSSRendering::IsCanvasFrame(aFrame) && bg) {
3665 : bool drawBackgroundImage;
3666 : color =
3667 48 : nsCSSRendering::DetermineBackgroundColor(presContext, bgSC, aFrame,
3668 48 : drawBackgroundImage, drawBackgroundColor);
3669 : }
3670 :
3671 72 : if (SpecialCutoutRegionCase(aBuilder, aFrame, aBackgroundRect, aList, color)) {
3672 : return false;
3673 : }
3674 :
3675 0 : const nsStyleBorder* borderStyle = aFrame->StyleBorder();
3676 0 : const nsStyleEffects* effectsStyle = aFrame->StyleEffects();
3677 0 : bool hasInsetShadow = effectsStyle->mBoxShadow &&
3678 232 : effectsStyle->mBoxShadow->HasShadowWithInset(true);
3679 0 : bool willPaintBorder = aAllowWillPaintBorderOptimization &&
3680 0 : !isThemed && !hasInsetShadow &&
3681 0 : borderStyle->HasBorder();
3682 :
3683 0 : nsPoint toRef = aBuilder->ToReferenceFrame(aFrame);
3684 :
3685 : // An auxiliary list is necessary in case we have background blending; if that
3686 : // is the case, background items need to be wrapped by a blend container to
3687 : // isolate blending to the background
3688 0 : nsDisplayList bgItemList;
3689 : // Even if we don't actually have a background color to paint, we may still need
3690 : // to create an item for hit testing.
3691 96 : if ((drawBackgroundColor && color != NS_RGBA(0,0,0,0)) ||
3692 0 : aBuilder->IsForEventDelivery()) {
3693 0 : Maybe<DisplayListClipState::AutoSaveRestore> clipState;
3694 96 : nsRect bgColorRect = bgRect;
3695 48 : if (bg && !aBuilder->IsForEventDelivery()) {
3696 : // Disable the will-paint-border optimization for background
3697 : // colors with no border-radius. Enabling it for background colors
3698 : // doesn't help much (there are no tiling issues) and clipping the
3699 : // background breaks detection of the element's border-box being
3700 : // opaque. For nonzero border-radius we still need it because we
3701 : // want to inset the background if possible to avoid antialiasing
3702 : // artifacts along the rounded corners.
3703 72 : bool useWillPaintBorderOptimization = willPaintBorder &&
3704 0 : nsLayoutUtils::HasNonZeroCorner(borderStyle->mBorderRadius);
3705 :
3706 96 : nsCSSRendering::ImageLayerClipState clip;
3707 144 : nsCSSRendering::GetImageLayerClip(bg->BottomLayer(), aFrame, *aFrame->StyleBorder(),
3708 : bgRect, bgRect, useWillPaintBorderOptimization,
3709 : aFrame->PresContext()->AppUnitsPerDevPixel(),
3710 96 : &clip);
3711 :
3712 0 : bgColorRect = bgColorRect.Intersect(clip.mBGClipArea);
3713 0 : if (clip.mHasAdditionalBGClipArea) {
3714 0 : bgColorRect = bgColorRect.Intersect(clip.mAdditionalBGClipArea);
3715 : }
3716 0 : if (clip.mHasRoundedCorners) {
3717 0 : clipState.emplace(aBuilder);
3718 0 : clipState->ClipContentDescendants(clip.mBGClipArea, clip.mRadii);
3719 : }
3720 : }
3721 : nsDisplayBackgroundColor *bgItem;
3722 48 : if (aSecondaryReferenceFrame) {
3723 : bgItem =
3724 0 : MakeDisplayItem<nsDisplayTableBackgroundColor>(aBuilder, aSecondaryReferenceFrame, bgColorRect, bgSC,
3725 0 : drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0),
3726 0 : aFrame);
3727 : } else {
3728 : bgItem =
3729 0 : MakeDisplayItem<nsDisplayBackgroundColor>(aBuilder, aFrame, bgColorRect, bgSC,
3730 0 : drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0));
3731 : }
3732 0 : bgItem->SetDependentFrame(aBuilder, dependentFrame);
3733 48 : bgItemList.AppendToTop(bgItem);
3734 : }
3735 :
3736 72 : if (isThemed) {
3737 16 : nsITheme* theme = presContext->GetTheme();
3738 32 : if (theme->NeedToClearBackgroundBehindWidget(aFrame, aFrame->StyleDisplay()->mAppearance) &&
3739 16 : aBuilder->IsInChromeDocumentOrPopup() && !aBuilder->IsInTransform()) {
3740 0 : bgItemList.AppendToTop(
3741 0 : MakeDisplayItem<nsDisplayClearBackground>(aBuilder, aFrame));
3742 : }
3743 0 : if (aSecondaryReferenceFrame) {
3744 : nsDisplayTableThemedBackground* bgItem =
3745 0 : MakeDisplayItem<nsDisplayTableThemedBackground>(aBuilder,
3746 : aSecondaryReferenceFrame,
3747 : bgRect,
3748 0 : aFrame);
3749 0 : bgItem->Init(aBuilder);
3750 0 : bgItemList.AppendToTop(bgItem);
3751 : } else {
3752 : nsDisplayThemedBackground* bgItem =
3753 0 : MakeDisplayItem<nsDisplayThemedBackground>(aBuilder, aFrame, bgRect);
3754 0 : bgItem->Init(aBuilder);
3755 0 : bgItemList.AppendToTop(bgItem);
3756 : }
3757 16 : aList->AppendToTop(&bgItemList);
3758 16 : return true;
3759 : }
3760 :
3761 0 : if (!bg) {
3762 0 : aList->AppendToTop(&bgItemList);
3763 0 : return false;
3764 : }
3765 :
3766 : const ActiveScrolledRoot* asr =
3767 0 : aBuilder->CurrentActiveScrolledRoot();
3768 :
3769 0 : bool needBlendContainer = false;
3770 :
3771 : // Passing bg == nullptr in this macro will result in one iteration with
3772 : // i = 0.
3773 0 : NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
3774 0 : if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
3775 0 : continue;
3776 : }
3777 :
3778 1 : if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
3779 0 : needBlendContainer = true;
3780 : }
3781 :
3782 0 : DisplayListClipState::AutoSaveRestore clipState(aBuilder);
3783 16 : if (!aBuilder->IsForEventDelivery()) {
3784 16 : const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
3785 0 : SetBackgroundClipRegion(clipState, aFrame, toRef,
3786 0 : layer, bgRect, willPaintBorder);
3787 : }
3788 :
3789 32 : nsDisplayList thisItemList;
3790 : nsDisplayBackgroundImage::InitData bgData =
3791 0 : nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgOriginRect, bgSC);
3792 :
3793 16 : if (bgData.shouldFixToViewport) {
3794 :
3795 0 : auto* displayData = aBuilder->GetCurrentFixedBackgroundDisplayData();
3796 : nsDisplayListBuilder::AutoBuildingDisplayList
3797 0 : buildingDisplayList(aBuilder, aFrame, aBuilder->GetVisibleRect(), aBuilder->GetDirtyRect(), false);
3798 :
3799 0 : nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
3800 0 : if (displayData) {
3801 0 : asrSetter.SetCurrentActiveScrolledRoot(
3802 0 : displayData->mContainingBlockActiveScrolledRoot);
3803 0 : if (nsLayoutUtils::UsesAsyncScrolling(aFrame)) {
3804 : // Override the dirty rect on the builder to be the dirty rect of
3805 : // the viewport.
3806 : // displayData->mDirtyRect is relative to the presshell's viewport
3807 : // frame (the root frame), and we need it to be relative to aFrame.
3808 0 : nsIFrame* rootFrame = aBuilder->CurrentPresShellState()->mPresShell->GetRootFrame();
3809 : // There cannot be any transforms between aFrame and rootFrame
3810 : // because then bgData.shouldFixToViewport would have been false.
3811 0 : nsRect visibleRect = displayData->mVisibleRect + aFrame->GetOffsetTo(rootFrame);
3812 0 : aBuilder->SetVisibleRect(visibleRect);
3813 0 : nsRect dirtyRect = displayData->mDirtyRect + aFrame->GetOffsetTo(rootFrame);
3814 0 : aBuilder->SetDirtyRect(dirtyRect);
3815 : }
3816 : }
3817 0 : nsDisplayBackgroundImage* bgItem = nullptr;
3818 : {
3819 : // The clip is captured by the nsDisplayFixedPosition, so clear the
3820 : // clip for the nsDisplayBackgroundImage inside.
3821 0 : DisplayListClipState::AutoSaveRestore bgImageClip(aBuilder);
3822 0 : bgImageClip.Clear();
3823 0 : if (aSecondaryReferenceFrame) {
3824 0 : nsDisplayBackgroundImage::InitData tableData = bgData;
3825 0 : nsIFrame* styleFrame = tableData.frame;
3826 0 : tableData.frame = aSecondaryReferenceFrame;
3827 0 : bgItem = MakeDisplayItem<nsDisplayTableBackgroundImage>(aBuilder, tableData, styleFrame);
3828 : } else {
3829 0 : bgItem = MakeDisplayItem<nsDisplayBackgroundImage>(aBuilder, bgData);
3830 : }
3831 : }
3832 0 : bgItem->SetDependentFrame(aBuilder, dependentFrame);
3833 0 : if (aSecondaryReferenceFrame) {
3834 0 : thisItemList.AppendToTop(
3835 0 : nsDisplayTableFixedPosition::CreateForFixedBackground(aBuilder,
3836 : aSecondaryReferenceFrame,
3837 : bgItem,
3838 : i,
3839 0 : aFrame));
3840 : } else {
3841 0 : thisItemList.AppendToTop(
3842 0 : nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i));
3843 : }
3844 :
3845 : } else {
3846 : nsDisplayBackgroundImage* bgItem;
3847 16 : if (aSecondaryReferenceFrame) {
3848 0 : nsDisplayBackgroundImage::InitData tableData = bgData;
3849 0 : nsIFrame* styleFrame = tableData.frame;
3850 0 : tableData.frame = aSecondaryReferenceFrame;
3851 :
3852 0 : bgItem = MakeDisplayItem<nsDisplayTableBackgroundImage>(aBuilder, tableData, styleFrame);
3853 : } else {
3854 0 : bgItem = MakeDisplayItem<nsDisplayBackgroundImage>(aBuilder, bgData);
3855 : }
3856 16 : bgItem->SetDependentFrame(aBuilder, dependentFrame);
3857 16 : thisItemList.AppendToTop(bgItem);
3858 : }
3859 :
3860 0 : if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
3861 0 : DisplayListClipState::AutoSaveRestore blendClip(aBuilder);
3862 : // asr is scrolled. Even if we wrap a fixed background layer, that's
3863 : // fine, because the item will have a scrolled clip that limits the
3864 : // item with respect to asr.
3865 0 : if (aSecondaryReferenceFrame) {
3866 0 : thisItemList.AppendToTop(
3867 0 : MakeDisplayItem<nsDisplayTableBlendMode>(aBuilder, aSecondaryReferenceFrame, &thisItemList,
3868 0 : bg->mImage.mLayers[i].mBlendMode,
3869 0 : asr, i + 1, aFrame));
3870 : } else {
3871 0 : thisItemList.AppendToTop(
3872 0 : MakeDisplayItem<nsDisplayBlendMode>(aBuilder, aFrame, &thisItemList,
3873 0 : bg->mImage.mLayers[i].mBlendMode,
3874 0 : asr, i + 1));
3875 : }
3876 : }
3877 16 : bgItemList.AppendToTop(&thisItemList);
3878 : }
3879 :
3880 56 : if (needBlendContainer) {
3881 0 : DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder);
3882 0 : if (aSecondaryReferenceFrame) {
3883 0 : bgItemList.AppendToTop(
3884 0 : nsDisplayTableBlendContainer::CreateForBackgroundBlendMode(aBuilder, aSecondaryReferenceFrame,
3885 0 : &bgItemList, asr, aFrame));
3886 : } else {
3887 0 : bgItemList.AppendToTop(
3888 0 : nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, aFrame, &bgItemList, asr));
3889 : }
3890 : }
3891 :
3892 56 : aList->AppendToTop(&bgItemList);
3893 0 : return false;
3894 : }
3895 :
3896 : // Check that the rounded border of aFrame, added to aToReferenceFrame,
3897 : // intersects aRect. Assumes that the unrounded border has already
3898 : // been checked for intersection.
3899 : static bool
3900 0 : RoundedBorderIntersectsRect(nsIFrame* aFrame,
3901 : const nsPoint& aFrameToReferenceFrame,
3902 : const nsRect& aTestRect)
3903 : {
3904 0 : if (!nsRect(aFrameToReferenceFrame, aFrame->GetSize()).Intersects(aTestRect))
3905 : return false;
3906 :
3907 : nscoord radii[8];
3908 0 : return !aFrame->GetBorderRadii(radii) ||
3909 0 : nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame,
3910 0 : aFrame->GetSize()),
3911 0 : radii, aTestRect);
3912 : }
3913 :
3914 : // Returns TRUE if aContainedRect is guaranteed to be contained in
3915 : // the rounded rect defined by aRoundedRect and aRadii. Complex cases are
3916 : // handled conservatively by returning FALSE in some situations where
3917 : // a more thorough analysis could return TRUE.
3918 : //
3919 : // See also RoundedRectIntersectsRect.
3920 0 : static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
3921 : const nscoord aRadii[8],
3922 : const nsRect& aContainedRect) {
3923 0 : nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
3924 0 : return rgn.Contains(aContainedRect);
3925 : }
3926 :
3927 : bool
3928 0 : nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager,
3929 : nsDisplayListBuilder* aBuilder)
3930 : {
3931 0 : if (!mBackgroundStyle) {
3932 : return false;
3933 : }
3934 :
3935 : // We currently can't handle tiled backgrounds.
3936 0 : if (!mDestRect.Contains(mFillRect)) {
3937 : return false;
3938 : }
3939 :
3940 : // For 'contain' and 'cover', we allow any pixel of the image to be sampled
3941 : // because there isn't going to be any spriting/atlasing going on.
3942 0 : const nsStyleImageLayers::Layer &layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
3943 : bool allowPartialImages =
3944 0 : (layer.mSize.mWidthType == nsStyleImageLayers::Size::eContain ||
3945 0 : layer.mSize.mWidthType == nsStyleImageLayers::Size::eCover);
3946 0 : if (!allowPartialImages && !mFillRect.Contains(mDestRect)) {
3947 : return false;
3948 : }
3949 :
3950 0 : return nsDisplayImageContainer::CanOptimizeToImageLayer(aManager, aBuilder);
3951 : }
3952 :
3953 : nsRect
3954 2 : nsDisplayBackgroundImage::GetDestRect() const
3955 : {
3956 2 : return mDestRect;
3957 : }
3958 :
3959 : already_AddRefed<imgIContainer>
3960 0 : nsDisplayBackgroundImage::GetImage()
3961 : {
3962 0 : nsCOMPtr<imgIContainer> image = mImage;
3963 0 : return image.forget();
3964 : }
3965 :
3966 : nsDisplayBackgroundImage::ImageLayerization
3967 16 : nsDisplayBackgroundImage::ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder,
3968 : LayerManager* aManager)
3969 : {
3970 16 : if (ForceActiveLayers()) {
3971 : return WHENEVER_POSSIBLE;
3972 : }
3973 :
3974 16 : nsIFrame* backgroundStyleFrame = nsCSSRendering::FindBackgroundStyleFrame(StyleFrame());
3975 16 : if (ActiveLayerTracker::IsBackgroundPositionAnimated(aBuilder,
3976 : backgroundStyleFrame)) {
3977 : return WHENEVER_POSSIBLE;
3978 : }
3979 :
3980 16 : if (nsLayoutUtils::AnimatedImageLayersEnabled() && mBackgroundStyle) {
3981 0 : const nsStyleImageLayers::Layer &layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
3982 0 : const nsStyleImage* image = &layer.mImage;
3983 0 : if (image->GetType() == eStyleImageType_Image) {
3984 0 : imgIRequest* imgreq = image->GetImageData();
3985 0 : nsCOMPtr<imgIContainer> image;
3986 0 : if (imgreq &&
3987 0 : NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) &&
3988 0 : image) {
3989 0 : bool animated = false;
3990 0 : if (NS_SUCCEEDED(image->GetAnimated(&animated)) && animated) {
3991 0 : return WHENEVER_POSSIBLE;
3992 : }
3993 : }
3994 : }
3995 : }
3996 :
3997 0 : if (nsLayoutUtils::GPUImageScalingEnabled() &&
3998 0 : aManager->IsCompositingCheap()) {
3999 : return ONLY_FOR_SCALING;
4000 : }
4001 :
4002 16 : return NO_LAYER_NEEDED;
4003 : }
4004 :
4005 16 : static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
4006 : {
4007 0 : nsDisplayItem* nextItem = aItem->GetAbove();
4008 16 : while (nextItem && nextItem->GetType() == DisplayItemType::TYPE_BACKGROUND) {
4009 0 : nextItem = nextItem->GetAbove();
4010 : }
4011 0 : if (nextItem &&
4012 0 : nextItem->Frame() == aItem->Frame() &&
4013 8 : nextItem->GetType() == DisplayItemType::TYPE_BORDER) {
4014 8 : aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
4015 : }
4016 16 : }
4017 :
4018 : LayerState
4019 1 : nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
4020 : LayerManager* aManager,
4021 : const ContainerLayerParameters& aParameters)
4022 : {
4023 1 : mImageFlags = aBuilder->GetBackgroundPaintFlags();
4024 1 : CheckForBorderItem(this, mImageFlags);
4025 :
4026 1 : ImageLayerization shouldLayerize = ShouldCreateOwnLayer(aBuilder, aManager);
4027 1 : if (shouldLayerize == NO_LAYER_NEEDED) {
4028 : // We can skip the call to CanOptimizeToImageLayer if we don't want a
4029 : // layer anyway.
4030 : return LAYER_NONE;
4031 : }
4032 :
4033 0 : if (CanOptimizeToImageLayer(aManager, aBuilder)) {
4034 0 : if (shouldLayerize == WHENEVER_POSSIBLE) {
4035 0 : return LAYER_ACTIVE;
4036 : }
4037 :
4038 0 : MOZ_ASSERT(shouldLayerize == ONLY_FOR_SCALING, "unhandled ImageLayerization value?");
4039 :
4040 0 : MOZ_ASSERT(mImage);
4041 : int32_t imageWidth;
4042 : int32_t imageHeight;
4043 0 : mImage->GetWidth(&imageWidth);
4044 0 : mImage->GetHeight(&imageHeight);
4045 0 : NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
4046 :
4047 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
4048 0 : LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(GetDestRect(), appUnitsPerDevPixel);
4049 :
4050 0 : const LayerRect destLayerRect = destRect * aParameters.Scale();
4051 :
4052 : // Calculate the scaling factor for the frame.
4053 0 : const gfxSize scale = gfxSize(destLayerRect.width / imageWidth,
4054 0 : destLayerRect.height / imageHeight);
4055 :
4056 0 : if ((scale.width != 1.0f || scale.height != 1.0f) &&
4057 0 : (destLayerRect.width * destLayerRect.height >= 64 * 64)) {
4058 : // Separate this image into a layer.
4059 : // There's no point in doing this if we are not scaling at all or if the
4060 : // target size is pretty small.
4061 : return LAYER_ACTIVE;
4062 : }
4063 : }
4064 :
4065 : return LAYER_NONE;
4066 : }
4067 :
4068 : already_AddRefed<Layer>
4069 0 : nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
4070 : LayerManager* aManager,
4071 : const ContainerLayerParameters& aParameters)
4072 : {
4073 : RefPtr<ImageLayer> layer = static_cast<ImageLayer*>
4074 0 : (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
4075 0 : if (!layer) {
4076 0 : layer = aManager->CreateImageLayer();
4077 0 : if (!layer)
4078 : return nullptr;
4079 : }
4080 0 : RefPtr<ImageContainer> imageContainer = GetContainer(aManager, aBuilder);
4081 0 : layer->SetContainer(imageContainer);
4082 0 : ConfigureLayer(layer, aParameters);
4083 0 : return layer.forget();
4084 : }
4085 :
4086 : bool
4087 0 : nsDisplayBackgroundImage::CanBuildWebRenderDisplayItems(LayerManager* aManager, nsDisplayListBuilder* aDisplayListBuilder)
4088 : {
4089 0 : if (aDisplayListBuilder) {
4090 0 : mImageFlags = aDisplayListBuilder->GetBackgroundPaintFlags();
4091 : }
4092 :
4093 0 : return mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mClip != StyleGeometryBox::Text &&
4094 0 : nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(aManager,
4095 0 : *StyleFrame()->PresContext(),
4096 0 : StyleFrame(),
4097 : mBackgroundStyle->StyleBackground(),
4098 0 : mLayer,
4099 0 : mImageFlags);
4100 : }
4101 :
4102 : bool
4103 0 : nsDisplayBackgroundImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
4104 : mozilla::wr::IpcResourceUpdateQueue& aResources,
4105 : const StackingContextHelper& aSc,
4106 : WebRenderLayerManager* aManager,
4107 : nsDisplayListBuilder* aDisplayListBuilder)
4108 : {
4109 0 : ContainerLayerParameters parameter;
4110 0 : if (!CanBuildWebRenderDisplayItems(aManager, aDisplayListBuilder)) {
4111 : return false;
4112 : }
4113 :
4114 0 : CheckForBorderItem(this, mImageFlags);
4115 : nsCSSRendering::PaintBGParams params =
4116 0 : nsCSSRendering::PaintBGParams::ForSingleLayer(*StyleFrame()->PresContext(),
4117 : GetPaintRect(), mBackgroundRect,
4118 0 : StyleFrame(), mImageFlags, mLayer,
4119 0 : CompositionOp::OP_OVER);
4120 0 : params.bgClipRect = &mBounds;
4121 : ImgDrawResult result =
4122 0 : nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(params, aBuilder, aResources, aSc, aManager, this);
4123 0 : nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
4124 :
4125 : return true;
4126 : }
4127 :
4128 : void
4129 0 : nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
4130 : const nsRect& aRect,
4131 : HitTestState* aState,
4132 : nsTArray<nsIFrame*> *aOutFrames)
4133 : {
4134 0 : if (RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
4135 0 : aOutFrames->AppendElement(mFrame);
4136 : }
4137 0 : }
4138 :
4139 : bool
4140 1 : nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
4141 : nsRegion* aVisibleRegion)
4142 : {
4143 8 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
4144 : return false;
4145 : }
4146 :
4147 : // Return false if the background was propagated away from this
4148 : // frame. We don't want this display item to show up and confuse
4149 : // anything.
4150 8 : return mBackgroundStyle;
4151 : }
4152 :
4153 : /* static */ nsRegion
4154 11 : nsDisplayBackgroundImage::GetInsideClipRegion(const nsDisplayItem* aItem,
4155 : StyleGeometryBox aClip,
4156 : const nsRect& aRect,
4157 : const nsRect& aBackgroundRect)
4158 : {
4159 1 : nsRegion result;
4160 1 : if (aRect.IsEmpty())
4161 0 : return result;
4162 :
4163 11 : nsIFrame *frame = aItem->Frame();
4164 :
4165 22 : nsRect clipRect = aBackgroundRect;
4166 0 : if (frame->IsCanvasFrame()) {
4167 0 : nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame);
4168 0 : clipRect = canvasFrame->CanvasArea() + aItem->ToReferenceFrame();
4169 11 : } else if (aClip == StyleGeometryBox::PaddingBox ||
4170 : aClip == StyleGeometryBox::ContentBox) {
4171 0 : nsMargin border = frame->GetUsedBorder();
4172 0 : if (aClip == StyleGeometryBox::ContentBox) {
4173 4 : border += frame->GetUsedPadding();
4174 : }
4175 6 : border.ApplySkipSides(frame->GetSkipSides());
4176 6 : clipRect.Deflate(border);
4177 : }
4178 :
4179 11 : return clipRect.Intersect(aRect);
4180 : }
4181 :
4182 : nsRegion
4183 4 : nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4184 : bool* aSnap) const
4185 : {
4186 4 : nsRegion result;
4187 0 : *aSnap = false;
4188 :
4189 8 : if (!mBackgroundStyle)
4190 : return result;
4191 :
4192 4 : *aSnap = true;
4193 :
4194 : // For StyleBoxDecorationBreak::Slice, don't try to optimize here, since
4195 : // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
4196 : // which expects frames to be sent to it in content order, not reverse
4197 : // content order which we'll produce here.
4198 : // Of course, if there's only one frame in the flow, it doesn't matter.
4199 8 : if (mFrame->StyleBorder()->mBoxDecorationBreak ==
4200 0 : StyleBoxDecorationBreak::Clone ||
4201 8 : (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
4202 0 : const nsStyleImageLayers::Layer& layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
4203 0 : if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL &&
4204 0 : layer.mRepeat.mXRepeat != StyleImageLayerRepeat::Space &&
4205 0 : layer.mRepeat.mYRepeat != StyleImageLayerRepeat::Space &&
4206 0 : layer.mClip != StyleGeometryBox::Text) {
4207 0 : result = GetInsideClipRegion(this, layer.mClip, mBounds, mBackgroundRect);
4208 : }
4209 : }
4210 :
4211 : return result;
4212 : }
4213 :
4214 : Maybe<nscolor>
4215 0 : nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder) const
4216 : {
4217 0 : if (!mBackgroundStyle) {
4218 0 : return Some(NS_RGBA(0,0,0,0));
4219 : }
4220 : return Nothing();
4221 : }
4222 :
4223 : nsRect
4224 0 : nsDisplayBackgroundImage::GetPositioningArea() const
4225 : {
4226 0 : if (!mBackgroundStyle) {
4227 0 : return nsRect();
4228 : }
4229 : nsIFrame* attachedToFrame;
4230 : bool transformedFixed;
4231 64 : return nsCSSRendering::ComputeImageLayerPositioningArea(
4232 16 : mFrame->PresContext(), mFrame,
4233 : mBackgroundRect,
4234 48 : mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer],
4235 : &attachedToFrame,
4236 0 : &transformedFixed) + ToReferenceFrame();
4237 : }
4238 :
4239 : bool
4240 0 : nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange() const
4241 : {
4242 0 : if (!mBackgroundStyle)
4243 : return false;
4244 :
4245 : nscoord radii[8];
4246 0 : if (mFrame->GetBorderRadii(radii)) {
4247 : // A change in the size of the positioning area might change the position
4248 : // of the rounded corners.
4249 : return true;
4250 : }
4251 :
4252 0 : const nsStyleImageLayers::Layer &layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
4253 0 : if (layer.RenderingMightDependOnPositioningAreaSizeChange()) {
4254 : return true;
4255 : }
4256 0 : return false;
4257 : }
4258 :
4259 : void
4260 4 : nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
4261 : gfxContext* aCtx) {
4262 8 : PaintInternal(aBuilder, aCtx, GetPaintRect(), &mBounds);
4263 0 : }
4264 :
4265 : void
4266 4 : nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
4267 : gfxContext* aCtx, const nsRect& aBounds,
4268 : nsRect* aClipRect) {
4269 0 : gfxContext* ctx = aCtx;
4270 8 : StyleGeometryBox clip = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mClip;
4271 :
4272 4 : if (clip == StyleGeometryBox::Text) {
4273 0 : if (!GenerateAndPushTextMask(StyleFrame(), aCtx, mBackgroundRect, aBuilder)) {
4274 0 : return;
4275 : }
4276 : }
4277 :
4278 : nsCSSRendering::PaintBGParams params =
4279 0 : nsCSSRendering::PaintBGParams::ForSingleLayer(*StyleFrame()->PresContext(),
4280 : aBounds, mBackgroundRect,
4281 8 : StyleFrame(), mImageFlags, mLayer,
4282 16 : CompositionOp::OP_OVER);
4283 0 : params.bgClipRect = aClipRect;
4284 4 : ImgDrawResult result = nsCSSRendering::PaintStyleImageLayer(params, *aCtx);
4285 :
4286 4 : if (clip == StyleGeometryBox::Text) {
4287 0 : ctx->PopGroupAndBlend();
4288 : }
4289 :
4290 0 : nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
4291 : }
4292 :
4293 : void
4294 14 : nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4295 : const nsDisplayItemGeometry* aGeometry,
4296 : nsRegion* aInvalidRegion) const
4297 : {
4298 28 : if (!mBackgroundStyle) {
4299 0 : return;
4300 : }
4301 :
4302 14 : const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
4303 :
4304 : bool snap;
4305 28 : nsRect bounds = GetBounds(aBuilder, &snap);
4306 0 : nsRect positioningArea = GetPositioningArea();
4307 0 : if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() ||
4308 42 : (positioningArea.Size() != geometry->mPositioningArea.Size() &&
4309 0 : RenderingMightDependOnPositioningAreaSizeChange())) {
4310 : // Positioning area changed in a way that could cause everything to change,
4311 : // so invalidate everything (both old and new painting areas).
4312 0 : aInvalidRegion->Or(bounds, geometry->mBounds);
4313 0 : return;
4314 : }
4315 14 : if (!mDestRect.IsEqualInterior(geometry->mDestRect)) {
4316 : // Dest area changed in a way that could cause everything to change,
4317 : // so invalidate everything (both old and new painting areas).
4318 0 : aInvalidRegion->Or(bounds, geometry->mBounds);
4319 0 : return;
4320 : }
4321 0 : if (aBuilder->ShouldSyncDecodeImages()) {
4322 0 : const nsStyleImage& image = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mImage;
4323 0 : if (image.GetType() == eStyleImageType_Image &&
4324 0 : geometry->ShouldInvalidateToSyncDecodeImages()) {
4325 0 : aInvalidRegion->Or(*aInvalidRegion, bounds);
4326 : }
4327 : }
4328 14 : if (!bounds.IsEqualInterior(geometry->mBounds)) {
4329 : // Positioning area is unchanged, so invalidate just the change in the
4330 : // painting area.
4331 0 : aInvalidRegion->Xor(bounds, geometry->mBounds);
4332 : }
4333 : }
4334 :
4335 : nsRect
4336 0 : nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder,
4337 : bool* aSnap) const
4338 : {
4339 0 : *aSnap = true;
4340 56 : return mBounds;
4341 : }
4342 :
4343 : nsRect
4344 0 : nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder* aBuilder,
4345 : nsIFrame* aFrameForBounds)
4346 : {
4347 : // This allows nsDisplayTableBackgroundImage to change the frame used for
4348 : // bounds calculation.
4349 0 : nsIFrame* frame = aFrameForBounds ? aFrameForBounds : mFrame;
4350 :
4351 16 : nsPresContext* presContext = frame->PresContext();
4352 :
4353 32 : if (!mBackgroundStyle) {
4354 0 : return nsRect();
4355 : }
4356 :
4357 32 : nsRect clipRect = mBackgroundRect;
4358 0 : if (frame->IsCanvasFrame()) {
4359 0 : nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame);
4360 0 : clipRect = canvasFrame->CanvasArea() + ToReferenceFrame();
4361 : }
4362 0 : const nsStyleImageLayers::Layer& layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer];
4363 : return nsCSSRendering::GetBackgroundLayerRect(presContext, frame,
4364 : mBackgroundRect, clipRect, layer,
4365 0 : aBuilder->GetBackgroundPaintFlags());
4366 : }
4367 :
4368 0 : nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder,
4369 : const InitData& aData,
4370 0 : nsIFrame* aCellFrame)
4371 : : nsDisplayBackgroundImage(aBuilder, aData, aCellFrame)
4372 : , mStyleFrame(aCellFrame)
4373 0 : , mTableType(GetTableTypeFromFrame(mStyleFrame))
4374 : {
4375 0 : if (aBuilder->IsRetainingDisplayList()) {
4376 0 : mStyleFrame->AddDisplayItem(this);
4377 : }
4378 0 : }
4379 :
4380 0 : nsDisplayTableBackgroundImage::~nsDisplayTableBackgroundImage()
4381 : {
4382 0 : if (mStyleFrame) {
4383 0 : mStyleFrame->RemoveDisplayItem(this);
4384 : }
4385 0 : }
4386 :
4387 : bool
4388 0 : nsDisplayTableBackgroundImage::IsInvalid(nsRect& aRect) const
4389 : {
4390 0 : bool result = mStyleFrame ? mStyleFrame->IsInvalid(aRect) : false;
4391 0 : aRect += ToReferenceFrame();
4392 0 : return result;
4393 : }
4394 :
4395 0 : nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder,
4396 : nsIFrame* aFrame,
4397 0 : const nsRect& aBackgroundRect)
4398 : : nsDisplayItem(aBuilder, aFrame)
4399 0 : , mBackgroundRect(aBackgroundRect)
4400 : {
4401 16 : MOZ_COUNT_CTOR(nsDisplayThemedBackground);
4402 0 : }
4403 :
4404 32 : nsDisplayThemedBackground::~nsDisplayThemedBackground()
4405 : {
4406 : #ifdef NS_BUILD_REFCNT_LOGGING
4407 0 : MOZ_COUNT_DTOR(nsDisplayThemedBackground);
4408 : #endif
4409 16 : }
4410 :
4411 : void
4412 0 : nsDisplayThemedBackground::Init(nsDisplayListBuilder* aBuilder)
4413 : {
4414 16 : const nsStyleDisplay* disp = StyleFrame()->StyleDisplay();
4415 0 : mAppearance = disp->mAppearance;
4416 16 : StyleFrame()->IsThemed(disp, &mThemeTransparency);
4417 :
4418 : // Perform necessary RegisterThemeGeometry
4419 0 : nsITheme* theme = StyleFrame()->PresContext()->GetTheme();
4420 : nsITheme::ThemeGeometryType type =
4421 16 : theme->ThemeGeometryTypeForWidget(StyleFrame(), disp->mAppearance);
4422 0 : if (type != nsITheme::eThemeGeometryTypeUnknown) {
4423 0 : RegisterThemeGeometry(aBuilder, this, StyleFrame(), type);
4424 : }
4425 :
4426 16 : if (disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
4427 : disp->mAppearance == NS_THEME_WIN_GLASS) {
4428 0 : aBuilder->SetGlassDisplayItem(this);
4429 : }
4430 :
4431 16 : mBounds = GetBoundsInternal();
4432 0 : }
4433 :
4434 : void
4435 0 : nsDisplayThemedBackground::WriteDebugInfo(std::stringstream& aStream)
4436 : {
4437 0 : aStream << " (themed, appearance:" << (int)mAppearance << ")";
4438 0 : }
4439 :
4440 : void
4441 0 : nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder,
4442 : const nsRect& aRect,
4443 : HitTestState* aState,
4444 : nsTArray<nsIFrame*> *aOutFrames)
4445 : {
4446 : // Assume that any point in our background rect is a hit.
4447 0 : if (mBackgroundRect.Intersects(aRect)) {
4448 0 : aOutFrames->AppendElement(mFrame);
4449 : }
4450 0 : }
4451 :
4452 : nsRegion
4453 0 : nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4454 : bool* aSnap) const
4455 : {
4456 0 : nsRegion result;
4457 12 : *aSnap = false;
4458 :
4459 0 : if (mThemeTransparency == nsITheme::eOpaque) {
4460 0 : result = mBackgroundRect;
4461 : }
4462 12 : return result;
4463 : }
4464 :
4465 : Maybe<nscolor>
4466 8 : nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder) const
4467 : {
4468 0 : if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
4469 : mAppearance == NS_THEME_WIN_GLASS) {
4470 0 : return Some(NS_RGBA(0,0,0,0));
4471 : }
4472 : return Nothing();
4473 : }
4474 :
4475 : nsRect
4476 0 : nsDisplayThemedBackground::GetPositioningArea() const
4477 : {
4478 0 : return mBackgroundRect;
4479 : }
4480 :
4481 : void
4482 4 : nsDisplayThemedBackground::Paint(nsDisplayListBuilder* aBuilder,
4483 : gfxContext* aCtx)
4484 : {
4485 0 : PaintInternal(aBuilder, aCtx, GetPaintRect(), nullptr);
4486 4 : }
4487 :
4488 :
4489 : void
4490 0 : nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder,
4491 : gfxContext* aCtx, const nsRect& aBounds,
4492 : nsRect* aClipRect)
4493 : {
4494 : // XXXzw this ignores aClipRect.
4495 8 : nsPresContext* presContext = StyleFrame()->PresContext();
4496 0 : nsITheme *theme = presContext->GetTheme();
4497 0 : nsRect drawing(mBackgroundRect);
4498 8 : theme->GetWidgetOverflow(presContext->DeviceContext(), StyleFrame(), mAppearance,
4499 0 : &drawing);
4500 4 : drawing.IntersectRect(drawing, aBounds);
4501 4 : theme->DrawWidgetBackground(aCtx, StyleFrame(), mAppearance, mBackgroundRect, drawing);
4502 4 : }
4503 :
4504 :
4505 : bool
4506 0 : nsDisplayThemedBackground::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
4507 : mozilla::wr::IpcResourceUpdateQueue& aResources,
4508 : const StackingContextHelper& aSc,
4509 : mozilla::layers::WebRenderLayerManager* aManager,
4510 : nsDisplayListBuilder* aDisplayListBuilder)
4511 : {
4512 0 : nsITheme *theme = StyleFrame()->PresContext()->GetTheme();
4513 0 : return theme->CreateWebRenderCommandsForWidget(aBuilder, aResources, aSc, aManager,
4514 0 : StyleFrame(), mAppearance, mBackgroundRect);
4515 : }
4516 :
4517 : bool
4518 2 : nsDisplayThemedBackground::IsWindowActive() const
4519 : {
4520 4 : EventStates docState = mFrame->GetContent()->OwnerDoc()->GetDocumentState();
4521 2 : return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
4522 : }
4523 :
4524 : void
4525 14 : nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4526 : const nsDisplayItemGeometry* aGeometry,
4527 : nsRegion* aInvalidRegion) const
4528 : {
4529 14 : const nsDisplayThemedBackgroundGeometry* geometry = static_cast<const nsDisplayThemedBackgroundGeometry*>(aGeometry);
4530 :
4531 : bool snap;
4532 0 : nsRect bounds = GetBounds(aBuilder, &snap);
4533 0 : nsRect positioningArea = GetPositioningArea();
4534 0 : if (!positioningArea.IsEqualInterior(geometry->mPositioningArea)) {
4535 : // Invalidate everything (both old and new painting areas).
4536 0 : aInvalidRegion->Or(bounds, geometry->mBounds);
4537 0 : return;
4538 : }
4539 0 : if (!bounds.IsEqualInterior(geometry->mBounds)) {
4540 : // Positioning area is unchanged, so invalidate just the change in the
4541 : // painting area.
4542 0 : aInvalidRegion->Xor(bounds, geometry->mBounds);
4543 : }
4544 28 : nsITheme* theme = StyleFrame()->PresContext()->GetTheme();
4545 14 : if (theme->WidgetAppearanceDependsOnWindowFocus(mAppearance) &&
4546 0 : IsWindowActive() != geometry->mWindowIsActive) {
4547 0 : aInvalidRegion->Or(*aInvalidRegion, bounds);
4548 : }
4549 : }
4550 :
4551 : nsRect
4552 56 : nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder,
4553 : bool* aSnap) const
4554 : {
4555 0 : *aSnap = true;
4556 56 : return mBounds;
4557 : }
4558 :
4559 : nsRect
4560 16 : nsDisplayThemedBackground::GetBoundsInternal() {
4561 32 : nsPresContext* presContext = mFrame->PresContext();
4562 :
4563 32 : nsRect r = mBackgroundRect - ToReferenceFrame();
4564 16 : presContext->GetTheme()->
4565 32 : GetWidgetOverflow(presContext->DeviceContext(), mFrame,
4566 0 : mFrame->StyleDisplay()->mAppearance, &r);
4567 32 : return r + ToReferenceFrame();
4568 : }
4569 :
4570 : void
4571 0 : nsDisplayImageContainer::ConfigureLayer(ImageLayer* aLayer,
4572 : const ContainerLayerParameters& aParameters)
4573 : {
4574 0 : aLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(mFrame));
4575 :
4576 0 : nsCOMPtr<imgIContainer> image = GetImage();
4577 0 : MOZ_ASSERT(image);
4578 : int32_t imageWidth;
4579 : int32_t imageHeight;
4580 0 : image->GetWidth(&imageWidth);
4581 0 : image->GetHeight(&imageHeight);
4582 0 : NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
4583 :
4584 0 : if (imageWidth > 0 && imageHeight > 0) {
4585 : // We're actually using the ImageContainer. Let our frame know that it
4586 : // should consider itself to have painted successfully.
4587 0 : UpdateDrawResult(ImgDrawResult::SUCCESS);
4588 : }
4589 :
4590 : // XXX(seth): Right now we ignore aParameters.Scale() and
4591 : // aParameters.Offset(), because FrameLayerBuilder already applies
4592 : // aParameters.Scale() via the layer's post-transform, and
4593 : // aParameters.Offset() is always zero.
4594 0 : MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0));
4595 :
4596 : // It's possible (for example, due to downscale-during-decode) that the
4597 : // ImageContainer this ImageLayer is holding has a different size from the
4598 : // intrinsic size of the image. For this reason we compute the transform using
4599 : // the ImageContainer's size rather than the image's intrinsic size.
4600 : // XXX(seth): In reality, since the size of the ImageContainer may change
4601 : // asynchronously, this is not enough. Bug 1183378 will provide a more
4602 : // complete fix, but this solution is safe in more cases than simply relying
4603 : // on the intrinsic size.
4604 0 : IntSize containerSize = aLayer->GetContainer()
4605 0 : ? aLayer->GetContainer()->GetCurrentSize()
4606 0 : : IntSize(imageWidth, imageHeight);
4607 :
4608 0 : const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
4609 : const LayoutDeviceRect destRect(
4610 0 : LayoutDeviceIntRect::FromAppUnitsToNearest(GetDestRect(), factor));
4611 :
4612 0 : const LayoutDevicePoint p = destRect.TopLeft();
4613 0 : Matrix transform = Matrix::Translation(p.x, p.y);
4614 0 : transform.PreScale(destRect.width / containerSize.width,
4615 0 : destRect.height / containerSize.height);
4616 0 : aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
4617 0 : }
4618 :
4619 : already_AddRefed<ImageContainer>
4620 0 : nsDisplayImageContainer::GetContainer(LayerManager* aManager,
4621 : nsDisplayListBuilder *aBuilder)
4622 : {
4623 0 : nsCOMPtr<imgIContainer> image = GetImage();
4624 0 : if (!image) {
4625 0 : MOZ_ASSERT_UNREACHABLE("Must call CanOptimizeToImage() and get true "
4626 : "before calling GetContainer()");
4627 : return nullptr;
4628 : }
4629 :
4630 0 : uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
4631 0 : if (aBuilder->ShouldSyncDecodeImages()) {
4632 0 : flags |= imgIContainer::FLAG_SYNC_DECODE;
4633 : }
4634 :
4635 0 : RefPtr<ImageContainer> container = image->GetImageContainer(aManager, flags);
4636 0 : if (!container || !container->HasCurrentImage()) {
4637 : return nullptr;
4638 : }
4639 :
4640 : return container.forget();
4641 : }
4642 :
4643 : bool
4644 0 : nsDisplayImageContainer::CanOptimizeToImageLayer(LayerManager* aManager,
4645 : nsDisplayListBuilder* aBuilder)
4646 : {
4647 0 : uint32_t flags = aBuilder->ShouldSyncDecodeImages()
4648 0 : ? imgIContainer::FLAG_SYNC_DECODE
4649 0 : : imgIContainer::FLAG_NONE;
4650 :
4651 0 : nsCOMPtr<imgIContainer> image = GetImage();
4652 0 : if (!image) {
4653 : return false;
4654 : }
4655 :
4656 0 : if (!image->IsImageContainerAvailable(aManager, flags)) {
4657 : return false;
4658 : }
4659 :
4660 : int32_t imageWidth;
4661 : int32_t imageHeight;
4662 0 : image->GetWidth(&imageWidth);
4663 0 : image->GetHeight(&imageHeight);
4664 :
4665 0 : if (imageWidth == 0 || imageHeight == 0) {
4666 0 : NS_ASSERTION(false, "invalid image size");
4667 0 : return false;
4668 : }
4669 :
4670 0 : const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
4671 : const LayoutDeviceRect destRect(
4672 0 : LayoutDeviceIntRect::FromAppUnitsToNearest(GetDestRect(), factor));
4673 :
4674 : // Calculate the scaling factor for the frame.
4675 0 : const gfxSize scale = gfxSize(destRect.width / imageWidth,
4676 0 : destRect.height / imageHeight);
4677 :
4678 0 : if (scale.width < 0.34 || scale.height < 0.34) {
4679 : // This would look awful as long as we can't use high-quality downscaling
4680 : // for image layers (bug 803703), so don't turn this into an image layer.
4681 : return false;
4682 : }
4683 :
4684 0 : if (mFrame->IsImageFrame()) {
4685 : // Image layer doesn't support draw focus ring for image map.
4686 0 : nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
4687 0 : if (f->HasImageMap()) {
4688 : return false;
4689 : }
4690 : }
4691 :
4692 : return true;
4693 : }
4694 :
4695 : void
4696 0 : nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
4697 : float aOpacity,
4698 : const DisplayItemClipChain* aClip)
4699 : {
4700 0 : NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
4701 0 : mColor.a = mColor.a * aOpacity;
4702 0 : IntersectClip(aBuilder, aClip, false);
4703 0 : }
4704 :
4705 : bool
4706 8 : nsDisplayBackgroundColor::CanApplyOpacity() const
4707 : {
4708 8 : return true;
4709 : }
4710 :
4711 : LayerState
4712 0 : nsDisplayBackgroundColor::GetLayerState(nsDisplayListBuilder* aBuilder,
4713 : LayerManager* aManager,
4714 : const ContainerLayerParameters& aParameters)
4715 : {
4716 112 : StyleGeometryBox clip = mBackgroundStyle->StyleBackground()->mImage.mLayers[0].mClip;
4717 56 : if (ForceActiveLayers() && clip != StyleGeometryBox::Text) {
4718 : return LAYER_ACTIVE;
4719 : }
4720 56 : return LAYER_NONE;
4721 : }
4722 :
4723 : already_AddRefed<Layer>
4724 0 : nsDisplayBackgroundColor::BuildLayer(nsDisplayListBuilder* aBuilder,
4725 : LayerManager* aManager,
4726 : const ContainerLayerParameters& aContainerParameters)
4727 : {
4728 0 : if (mColor == Color()) {
4729 : return nullptr;
4730 : }
4731 :
4732 : RefPtr<ColorLayer> layer = static_cast<ColorLayer*>
4733 0 : (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
4734 0 : if (!layer) {
4735 0 : layer = aManager->CreateColorLayer();
4736 0 : if (!layer)
4737 : return nullptr;
4738 : }
4739 0 : layer->SetColor(mColor);
4740 :
4741 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
4742 0 : layer->SetBounds(mBackgroundRect.ToNearestPixels(appUnitsPerDevPixel));
4743 0 : layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
4744 0 : aContainerParameters.mOffset.y, 0));
4745 :
4746 0 : return layer.forget();
4747 : }
4748 :
4749 : bool
4750 0 : nsDisplayBackgroundColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
4751 : mozilla::wr::IpcResourceUpdateQueue& aResources,
4752 : const StackingContextHelper& aSc,
4753 : mozilla::layers::WebRenderLayerManager* aManager,
4754 : nsDisplayListBuilder* aDisplayListBuilder)
4755 : {
4756 0 : if (mColor == Color()) {
4757 : return true;
4758 : }
4759 :
4760 0 : StyleGeometryBox clip = mBackgroundStyle->StyleBackground()->mImage.mLayers[0].mClip;
4761 0 : if (clip == StyleGeometryBox::Text) {
4762 : return false;
4763 : }
4764 :
4765 : LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
4766 0 : mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel());
4767 0 : wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(bounds);
4768 :
4769 0 : aBuilder.PushRect(roundedRect,
4770 : roundedRect,
4771 0 : !BackfaceIsHidden(),
4772 0 : wr::ToColorF(ToDeviceColor(mColor)));
4773 :
4774 0 : return true;
4775 : }
4776 :
4777 : void
4778 0 : nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
4779 : gfxContext* aCtx)
4780 : {
4781 0 : if (mColor == Color()) {
4782 0 : return;
4783 : }
4784 :
4785 : #if 0
4786 : // See https://bugzilla.mozilla.org/show_bug.cgi?id=1148418#c21 for why this
4787 : // results in a precision induced rounding issue that makes the rect one
4788 : // pixel shorter in rare cases. Disabled in favor of the old code for now.
4789 : // Note that the pref layout.css.devPixelsPerPx needs to be set to 1 to
4790 : // reproduce the bug.
4791 : //
4792 : // TODO:
4793 : // This new path does not include support for background-clip:text; need to
4794 : // be fixed if/when we switch to this new code path.
4795 :
4796 : DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
4797 :
4798 : Rect rect = NSRectToSnappedRect(mBackgroundRect,
4799 : mFrame->PresContext()->AppUnitsPerDevPixel(),
4800 : aDrawTarget);
4801 : ColorPattern color(ToDeviceColor(mColor));
4802 : aDrawTarget.FillRect(rect, color);
4803 : #else
4804 1 : gfxContext* ctx = aCtx;
4805 : gfxRect bounds =
4806 : nsLayoutUtils::RectToGfxRect(mBackgroundRect,
4807 26 : mFrame->PresContext()->AppUnitsPerDevPixel());
4808 :
4809 1 : StyleGeometryBox clip = mBackgroundStyle->StyleBackground()->mImage.mLayers[0].mClip;
4810 13 : if (clip == StyleGeometryBox::Text) {
4811 0 : if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
4812 : return;
4813 : }
4814 :
4815 0 : ctx->SetColor(mColor);
4816 0 : ctx->NewPath();
4817 0 : ctx->Rectangle(bounds, true);
4818 0 : ctx->Fill();
4819 0 : ctx->PopGroupAndBlend();
4820 0 : return;
4821 : }
4822 :
4823 13 : ctx->SetColor(mColor);
4824 13 : ctx->NewPath();
4825 13 : ctx->Rectangle(bounds, true);
4826 13 : ctx->Fill();
4827 : #endif
4828 : }
4829 :
4830 : nsRegion
4831 13 : nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4832 : bool* aSnap) const
4833 : {
4834 13 : *aSnap = false;
4835 :
4836 13 : if (mColor.a != 1) {
4837 2 : return nsRegion();
4838 : }
4839 :
4840 22 : if (!mBackgroundStyle)
4841 0 : return nsRegion();
4842 :
4843 :
4844 0 : const nsStyleImageLayers::Layer& bottomLayer = mBackgroundStyle->StyleBackground()->BottomLayer();
4845 11 : if (bottomLayer.mClip == StyleGeometryBox::Text) {
4846 0 : return nsRegion();
4847 : }
4848 :
4849 11 : *aSnap = true;
4850 11 : return nsDisplayBackgroundImage::GetInsideClipRegion(this, bottomLayer.mClip,
4851 22 : mBackgroundRect, mBackgroundRect);
4852 : }
4853 :
4854 : Maybe<nscolor>
4855 0 : nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder) const
4856 : {
4857 0 : return Some(mColor.ToABGR());
4858 : }
4859 :
4860 : void
4861 0 : nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder,
4862 : const nsRect& aRect,
4863 : HitTestState* aState,
4864 : nsTArray<nsIFrame*> *aOutFrames)
4865 : {
4866 0 : if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
4867 : // aRect doesn't intersect our border-radius curve.
4868 : return;
4869 : }
4870 :
4871 0 : aOutFrames->AppendElement(mFrame);
4872 : }
4873 :
4874 : void
4875 0 : nsDisplayBackgroundColor::WriteDebugInfo(std::stringstream& aStream)
4876 : {
4877 0 : aStream << " (rgba " << mColor.r << "," << mColor.g << ","
4878 0 : << mColor.b << "," << mColor.a << ")";
4879 0 : }
4880 :
4881 : already_AddRefed<Layer>
4882 0 : nsDisplayClearBackground::BuildLayer(nsDisplayListBuilder* aBuilder,
4883 : LayerManager* aManager,
4884 : const ContainerLayerParameters& aParameters)
4885 : {
4886 : RefPtr<ColorLayer> layer = static_cast<ColorLayer*>
4887 0 : (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
4888 0 : if (!layer) {
4889 0 : layer = aManager->CreateColorLayer();
4890 0 : if (!layer)
4891 : return nullptr;
4892 : }
4893 0 : layer->SetColor(Color());
4894 0 : layer->SetMixBlendMode(gfx::CompositionOp::OP_SOURCE);
4895 :
4896 : bool snap;
4897 0 : nsRect bounds = GetBounds(aBuilder, &snap);
4898 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
4899 0 : layer->SetBounds(bounds.ToNearestPixels(appUnitsPerDevPixel)); // XXX Do we need to respect the parent layer's scale here?
4900 :
4901 0 : return layer.forget();
4902 : }
4903 :
4904 : bool
4905 0 : nsDisplayClearBackground::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
4906 : mozilla::wr::IpcResourceUpdateQueue& aResources,
4907 : const StackingContextHelper& aSc,
4908 : mozilla::layers::WebRenderLayerManager* aManager,
4909 : nsDisplayListBuilder* aDisplayListBuilder)
4910 : {
4911 : LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
4912 0 : nsRect(ToReferenceFrame(), mFrame->GetSize()),
4913 0 : mFrame->PresContext()->AppUnitsPerDevPixel());
4914 :
4915 0 : aBuilder.PushClearRect(wr::ToRoundedLayoutRect(bounds));
4916 :
4917 0 : return true;
4918 : }
4919 :
4920 : nsRect
4921 0 : nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder,
4922 : bool* aSnap) const
4923 : {
4924 0 : *aSnap = false;
4925 0 : return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
4926 : }
4927 :
4928 : void
4929 0 : nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
4930 : gfxContext* aCtx) {
4931 : // TODO join outlines together
4932 0 : MOZ_ASSERT(mFrame->StyleOutline()->ShouldPaintOutline(),
4933 : "Should have not created a nsDisplayOutline!");
4934 :
4935 0 : nsPoint offset = ToReferenceFrame();
4936 0 : nsCSSRendering::PaintOutline(mFrame->PresContext(), *aCtx, mFrame,
4937 : GetPaintRect(),
4938 0 : nsRect(offset, mFrame->GetSize()),
4939 0 : mFrame->Style());
4940 0 : }
4941 :
4942 : bool
4943 0 : nsDisplayOutline::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
4944 : mozilla::wr::IpcResourceUpdateQueue& aResources,
4945 : const StackingContextHelper& aSc,
4946 : mozilla::layers::WebRenderLayerManager* aManager,
4947 : nsDisplayListBuilder* aDisplayListBuilder)
4948 : {
4949 0 : ContainerLayerParameters parameter;
4950 :
4951 0 : uint8_t outlineStyle = mFrame->Style()->StyleOutline()->mOutlineStyle;
4952 0 : if (outlineStyle == NS_STYLE_BORDER_STYLE_AUTO && nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
4953 0 : nsITheme* theme = mFrame->PresContext()->GetTheme();
4954 0 : if (theme && theme->ThemeSupportsWidget(mFrame->PresContext(), mFrame,
4955 0 : NS_THEME_FOCUS_OUTLINE)) {
4956 : return false;
4957 : }
4958 : }
4959 :
4960 0 : nsPoint offset = ToReferenceFrame();
4961 :
4962 : mozilla::Maybe<nsCSSBorderRenderer> borderRenderer =
4963 0 : nsCSSRendering::CreateBorderRendererForOutline(mFrame->PresContext(),
4964 : nullptr, mFrame,
4965 : GetPaintRect(),
4966 0 : nsRect(offset, mFrame->GetSize()),
4967 0 : mFrame->Style());
4968 :
4969 0 : if (!borderRenderer) {
4970 : // No border renderer means "there is no outline".
4971 : // Paint nothing and return success.
4972 : return true;
4973 : }
4974 :
4975 0 : borderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
4976 0 : return true;
4977 : }
4978 :
4979 : bool
4980 0 : nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect) const
4981 : {
4982 0 : const nsStyleOutline* outline = mFrame->StyleOutline();
4983 0 : nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
4984 0 : if (borderBox.Contains(aRect) &&
4985 0 : !nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) {
4986 0 : if (outline->mOutlineOffset >= 0) {
4987 : // aRect is entirely inside the border-rect, and the outline isn't
4988 : // rendered inside the border-rect, so the outline is not visible.
4989 : return true;
4990 : }
4991 : }
4992 :
4993 0 : return false;
4994 : }
4995 :
4996 : void
4997 0 : nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder,
4998 : const nsRect& aRect,
4999 : HitTestState* aState,
5000 : nsTArray<nsIFrame*> *aOutFrames)
5001 : {
5002 0 : if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
5003 : // aRect doesn't intersect our border-radius curve.
5004 : return;
5005 : }
5006 :
5007 0 : aOutFrames->AppendElement(mFrame);
5008 : }
5009 :
5010 : bool
5011 0 : nsDisplayEventReceiver::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5012 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5013 : const StackingContextHelper& aSc,
5014 : mozilla::layers::WebRenderLayerManager* aManager,
5015 : nsDisplayListBuilder* aDisplayListBuilder)
5016 : {
5017 : // This display item should never be getting created when building a display
5018 : // list for WebRender consumption, so this function should never get called.
5019 0 : MOZ_ASSERT(false);
5020 : return true;
5021 : }
5022 :
5023 114 : nsDisplayCompositorHitTestInfo::nsDisplayCompositorHitTestInfo(nsDisplayListBuilder* aBuilder,
5024 : nsIFrame* aFrame,
5025 : mozilla::gfx::CompositorHitTestInfo aHitTestInfo,
5026 : uint32_t aIndex,
5027 0 : const mozilla::Maybe<nsRect>& aArea)
5028 : : nsDisplayEventReceiver(aBuilder, aFrame)
5029 : , mHitTestInfo(aHitTestInfo)
5030 : , mIndex(aIndex)
5031 0 : , mAppUnitsPerDevPixel(mFrame->PresContext()->AppUnitsPerDevPixel())
5032 : {
5033 114 : MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
5034 : // We should never even create this display item if we're not building
5035 : // compositor hit-test info or if the computed hit info indicated the
5036 : // frame is invisible to hit-testing
5037 114 : MOZ_ASSERT(aBuilder->BuildCompositorHitTestInfo());
5038 114 : MOZ_ASSERT(mHitTestInfo != mozilla::gfx::CompositorHitTestInfo::eInvisibleToHitTest);
5039 :
5040 228 : if (aBuilder->GetCurrentScrollbarDirection().isSome()) {
5041 : // In the case of scrollbar frames, we use the scrollbar's target scrollframe
5042 : // instead of the scrollframe with which the scrollbar actually moves.
5043 0 : MOZ_ASSERT(mHitTestInfo & CompositorHitTestInfo::eScrollbar);
5044 0 : mScrollTarget = Some(aBuilder->GetCurrentScrollbarTarget());
5045 : }
5046 :
5047 114 : if (aArea.isSome()) {
5048 0 : mArea = *aArea;
5049 : } else {
5050 114 : mArea = GetFrameArea(aBuilder, aFrame);
5051 : }
5052 114 : }
5053 :
5054 : bool
5055 0 : nsDisplayCompositorHitTestInfo::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5056 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5057 : const StackingContextHelper& aSc,
5058 : mozilla::layers::WebRenderLayerManager* aManager,
5059 : nsDisplayListBuilder* aDisplayListBuilder)
5060 : {
5061 0 : if (mArea.IsEmpty()) {
5062 : return true;
5063 : }
5064 :
5065 : // XXX: eventually this scrollId computation and the SetHitTestInfo
5066 : // call will get moved out into the WR display item iteration code so that
5067 : // we don't need to do it as often, and so that we can do it for other
5068 : // display item types as well (reducing the need for as many instances of
5069 : // this display item).
5070 0 : FrameMetrics::ViewID scrollId = mScrollTarget.valueOrFrom(
5071 0 : [&]() -> FrameMetrics::ViewID {
5072 0 : const ActiveScrolledRoot* asr = GetActiveScrolledRoot();
5073 : Maybe<FrameMetrics::ViewID> fixedTarget =
5074 0 : aBuilder.GetContainingFixedPosScrollTarget(asr);
5075 0 : if (fixedTarget) {
5076 0 : return *fixedTarget;
5077 : }
5078 0 : if (asr) {
5079 0 : return asr->GetViewId();
5080 : }
5081 0 : return FrameMetrics::NULL_SCROLL_ID;
5082 0 : });
5083 :
5084 : // Insert a transparent rectangle with the hit-test info
5085 0 : aBuilder.SetHitTestInfo(scrollId, mHitTestInfo);
5086 :
5087 : const LayoutDeviceRect devRect =
5088 0 : LayoutDeviceRect::FromAppUnits(mArea, mAppUnitsPerDevPixel);
5089 :
5090 0 : const wr::LayoutRect rect = wr::ToRoundedLayoutRect(devRect);
5091 :
5092 0 : aBuilder.PushRect(rect, rect, !BackfaceIsHidden(), wr::ToColorF(gfx::Color()));
5093 0 : aBuilder.ClearHitTestInfo();
5094 :
5095 0 : return true;
5096 : }
5097 :
5098 : void
5099 0 : nsDisplayCompositorHitTestInfo::WriteDebugInfo(std::stringstream& aStream)
5100 : {
5101 0 : aStream << nsPrintfCString(" (hitTestInfo 0x%x)", (int)mHitTestInfo).get();
5102 0 : AppendToString(aStream, mArea, " hitTestArea");
5103 0 : }
5104 :
5105 : uint32_t
5106 1 : nsDisplayCompositorHitTestInfo::GetPerFrameKey() const
5107 : {
5108 68 : return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
5109 : }
5110 :
5111 : int32_t
5112 0 : nsDisplayCompositorHitTestInfo::ZIndex() const
5113 : {
5114 0 : return mOverrideZIndex ? *mOverrideZIndex : nsDisplayItem::ZIndex();
5115 : }
5116 :
5117 : void
5118 0 : nsDisplayCompositorHitTestInfo::SetOverrideZIndex(int32_t aZIndex)
5119 : {
5120 0 : mOverrideZIndex = Some(aZIndex);
5121 0 : }
5122 :
5123 1 : nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder,
5124 5 : nsIFrame* aCaretFrame)
5125 : : nsDisplayItem(aBuilder, aCaretFrame)
5126 : , mCaret(aBuilder->GetCaret())
5127 1 : , mBounds(aBuilder->GetCaretRect() + ToReferenceFrame())
5128 : {
5129 1 : MOZ_COUNT_CTOR(nsDisplayCaret);
5130 1 : }
5131 :
5132 : #ifdef NS_BUILD_REFCNT_LOGGING
5133 10 : nsDisplayCaret::~nsDisplayCaret()
5134 : {
5135 5 : MOZ_COUNT_DTOR(nsDisplayCaret);
5136 0 : }
5137 : #endif
5138 :
5139 : nsRect
5140 0 : nsDisplayCaret::GetBounds(nsDisplayListBuilder* aBuilder,
5141 : bool* aSnap) const
5142 : {
5143 18 : *aSnap = true;
5144 : // The caret returns a rect in the coordinates of mFrame.
5145 18 : return mBounds;
5146 : }
5147 :
5148 : void
5149 0 : nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
5150 : gfxContext* aCtx) {
5151 : // Note: Because we exist, we know that the caret is visible, so we don't
5152 : // need to check for the caret's visibility.
5153 4 : mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
5154 2 : }
5155 :
5156 : bool
5157 0 : nsDisplayCaret::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5158 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5159 : const StackingContextHelper& aSc,
5160 : mozilla::layers::WebRenderLayerManager* aManager,
5161 : nsDisplayListBuilder* aDisplayListBuilder)
5162 : {
5163 : using namespace mozilla::layers;
5164 : int32_t contentOffset;
5165 0 : nsIFrame* frame = mCaret->GetFrame(&contentOffset);
5166 0 : if (!frame) {
5167 : return true;
5168 : }
5169 0 : NS_ASSERTION(frame == mFrame, "We're referring different frame");
5170 :
5171 0 : int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
5172 :
5173 0 : nsRect caretRect;
5174 0 : nsRect hookRect;
5175 0 : mCaret->ComputeCaretRects(frame, contentOffset, &caretRect, &hookRect);
5176 :
5177 0 : gfx::Color color = ToDeviceColor(frame->GetCaretColorAt(contentOffset));
5178 : LayoutDeviceRect devCaretRect = LayoutDeviceRect::FromAppUnits(
5179 0 : caretRect + ToReferenceFrame(), appUnitsPerDevPixel);
5180 : LayoutDeviceRect devHookRect = LayoutDeviceRect::FromAppUnits(
5181 0 : hookRect + ToReferenceFrame(), appUnitsPerDevPixel);
5182 :
5183 0 : wr::LayoutRect caret = wr::ToRoundedLayoutRect(devCaretRect);
5184 0 : wr::LayoutRect hook = wr::ToRoundedLayoutRect(devHookRect);
5185 :
5186 : // Note, WR will pixel snap anything that is layout aligned.
5187 0 : aBuilder.PushRect(caret,
5188 : caret,
5189 0 : !BackfaceIsHidden(),
5190 0 : wr::ToColorF(color));
5191 :
5192 0 : if (!devHookRect.IsEmpty()) {
5193 0 : aBuilder.PushRect(hook,
5194 : hook,
5195 0 : !BackfaceIsHidden(),
5196 0 : wr::ToColorF(color));
5197 : }
5198 : return true;
5199 : }
5200 :
5201 48 : nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
5202 : : nsDisplayItem(aBuilder, aFrame)
5203 288 : , mBorderIsEmpty(false)
5204 : {
5205 1 : MOZ_COUNT_CTOR(nsDisplayBorder);
5206 :
5207 48 : mBounds = CalculateBounds<nsRect>(*mFrame->StyleBorder());
5208 48 : }
5209 :
5210 : bool
5211 1 : nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect) const
5212 : {
5213 36 : nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
5214 1 : ToReferenceFrame();
5215 : const nsStyleBorder *styleBorder;
5216 1 : if (paddingRect.Contains(aRect) &&
5217 16 : !(styleBorder = mFrame->StyleBorder())->IsBorderImageLoaded() &&
5218 2 : !nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) {
5219 : // aRect is entirely inside the content rect, and no part
5220 : // of the border is rendered inside the content rect, so we are not
5221 : // visible
5222 : // Skip this if there's a border-image (which draws a background
5223 : // too) or if there is a border-radius (which makes the border draw
5224 : // further in).
5225 : return true;
5226 : }
5227 :
5228 12 : return false;
5229 : }
5230 :
5231 : nsDisplayItemGeometry*
5232 7 : nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
5233 : {
5234 7 : return new nsDisplayBorderGeometry(this, aBuilder);
5235 : }
5236 :
5237 : void
5238 1 : nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
5239 : const nsDisplayItemGeometry* aGeometry,
5240 : nsRegion* aInvalidRegion) const
5241 : {
5242 1 : const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
5243 : bool snap;
5244 :
5245 41 : if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap))) {
5246 : // We can probably get away with only invalidating the difference
5247 : // between the border and padding rects, but the XUL ui at least
5248 : // is apparently painting a background with this?
5249 0 : aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
5250 : }
5251 :
5252 1 : if (aBuilder->ShouldSyncDecodeImages() &&
5253 0 : geometry->ShouldInvalidateToSyncDecodeImages()) {
5254 0 : aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
5255 : }
5256 1 : }
5257 :
5258 : LayerState
5259 1 : nsDisplayBorder::GetLayerState(nsDisplayListBuilder* aBuilder,
5260 : LayerManager* aManager,
5261 : const ContainerLayerParameters& aParameters)
5262 : {
5263 56 : if (!ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowBorderLayers)) {
5264 : return LAYER_NONE;
5265 : }
5266 :
5267 0 : mBorderIsEmpty = false;
5268 0 : nsPoint offset = ToReferenceFrame();
5269 : Maybe<nsCSSBorderRenderer> br =
5270 0 : nsCSSRendering::CreateBorderRenderer(mFrame->PresContext(),
5271 : nullptr,
5272 : mFrame,
5273 0 : nsRect(),
5274 0 : nsRect(offset, mFrame->GetSize()),
5275 0 : mFrame->Style(),
5276 : &mBorderIsEmpty,
5277 0 : mFrame->GetSkipSides());
5278 :
5279 0 : mBorderRenderer = Nothing();
5280 0 : mBorderImageRenderer = Nothing();
5281 0 : if (!br) {
5282 0 : if (mBorderIsEmpty) {
5283 : return LAYER_ACTIVE;
5284 : }
5285 0 : return LAYER_NONE;
5286 : }
5287 :
5288 0 : if (!br->AllBordersSolid()) {
5289 : return LAYER_NONE;
5290 : }
5291 :
5292 : // We don't support this yet as we don't copy the values to
5293 : // the layer, and BasicBorderLayer doesn't support it yet.
5294 0 : if (!br->mNoBorderRadius) {
5295 : return LAYER_NONE;
5296 : }
5297 :
5298 : // We copy these values correctly to the layer, but BasicBorderLayer
5299 : // won't render them
5300 0 : if (!br->AreBorderSideFinalStylesSame(eSideBitsAll) ||
5301 0 : !br->AllBordersSameWidth()) {
5302 : return LAYER_NONE;
5303 : }
5304 :
5305 0 : NS_FOR_CSS_SIDES(i) {
5306 0 : if (br->mBorderStyles[i] == NS_STYLE_BORDER_STYLE_SOLID) {
5307 0 : mColors[i] = ToDeviceColor(br->mBorderColors[i]);
5308 0 : mWidths[i] = br->mBorderWidths[i];
5309 0 : mBorderStyles[i] = br->mBorderStyles[i];
5310 : } else {
5311 0 : mWidths[i] = 0;
5312 : }
5313 : }
5314 0 : NS_FOR_CSS_FULL_CORNERS(corner) {
5315 0 : mCorners[corner] = LayerSize(br->mBorderRadii[corner].width, br->mBorderRadii[corner].height);
5316 : }
5317 :
5318 0 : mRect = ViewAs<LayerPixel>(br->mOuterRect);
5319 0 : return LAYER_ACTIVE;
5320 : }
5321 :
5322 : already_AddRefed<Layer>
5323 0 : nsDisplayBorder::BuildLayer(nsDisplayListBuilder* aBuilder,
5324 : LayerManager* aManager,
5325 : const ContainerLayerParameters& aContainerParameters)
5326 : {
5327 0 : if (mBorderIsEmpty) {
5328 : return nullptr;
5329 : }
5330 :
5331 : RefPtr<BorderLayer> layer = static_cast<BorderLayer*>
5332 0 : (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
5333 0 : if (!layer) {
5334 0 : layer = aManager->CreateBorderLayer();
5335 0 : if (!layer)
5336 : return nullptr;
5337 : }
5338 0 : layer->SetRect(mRect);
5339 0 : layer->SetCornerRadii(mCorners);
5340 0 : layer->SetColors(mColors);
5341 0 : layer->SetWidths(mWidths);
5342 0 : layer->SetStyles(mBorderStyles);
5343 0 : layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
5344 0 : aContainerParameters.mOffset.y, 0));
5345 0 : return layer.forget();
5346 : }
5347 :
5348 : bool
5349 0 : nsDisplayBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5350 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5351 : const StackingContextHelper& aSc,
5352 : mozilla::layers::WebRenderLayerManager* aManager,
5353 : nsDisplayListBuilder* aDisplayListBuilder)
5354 : {
5355 0 : nsRect rect = nsRect(ToReferenceFrame(), mFrame->GetSize());
5356 :
5357 0 : return nsCSSRendering::CreateWebRenderCommandsForBorder(this,
5358 : mFrame,
5359 : rect,
5360 : aBuilder,
5361 : aResources,
5362 : aSc,
5363 : aManager,
5364 0 : aDisplayListBuilder);
5365 : };
5366 :
5367 : void
5368 0 : nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5369 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5370 : const StackingContextHelper& aSc,
5371 : mozilla::layers::WebRenderLayerManager* aManager,
5372 : nsDisplayListBuilder* aDisplayListBuilder)
5373 : {
5374 0 : MOZ_ASSERT(mBorderImageRenderer);
5375 0 : if (!mBorderImageRenderer->mImageRenderer.IsReady()) {
5376 0 : return;
5377 : }
5378 :
5379 : float widths[4];
5380 : float slice[4];
5381 : float outset[4];
5382 0 : const int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
5383 0 : NS_FOR_CSS_SIDES(i) {
5384 0 : slice[i] = (float)(mBorderImageRenderer->mSlice.Side(i)) / appUnitsPerDevPixel;
5385 0 : widths[i] = (float)(mBorderImageRenderer->mWidths.Side(i)) / appUnitsPerDevPixel;
5386 0 : outset[i] = (float)(mBorderImageRenderer->mImageOutset.Side(i)) / appUnitsPerDevPixel;
5387 : }
5388 :
5389 : LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(
5390 0 : mBorderImageRenderer->mArea, appUnitsPerDevPixel);
5391 0 : wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
5392 :
5393 0 : wr::LayoutRect clip = dest;
5394 0 : if (!mBorderImageRenderer->mClip.IsEmpty()) {
5395 : LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(
5396 0 : mBorderImageRenderer->mClip, appUnitsPerDevPixel);
5397 0 : clip = wr::ToRoundedLayoutRect(clipRect);
5398 : }
5399 :
5400 0 : switch (mBorderImageRenderer->mImageRenderer.GetType()) {
5401 : case eStyleImageType_Image:
5402 : {
5403 0 : uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
5404 0 : if (aDisplayListBuilder->IsPaintingToWindow()) {
5405 0 : flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
5406 : }
5407 0 : if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
5408 0 : flags |= imgIContainer::FLAG_SYNC_DECODE;
5409 : }
5410 :
5411 0 : RefPtr<imgIContainer> img = mBorderImageRenderer->mImageRenderer.GetImage();
5412 0 : Maybe<SVGImageContext> svgContext;
5413 : gfx::IntSize decodeSize =
5414 : nsLayoutUtils::ComputeImageContainerDrawingParameters(img, mFrame, destRect,
5415 0 : aSc, flags, svgContext);
5416 : RefPtr<layers::ImageContainer> container =
5417 0 : img->GetImageContainerAtSize(aManager, decodeSize, svgContext, flags);
5418 0 : if (!container) {
5419 0 : return;
5420 : }
5421 :
5422 0 : gfx::IntSize size;
5423 0 : Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(this, container, aBuilder,
5424 0 : aResources, aSc, size, Nothing());
5425 0 : if (key.isNothing()) {
5426 : return;
5427 : }
5428 :
5429 0 : aBuilder.PushBorderImage(dest,
5430 : clip,
5431 0 : !BackfaceIsHidden(),
5432 0 : wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
5433 : key.value(),
5434 0 : (float)(mBorderImageRenderer->mImageSize.width) / appUnitsPerDevPixel,
5435 0 : (float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
5436 0 : wr::ToSideOffsets2D_u32(slice[0], slice[1], slice[2], slice[3]),
5437 0 : wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]),
5438 0 : wr::ToRepeatMode(mBorderImageRenderer->mRepeatModeHorizontal),
5439 0 : wr::ToRepeatMode(mBorderImageRenderer->mRepeatModeVertical));
5440 0 : break;
5441 : }
5442 : case eStyleImageType_Gradient:
5443 : {
5444 0 : RefPtr<nsStyleGradient> gradientData = mBorderImageRenderer->mImageRenderer.GetGradientData();
5445 : nsCSSGradientRenderer renderer =
5446 0 : nsCSSGradientRenderer::Create(mFrame->PresContext(), mFrame->Style(),
5447 0 : gradientData, mBorderImageRenderer->mImageSize);
5448 :
5449 : wr::ExtendMode extendMode;
5450 0 : nsTArray<wr::GradientStop> stops;
5451 0 : LayoutDevicePoint lineStart;
5452 0 : LayoutDevicePoint lineEnd;
5453 0 : LayoutDeviceSize gradientRadius;
5454 0 : renderer.BuildWebRenderParameters(1.0, extendMode, stops, lineStart, lineEnd, gradientRadius);
5455 :
5456 0 : if (gradientData->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
5457 0 : LayoutDevicePoint startPoint = LayoutDevicePoint(dest.origin.x, dest.origin.y) + lineStart;
5458 0 : LayoutDevicePoint endPoint = LayoutDevicePoint(dest.origin.x, dest.origin.y) + lineEnd;
5459 :
5460 0 : aBuilder.PushBorderGradient(dest,
5461 : clip,
5462 0 : !BackfaceIsHidden(),
5463 0 : wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
5464 0 : wr::ToLayoutPoint(startPoint),
5465 0 : wr::ToLayoutPoint(endPoint),
5466 : stops,
5467 : extendMode,
5468 0 : wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
5469 : } else {
5470 0 : aBuilder.PushBorderRadialGradient(dest,
5471 : clip,
5472 0 : !BackfaceIsHidden(),
5473 0 : wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
5474 0 : wr::ToLayoutPoint(lineStart),
5475 0 : wr::ToLayoutSize(gradientRadius),
5476 : stops,
5477 : extendMode,
5478 0 : wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
5479 : }
5480 : break;
5481 : }
5482 : default:
5483 0 : MOZ_ASSERT_UNREACHABLE("Unsupport border image type");
5484 : }
5485 : }
5486 :
5487 : void
5488 0 : nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
5489 : gfxContext* aCtx) {
5490 24 : nsPoint offset = ToReferenceFrame();
5491 :
5492 1 : PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
5493 1 : ? PaintBorderFlags::SYNC_DECODE_IMAGES
5494 12 : : PaintBorderFlags();
5495 :
5496 : ImgDrawResult result =
5497 60 : nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
5498 : GetPaintRect(),
5499 1 : nsRect(offset, mFrame->GetSize()),
5500 1 : mFrame->Style(),
5501 : flags,
5502 1 : mFrame->GetSkipSides());
5503 :
5504 1 : nsDisplayBorderGeometry::UpdateDrawResult(this, result);
5505 1 : }
5506 :
5507 : nsRect
5508 172 : nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder,
5509 : bool* aSnap) const
5510 : {
5511 172 : *aSnap = true;
5512 172 : return mBounds;
5513 : }
5514 :
5515 : // Given a region, compute a conservative approximation to it as a list
5516 : // of rectangles that aren't vertically adjacent (i.e., vertically
5517 : // adjacent or overlapping rectangles are combined).
5518 : // Right now this is only approximate, some vertically overlapping rectangles
5519 : // aren't guaranteed to be combined.
5520 : static void
5521 4 : ComputeDisjointRectangles(const nsRegion& aRegion,
5522 : nsTArray<nsRect>* aRects) {
5523 4 : nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25);
5524 8 : nsRect accumulated;
5525 :
5526 1 : for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
5527 20 : const nsRect& r = iter.Get();
5528 24 : if (accumulated.IsEmpty()) {
5529 4 : accumulated = r;
5530 1 : continue;
5531 : }
5532 :
5533 1 : if (accumulated.YMost() >= r.y - accumulationMargin) {
5534 1 : accumulated.UnionRect(accumulated, r);
5535 : } else {
5536 0 : aRects->AppendElement(accumulated);
5537 0 : accumulated = r;
5538 : }
5539 : }
5540 :
5541 : // Finish the in-flight rectangle, if there is one.
5542 8 : if (!accumulated.IsEmpty()) {
5543 1 : aRects->AppendElement(accumulated);
5544 : }
5545 4 : }
5546 :
5547 : void
5548 1 : nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
5549 : gfxContext* aCtx) {
5550 8 : nsPoint offset = ToReferenceFrame();
5551 8 : nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
5552 1 : nsPresContext* presContext = mFrame->PresContext();
5553 8 : AutoTArray<nsRect,10> rects;
5554 4 : ComputeDisjointRectangles(mVisibleRegion, &rects);
5555 :
5556 8 : AUTO_PROFILER_LABEL("nsDisplayBoxShadowOuter::Paint", GRAPHICS);
5557 :
5558 1 : for (uint32_t i = 0; i < rects.Length(); ++i) {
5559 1 : nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
5560 1 : borderRect, rects[i], mOpacity);
5561 : }
5562 4 : }
5563 :
5564 : nsRect
5565 1 : nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
5566 : bool* aSnap) const
5567 : {
5568 1 : *aSnap = false;
5569 1 : return mBounds;
5570 : }
5571 :
5572 : nsRect
5573 16 : nsDisplayBoxShadowOuter::GetBoundsInternal() {
5574 1 : return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame, mFrame->GetSize()) +
5575 48 : ToReferenceFrame();
5576 : }
5577 :
5578 : bool
5579 4 : nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect) const
5580 : {
5581 8 : nsPoint origin = ToReferenceFrame();
5582 1 : nsRect frameRect(origin, mFrame->GetSize());
5583 4 : if (!frameRect.Contains(aRect))
5584 : return false;
5585 :
5586 : // the visible region is entirely inside the border-rect, and box shadows
5587 : // never render within the border-rect (unless there's a border radius).
5588 : nscoord twipsRadii[8];
5589 0 : bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
5590 0 : if (!hasBorderRadii)
5591 : return true;
5592 :
5593 0 : return RoundedRectContainsRect(frameRect, twipsRadii, aRect);
5594 : }
5595 :
5596 : bool
5597 8 : nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
5598 : nsRegion* aVisibleRegion) {
5599 1 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
5600 : return false;
5601 : }
5602 :
5603 8 : mVisibleRegion.And(*aVisibleRegion, GetPaintRect());
5604 4 : return true;
5605 : }
5606 :
5607 : bool
5608 0 : nsDisplayBoxShadowOuter::CanBuildWebRenderDisplayItems()
5609 : {
5610 0 : nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
5611 0 : if (!shadows) {
5612 : return false;
5613 : }
5614 :
5615 : bool hasBorderRadius;
5616 : bool nativeTheme =
5617 0 : nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
5618 :
5619 : // We don't support native themed things yet like box shadows around
5620 : // input buttons.
5621 0 : if (nativeTheme) {
5622 : return false;
5623 : }
5624 :
5625 0 : return true;
5626 : }
5627 :
5628 : bool
5629 0 : nsDisplayBoxShadowOuter::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5630 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5631 : const StackingContextHelper& aSc,
5632 : mozilla::layers::WebRenderLayerManager* aManager,
5633 : nsDisplayListBuilder* aDisplayListBuilder)
5634 : {
5635 0 : if (!CanBuildWebRenderDisplayItems()) {
5636 : return false;
5637 : }
5638 :
5639 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
5640 0 : nsPoint offset = ToReferenceFrame();
5641 0 : nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
5642 0 : AutoTArray<nsRect,10> rects;
5643 : bool snap;
5644 0 : nsRect bounds = GetBounds(aDisplayListBuilder, &snap);
5645 0 : ComputeDisjointRectangles(bounds, &rects);
5646 :
5647 : bool hasBorderRadius;
5648 0 : bool nativeTheme = nsCSSRendering::HasBoxShadowNativeTheme(mFrame,
5649 0 : hasBorderRadius);
5650 :
5651 : // Don't need the full size of the shadow rect like we do in
5652 : // nsCSSRendering since WR takes care of calculations for blur
5653 : // and spread radius.
5654 : nsRect frameRect = nsCSSRendering::GetShadowRect(borderRect,
5655 : nativeTheme,
5656 0 : mFrame);
5657 :
5658 0 : RectCornerRadii borderRadii;
5659 0 : if (hasBorderRadius) {
5660 0 : hasBorderRadius = nsCSSRendering::GetBorderRadii(frameRect,
5661 : borderRect,
5662 : mFrame,
5663 : borderRadii);
5664 : }
5665 :
5666 : // Everything here is in app units, change to device units.
5667 0 : for (uint32_t i = 0; i < rects.Length(); ++i) {
5668 : LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(
5669 0 : rects[i], appUnitsPerDevPixel);
5670 0 : nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
5671 0 : MOZ_ASSERT(shadows);
5672 :
5673 0 : for (uint32_t j = shadows->Length(); j > 0; j--) {
5674 0 : nsCSSShadowItem* shadow = shadows->ShadowAt(j - 1);
5675 0 : if (shadow->mInset) {
5676 0 : continue;
5677 : }
5678 :
5679 0 : float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
5680 : gfx::Color shadowColor = nsCSSRendering::GetShadowColor(shadow,
5681 : mFrame,
5682 0 : mOpacity);
5683 :
5684 : // We don't move the shadow rect here since WR does it for us
5685 : // Now translate everything to device pixels.
5686 0 : nsRect shadowRect = frameRect;
5687 : LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
5688 0 : nsPoint(shadow->mXOffset, shadow->mYOffset),
5689 0 : appUnitsPerDevPixel);
5690 :
5691 : LayoutDeviceRect deviceBox = LayoutDeviceRect::FromAppUnits(
5692 0 : shadowRect, appUnitsPerDevPixel);
5693 0 : wr::LayoutRect deviceBoxRect = wr::ToRoundedLayoutRect(deviceBox);
5694 0 : wr::LayoutRect deviceClipRect = wr::ToRoundedLayoutRect(clipRect);
5695 :
5696 0 : LayoutDeviceSize zeroSize;
5697 : wr::BorderRadius borderRadius = wr::ToBorderRadius(zeroSize, zeroSize,
5698 0 : zeroSize, zeroSize);
5699 0 : if (hasBorderRadius) {
5700 : borderRadius = wr::ToBorderRadius(
5701 0 : LayoutDeviceSize::FromUnknownSize(borderRadii.TopLeft()),
5702 0 : LayoutDeviceSize::FromUnknownSize(borderRadii.TopRight()),
5703 0 : LayoutDeviceSize::FromUnknownSize(borderRadii.BottomLeft()),
5704 0 : LayoutDeviceSize::FromUnknownSize(borderRadii.BottomRight()));
5705 : }
5706 :
5707 0 : float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
5708 :
5709 0 : aBuilder.PushBoxShadow(deviceBoxRect,
5710 : deviceClipRect,
5711 0 : !BackfaceIsHidden(),
5712 : deviceBoxRect,
5713 0 : wr::ToLayoutVector2D(shadowOffset),
5714 0 : wr::ToColorF(shadowColor),
5715 : blurRadius,
5716 : spreadRadius,
5717 : borderRadius,
5718 0 : wr::BoxShadowClipMode::Outset);
5719 : }
5720 : }
5721 :
5722 : return true;
5723 : }
5724 :
5725 : void
5726 14 : nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
5727 : const nsDisplayItemGeometry* aGeometry,
5728 : nsRegion* aInvalidRegion) const
5729 : {
5730 : const nsDisplayBoxShadowOuterGeometry* geometry =
5731 14 : static_cast<const nsDisplayBoxShadowOuterGeometry*>(aGeometry);
5732 : bool snap;
5733 0 : if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
5734 42 : !geometry->mBorderRect.IsEqualInterior(GetBorderRect()) ||
5735 14 : mOpacity != geometry->mOpacity) {
5736 0 : nsRegion oldShadow, newShadow;
5737 : nscoord dontCare[8];
5738 0 : bool hasBorderRadius = mFrame->GetBorderRadii(dontCare);
5739 0 : if (hasBorderRadius) {
5740 : // If we have rounded corners then we need to invalidate the frame area
5741 : // too since we paint into it.
5742 0 : oldShadow = geometry->mBounds;
5743 0 : newShadow = GetBounds(aBuilder, &snap);
5744 : } else {
5745 0 : oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
5746 0 : newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
5747 : }
5748 0 : aInvalidRegion->Or(oldShadow, newShadow);
5749 : }
5750 14 : }
5751 :
5752 :
5753 : void
5754 0 : nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
5755 : gfxContext* aCtx) {
5756 0 : nsPoint offset = ToReferenceFrame();
5757 0 : nsRect borderRect = nsRect(offset, mFrame->GetSize());
5758 0 : nsPresContext* presContext = mFrame->PresContext();
5759 0 : AutoTArray<nsRect,10> rects;
5760 0 : ComputeDisjointRectangles(mVisibleRegion, &rects);
5761 :
5762 0 : AUTO_PROFILER_LABEL("nsDisplayBoxShadowInner::Paint", GRAPHICS);
5763 :
5764 0 : DrawTarget* drawTarget = aCtx->GetDrawTarget();
5765 0 : gfxContext* gfx = aCtx;
5766 0 : int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
5767 :
5768 0 : for (uint32_t i = 0; i < rects.Length(); ++i) {
5769 0 : gfx->Save();
5770 0 : gfx->Clip(NSRectToSnappedRect(rects[i], appUnitsPerDevPixel, *drawTarget));
5771 0 : nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame, borderRect);
5772 0 : gfx->Restore();
5773 : }
5774 0 : }
5775 :
5776 : bool
5777 0 : nsDisplayBoxShadowInner::CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder,
5778 : nsIFrame* aFrame,
5779 : nsPoint aReferenceOffset)
5780 : {
5781 0 : nsCSSShadowArray *shadows = aFrame->StyleEffects()->mBoxShadow;
5782 0 : if (!shadows) {
5783 : // Means we don't have to paint anything
5784 : return true;
5785 : }
5786 :
5787 : bool hasBorderRadius;
5788 : bool nativeTheme =
5789 0 : nsCSSRendering::HasBoxShadowNativeTheme(aFrame, hasBorderRadius);
5790 :
5791 : // We don't support native themed things yet like box shadows around
5792 : // input buttons.
5793 0 : if (nativeTheme) {
5794 : return false;
5795 : }
5796 :
5797 0 : return true;
5798 : }
5799 :
5800 : /* static */ void
5801 0 : nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5802 : const StackingContextHelper& aSc,
5803 : nsRegion& aVisibleRegion,
5804 : nsIFrame* aFrame,
5805 : const nsRect aBorderRect)
5806 : {
5807 0 : if (!nsCSSRendering::ShouldPaintBoxShadowInner(aFrame)) {
5808 0 : return;
5809 : }
5810 :
5811 0 : int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
5812 :
5813 0 : AutoTArray<nsRect,10> rects;
5814 0 : ComputeDisjointRectangles(aVisibleRegion, &rects);
5815 :
5816 0 : nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
5817 :
5818 0 : for (uint32_t i = 0; i < rects.Length(); ++i) {
5819 : LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(
5820 0 : rects[i], appUnitsPerDevPixel);
5821 :
5822 0 : for (uint32_t i = shadows->Length(); i > 0; --i) {
5823 0 : nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
5824 0 : if (!shadowItem->mInset) {
5825 0 : continue;
5826 : }
5827 :
5828 : nsRect shadowRect =
5829 0 : nsCSSRendering::GetBoxShadowInnerPaddingRect(aFrame, aBorderRect);
5830 0 : RectCornerRadii innerRadii;
5831 0 : nsCSSRendering::GetShadowInnerRadii(aFrame, aBorderRect, innerRadii);
5832 :
5833 : // Now translate everything to device pixels.
5834 : LayoutDeviceRect deviceBoxRect = LayoutDeviceRect::FromAppUnits(
5835 0 : shadowRect, appUnitsPerDevPixel);
5836 0 : wr::LayoutRect deviceClipRect = wr::ToRoundedLayoutRect(clipRect);
5837 0 : Color shadowColor = nsCSSRendering::GetShadowColor(shadowItem, aFrame, 1.0);
5838 :
5839 : LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
5840 0 : nsPoint(shadowItem->mXOffset, shadowItem->mYOffset),
5841 0 : appUnitsPerDevPixel);
5842 :
5843 0 : float blurRadius = float(shadowItem->mRadius) / float(appUnitsPerDevPixel);
5844 :
5845 : wr::BorderRadius borderRadius = wr::ToBorderRadius(
5846 0 : LayoutDeviceSize::FromUnknownSize(innerRadii.TopLeft()),
5847 0 : LayoutDeviceSize::FromUnknownSize(innerRadii.TopRight()),
5848 0 : LayoutDeviceSize::FromUnknownSize(innerRadii.BottomLeft()),
5849 0 : LayoutDeviceSize::FromUnknownSize(innerRadii.BottomRight()));
5850 : // NOTE: Any spread radius > 0 will render nothing. WR Bug.
5851 0 : float spreadRadius = float(shadowItem->mSpread) / float(appUnitsPerDevPixel);
5852 :
5853 0 : aBuilder.PushBoxShadow(wr::ToLayoutRect(deviceBoxRect),
5854 : deviceClipRect,
5855 0 : !aFrame->BackfaceIsHidden(),
5856 0 : wr::ToLayoutRect(deviceBoxRect),
5857 0 : wr::ToLayoutVector2D(shadowOffset),
5858 0 : wr::ToColorF(shadowColor),
5859 : blurRadius,
5860 : spreadRadius,
5861 : borderRadius,
5862 : wr::BoxShadowClipMode::Inset
5863 0 : );
5864 : }
5865 : }
5866 : }
5867 :
5868 : bool
5869 0 : nsDisplayBoxShadowInner::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
5870 : mozilla::wr::IpcResourceUpdateQueue& aResources,
5871 : const StackingContextHelper& aSc,
5872 : mozilla::layers::WebRenderLayerManager* aManager,
5873 : nsDisplayListBuilder* aDisplayListBuilder)
5874 : {
5875 0 : if (!CanCreateWebRenderCommands(aDisplayListBuilder, mFrame, ToReferenceFrame())) {
5876 : return false;
5877 : }
5878 :
5879 : bool snap;
5880 0 : nsRegion visible = GetBounds(aDisplayListBuilder, &snap);
5881 0 : nsPoint offset = ToReferenceFrame();
5882 0 : nsRect borderRect = nsRect(offset, mFrame->GetSize());
5883 0 : nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(aBuilder, aSc, visible,
5884 0 : mFrame, borderRect);
5885 :
5886 : return true;
5887 : }
5888 :
5889 : bool
5890 0 : nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
5891 : nsRegion* aVisibleRegion) {
5892 0 : if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
5893 : return false;
5894 : }
5895 :
5896 0 : mVisibleRegion.And(*aVisibleRegion, GetPaintRect());
5897 0 : return true;
5898 : }
5899 :
5900 1 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
5901 1 : nsIFrame* aFrame, nsDisplayList* aList, bool aAnonymous)
5902 : : nsDisplayWrapList(aBuilder, aFrame, aList,
5903 22 : aBuilder->CurrentActiveScrolledRoot(), false, 0, aAnonymous)
5904 1 : {}
5905 :
5906 136 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
5907 : nsIFrame* aFrame, nsDisplayList* aList,
5908 : const ActiveScrolledRoot* aActiveScrolledRoot,
5909 : bool aClearClipChain,
5910 : uint32_t aIndex,
5911 1 : bool aAnonymous)
5912 : : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot, aAnonymous)
5913 : , mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot())
5914 : , mOverrideZIndex(0)
5915 : , mIndex(aIndex)
5916 : , mHasZIndexOverride(false)
5917 1 : , mClearingClipChain(aClearClipChain)
5918 : {
5919 1 : MOZ_COUNT_CTOR(nsDisplayWrapList);
5920 :
5921 1 : mBaseBuildingRect = GetBuildingRect();
5922 :
5923 1 : mListPtr = &mList;
5924 1 : mListPtr->AppendToTop(aList);
5925 136 : UpdateBounds(aBuilder);
5926 :
5927 1 : if (!aFrame || !aFrame->IsTransformed()) {
5928 1 : return;
5929 : }
5930 :
5931 : // If we're a transformed frame, then we need to find out if we're inside
5932 : // the nsDisplayTransform or outside of it. Frames inside the transform
5933 : // need mReferenceFrame == mFrame, outside needs the next ancestor
5934 : // reference frame.
5935 : // If we're inside the transform, then the nsDisplayItem constructor
5936 : // will have done the right thing.
5937 : // If we're outside the transform, then we should have only one child
5938 : // (since nsDisplayTransform wraps all actual content), and that child
5939 : // will have the correct reference frame set (since nsDisplayTransform
5940 : // handles this explictly).
5941 22 : nsDisplayItem *i = mListPtr->GetBottom();
5942 42 : if (i && (!i->GetAbove() || i->GetType() == DisplayItemType::TYPE_TRANSFORM) &&
5943 1 : i->Frame() == mFrame) {
5944 11 : mReferenceFrame = i->ReferenceFrame();
5945 11 : mToReferenceFrame = i->ToReferenceFrame();
5946 : }
5947 :
5948 : nsRect visible = aBuilder->GetVisibleRect() +
5949 66 : aBuilder->GetCurrentFrameOffsetToReferenceFrame();
5950 :
5951 0 : SetBuildingRect(visible);
5952 : }
5953 :
5954 0 : nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
5955 0 : nsIFrame* aFrame, nsDisplayItem* aItem, bool aAnonymous)
5956 : : nsDisplayItem(aBuilder, aFrame, aBuilder->CurrentActiveScrolledRoot(), aAnonymous)
5957 : , mOverrideZIndex(0)
5958 : , mIndex(0)
5959 0 : , mHasZIndexOverride(false)
5960 : {
5961 0 : MOZ_COUNT_CTOR(nsDisplayWrapList);
5962 :
5963 0 : mBaseBuildingRect = GetBuildingRect();
5964 :
5965 0 : mListPtr = &mList;
5966 0 : mListPtr->AppendToTop(aItem);
5967 0 : UpdateBounds(aBuilder);
5968 :
5969 0 : if (!aFrame || !aFrame->IsTransformed()) {
5970 0 : return;
5971 : }
5972 :
5973 : // See the previous nsDisplayWrapList constructor
5974 0 : if (aItem->Frame() == aFrame) {
5975 0 : mReferenceFrame = aItem->ReferenceFrame();
5976 0 : mToReferenceFrame = aItem->ToReferenceFrame();
5977 : }
5978 :
5979 : nsRect visible = aBuilder->GetVisibleRect() +
5980 0 : aBuilder->GetCurrentFrameOffsetToReferenceFrame();
5981 :
5982 0 : SetBuildingRect(visible);
5983 : }
5984 :
5985 0 : nsDisplayWrapList::~nsDisplayWrapList() {
5986 136 : MOZ_COUNT_DTOR(nsDisplayWrapList);
5987 0 : }
5988 :
5989 : void
5990 0 : nsDisplayWrapList::MergeDisplayListFromItem(nsDisplayListBuilder* aBuilder,
5991 : const nsDisplayItem* aItem)
5992 : {
5993 0 : const nsDisplayWrapList* wrappedItem = aItem->AsDisplayWrapList();
5994 0 : MOZ_ASSERT(wrappedItem);
5995 :
5996 : // Create a new nsDisplayWrapList using a copy-constructor. This is done
5997 : // to preserve the information about bounds.
5998 0 : nsDisplayWrapList* wrapper = MakeDisplayItem<nsDisplayWrapList>(aBuilder, *wrappedItem);
5999 :
6000 : // Set the display list pointer of the new wrapper item to the display list
6001 : // of the wrapped item.
6002 0 : wrapper->mListPtr = wrappedItem->mListPtr;
6003 :
6004 0 : mListPtr->AppendToBottom(wrapper);
6005 0 : }
6006 :
6007 : void
6008 0 : nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
6009 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
6010 0 : mListPtr->HitTest(aBuilder, aRect, aState, aOutFrames);
6011 0 : }
6012 :
6013 : nsRect
6014 1 : nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder,
6015 : bool* aSnap) const
6016 : {
6017 232 : *aSnap = false;
6018 1 : return mBounds;
6019 : }
6020 :
6021 : bool
6022 1 : nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
6023 : nsRegion* aVisibleRegion) {
6024 : // Convert the passed in visible region to our appunits.
6025 32 : nsRegion visibleRegion;
6026 : // mVisibleRect has been clipped to GetClippedBounds
6027 32 : visibleRegion.And(*aVisibleRegion, GetPaintRect());
6028 32 : nsRegion originalVisibleRegion = visibleRegion;
6029 :
6030 : bool retval =
6031 16 : mListPtr->ComputeVisibilityForSublist(aBuilder,
6032 : &visibleRegion,
6033 1 : GetPaintRect());
6034 32 : nsRegion removed;
6035 : // removed = originalVisibleRegion - visibleRegion
6036 1 : removed.Sub(originalVisibleRegion, visibleRegion);
6037 : // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
6038 : // SubtractFromVisibleRegion does)
6039 1 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
6040 :
6041 1 : return retval;
6042 : }
6043 :
6044 : nsRegion
6045 0 : nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
6046 : bool* aSnap) const
6047 : {
6048 0 : *aSnap = false;
6049 0 : nsRegion result;
6050 0 : if (mListPtr->IsOpaque()) {
6051 : // Everything within GetBounds that's visible is opaque.
6052 0 : result = GetBounds(aBuilder, aSnap);
6053 0 : } else if (aBuilder->HitTestIsForVisibility()) {
6054 : // If we care about an accurate opaque region, iterate the display list
6055 : // and build up a region of opaque bounds.
6056 0 : nsDisplayItem* item = mList.GetBottom();
6057 0 : while (item) {
6058 0 : result.OrWith(item->GetOpaqueRegion(aBuilder, aSnap));
6059 0 : item = item->GetAbove();
6060 : }
6061 : }
6062 0 : *aSnap = false;
6063 0 : return result;
6064 : }
6065 :
6066 : Maybe<nscolor>
6067 0 : nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder) const
6068 : {
6069 : // We could try to do something but let's conservatively just return Nothing.
6070 0 : return Nothing();
6071 : }
6072 :
6073 0 : void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
6074 : gfxContext* aCtx) {
6075 0 : NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
6076 0 : }
6077 :
6078 : /**
6079 : * Returns true if all descendant display items can be placed in the same
6080 : * PaintedLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
6081 : * and they all have the expected animated geometry root.
6082 : */
6083 : static LayerState
6084 54 : RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
6085 : LayerManager* aManager,
6086 : const ContainerLayerParameters& aParameters,
6087 : const nsDisplayList& aList,
6088 : AnimatedGeometryRoot* aExpectedAnimatedGeometryRootForChildren)
6089 : {
6090 54 : LayerState result = LAYER_INACTIVE;
6091 158 : for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
6092 208 : if (result == LAYER_INACTIVE &&
6093 104 : i->GetAnimatedGeometryRoot() != aExpectedAnimatedGeometryRootForChildren) {
6094 0 : result = LAYER_ACTIVE;
6095 : }
6096 :
6097 104 : LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
6098 208 : if (state == LAYER_ACTIVE &&
6099 0 : (i->GetType() == DisplayItemType::TYPE_BLEND_MODE ||
6100 0 : i->GetType() == DisplayItemType::TYPE_TABLE_BLEND_MODE)) {
6101 : // nsDisplayBlendMode always returns LAYER_ACTIVE to ensure that the
6102 : // blending operation happens in the intermediate surface of its parent
6103 : // display item (usually an nsDisplayBlendContainer). But this does not
6104 : // mean that it needs all its ancestor display items to become active.
6105 : // So we ignore its layer state and look at its children instead.
6106 0 : state = RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
6107 0 : *i->GetSameCoordinateSystemChildren(), i->GetAnimatedGeometryRoot());
6108 : }
6109 1 : if ((state == LAYER_ACTIVE || state == LAYER_ACTIVE_FORCE) &&
6110 0 : state > result) {
6111 0 : result = state;
6112 : }
6113 104 : if (state == LAYER_ACTIVE_EMPTY && state > result) {
6114 0 : result = LAYER_ACTIVE_FORCE;
6115 : }
6116 104 : if (state == LAYER_NONE) {
6117 0 : nsDisplayList* list = i->GetSameCoordinateSystemChildren();
6118 104 : if (list) {
6119 : LayerState childState =
6120 : RequiredLayerStateForChildren(aBuilder, aManager, aParameters, *list,
6121 0 : aExpectedAnimatedGeometryRootForChildren);
6122 0 : if (childState > result) {
6123 0 : result = childState;
6124 : }
6125 : }
6126 : }
6127 : }
6128 0 : return result;
6129 : }
6130 :
6131 0 : nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const
6132 : {
6133 32 : nsRect bounds;
6134 112 : for (nsDisplayItem* i = mListPtr->GetBottom(); i; i = i->GetAbove()) {
6135 80 : bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
6136 : }
6137 32 : return bounds;
6138 : }
6139 :
6140 : void
6141 0 : nsDisplayWrapList::SetReferenceFrame(const nsIFrame* aFrame)
6142 : {
6143 0 : mReferenceFrame = aFrame;
6144 0 : mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
6145 0 : }
6146 :
6147 : bool
6148 0 : nsDisplayWrapList::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
6149 : mozilla::wr::IpcResourceUpdateQueue& aResources,
6150 : const StackingContextHelper& aSc,
6151 : mozilla::layers::WebRenderLayerManager* aManager,
6152 : nsDisplayListBuilder* aDisplayListBuilder)
6153 : {
6154 0 : aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(GetChildren(),
6155 : this,
6156 : aDisplayListBuilder,
6157 : aSc,
6158 : aBuilder,
6159 0 : aResources);
6160 0 : return true;
6161 : }
6162 :
6163 : static nsresult
6164 0 : WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6165 : nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
6166 0 : if (!aList->GetTop())
6167 : return NS_OK;
6168 0 : nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
6169 0 : if (!item)
6170 : return NS_ERROR_OUT_OF_MEMORY;
6171 : // aList was emptied
6172 0 : aList->AppendToTop(item);
6173 0 : return NS_OK;
6174 : }
6175 :
6176 : static nsresult
6177 0 : WrapEachDisplayItem(nsDisplayListBuilder* aBuilder,
6178 : nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
6179 0 : nsDisplayList newList;
6180 : nsDisplayItem* item;
6181 0 : while ((item = aList->RemoveBottom())) {
6182 0 : item = aWrapper->WrapItem(aBuilder, item);
6183 0 : if (!item)
6184 : return NS_ERROR_OUT_OF_MEMORY;
6185 0 : newList.AppendToTop(item);
6186 : }
6187 : // aList was emptied
6188 0 : aList->AppendToTop(&newList);
6189 0 : return NS_OK;
6190 : }
6191 :
6192 0 : nsresult nsDisplayWrapper::WrapLists(nsDisplayListBuilder* aBuilder,
6193 : nsIFrame* aFrame, const nsDisplayListSet& aIn, const nsDisplayListSet& aOut)
6194 : {
6195 0 : nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn);
6196 0 : NS_ENSURE_SUCCESS(rv, rv);
6197 :
6198 0 : if (&aOut == &aIn)
6199 : return NS_OK;
6200 0 : aOut.BorderBackground()->AppendToTop(aIn.BorderBackground());
6201 0 : aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds());
6202 0 : aOut.Floats()->AppendToTop(aIn.Floats());
6203 0 : aOut.Content()->AppendToTop(aIn.Content());
6204 0 : aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants());
6205 0 : aOut.Outlines()->AppendToTop(aIn.Outlines());
6206 0 : return NS_OK;
6207 : }
6208 :
6209 0 : nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder,
6210 : nsIFrame* aFrame, const nsDisplayListSet& aLists)
6211 : {
6212 : nsresult rv;
6213 0 : if (WrapBorderBackground()) {
6214 : // Our border-backgrounds are in-flow
6215 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this);
6216 0 : NS_ENSURE_SUCCESS(rv, rv);
6217 : }
6218 : // Our block border-backgrounds are in-flow
6219 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this);
6220 0 : NS_ENSURE_SUCCESS(rv, rv);
6221 : // The floats are not in flow
6222 0 : rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this);
6223 0 : NS_ENSURE_SUCCESS(rv, rv);
6224 : // Our child content is in flow
6225 0 : rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this);
6226 0 : NS_ENSURE_SUCCESS(rv, rv);
6227 : // The positioned descendants may not be in-flow
6228 0 : rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
6229 0 : NS_ENSURE_SUCCESS(rv, rv);
6230 : // The outlines may not be in-flow
6231 0 : return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
6232 : }
6233 :
6234 32 : nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
6235 : nsIFrame* aFrame, nsDisplayList* aList,
6236 : const ActiveScrolledRoot* aActiveScrolledRoot,
6237 32 : bool aForEventsAndPluginsOnly)
6238 : : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true)
6239 0 : , mOpacity(aFrame->StyleEffects()->mOpacity)
6240 : , mForEventsAndPluginsOnly(aForEventsAndPluginsOnly)
6241 64 : , mOpacityAppliedToChildren(false)
6242 : {
6243 0 : MOZ_COUNT_CTOR(nsDisplayOpacity);
6244 32 : mState.mOpacity = mOpacity;
6245 32 : }
6246 :
6247 : #ifdef NS_BUILD_REFCNT_LOGGING
6248 64 : nsDisplayOpacity::~nsDisplayOpacity() {
6249 32 : MOZ_COUNT_DTOR(nsDisplayOpacity);
6250 0 : }
6251 : #endif
6252 :
6253 0 : nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
6254 : bool* aSnap) const
6255 : {
6256 0 : *aSnap = false;
6257 : // The only time where mOpacity == 1.0 should be when we have will-change.
6258 : // We could report this as opaque then but when the will-change value starts
6259 : // animating the element would become non opaque and could cause repaints.
6260 6 : return nsRegion();
6261 : }
6262 :
6263 : // nsDisplayOpacity uses layers for rendering
6264 : already_AddRefed<Layer>
6265 0 : nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
6266 : LayerManager* aManager,
6267 : const ContainerLayerParameters& aContainerParameters) {
6268 0 : ContainerLayerParameters params = aContainerParameters;
6269 0 : params.mForEventsAndPluginsOnly = mForEventsAndPluginsOnly;
6270 : RefPtr<Layer> container = aManager->GetLayerBuilder()->
6271 0 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
6272 : params, nullptr,
6273 0 : FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
6274 0 : if (!container)
6275 : return nullptr;
6276 :
6277 0 : container->SetOpacity(mOpacity);
6278 0 : nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
6279 : this, mFrame,
6280 0 : eCSSProperty_opacity);
6281 : return container.forget();
6282 : }
6283 :
6284 : /**
6285 : * This doesn't take into account layer scaling --- the layer may be
6286 : * rendered at a higher (or lower) resolution, affecting the retained layer
6287 : * size --- but this should be good enough.
6288 : */
6289 : static bool
6290 0 : IsItemTooSmallForActiveLayer(nsIFrame* aFrame)
6291 : {
6292 0 : nsIntRect visibleDevPixels = aFrame->GetVisualOverflowRectRelativeToSelf().ToOutsidePixels(
6293 0 : aFrame->PresContext()->AppUnitsPerDevPixel());
6294 0 : return visibleDevPixels.Size() <
6295 0 : nsIntSize(gfxPrefs::LayoutMinActiveLayerSize(),
6296 0 : gfxPrefs::LayoutMinActiveLayerSize());
6297 : }
6298 :
6299 : /* static */ bool
6300 1 : nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
6301 : {
6302 112 : if (EffectCompositor::HasAnimationsForCompositor(aFrame,
6303 112 : eCSSProperty_opacity) ||
6304 56 : (ActiveLayerTracker::IsStyleAnimated(aBuilder, aFrame,
6305 0 : eCSSProperty_opacity) &&
6306 0 : !IsItemTooSmallForActiveLayer(aFrame))) {
6307 : return true;
6308 : }
6309 0 : return false;
6310 : }
6311 :
6312 : void
6313 0 : nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
6314 : float aOpacity,
6315 0 : const DisplayItemClipChain* aClip)
6316 : {
6317 : NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
6318 : mOpacity = mOpacity * aOpacity;
6319 0 : IntersectClip(aBuilder, aClip, false);
6320 : }
6321 :
6322 : bool
6323 0 : nsDisplayOpacity::CanApplyOpacity() const
6324 0 : {
6325 0 : return !EffectCompositor::HasAnimationsForCompositor(mFrame,
6326 0 : eCSSProperty_opacity);
6327 : }
6328 :
6329 0 : /**
6330 : * Recursively iterates through |aList| and collects at most |aMaxChildCount|
6331 0 : * display item pointers to items that return true for CanApplyOpacity().
6332 0 : * The item pointers are added to |aArray|.
6333 : *
6334 : * LayerEventRegions and WrapList items are ignored.
6335 : *
6336 : * We need to do this recursively, because the child display items might contain
6337 : * nested nsDisplayWrapLists.
6338 : *
6339 : * Returns false if there are more than |aMaxChildCount| items, or if an item
6340 : * that returns false for CanApplyOpacity() is encountered.
6341 : * Otherwise returns true.
6342 : */
6343 : static bool
6344 : CollectItemsWithOpacity(nsDisplayList* aList,
6345 : nsTArray<nsDisplayItem*>& aArray,
6346 : const size_t aMaxChildCount)
6347 : {
6348 : for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
6349 : DisplayItemType type = i->GetType();
6350 32 : nsDisplayList* children = i->GetChildren();
6351 :
6352 : // Descend only into wraplists.
6353 : if (type == DisplayItemType::TYPE_WRAP_LIST && children) {
6354 72 : // The current display item has children, process them first.
6355 64 : if (!CollectItemsWithOpacity(children, aArray, aMaxChildCount)) {
6356 0 : return false;
6357 : }
6358 : }
6359 0 :
6360 : if (type == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO ||
6361 0 : type == DisplayItemType::TYPE_WRAP_LIST) {
6362 0 : continue;
6363 : }
6364 :
6365 : if (!i->CanApplyOpacity() || aArray.Length() == aMaxChildCount) {
6366 1 : return false;
6367 : }
6368 :
6369 : aArray.AppendElement(i);
6370 : }
6371 56 :
6372 : return true;
6373 : }
6374 :
6375 16 : bool
6376 : nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder)
6377 : {
6378 8 : // Only try folding our opacity down if we have at most kMaxChildCount
6379 : // children that don't overlap and can all apply the opacity to themselves.
6380 : static const size_t kMaxChildCount = 3;
6381 :
6382 32 : // Iterate through the child display list and copy at most kMaxChildCount
6383 : // child display item pointers to a temporary list.
6384 : AutoTArray<nsDisplayItem*, kMaxChildCount> items;
6385 : if (!CollectItemsWithOpacity(&mList, items, kMaxChildCount)) {
6386 : return false;
6387 : }
6388 :
6389 : struct {
6390 64 : nsDisplayItem* item;
6391 0 : nsRect bounds;
6392 : } children[kMaxChildCount];
6393 :
6394 : bool snap;
6395 48 : size_t childCount = 0;
6396 : for (nsDisplayItem* item : items) {
6397 : children[childCount].item = item;
6398 0 : children[childCount].bounds = item->GetBounds(aBuilder, &snap);
6399 : childCount++;
6400 : }
6401 8 :
6402 0 : for (size_t i = 0; i < childCount; i++) {
6403 8 : for (size_t j = i+1; j < childCount; j++) {
6404 0 : if (children[i].bounds.Intersects(children[j].bounds)) {
6405 8 : return false;
6406 : }
6407 : }
6408 0 : }
6409 8 :
6410 0 : for (uint32_t i = 0; i < childCount; i++) {
6411 : children[i].item->ApplyOpacity(aBuilder, mOpacity, mClipChain);
6412 : }
6413 :
6414 : mOpacityAppliedToChildren = true;
6415 : return true;
6416 24 : }
6417 0 :
6418 : bool
6419 : nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
6420 0 : {
6421 0 : // ShouldFlattenAway() should be called only once during painting.
6422 : MOZ_ASSERT(!mOpacityAppliedToChildren);
6423 :
6424 : if (mFrame->GetPrevContinuation() || mFrame->GetNextContinuation() ||
6425 0 : mFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) {
6426 : // If we've been split, then we might need to merge, so
6427 : // don't flatten us away.
6428 0 : return false;
6429 : }
6430 0 :
6431 0 : if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) {
6432 : // If our opacity is zero then we'll discard all descendant display items
6433 : // except for layer event regions, so there's no point in doing this
6434 : // optimization (and if we do do it, then invalidations of those descendants
6435 : // might trigger repainting).
6436 : return false;
6437 32 : }
6438 :
6439 : if (mList.IsEmpty()) {
6440 : return false;
6441 : }
6442 :
6443 : // Return true if we successfully applied opacity to child items, or if
6444 : // WebRender is not in use. In the latter case, the opacity gets flattened and
6445 0 : // applied during layer building.
6446 : return ApplyOpacityToChildren(aBuilder) || !gfxVars::UseWebRender();
6447 : }
6448 :
6449 : nsDisplayItem::LayerState
6450 : nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
6451 : LayerManager* aManager,
6452 32 : const ContainerLayerParameters& aParameters) {
6453 : // If we only created this item so that we'd get correct nsDisplayEventRegions for child
6454 : // frames, then force us to inactive to avoid unnecessary layerization changes for content
6455 : // that won't ever be painted.
6456 0 : if (mForEventsAndPluginsOnly) {
6457 : MOZ_ASSERT(mOpacity == 0);
6458 : return LAYER_INACTIVE;
6459 : }
6460 :
6461 : if (NeedsActiveLayer(aBuilder, mFrame)) {
6462 0 : // Returns LAYER_ACTIVE_FORCE to avoid flatterning the layer for async
6463 0 : // animations.
6464 : return LAYER_ACTIVE_FORCE;
6465 : }
6466 :
6467 24 : return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, GetAnimatedGeometryRoot());
6468 : }
6469 :
6470 : bool
6471 : nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
6472 : nsRegion* aVisibleRegion) {
6473 0 : // Our children are translucent so we should not allow them to subtract
6474 : // area from aVisibleRegion. We do need to find out what is visible under
6475 : // our children in the temporary compositing buffer, because if our children
6476 : // paint our entire bounds opaquely then we don't need an alpha channel in
6477 12 : // the temporary compositing buffer.
6478 : nsRect bounds = GetClippedBounds(aBuilder);
6479 : nsRegion visibleUnderChildren;
6480 : visibleUnderChildren.And(*aVisibleRegion, bounds);
6481 : return
6482 : nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
6483 : }
6484 24 :
6485 0 : void
6486 12 : nsDisplayOpacity::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
6487 : const nsDisplayItemGeometry* aGeometry,
6488 24 : nsRegion* aInvalidRegion) const
6489 : {
6490 : const nsDisplayOpacityGeometry* geometry =
6491 : static_cast<const nsDisplayOpacityGeometry*>(aGeometry);
6492 19 :
6493 : bool snap;
6494 : if (mOpacity != geometry->mOpacity) {
6495 : aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
6496 : }
6497 19 : }
6498 :
6499 : void
6500 19 : nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
6501 0 : {
6502 : aStream << " (opacity " << mOpacity << ")";
6503 0 : }
6504 :
6505 : bool
6506 0 : nsDisplayOpacity::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
6507 : mozilla::wr::IpcResourceUpdateQueue& aResources,
6508 0 : const StackingContextHelper& aSc,
6509 0 : mozilla::layers::WebRenderLayerManager* aManager,
6510 : nsDisplayListBuilder* aDisplayListBuilder)
6511 : {
6512 0 : float* opacityForSC = &mOpacity;
6513 :
6514 : RefPtr<WebRenderAnimationData> animationData = aManager->CommandBuilder().CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(this);
6515 : AnimationInfo& animationInfo = animationData->GetAnimationInfo();
6516 : AddAnimationsForProperty(Frame(), aDisplayListBuilder,
6517 : this, eCSSProperty_opacity,
6518 0 : animationInfo, false, true);
6519 : animationInfo.StartPendingAnimations(aManager->GetAnimationReadyTime());
6520 0 :
6521 0 : // Note that animationsId can be 0 (uninitialized in AnimationInfo) if there
6522 0 : // are no active animations.
6523 : uint64_t animationsId = animationInfo.GetCompositorAnimationsId();
6524 0 : wr::WrAnimationProperty prop;
6525 0 :
6526 : if (!animationInfo.GetAnimations().IsEmpty()) {
6527 : prop.id = animationsId;
6528 : prop.effect_type = wr::WrAnimationType::Opacity;
6529 0 :
6530 :
6531 : OpAddCompositorAnimations
6532 0 : anim(CompositorAnimations(animationInfo.GetAnimations(), animationsId));
6533 0 : aManager->WrBridge()->AddWebRenderParentCommand(anim);
6534 0 : aManager->AddActiveCompositorAnimationId(animationsId);
6535 : } else if (animationsId) {
6536 : aManager->AddCompositorAnimationsIdForDiscard(animationsId);
6537 : animationsId = 0;
6538 0 : }
6539 0 :
6540 0 : nsTArray<mozilla::wr::WrFilterOp> filters;
6541 0 : StackingContextHelper sc(aSc, aBuilder, filters, LayoutDeviceRect(), nullptr,
6542 0 : animationsId ? &prop : nullptr,
6543 0 : opacityForSC);
6544 :
6545 : aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(&mList,
6546 0 : this,
6547 0 : aDisplayListBuilder,
6548 : sc,
6549 0 : aBuilder,
6550 : aResources);
6551 0 : return true;
6552 : }
6553 :
6554 : nsDisplayBlendMode::nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
6555 : nsIFrame* aFrame, nsDisplayList* aList,
6556 0 : uint8_t aBlendMode,
6557 0 : const ActiveScrolledRoot* aActiveScrolledRoot,
6558 : uint32_t aIndex)
6559 : : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true)
6560 0 : , mBlendMode(aBlendMode)
6561 : , mIndex(aIndex)
6562 : {
6563 : MOZ_COUNT_CTOR(nsDisplayBlendMode);
6564 0 : }
6565 :
6566 : #ifdef NS_BUILD_REFCNT_LOGGING
6567 0 : nsDisplayBlendMode::~nsDisplayBlendMode() {
6568 : MOZ_COUNT_DTOR(nsDisplayBlendMode);
6569 0 : }
6570 0 : #endif
6571 :
6572 : nsRegion nsDisplayBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
6573 0 : bool* aSnap) const
6574 0 : {
6575 0 : *aSnap = false;
6576 : // We are never considered opaque
6577 : return nsRegion();
6578 0 : }
6579 :
6580 : LayerState
6581 0 : nsDisplayBlendMode::GetLayerState(nsDisplayListBuilder* aBuilder,
6582 : LayerManager* aManager,
6583 0 : const ContainerLayerParameters& aParameters)
6584 : {
6585 : return LAYER_ACTIVE;
6586 : }
6587 0 :
6588 : bool
6589 : nsDisplayBlendMode::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
6590 : mozilla::wr::IpcResourceUpdateQueue& aResources,
6591 0 : const StackingContextHelper& aSc,
6592 : mozilla::layers::WebRenderLayerManager* aManager,
6593 : nsDisplayListBuilder* aDisplayListBuilder)
6594 : {
6595 0 : nsTArray<mozilla::wr::WrFilterOp> filters;
6596 : StackingContextHelper sc(aSc, aBuilder, filters, LayoutDeviceRect(), nullptr,
6597 : nullptr, nullptr, nullptr, nullptr,
6598 : nsCSSRendering::GetGFXBlendMode(mBlendMode));
6599 :
6600 : return nsDisplayWrapList::CreateWebRenderCommands(aBuilder,aResources, sc,
6601 0 : aManager, aDisplayListBuilder);
6602 0 : }
6603 :
6604 0 : // nsDisplayBlendMode uses layers for rendering
6605 : already_AddRefed<Layer>
6606 0 : nsDisplayBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
6607 0 : LayerManager* aManager,
6608 : const ContainerLayerParameters& aContainerParameters) {
6609 : ContainerLayerParameters newContainerParameters = aContainerParameters;
6610 : newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
6611 :
6612 0 : RefPtr<Layer> container = aManager->GetLayerBuilder()->
6613 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
6614 : newContainerParameters, nullptr);
6615 0 : if (!container) {
6616 0 : return nullptr;
6617 : }
6618 :
6619 0 : container->SetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mBlendMode));
6620 0 :
6621 0 : return container.forget();
6622 : }
6623 :
6624 : mozilla::gfx::CompositionOp
6625 0 : nsDisplayBlendMode::BlendMode()
6626 : {
6627 : return nsCSSRendering::GetGFXBlendMode(mBlendMode);
6628 : }
6629 :
6630 : bool
6631 0 : nsDisplayBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
6632 : nsRegion* aVisibleRegion) {
6633 0 : // Our children are need their backdrop so we should not allow them to subtract
6634 : // area from aVisibleRegion. We do need to find out what is visible under
6635 : // our children in the temporary compositing buffer, because if our children
6636 : // paint our entire bounds opaquely then we don't need an alpha channel in
6637 0 : // the temporary compositing buffer.
6638 : nsRect bounds = GetClippedBounds(aBuilder);
6639 : nsRegion visibleUnderChildren;
6640 : visibleUnderChildren.And(*aVisibleRegion, bounds);
6641 : return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
6642 : }
6643 :
6644 0 : bool
6645 0 : nsDisplayBlendMode::CanMerge(const nsDisplayItem* aItem) const
6646 0 : {
6647 0 : // Items for the same content element should be merged into a single
6648 : // compositing group.
6649 : if (!HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) {
6650 : return false;
6651 0 : }
6652 :
6653 : const nsDisplayBlendMode* item =
6654 : static_cast<const nsDisplayBlendMode*>(aItem);
6655 0 :
6656 : if (item->mIndex != 0 || mIndex != 0) {
6657 : // Don't merge background-blend-mode items
6658 : return false;
6659 : }
6660 0 :
6661 : return true;
6662 0 : }
6663 :
6664 : /* static */ nsDisplayBlendContainer*
6665 : nsDisplayBlendContainer::CreateForMixBlendMode(nsDisplayListBuilder* aBuilder,
6666 : nsIFrame* aFrame, nsDisplayList* aList,
6667 0 : const ActiveScrolledRoot* aActiveScrolledRoot)
6668 : {
6669 : return MakeDisplayItem<nsDisplayBlendContainer>(aBuilder, aFrame, aList, aActiveScrolledRoot, false);
6670 : }
6671 0 :
6672 : /* static */ nsDisplayBlendContainer*
6673 : nsDisplayBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder,
6674 : nsIFrame* aFrame, nsDisplayList* aList,
6675 0 : const ActiveScrolledRoot* aActiveScrolledRoot)
6676 : {
6677 : return MakeDisplayItem<nsDisplayBlendContainer>(aBuilder, aFrame, aList, aActiveScrolledRoot, true);
6678 : }
6679 0 :
6680 : nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
6681 : nsIFrame* aFrame, nsDisplayList* aList,
6682 : const ActiveScrolledRoot* aActiveScrolledRoot,
6683 0 : bool aIsForBackground)
6684 : : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true)
6685 : , mIsForBackground(aIsForBackground)
6686 0 : {
6687 : MOZ_COUNT_CTOR(nsDisplayBlendContainer);
6688 : }
6689 0 :
6690 : #ifdef NS_BUILD_REFCNT_LOGGING
6691 0 : nsDisplayBlendContainer::~nsDisplayBlendContainer() {
6692 : MOZ_COUNT_DTOR(nsDisplayBlendContainer);
6693 0 : }
6694 0 : #endif
6695 :
6696 : // nsDisplayBlendContainer uses layers for rendering
6697 0 : already_AddRefed<Layer>
6698 0 : nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder* aBuilder,
6699 0 : LayerManager* aManager,
6700 : const ContainerLayerParameters& aContainerParameters) {
6701 : // turn off anti-aliasing in the parent stacking context because it changes
6702 : // how the group is initialized.
6703 : ContainerLayerParameters newContainerParameters = aContainerParameters;
6704 0 : newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
6705 :
6706 : RefPtr<Layer> container = aManager->GetLayerBuilder()->
6707 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
6708 : newContainerParameters, nullptr);
6709 0 : if (!container) {
6710 0 : return nullptr;
6711 : }
6712 :
6713 0 : container->SetForceIsolatedGroup(true);
6714 0 : return container.forget();
6715 0 : }
6716 :
6717 : LayerState
6718 : nsDisplayBlendContainer::GetLayerState(nsDisplayListBuilder* aBuilder,
6719 0 : LayerManager* aManager,
6720 : const ContainerLayerParameters& aParameters)
6721 : {
6722 : return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, GetAnimatedGeometryRoot());
6723 : }
6724 0 :
6725 : bool
6726 : nsDisplayBlendContainer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
6727 : mozilla::wr::IpcResourceUpdateQueue& aResources,
6728 0 : const StackingContextHelper& aSc,
6729 : mozilla::layers::WebRenderLayerManager* aManager,
6730 : nsDisplayListBuilder* aDisplayListBuilder)
6731 : {
6732 0 : StackingContextHelper sc(aSc, aBuilder);
6733 :
6734 : return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc,
6735 : aManager, aDisplayListBuilder);
6736 : }
6737 :
6738 0 : /* static */ nsDisplayTableBlendContainer*
6739 : nsDisplayTableBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder,
6740 0 : nsIFrame* aFrame, nsDisplayList* aList,
6741 0 : const ActiveScrolledRoot* aActiveScrolledRoot,
6742 : nsIFrame* aAncestorFrame)
6743 : {
6744 : return MakeDisplayItem<nsDisplayTableBlendContainer>(aBuilder, aFrame, aList, aActiveScrolledRoot, true, aAncestorFrame);
6745 0 : }
6746 :
6747 : nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
6748 : nsIFrame* aFrame, nsDisplayList* aList,
6749 : const ActiveScrolledRoot* aActiveScrolledRoot,
6750 0 : nsDisplayOwnLayerFlags aFlags,
6751 : const ScrollbarData& aScrollbarData,
6752 : bool aForceActive,
6753 0 : bool aClearClipChain)
6754 : : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, aClearClipChain)
6755 : , mFlags(aFlags)
6756 : , mScrollbarData(aScrollbarData)
6757 : , mForceActive(aForceActive)
6758 : , mWrAnimationId(0)
6759 0 : {
6760 : MOZ_COUNT_CTOR(nsDisplayOwnLayer);
6761 :
6762 : // For scroll thumb layers, override the AGR to be the thumb's AGR rather
6763 : // than the AGR for mFrame (which is the slider frame).
6764 0 : if (IsScrollThumbLayer()) {
6765 : if (nsIFrame* thumbFrame = nsBox::GetChildXULBox(mFrame)) {
6766 0 : mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(thumbFrame);
6767 : }
6768 : }
6769 : }
6770 0 :
6771 0 : #ifdef NS_BUILD_REFCNT_LOGGING
6772 0 : nsDisplayOwnLayer::~nsDisplayOwnLayer() {
6773 : MOZ_COUNT_DTOR(nsDisplayOwnLayer);
6774 : }
6775 0 : #endif
6776 :
6777 : LayerState
6778 0 : nsDisplayOwnLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
6779 0 : LayerManager* aManager,
6780 0 : const ContainerLayerParameters& aParameters)
6781 : {
6782 : if (mForceActive) {
6783 : return mozilla::LAYER_ACTIVE_FORCE;
6784 0 : }
6785 :
6786 : return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mAnimatedGeometryRoot);
6787 : }
6788 0 :
6789 : bool
6790 : nsDisplayOwnLayer::IsScrollThumbLayer() const
6791 : {
6792 0 : return mScrollbarData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb;
6793 : }
6794 :
6795 : bool
6796 0 : nsDisplayOwnLayer::IsScrollbarContainer() const
6797 : {
6798 0 : return mScrollbarData.mScrollbarLayerType == layers::ScrollbarLayerType::Container;
6799 : }
6800 :
6801 : bool
6802 0 : nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
6803 : {
6804 0 : // Render scroll thumb layers even if they are invisible, because async
6805 : // scrolling might bring them into view.
6806 : return IsScrollThumbLayer();
6807 : }
6808 0 :
6809 : // nsDisplayOpacity uses layers for rendering
6810 : already_AddRefed<Layer>
6811 : nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
6812 0 : LayerManager* aManager,
6813 : const ContainerLayerParameters& aContainerParameters)
6814 : {
6815 : RefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
6816 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
6817 0 : aContainerParameters, nullptr,
6818 : FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
6819 :
6820 : if (IsScrollThumbLayer() || IsScrollbarContainer()) {
6821 : layer->SetScrollbarData(mScrollbarData);
6822 0 : }
6823 :
6824 0 : if (mFlags & nsDisplayOwnLayerFlags::eGenerateSubdocInvalidations) {
6825 : mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
6826 0 : }
6827 0 : return layer.forget();
6828 : }
6829 :
6830 0 : bool
6831 0 : nsDisplayOwnLayer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
6832 : mozilla::wr::IpcResourceUpdateQueue& aResources,
6833 0 : const StackingContextHelper& aSc,
6834 : WebRenderLayerManager* aManager,
6835 : nsDisplayListBuilder* aDisplayListBuilder)
6836 : {
6837 0 : if (!aManager->AsyncPanZoomEnabled() || !IsScrollThumbLayer()) {
6838 : return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, aSc,
6839 : aManager, aDisplayListBuilder);
6840 : }
6841 :
6842 : // APZ is enabled and this is a scroll thumb, so we need to create and
6843 0 : // set an animation id. That way APZ can move this scrollthumb around as
6844 0 : // needed.
6845 0 : RefPtr<WebRenderAnimationData> animationData = aManager->CommandBuilder().CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(this);
6846 : AnimationInfo& animationInfo = animationData->GetAnimationInfo();
6847 : animationInfo.EnsureAnimationsId();
6848 : mWrAnimationId = animationInfo.GetCompositorAnimationsId();
6849 :
6850 :
6851 0 : wr::WrAnimationProperty prop;
6852 0 : prop.id = mWrAnimationId;
6853 0 : prop.effect_type = wr::WrAnimationType::Transform;
6854 0 :
6855 : StackingContextHelper sc(aSc, aBuilder, nsTArray<wr::WrFilterOp>(),
6856 : LayoutDeviceRect(), nullptr, &prop);
6857 :
6858 0 : nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc,
6859 0 : aManager, aDisplayListBuilder);
6860 : return true;
6861 0 : }
6862 0 :
6863 : bool
6864 0 : nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
6865 0 : mozilla::layers::WebRenderLayerScrollData* aLayerData)
6866 : {
6867 : bool ret = false;
6868 :
6869 : if (IsScrollThumbLayer() || IsScrollbarContainer()) {
6870 0 : ret = true;
6871 : if (aLayerData) {
6872 : aLayerData->SetScrollbarData(mScrollbarData);
6873 0 : if (IsScrollThumbLayer()) {
6874 : aLayerData->SetScrollbarAnimationId(mWrAnimationId);
6875 0 : }
6876 0 : }
6877 0 : }
6878 0 : return ret;
6879 0 : }
6880 0 :
6881 : void
6882 : nsDisplayOwnLayer::WriteDebugInfo(std::stringstream& aStream)
6883 : {
6884 0 : aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")", (int)mFlags, mScrollbarData.mTargetViewId).get();
6885 : }
6886 :
6887 : nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
6888 0 : nsIFrame* aFrame,
6889 : nsSubDocumentFrame* aSubDocFrame,
6890 0 : nsDisplayList* aList,
6891 0 : nsDisplayOwnLayerFlags aFlags)
6892 : : nsDisplayOwnLayer(aBuilder, aFrame, aList, aBuilder->CurrentActiveScrolledRoot(), aFlags)
6893 0 : , mScrollParentId(aBuilder->GetCurrentScrollParentId())
6894 : , mShouldFlatten(false)
6895 : , mSubDocFrame(aSubDocFrame)
6896 : {
6897 0 : MOZ_COUNT_CTOR(nsDisplaySubDocument);
6898 :
6899 0 : // The SubDocument display item is conceptually outside the viewport frame,
6900 : // so in cases where the viewport frame is an AGR, the SubDocument's AGR
6901 0 : // should be not the viewport frame itself, but its parent AGR.
6902 : if (*mAnimatedGeometryRoot == mFrame && mAnimatedGeometryRoot->mParentAGR) {
6903 0 : mAnimatedGeometryRoot = mAnimatedGeometryRoot->mParentAGR;
6904 : }
6905 :
6906 : if (mSubDocFrame && mSubDocFrame != mFrame) {
6907 : mSubDocFrame->AddDisplayItem(this);
6908 0 : }
6909 0 : }
6910 :
6911 : nsDisplaySubDocument::~nsDisplaySubDocument() {
6912 0 : MOZ_COUNT_DTOR(nsDisplaySubDocument);
6913 0 : if (mSubDocFrame) {
6914 : mSubDocFrame->RemoveDisplayItem(this);
6915 0 : }
6916 : }
6917 0 :
6918 0 : nsIFrame*
6919 0 : nsDisplaySubDocument::FrameForInvalidation() const
6920 0 : {
6921 : return mSubDocFrame ? mSubDocFrame : mFrame;
6922 0 : }
6923 :
6924 : bool
6925 0 : nsDisplaySubDocument::HasDeletedFrame() const
6926 : {
6927 0 : return !mSubDocFrame || nsDisplayItem::HasDeletedFrame();
6928 : }
6929 :
6930 : void
6931 0 : nsDisplaySubDocument::RemoveFrame(nsIFrame* aFrame)
6932 : {
6933 0 : if (aFrame == mSubDocFrame) {
6934 : mSubDocFrame = nullptr;
6935 : }
6936 : nsDisplayItem::RemoveFrame(aFrame);
6937 0 : }
6938 :
6939 0 : void
6940 0 : nsDisplaySubDocument::Disown()
6941 : {
6942 0 : if (mFrame) {
6943 0 : mFrame->RemoveDisplayItem(this);
6944 : mFrame = nullptr;
6945 : }
6946 0 : if (mSubDocFrame) {
6947 : mSubDocFrame->RemoveDisplayItem(this);
6948 : mSubDocFrame = nullptr;
6949 0 : }
6950 : }
6951 :
6952 : UniquePtr<ScrollMetadata>
6953 0 : nsDisplaySubDocument::ComputeScrollMetadata(LayerManager* aLayerManager,
6954 0 : const ContainerLayerParameters& aContainerParameters)
6955 0 : {
6956 0 : if (!(mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer)) {
6957 : return UniquePtr<ScrollMetadata>(nullptr);
6958 0 : }
6959 0 :
6960 0 : nsPresContext* presContext = mFrame->PresContext();
6961 : nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
6962 0 : bool isRootContentDocument = presContext->IsRootContentDocument();
6963 0 : nsIPresShell* presShell = presContext->PresShell();
6964 0 : ContainerLayerParameters params(
6965 : aContainerParameters.mXScale * presShell->GetResolution(),
6966 : aContainerParameters.mYScale * presShell->GetResolution(),
6967 0 : nsIntPoint(), aContainerParameters);
6968 :
6969 : nsRect viewport = mFrame->GetRect() -
6970 0 : mFrame->GetPosition() +
6971 : mFrame->GetOffsetToCrossDoc(ReferenceFrame());
6972 :
6973 : return MakeUnique<ScrollMetadata>(
6974 0 : nsLayoutUtils::ComputeScrollMetadata(
6975 : mFrame, rootScrollFrame, rootScrollFrame->GetContent(), ReferenceFrame(),
6976 0 : aLayerManager, mScrollParentId, viewport, Nothing(),
6977 0 : isRootContentDocument, params));
6978 : }
6979 :
6980 : static bool
6981 0 : UseDisplayPortForViewport(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
6982 : {
6983 : return aBuilder->IsPaintingToWindow() &&
6984 0 : nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext());
6985 : }
6986 0 :
6987 0 : nsRect
6988 0 : nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder,
6989 : bool* aSnap) const
6990 : {
6991 0 : bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
6992 :
6993 : if ((mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer) && usingDisplayPort) {
6994 : *aSnap = false;
6995 0 : return mFrame->GetRect() + aBuilder->ToReferenceFrame(mFrame);
6996 : }
6997 :
6998 0 : return nsDisplayOwnLayer::GetBounds(aBuilder, aSnap);
6999 : }
7000 0 :
7001 0 : bool
7002 : nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder,
7003 : nsRegion* aVisibleRegion)
7004 0 : {
7005 0 : bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
7006 0 :
7007 0 : if (!(mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer) || !usingDisplayPort) {
7008 : return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion);
7009 : }
7010 0 :
7011 : nsRect displayport;
7012 : nsIFrame* rootScrollFrame = mFrame->PresShell()->GetRootScrollFrame();
7013 : MOZ_ASSERT(rootScrollFrame);
7014 0 : Unused << nsLayoutUtils::GetDisplayPort(rootScrollFrame->GetContent(), &displayport,
7015 : RelativeTo::ScrollFrame);
7016 :
7017 0 : nsRegion childVisibleRegion;
7018 0 : // The visible region for the children may be much bigger than the hole we
7019 : // are viewing the children from, so that the compositor process has enough
7020 0 : // content to asynchronously pan while content is being refreshed.
7021 : childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame());
7022 :
7023 : nsRect boundedRect =
7024 : childVisibleRegion.GetBounds().Intersect(
7025 0 : mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot));
7026 : bool visible = mList.ComputeVisibilityForSublist(
7027 0 : aBuilder, &childVisibleRegion, boundedRect);
7028 0 :
7029 0 : // If APZ is enabled then don't allow this computation to influence
7030 : // aVisibleRegion, on the assumption that the layer can be asynchronously
7031 0 : // scrolled so we'll definitely need all the content under it.
7032 : if (!nsLayoutUtils::UsesAsyncScrolling(mFrame)) {
7033 : bool snap;
7034 : nsRect bounds = GetBounds(aBuilder, &snap);
7035 : nsRegion removed;
7036 : removed.Sub(bounds, childVisibleRegion);
7037 :
7038 0 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
7039 : }
7040 0 :
7041 : return visible;
7042 0 : }
7043 :
7044 : bool
7045 : nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
7046 0 : {
7047 : bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
7048 :
7049 : if ((mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer) && usingDisplayPort) {
7050 0 : return true;
7051 : }
7052 :
7053 0 : return nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(aBuilder);
7054 : }
7055 0 :
7056 0 : nsRegion
7057 0 : nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
7058 : bool* aSnap) const
7059 : {
7060 0 : bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
7061 :
7062 : if ((mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer) && usingDisplayPort) {
7063 0 : *aSnap = false;
7064 : return nsRegion();
7065 0 : }
7066 0 :
7067 0 : return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder, aSnap);
7068 0 : }
7069 :
7070 : nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder* aBuilder,
7071 0 : nsIFrame* aFrame, nsDisplayList* aList,
7072 0 : nsDisplayOwnLayerFlags aFlags)
7073 0 : : nsDisplaySubDocument(aBuilder, aFrame, nullptr, aList, aFlags) {
7074 : MOZ_COUNT_CTOR(nsDisplayResolution);
7075 : }
7076 :
7077 0 : #ifdef NS_BUILD_REFCNT_LOGGING
7078 : nsDisplayResolution::~nsDisplayResolution() {
7079 : MOZ_COUNT_DTOR(nsDisplayResolution);
7080 : }
7081 : #endif
7082 0 :
7083 0 : void
7084 0 : nsDisplayResolution::HitTest(nsDisplayListBuilder* aBuilder,
7085 0 : const nsRect& aRect,
7086 : HitTestState* aState,
7087 : nsTArray<nsIFrame*> *aOutFrames)
7088 0 : {
7089 : nsIPresShell* presShell = mFrame->PresShell();
7090 : nsRect rect = aRect.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
7091 0 : mList.HitTest(aBuilder, rect, aState, aOutFrames);
7092 : }
7093 0 :
7094 0 : already_AddRefed<Layer>
7095 : nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
7096 0 : LayerManager* aManager,
7097 0 : const ContainerLayerParameters& aContainerParameters) {
7098 0 : nsIPresShell* presShell = mFrame->PresShell();
7099 0 : ContainerLayerParameters containerParameters(
7100 0 : presShell->GetResolution(), presShell->GetResolution(), nsIntPoint(),
7101 0 : aContainerParameters);
7102 0 :
7103 : RefPtr<Layer> layer = nsDisplaySubDocument::BuildLayer(
7104 : aBuilder, aManager, containerParameters);
7105 0 : layer->SetPostScale(1.0f / presShell->GetResolution(),
7106 : 1.0f / presShell->GetResolution());
7107 : layer->AsContainerLayer()->SetScaleToResolution(
7108 : presShell->ScaleToResolution(), presShell->GetResolution());
7109 0 : return layer.forget();
7110 : }
7111 :
7112 : nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
7113 0 : nsIFrame* aFrame,
7114 : nsDisplayList* aList,
7115 0 : const ActiveScrolledRoot* aActiveScrolledRoot,
7116 0 : const ActiveScrolledRoot* aContainerASR)
7117 0 : : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot)
7118 : , mIndex(0)
7119 0 : , mIsFixedBackground(false)
7120 : , mContainerASR(aContainerASR)
7121 : {
7122 0 : MOZ_COUNT_CTOR(nsDisplayFixedPosition);
7123 : Init(aBuilder);
7124 : }
7125 :
7126 0 : nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
7127 : nsIFrame* aFrame,
7128 0 : nsDisplayList* aList,
7129 0 : uint32_t aIndex)
7130 0 : : nsDisplayOwnLayer(aBuilder, aFrame, aList, aBuilder->CurrentActiveScrolledRoot())
7131 : , mIndex(aIndex)
7132 : , mIsFixedBackground(true)
7133 0 : , mContainerASR(nullptr) // XXX maybe this should be something?
7134 : {
7135 0 : MOZ_COUNT_CTOR(nsDisplayFixedPosition);
7136 0 : Init(aBuilder);
7137 0 : }
7138 :
7139 0 : void
7140 : nsDisplayFixedPosition::Init(nsDisplayListBuilder* aBuilder)
7141 : {
7142 0 : mAnimatedGeometryRootForScrollMetadata = mAnimatedGeometryRoot;
7143 : if (ShouldFixToViewport(aBuilder)) {
7144 : mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this);
7145 : }
7146 : }
7147 0 :
7148 0 : /* static */ nsDisplayFixedPosition*
7149 : nsDisplayFixedPosition::CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
7150 0 : nsIFrame* aFrame,
7151 : nsDisplayBackgroundImage* aImage,
7152 : uint32_t aIndex)
7153 : {
7154 : nsDisplayList temp;
7155 0 : temp.AppendToTop(aImage);
7156 0 :
7157 0 : return MakeDisplayItem<nsDisplayFixedPosition>(aBuilder, aFrame, &temp, aIndex + 1);
7158 : }
7159 :
7160 :
7161 0 : #ifdef NS_BUILD_REFCNT_LOGGING
7162 : nsDisplayFixedPosition::~nsDisplayFixedPosition() {
7163 : MOZ_COUNT_DTOR(nsDisplayFixedPosition);
7164 : }
7165 0 : #endif
7166 :
7167 0 : already_AddRefed<Layer>
7168 : nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
7169 0 : LayerManager* aManager,
7170 0 : const ContainerLayerParameters& aContainerParameters) {
7171 : RefPtr<Layer> layer =
7172 0 : nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
7173 :
7174 : layer->SetIsFixedPosition(true);
7175 0 :
7176 0 : nsPresContext* presContext = mFrame->PresContext();
7177 : nsIFrame* fixedFrame = mIsFixedBackground ? presContext->PresShell()->GetRootFrame() : mFrame;
7178 :
7179 0 : const nsIFrame* viewportFrame = fixedFrame->GetParent();
7180 0 : // anchorRect will be in the container's coordinate system (aLayer's parent layer).
7181 : // This is the same as the display items' reference frame.
7182 0 : nsRect anchorRect;
7183 : if (viewportFrame) {
7184 : // Fixed position frames are reflowed into the scroll-port size if one has
7185 : // been set.
7186 : if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
7187 : anchorRect.SizeTo(presContext->PresShell()->GetScrollPositionClampingScrollPortSize());
7188 : } else {
7189 : anchorRect.SizeTo(viewportFrame->GetSize());
7190 : }
7191 0 : } else {
7192 : // A display item directly attached to the viewport.
7193 0 : // For background-attachment:fixed items, the anchor point is always the
7194 0 : // top-left of the viewport currently.
7195 : viewportFrame = fixedFrame;
7196 0 : }
7197 : // The anchorRect top-left is always the viewport top-left.
7198 : anchorRect.MoveTo(viewportFrame->GetOffsetToCrossDoc(ReferenceFrame()));
7199 :
7200 0 : nsLayoutUtils::SetFixedPositionLayerData(layer,
7201 : viewportFrame, anchorRect, fixedFrame, presContext, aContainerParameters);
7202 0 :
7203 0 : return layer.forget();
7204 : }
7205 0 :
7206 : ViewID
7207 : nsDisplayFixedPosition::GetScrollTargetId()
7208 : {
7209 0 : if (mContainerASR && !nsLayoutUtils::IsReallyFixedPos(mFrame)) {
7210 : return mContainerASR->GetViewId();
7211 : }
7212 : return nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext());
7213 : }
7214 :
7215 : bool
7216 : nsDisplayFixedPosition::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
7217 : mozilla::wr::IpcResourceUpdateQueue& aResources,
7218 : const StackingContextHelper& aSc,
7219 : mozilla::layers::WebRenderLayerManager* aManager,
7220 : nsDisplayListBuilder* aDisplayListBuilder)
7221 : {
7222 0 : // We install this RAII scrolltarget tracker so that any
7223 0 : // nsDisplayCompositorHitTestInfo items inside this fixed-pos item (and that
7224 0 : // share the same ASR as this item) use the correct scroll target. That way
7225 : // attempts to scroll on those items will scroll the root scroll frame.
7226 : mozilla::wr::DisplayListBuilder::FixedPosScrollTargetTracker tracker(
7227 : aBuilder,
7228 0 : GetActiveScrolledRoot(),
7229 : GetScrollTargetId());
7230 : return nsDisplayOwnLayer::CreateWebRenderCommands(aBuilder, aResources, aSc,
7231 0 : aManager, aDisplayListBuilder);
7232 0 : }
7233 :
7234 0 : bool
7235 : nsDisplayFixedPosition::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
7236 : mozilla::layers::WebRenderLayerScrollData* aLayerData)
7237 : {
7238 0 : if (aLayerData) {
7239 : aLayerData->SetFixedPositionScrollContainerId(GetScrollTargetId());
7240 0 : }
7241 0 : return nsDisplayOwnLayer::UpdateScrollData(aData, aLayerData) | true;
7242 0 : }
7243 0 :
7244 : void
7245 : nsDisplayFixedPosition::WriteDebugInfo(std::stringstream& aStream)
7246 0 : {
7247 : aStream << nsPrintfCString(" (containerASR %s) (scrolltarget %" PRIu64 ")",
7248 0 : ActiveScrolledRoot::ToString(mContainerASR).get(),
7249 : GetScrollTargetId()).get();
7250 : }
7251 :
7252 0 : TableType
7253 : GetTableTypeFromFrame(nsIFrame* aFrame)
7254 : {
7255 : if (aFrame->IsTableFrame()) {
7256 0 : return TableType::TABLE;
7257 : }
7258 :
7259 : if (aFrame->IsTableColFrame()) {
7260 0 : return TableType::TABLE_COL;
7261 : }
7262 :
7263 : if (aFrame->IsTableColGroupFrame()) {
7264 0 : return TableType::TABLE_COL_GROUP;
7265 : }
7266 :
7267 : if (aFrame->IsTableRowFrame()) {
7268 0 : return TableType::TABLE_ROW;
7269 : }
7270 :
7271 : if (aFrame->IsTableRowGroupFrame()) {
7272 0 : return TableType::TABLE_ROW_GROUP;
7273 : }
7274 :
7275 : if (aFrame->IsTableCellFrame()) {
7276 0 : return TableType::TABLE_CELL;
7277 : }
7278 :
7279 : MOZ_ASSERT_UNREACHABLE("Invalid frame.");
7280 0 : return TableType::TABLE;
7281 : }
7282 :
7283 0 : nsDisplayTableFixedPosition::nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder,
7284 : nsIFrame* aFrame,
7285 0 : nsDisplayList* aList,
7286 0 : uint32_t aIndex,
7287 : nsIFrame* aAncestorFrame)
7288 0 : : nsDisplayFixedPosition(aBuilder, aFrame, aList, aIndex)
7289 : , mAncestorFrame(aAncestorFrame)
7290 : , mTableType(GetTableTypeFromFrame(aAncestorFrame))
7291 0 : {
7292 : if (aBuilder->IsRetainingDisplayList()) {
7293 : mAncestorFrame->AddDisplayItem(this);
7294 : }
7295 : }
7296 :
7297 0 : /* static */ nsDisplayTableFixedPosition*
7298 0 : nsDisplayTableFixedPosition::CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
7299 : nsIFrame* aFrame,
7300 0 : nsDisplayBackgroundImage* aImage,
7301 : uint32_t aIndex,
7302 : nsIFrame* aAncestorFrame)
7303 0 : {
7304 : nsDisplayList temp;
7305 : temp.AppendToTop(aImage);
7306 :
7307 0 : return MakeDisplayItem<nsDisplayTableFixedPosition>(aBuilder, aFrame, &temp, aIndex + 1, aAncestorFrame);
7308 : }
7309 0 :
7310 : nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
7311 0 : nsIFrame* aFrame,
7312 0 : nsDisplayList* aList,
7313 : const ActiveScrolledRoot* aActiveScrolledRoot,
7314 : const ActiveScrolledRoot* aContainerASR)
7315 0 : : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot)
7316 : , mContainerASR(aContainerASR)
7317 : {
7318 0 : MOZ_COUNT_CTOR(nsDisplayStickyPosition);
7319 0 : }
7320 :
7321 : void
7322 : nsDisplayStickyPosition::SetClipChain(const DisplayItemClipChain* aClipChain,
7323 0 : bool aStore)
7324 0 : {
7325 0 : mClipChain = aClipChain;
7326 : mClip = nullptr;
7327 0 :
7328 : MOZ_ASSERT(!mClip, "There should never be a clip on this item because no clip moves with it.");
7329 :
7330 0 : if (aStore) {
7331 0 : mState.mClipChain = aClipChain;
7332 0 : mState.mClip = mClip;
7333 : }
7334 : }
7335 :
7336 0 : #ifdef NS_BUILD_REFCNT_LOGGING
7337 : nsDisplayStickyPosition::~nsDisplayStickyPosition() {
7338 : MOZ_COUNT_DTOR(nsDisplayStickyPosition);
7339 : }
7340 0 : #endif
7341 :
7342 : already_AddRefed<Layer>
7343 0 : nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
7344 0 : LayerManager* aManager,
7345 : const ContainerLayerParameters& aContainerParameters) {
7346 : RefPtr<Layer> layer =
7347 : nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
7348 0 :
7349 0 : StickyScrollContainer* stickyScrollContainer = StickyScrollContainer::
7350 : GetStickyScrollContainerForFrame(mFrame);
7351 : if (!stickyScrollContainer) {
7352 : return layer.forget();
7353 0 : }
7354 0 :
7355 0 : nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
7356 : nsPresContext* presContext = scrollFrame->PresContext();
7357 0 :
7358 : // Sticky position frames whose scroll frame is the root scroll frame are
7359 : // reflowed into the scroll-port size if one has been set.
7360 0 : nsSize scrollFrameSize = scrollFrame->GetSize();
7361 0 : if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() &&
7362 0 : presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
7363 : scrollFrameSize = presContext->PresShell()->
7364 0 : GetScrollPositionClampingScrollPortSize();
7365 0 : }
7366 :
7367 0 : nsLayoutUtils::SetFixedPositionLayerData(layer, scrollFrame,
7368 0 : nsRect(scrollFrame->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize),
7369 0 : mFrame, presContext, aContainerParameters);
7370 0 :
7371 0 : ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
7372 : stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent());
7373 0 :
7374 : float factor = presContext->AppUnitsPerDevPixel();
7375 0 : nsRectAbsolute outer;
7376 0 : nsRectAbsolute inner;
7377 0 : stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
7378 0 : LayerRectAbsolute stickyOuter(NSAppUnitsToFloatPixels(outer.X(), factor) *
7379 0 : aContainerParameters.mXScale,
7380 : NSAppUnitsToFloatPixels(outer.Y(), factor) *
7381 0 : aContainerParameters.mYScale,
7382 : NSAppUnitsToFloatPixels(outer.XMost(), factor) *
7383 0 : aContainerParameters.mXScale,
7384 : NSAppUnitsToFloatPixels(outer.YMost(), factor) *
7385 0 : aContainerParameters.mYScale);
7386 0 : LayerRectAbsolute stickyInner(NSAppUnitsToFloatPixels(inner.X(), factor) *
7387 0 : aContainerParameters.mXScale,
7388 : NSAppUnitsToFloatPixels(inner.Y(), factor) *
7389 : aContainerParameters.mYScale,
7390 : NSAppUnitsToFloatPixels(inner.XMost(), factor) *
7391 : aContainerParameters.mXScale,
7392 : NSAppUnitsToFloatPixels(inner.YMost(), factor) *
7393 : aContainerParameters.mYScale);
7394 0 : layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner);
7395 0 :
7396 0 : return layer.forget();
7397 : }
7398 :
7399 0 : // Returns the smallest distance from "0" to the range [min, max] where
7400 : // min <= max.
7401 : static nscoord DistanceToRange(nscoord min, nscoord max) {
7402 : MOZ_ASSERT(min <= max);
7403 : if (max < 0) {
7404 : return max;
7405 : }
7406 : if (min > 0) {
7407 0 : return min;
7408 : }
7409 : MOZ_ASSERT(min <= 0 && max >= 0);
7410 : return 0;
7411 : }
7412 :
7413 0 : bool
7414 0 : nsDisplayStickyPosition::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
7415 : mozilla::wr::IpcResourceUpdateQueue& aResources,
7416 : const StackingContextHelper& aSc,
7417 : WebRenderLayerManager* aManager,
7418 : nsDisplayListBuilder* aDisplayListBuilder)
7419 : {
7420 : StickyScrollContainer* stickyScrollContainer = StickyScrollContainer::GetStickyScrollContainerForFrame(mFrame);
7421 : if (stickyScrollContainer) {
7422 : // If there's no ASR for the scrollframe that this sticky item is attached
7423 : // to, then don't create a WR sticky item for it either. Trying to do so
7424 : // will end in sadness because WR will interpret some coordinates as
7425 : // relative to the nearest enclosing scrollframe, which will correspond
7426 0 : // to the nearest ancestor ASR on the gecko side. That ASR will not be the
7427 0 : // same as the scrollframe this sticky item is actually supposed to be
7428 : // attached to, thus the sadness.
7429 : // Not sending WR the sticky item is ok, because the enclosing scrollframe
7430 : // will never be asynchronously scrolled. Instead we will always position
7431 0 : // the sticky items correctly on the gecko side and WR will never need to
7432 0 : // adjust their position itself.
7433 : if (!stickyScrollContainer->ScrollFrame()->IsMaybeAsynchronouslyScrolled()) {
7434 : stickyScrollContainer = nullptr;
7435 0 : }
7436 : }
7437 0 :
7438 0 : if (stickyScrollContainer) {
7439 0 : float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
7440 0 :
7441 0 : bool snap;
7442 0 : nsRect itemBounds = GetBounds(aDisplayListBuilder, &snap);
7443 0 :
7444 : Maybe<float> topMargin;
7445 0 : Maybe<float> rightMargin;
7446 0 : Maybe<float> bottomMargin;
7447 0 : Maybe<float> leftMargin;
7448 : wr::StickyOffsetBounds vBounds = { 0.0, 0.0 };
7449 0 : wr::StickyOffsetBounds hBounds = { 0.0, 0.0 };
7450 0 : nsPoint appliedOffset;
7451 :
7452 : nsRectAbsolute outer;
7453 : nsRectAbsolute inner;
7454 0 : stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
7455 0 :
7456 : nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
7457 : nsPoint offset = scrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
7458 :
7459 : // Adjust the scrollPort coordinates to be relative to the reference frame,
7460 : // so that it is in the same space as everything else.
7461 0 : nsRect scrollPort = stickyScrollContainer->ScrollFrame()->GetScrollPortRect();
7462 : scrollPort += offset;
7463 :
7464 : // The following computations make more sense upon understanding the
7465 : // semantics of "inner" and "outer", which is explained in the comment on
7466 : // SetStickyPositionData in Layers.h.
7467 :
7468 : if (outer.YMost() != inner.YMost()) {
7469 : // Question: How far will itemBounds.y be from the top of the scrollport
7470 : // when we have scrolled from the current scroll position of "0" to
7471 : // reach the range [inner.YMost(), outer.YMost()] where the item gets
7472 : // stuck?
7473 : // Answer: the current distance is "itemBounds.y - scrollPort.y". That
7474 : // needs to be adjusted by the distance to the range. If the distance is
7475 : // negative (i.e. inner.YMost() <= outer.YMost() < 0) then we would be
7476 : // scrolling upwards (decreasing scroll offset) to reach that range,
7477 0 : // which would increase itemBounds.y and make it farther away from the
7478 0 : // top of the scrollport. So in that case the adjustment is -distance.
7479 : // If the distance is positive (0 < inner.YMost() <= outer.YMost()) then
7480 : // we would be scrolling downwards, itemBounds.y would decrease, and we
7481 : // again need to adjust by -distance. If we are already in the range
7482 : // then no adjustment is needed and distance is 0 so again using
7483 : // -distance works.
7484 : nscoord distance = DistanceToRange(inner.YMost(), outer.YMost());
7485 0 : topMargin = Some(NSAppUnitsToFloatPixels(itemBounds.y - scrollPort.y - distance, auPerDevPixel));
7486 : // Question: What is the maximum positive ("downward") offset that WR
7487 : // will have to apply to this item in order to prevent the item from
7488 : // visually moving?
7489 : // Answer: Since the item is "sticky" in the range [inner.YMost(), outer.YMost()],
7490 : // the maximum offset will be the size of the range, which is
7491 : // outer.YMost() - inner.YMost().
7492 : vBounds.max = NSAppUnitsToFloatPixels(outer.YMost() - inner.YMost(), auPerDevPixel);
7493 0 : // Question: how much of an offset has layout already applied to the item?
7494 0 : // Answer: if we are
7495 0 : // (a) inside the sticky range (inner.YMost() < 0 <= outer.YMost()), or
7496 : // (b) past the sticky range (inner.YMost() < outer.YMost() < 0)
7497 : // then layout has already applied some offset to the position of the
7498 0 : // item. The amount of the adjustment is |0 - inner.YMost()| in case (a)
7499 : // and |outer.YMost() - inner.YMost()| in case (b).
7500 : if (inner.YMost() < 0) {
7501 0 : appliedOffset.y = std::min(0, outer.YMost()) - inner.YMost();
7502 0 : MOZ_ASSERT(appliedOffset.y > 0);
7503 : }
7504 : }
7505 0 : if (outer.Y() != inner.Y()) {
7506 : // Similar logic as in the previous section, but this time we care about
7507 : // the distance from itemBounds.YMost() to scrollPort.YMost().
7508 : nscoord distance = DistanceToRange(outer.Y(), inner.Y());
7509 0 : bottomMargin = Some(NSAppUnitsToFloatPixels(scrollPort.YMost() - itemBounds.YMost() + distance, auPerDevPixel));
7510 0 : // And here WR will be moving the item upwards rather than downwards so
7511 0 : // again things are inverted from the previous block.
7512 : vBounds.min = NSAppUnitsToFloatPixels(outer.Y() - inner.Y(), auPerDevPixel);
7513 : // We can't have appliedOffset be both positive and negative, and the top
7514 : // adjustment takes priority. So here we only update appliedOffset.y if
7515 0 : // it wasn't set by the top-sticky case above.
7516 0 : if (appliedOffset.y == 0 && inner.Y() > 0) {
7517 0 : appliedOffset.y = std::max(0, outer.Y()) - inner.Y();
7518 0 : MOZ_ASSERT(appliedOffset.y < 0);
7519 0 : }
7520 0 : }
7521 0 : // Same as above, but for the x-axis
7522 : if (outer.XMost() != inner.XMost()) {
7523 : nscoord distance = DistanceToRange(inner.XMost(), outer.XMost());
7524 0 : leftMargin = Some(NSAppUnitsToFloatPixels(itemBounds.x - scrollPort.x - distance, auPerDevPixel));
7525 0 : hBounds.max = NSAppUnitsToFloatPixels(outer.XMost() - inner.XMost(), auPerDevPixel);
7526 0 : if (inner.XMost() < 0) {
7527 0 : appliedOffset.x = std::min(0, outer.XMost()) - inner.XMost();
7528 0 : MOZ_ASSERT(appliedOffset.x > 0);
7529 0 : }
7530 0 : }
7531 : if (outer.X() != inner.X()) {
7532 : nscoord distance = DistanceToRange(outer.X(), inner.X());
7533 : rightMargin = Some(NSAppUnitsToFloatPixels(scrollPort.XMost() - itemBounds.XMost() + distance, auPerDevPixel));
7534 0 : hBounds.min = NSAppUnitsToFloatPixels(outer.X() - inner.X(), auPerDevPixel);
7535 : if (appliedOffset.x == 0 && inner.X() > 0) {
7536 0 : appliedOffset.x = std::max(0, outer.X()) - inner.X();
7537 0 : MOZ_ASSERT(appliedOffset.x < 0);
7538 0 : }
7539 0 : }
7540 0 :
7541 0 : LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(itemBounds, auPerDevPixel);
7542 0 : wr::LayoutVector2D applied = {
7543 : NSAppUnitsToFloatPixels(appliedOffset.x, auPerDevPixel),
7544 0 : NSAppUnitsToFloatPixels(appliedOffset.y, auPerDevPixel)
7545 0 : };
7546 : wr::WrClipId id = aBuilder.DefineStickyFrame(wr::ToRoundedLayoutRect(bounds),
7547 : topMargin.ptrOr(nullptr), rightMargin.ptrOr(nullptr),
7548 0 : bottomMargin.ptrOr(nullptr), leftMargin.ptrOr(nullptr),
7549 0 : vBounds, hBounds, applied);
7550 :
7551 0 : aBuilder.PushClip(id);
7552 0 : aManager->CommandBuilder().PushOverrideForASR(mContainerASR, Some(id));
7553 0 : }
7554 :
7555 : nsDisplayOwnLayer::CreateWebRenderCommands(aBuilder, aResources, aSc,
7556 0 : aManager, aDisplayListBuilder);
7557 :
7558 : if (stickyScrollContainer) {
7559 0 : aManager->CommandBuilder().PopOverrideForASR(mContainerASR);
7560 : aBuilder.PopClip();
7561 : }
7562 0 :
7563 : return true;
7564 : }
7565 :
7566 0 : nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
7567 : nsDisplayListBuilder* aBuilder,
7568 : nsIFrame* aScrolledFrame,
7569 0 : nsIFrame* aScrollFrame)
7570 : : nsDisplayWrapList(aBuilder, aScrollFrame)
7571 0 : , mScrollFrame(aScrollFrame)
7572 : , mScrolledFrame(aScrolledFrame)
7573 : , mScrollParentId(aBuilder->GetCurrentScrollParentId())
7574 0 : {
7575 : #ifdef NS_BUILD_REFCNT_LOGGING
7576 0 : MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
7577 0 : #endif
7578 : }
7579 :
7580 : #ifdef NS_BUILD_REFCNT_LOGGING
7581 0 : nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
7582 : {
7583 : MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
7584 : }
7585 : #endif
7586 :
7587 : already_AddRefed<Layer>
7588 : nsDisplayScrollInfoLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
7589 : LayerManager* aManager,
7590 : const ContainerLayerParameters& aContainerParameters)
7591 0 : {
7592 : // In general for APZ with event-regions we no longer have a need for
7593 0 : // scrollinfo layers. However, in some cases, there might be content that
7594 : // cannot be layerized, and so needs to scroll synchronously. To handle those
7595 : // cases, we still want to generate scrollinfo layers.
7596 :
7597 0 : return aManager->GetLayerBuilder()->
7598 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
7599 : aContainerParameters, nullptr,
7600 : FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
7601 0 : }
7602 :
7603 : LayerState
7604 : nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
7605 0 : LayerManager* aManager,
7606 : const ContainerLayerParameters& aParameters)
7607 : {
7608 0 : return LAYER_ACTIVE_EMPTY;
7609 0 : }
7610 0 :
7611 : UniquePtr<ScrollMetadata>
7612 : nsDisplayScrollInfoLayer::ComputeScrollMetadata(LayerManager* aLayerManager,
7613 0 : const ContainerLayerParameters& aContainerParameters)
7614 : {
7615 0 : nsRect viewport = mScrollFrame->GetRect() -
7616 0 : mScrollFrame->GetPosition() +
7617 : mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
7618 0 :
7619 : ScrollMetadata metadata = nsLayoutUtils::ComputeScrollMetadata(
7620 : mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(),
7621 : ReferenceFrame(), aLayerManager,
7622 0 : mScrollParentId, viewport, Nothing(), false, aContainerParameters);
7623 : metadata.GetMetrics().SetIsScrollInfoLayer(true);
7624 :
7625 0 : return UniquePtr<ScrollMetadata>(new ScrollMetadata(metadata));
7626 : }
7627 0 :
7628 0 : bool
7629 0 : nsDisplayScrollInfoLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
7630 0 : mozilla::layers::WebRenderLayerScrollData* aLayerData)
7631 : {
7632 0 : if (aLayerData) {
7633 : UniquePtr<ScrollMetadata> metadata =
7634 : ComputeScrollMetadata(aData->GetManager(), ContainerLayerParameters());
7635 : MOZ_ASSERT(aData);
7636 0 : MOZ_ASSERT(metadata);
7637 : aLayerData->AppendScrollMetadata(*aData, *metadata);
7638 0 : }
7639 0 : return true;
7640 0 : }
7641 :
7642 0 : void
7643 : nsDisplayScrollInfoLayer::WriteDebugInfo(std::stringstream& aStream)
7644 : {
7645 0 : aStream << " (scrollframe " << mScrollFrame
7646 : << " scrolledFrame " << mScrolledFrame << ")";
7647 0 : }
7648 0 :
7649 0 : nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
7650 : nsIFrame* aFrame, nsDisplayList* aList,
7651 : int32_t aAPD, int32_t aParentAPD,
7652 0 : nsDisplayOwnLayerFlags aFlags)
7653 0 : : nsDisplaySubDocument(aBuilder, aFrame, nullptr, aList, aFlags)
7654 0 : , mAPD(aAPD), mParentAPD(aParentAPD) {
7655 : MOZ_COUNT_CTOR(nsDisplayZoom);
7656 : }
7657 0 :
7658 : #ifdef NS_BUILD_REFCNT_LOGGING
7659 : nsDisplayZoom::~nsDisplayZoom() {
7660 0 : MOZ_COUNT_DTOR(nsDisplayZoom);
7661 0 : }
7662 0 : #endif
7663 :
7664 : nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder,
7665 0 : bool* aSnap) const
7666 : {
7667 : nsRect bounds = nsDisplaySubDocument::GetBounds(aBuilder, aSnap);
7668 : *aSnap = false;
7669 : return bounds.ScaleToOtherAppUnitsRoundOut(mAPD, mParentAPD);
7670 0 : }
7671 :
7672 : void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder,
7673 0 : const nsRect& aRect,
7674 0 : HitTestState *aState,
7675 0 : nsTArray<nsIFrame*> *aOutFrames)
7676 : {
7677 0 : nsRect rect;
7678 : // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
7679 0 : // rect as well instead of possibly rounding the width or height to zero.
7680 0 : if (aRect.width == 1 && aRect.height == 1) {
7681 : rect.MoveTo(aRect.TopLeft().ScaleToOtherAppUnits(mParentAPD, mAPD));
7682 0 : rect.width = rect.height = 1;
7683 : } else {
7684 : rect = aRect.ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
7685 : }
7686 0 : mList.HitTest(aBuilder, rect, aState, aOutFrames);
7687 : }
7688 0 :
7689 0 : bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
7690 0 : nsRegion *aVisibleRegion)
7691 : {
7692 : // Convert the passed in visible region to our appunits.
7693 0 : nsRegion visibleRegion;
7694 : // mVisibleRect has been clipped to GetClippedBounds
7695 : visibleRegion.And(*aVisibleRegion, GetPaintRect());
7696 : visibleRegion = visibleRegion.ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
7697 : nsRegion originalVisibleRegion = visibleRegion;
7698 0 :
7699 0 : nsRect transformedVisibleRect =
7700 : GetPaintRect().ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
7701 0 : bool retval;
7702 0 : // If we are to generate a scrollable layer we call
7703 : // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments
7704 : // for ComputeVisibility, it does all it's calculations in the child APD.
7705 0 : bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
7706 : if (!(mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer) || !usingDisplayPort) {
7707 : retval =
7708 0 : mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
7709 : transformedVisibleRect);
7710 0 : } else {
7711 : retval =
7712 0 : nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion);
7713 : }
7714 :
7715 0 : nsRegion removed;
7716 : // removed = originalVisibleRegion - visibleRegion
7717 0 : removed.Sub(originalVisibleRegion, visibleRegion);
7718 : // Convert removed region to parent appunits.
7719 : removed = removed.ScaleToOtherAppUnitsRoundIn(mAPD, mParentAPD);
7720 : // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
7721 : // SubtractFromVisibleRegion does)
7722 : aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
7723 :
7724 : return retval;
7725 : }
7726 :
7727 : ///////////////////////////////////////////////////
7728 : // nsDisplayTransform Implementation
7729 : //
7730 :
7731 : // Write #define UNIFIED_CONTINUATIONS here and in
7732 : // TransformReferenceBox::Initialize to have the transform property try
7733 : // to transform content with continuations as one unified block instead of
7734 : // several smaller ones. This is currently disabled because it doesn't work
7735 : // correctly, since when the frames are initially being reflowed, their
7736 0 : // continuations all compute their bounding rects independently of each other
7737 : // and consequently get the wrong value. Write #define DEBUG_HIT here to have
7738 : // the nsDisplayTransform class dump out a bunch of information about hit
7739 : // detection.
7740 0 : #undef UNIFIED_CONTINUATIONS
7741 : #undef DEBUG_HIT
7742 :
7743 : nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
7744 : nsIFrame *aFrame, nsDisplayList *aList,
7745 : const nsRect& aChildrenBuildingRect,
7746 : ComputeTransformFunction aTransformGetter,
7747 : uint32_t aIndex)
7748 : : nsDisplayItem(aBuilder, aFrame)
7749 : , mStoredList(aBuilder, aFrame, aList)
7750 : , mTransformGetter(aTransformGetter)
7751 0 : , mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
7752 : , mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
7753 0 : , mChildrenBuildingRect(aChildrenBuildingRect)
7754 0 : , mIndex(aIndex)
7755 0 : , mNoExtendContext(false)
7756 0 : , mIsTransformSeparator(false)
7757 : , mTransformPreserves3DInited(false)
7758 : , mAllowAsyncAnimation(false)
7759 11 : {
7760 : MOZ_COUNT_CTOR(nsDisplayTransform);
7761 11 : MOZ_ASSERT(aFrame, "Must have a frame!");
7762 : Init(aBuilder);
7763 : }
7764 11 :
7765 0 : void
7766 0 : nsDisplayTransform::SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder)
7767 11 : {
7768 11 : if (mFrame == aBuilder->RootReferenceFrame()) {
7769 : return;
7770 : }
7771 : nsIFrame *outerFrame = nsLayoutUtils::GetCrossDocParentFrame(mFrame);
7772 : mReferenceFrame =
7773 : aBuilder->FindReferenceFrameFor(outerFrame);
7774 0 : mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
7775 11 : if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(mFrame)) {
7776 0 : // This is an odd special case. If we are both IsFixedPosFrameInDisplayPort
7777 : // and transformed that we are our own AGR parent.
7778 : // We want our frame to be our AGR because FrameLayerBuilder uses our AGR to
7779 : // determine if we are inside a fixed pos subtree. If we use the outer AGR
7780 0 : // from outside the fixed pos subtree FLB can't tell that we are fixed pos.
7781 22 : mAnimatedGeometryRoot = mAnimatedGeometryRootForChildren;
7782 0 : } else if (mFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
7783 0 : IsStickyFrameActive(aBuilder, mFrame, nullptr)) {
7784 : // Similar to the IsFixedPosFrameInDisplayPort case we are our own AGR.
7785 : // We are inside the sticky position, so our AGR is the sticky positioned
7786 : // frame, which is our AGR, not the parent AGR.
7787 : mAnimatedGeometryRoot = mAnimatedGeometryRootForChildren;
7788 : } else if (mAnimatedGeometryRoot->mParentAGR) {
7789 0 : mAnimatedGeometryRootForScrollMetadata = mAnimatedGeometryRoot->mParentAGR;
7790 : if (!MayBeAnimated(aBuilder)) {
7791 : // If we're an animated transform then we want the same AGR as our children
7792 : // so that FrameLayerBuilder knows that this layer moves with the transform
7793 22 : // and won't compute occlusions. If we're not animated then use our parent
7794 : // AGR so that inactive transform layers can go in the same PaintedLayer as
7795 : // surrounding content.
7796 : mAnimatedGeometryRoot = mAnimatedGeometryRoot->mParentAGR;
7797 0 : }
7798 : }
7799 0 :
7800 11 : SetBuildingRect(aBuilder->GetVisibleRect() + mToReferenceFrame);
7801 11 : }
7802 0 :
7803 : void
7804 0 : nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder)
7805 : {
7806 : mHasBounds = false;
7807 : mStoredList.SetClipChain(nullptr, true);
7808 11 : mStoredList.SetBuildingRect(mChildrenBuildingRect);
7809 : }
7810 :
7811 : nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
7812 : nsIFrame *aFrame, nsDisplayList *aList,
7813 : const nsRect& aChildrenBuildingRect,
7814 : uint32_t aIndex,
7815 : bool aAllowAsyncAnimation)
7816 : : nsDisplayItem(aBuilder, aFrame)
7817 : , mStoredList(aBuilder, aFrame, aList)
7818 : , mTransformGetter(nullptr)
7819 1 : , mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
7820 : , mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
7821 1 : , mChildrenBuildingRect(aChildrenBuildingRect)
7822 11 : , mIndex(aIndex)
7823 11 : , mNoExtendContext(false)
7824 11 : , mIsTransformSeparator(false)
7825 1 : , mTransformPreserves3DInited(false)
7826 11 : , mAllowAsyncAnimation(aAllowAsyncAnimation)
7827 : {
7828 0 : MOZ_COUNT_CTOR(nsDisplayTransform);
7829 : MOZ_ASSERT(aFrame, "Must have a frame!");
7830 : SetReferenceFrameToAncestor(aBuilder);
7831 : Init(aBuilder);
7832 0 : UpdateBoundsFor3D(aBuilder);
7833 : }
7834 :
7835 0 : nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
7836 : nsIFrame *aFrame, nsDisplayList *aList,
7837 : const nsRect& aChildrenBuildingRect,
7838 : const Matrix4x4& aTransform,
7839 : uint32_t aIndex)
7840 : : nsDisplayItem(aBuilder, aFrame)
7841 : , mStoredList(aBuilder, aFrame, aList)
7842 : , mTransform(Some(aTransform))
7843 : , mTransformGetter(nullptr)
7844 0 : , mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
7845 : , mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
7846 0 : , mChildrenBuildingRect(aChildrenBuildingRect)
7847 0 : , mIndex(aIndex)
7848 0 : , mNoExtendContext(false)
7849 0 : , mIsTransformSeparator(true)
7850 0 : , mTransformPreserves3DInited(false)
7851 : , mAllowAsyncAnimation(false)
7852 : {
7853 : MOZ_COUNT_CTOR(nsDisplayTransform);
7854 : MOZ_ASSERT(aFrame, "Must have a frame!");
7855 : Init(aBuilder);
7856 : UpdateBoundsFor3D(aBuilder);
7857 : }
7858 95 :
7859 : /* Returns the delta specified by the transform-origin property.
7860 : * This is a positive delta, meaning that it indicates the direction to move
7861 : * to get from (0, 0) of the frame to the transform origin. This function is
7862 0 : * called off the main thread.
7863 0 : */
7864 : /* static */ Point3D
7865 : nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
7866 : float aAppUnitsPerPixel,
7867 : const nsRect* aBoundsOverride)
7868 0 : {
7869 0 : MOZ_ASSERT(aFrame, "Can't get delta for a null frame!");
7870 : MOZ_ASSERT(aFrame->IsTransformed() ||
7871 : aFrame->BackfaceIsHidden() ||
7872 : aFrame->Combines3DTransformWithAncestors(),
7873 : "Shouldn't get a delta for an untransformed frame!");
7874 :
7875 : if (!aFrame->IsTransformed()) {
7876 95 : return Point3D();
7877 : }
7878 :
7879 : /* For both of the coordinates, if the value of transform is a
7880 95 : * percentage, it's relative to the size of the frame. Otherwise, if it's
7881 95 : * a distance, it's already computed for us!
7882 0 : */
7883 0 : const nsStyleDisplay* display = aFrame->StyleDisplay();
7884 : // We don't use aBoundsOverride for SVG since we need to account for
7885 95 : // refBox.X/Y(). This happens to work because ReflowSVG sets the frame's
7886 : // mRect before calling FinishAndStoreOverflow so we don't need the override.
7887 : TransformReferenceBox refBox;
7888 : if (aBoundsOverride &&
7889 : !(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
7890 : refBox.Init(aBoundsOverride->Size());
7891 0 : } else {
7892 : refBox.Init(aFrame);
7893 95 : }
7894 :
7895 285 : /* Allows us to access dimension getters by index. */
7896 : float transformOrigin[2];
7897 : TransformReferenceBox::DimensionGetter dimensionGetter[] =
7898 : { &TransformReferenceBox::Width, &TransformReferenceBox::Height };
7899 0 : TransformReferenceBox::DimensionGetter offsetGetter[] =
7900 190 : { &TransformReferenceBox::X, &TransformReferenceBox::Y };
7901 0 :
7902 0 : for (uint8_t index = 0; index < 2; ++index) {
7903 0 : /* If the transform-origin specifies a percentage, take the percentage
7904 0 : * of the size of the box.
7905 0 : */
7906 0 : const nsStyleCoord& originValue = display->mTransformOrigin[index];
7907 190 : if (originValue.GetUnit() == eStyleUnit_Calc) {
7908 570 : const nsStyleCoord::Calc *calc = originValue.GetCalcValue();
7909 190 : transformOrigin[index] =
7910 : NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
7911 0 : calc->mPercent +
7912 : NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
7913 0 : } else if (originValue.GetUnit() == eStyleUnit_Percent) {
7914 0 : transformOrigin[index] =
7915 : NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
7916 : originValue.GetPercentValue();
7917 : } else {
7918 380 : MOZ_ASSERT(originValue.GetUnit() == eStyleUnit_Coord,
7919 : "unexpected unit");
7920 : transformOrigin[index] =
7921 : NSAppUnitsToFloatPixels(originValue.GetCoordValue(),
7922 162 : aAppUnitsPerPixel);
7923 324 : }
7924 :
7925 : if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
7926 : // SVG frames (unlike other frames) have a reference box that can be (and
7927 285 : // typically is) offset from the TopLeft() of the frame. We need to
7928 : // account for that here.
7929 0 : transformOrigin[index] +=
7930 : NSAppUnitsToFloatPixels((refBox.*offsetGetter[index])(), aAppUnitsPerPixel);
7931 : }
7932 : }
7933 95 :
7934 : return Point3D(transformOrigin[0], transformOrigin[1],
7935 : NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
7936 : aAppUnitsPerPixel));
7937 95 : }
7938 95 :
7939 : /* static */ bool
7940 : nsDisplayTransform::ComputePerspectiveMatrix(const nsIFrame* aFrame,
7941 : float aAppUnitsPerPixel,
7942 0 : Matrix4x4& aOutMatrix)
7943 : {
7944 0 : MOZ_ASSERT(aFrame, "Can't get delta for a null frame!");
7945 : MOZ_ASSERT(aFrame->IsTransformed() ||
7946 : aFrame->BackfaceIsHidden() ||
7947 : aFrame->Combines3DTransformWithAncestors(),
7948 : "Shouldn't get a delta for an untransformed frame!");
7949 : MOZ_ASSERT(aOutMatrix.IsIdentity(), "Must have a blank output matrix");
7950 :
7951 : if (!aFrame->IsTransformed()) {
7952 : return false;
7953 : }
7954 0 :
7955 0 : /* Find our containing block, which is the element that provides the
7956 : * value for perspective we need to use
7957 : */
7958 :
7959 : //TODO: Is it possible that the cbFrame's bounds haven't been set correctly yet
7960 : // (similar to the aBoundsOverride case for GetResultingTransformMatrix)?
7961 95 : nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
7962 95 : if (!cbFrame) {
7963 : return false;
7964 : }
7965 0 :
7966 0 : /* Grab the values for perspective and perspective-origin (if present) */
7967 :
7968 : const nsStyleDisplay* cbDisplay = cbFrame->StyleDisplay();
7969 : if (cbDisplay->mChildPerspective.GetUnit() != eStyleUnit_Coord) {
7970 0 : return false;
7971 : }
7972 : nscoord perspective = cbDisplay->mChildPerspective.GetCoordValue();
7973 : if (perspective < std::numeric_limits<Float>::epsilon()) {
7974 0 : return true;
7975 : }
7976 :
7977 : TransformReferenceBox refBox(cbFrame);
7978 :
7979 : Point perspectiveOrigin =
7980 0 : nsStyleTransformMatrix::Convert2DPosition(cbDisplay->mPerspectiveOrigin,
7981 : refBox, aAppUnitsPerPixel);
7982 :
7983 0 : /* GetOffsetTo computes the offset required to move from 0,0 in cbFrame to 0,0
7984 : * in aFrame. Although we actually want the inverse of this, it's faster to
7985 : * compute this way.
7986 : */
7987 : nsPoint frameToCbOffset = -aFrame->GetOffsetTo(cbFrame);
7988 0 : Point frameToCbGfxOffset(
7989 : NSAppUnitsToFloatPixels(frameToCbOffset.x, aAppUnitsPerPixel),
7990 0 : NSAppUnitsToFloatPixels(frameToCbOffset.y, aAppUnitsPerPixel));
7991 0 :
7992 : /* Move the perspective origin to be relative to aFrame, instead of relative
7993 0 : * to the containing block which is how it was specified in the style system.
7994 0 : */
7995 : perspectiveOrigin += frameToCbGfxOffset;
7996 :
7997 0 : aOutMatrix._34 =
7998 : -1.0 / NSAppUnitsToFloatPixels(perspective, aAppUnitsPerPixel);
7999 95 :
8000 : aOutMatrix.ChangeBasis(Point3D(perspectiveOrigin.x, perspectiveOrigin.y, 0));
8001 190 : return true;
8002 380 : }
8003 :
8004 95 : nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame,
8005 : float aAppUnitsPerPixel,
8006 : const nsRect* aBoundsOverride)
8007 : : mFrame(aFrame)
8008 : , mTransformList(aFrame->StyleDisplay()->GetCombinedTransform())
8009 : , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
8010 : {
8011 0 : }
8012 :
8013 : /* Wraps up the transform matrix in a change-of-basis matrix pair that
8014 : * translates from local coordinate space to transform coordinate space, then
8015 : * hands it back.
8016 : */
8017 : Matrix4x4
8018 0 : nsDisplayTransform::GetResultingTransformMatrix(const FrameTransformProperties& aProperties,
8019 : const nsPoint& aOrigin,
8020 : float aAppUnitsPerPixel,
8021 : uint32_t aFlags,
8022 95 : const nsRect* aBoundsOverride)
8023 : {
8024 : return GetResultingTransformMatrixInternal(aProperties, aOrigin, aAppUnitsPerPixel,
8025 : aFlags, aBoundsOverride);
8026 : }
8027 :
8028 : Matrix4x4
8029 : nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
8030 190 : const nsPoint& aOrigin,
8031 : float aAppUnitsPerPixel,
8032 : uint32_t aFlags,
8033 1 : const nsRect* aBoundsOverride)
8034 : {
8035 : FrameTransformProperties props(aFrame,
8036 : aAppUnitsPerPixel,
8037 1 : aBoundsOverride);
8038 :
8039 : return GetResultingTransformMatrixInternal(props, aOrigin, aAppUnitsPerPixel,
8040 : aFlags, aBoundsOverride);
8041 : }
8042 :
8043 0 : Matrix4x4
8044 95 : nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
8045 : const nsPoint& aOrigin,
8046 : float aAppUnitsPerPixel,
8047 : uint32_t aFlags,
8048 : const nsRect* aBoundsOverride)
8049 : {
8050 : const nsIFrame *frame = aProperties.mFrame;
8051 95 : NS_ASSERTION(frame || !(aFlags & INCLUDE_PERSPECTIVE), "Must have a frame to compute perspective!");
8052 190 :
8053 0 : // Get the underlying transform matrix:
8054 0 :
8055 : // We don't use aBoundsOverride for SVG since we need to account for
8056 95 : // refBox.X/Y(). This happens to work because ReflowSVG sets the frame's
8057 : // mRect before calling FinishAndStoreOverflow so we don't need the override.
8058 : TransformReferenceBox refBox;
8059 : if (aBoundsOverride &&
8060 : (!frame || !(frame->GetStateBits() & NS_FRAME_SVG_LAYOUT))) {
8061 0 : refBox.Init(aBoundsOverride->Size());
8062 : } else {
8063 : refBox.Init(frame);
8064 : }
8065 95 :
8066 : /* Get the matrix, then change its basis to factor in the origin. */
8067 190 : bool dummyBool;
8068 190 : Matrix4x4 result;
8069 : // Call IsSVGTransformed() regardless of the value of
8070 190 : // disp->mSpecifiedTransform, since we still need any
8071 14 : // parentsChildrenOnlyTransform.
8072 : Matrix svgTransform, parentsChildrenOnlyTransform;
8073 : bool hasSVGTransforms =
8074 0 : frame && frame->IsSVGTransformed(&svgTransform,
8075 : &parentsChildrenOnlyTransform);
8076 81 : /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
8077 81 : if (aProperties.mTransformList) {
8078 81 : result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
8079 0 : refBox, aAppUnitsPerPixel,
8080 0 : &dummyBool);
8081 : } else if (hasSVGTransforms) {
8082 : // Correct the translation components for zoom:
8083 : float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
8084 95 : aAppUnitsPerPixel;
8085 : svgTransform._31 *= pixelsPerCSSPx;
8086 : svgTransform._32 *= pixelsPerCSSPx;
8087 : result = Matrix4x4::From2D(svgTransform);
8088 : }
8089 95 :
8090 : // Apply any translation due to 'transform-origin' and/or 'transform-box':
8091 0 : result.ChangeBasis(aProperties.mToTransformOrigin);
8092 :
8093 0 : // See the comment for nsSVGContainerFrame::HasChildrenOnlyTransform for
8094 0 : // an explanation of what children-only transforms are.
8095 0 : bool parentHasChildrenOnlyTransform =
8096 : hasSVGTransforms && !parentsChildrenOnlyTransform.IsIdentity();
8097 :
8098 0 : if (parentHasChildrenOnlyTransform) {
8099 0 : float pixelsPerCSSPx =
8100 0 : frame->PresContext()->AppUnitsPerCSSPixel() / aAppUnitsPerPixel;
8101 : parentsChildrenOnlyTransform._31 *= pixelsPerCSSPx;
8102 0 : parentsChildrenOnlyTransform._32 *= pixelsPerCSSPx;
8103 :
8104 0 : Point3D frameOffset(
8105 : NSAppUnitsToFloatPixels(-frame->GetPosition().x, aAppUnitsPerPixel),
8106 : NSAppUnitsToFloatPixels(-frame->GetPosition().y, aAppUnitsPerPixel),
8107 95 : 0);
8108 95 : Matrix4x4 parentsChildrenOnlyTransform3D =
8109 95 : Matrix4x4::From2D(parentsChildrenOnlyTransform).ChangeBasis(frameOffset);
8110 0 :
8111 0 : result *= parentsChildrenOnlyTransform3D;
8112 : }
8113 :
8114 : Matrix4x4 perspectiveMatrix;
8115 0 : bool hasPerspective = aFlags & INCLUDE_PERSPECTIVE;
8116 0 : if (hasPerspective) {
8117 : if (ComputePerspectiveMatrix(frame, aAppUnitsPerPixel, perspectiveMatrix)) {
8118 0 : result *= perspectiveMatrix;
8119 0 : }
8120 : }
8121 :
8122 : if ((aFlags & INCLUDE_PRESERVE3D_ANCESTORS) &&
8123 : frame && frame->Combines3DTransformWithAncestors()) {
8124 0 : // Include the transform set on our parent
8125 : nsIFrame* parentFrame = frame->GetInFlowParent();
8126 0 : NS_ASSERTION(parentFrame && parentFrame->IsTransformed() &&
8127 : parentFrame->Extend3DContext(),
8128 : "Preserve3D mismatch!");
8129 : FrameTransformProperties props(parentFrame,
8130 : aAppUnitsPerPixel,
8131 : nullptr);
8132 0 :
8133 0 : uint32_t flags = aFlags & (INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE);
8134 :
8135 : // If this frame isn't transformed (but we exist for backface-visibility),
8136 : // then we're not a reference frame so no offset to origin will be added.
8137 0 : // Otherwise we need to manually translate into our parent's coordinate
8138 : // space.
8139 0 : if (frame->IsTransformed()) {
8140 0 : nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, !hasSVGTransforms);
8141 : }
8142 : Matrix4x4 parent =
8143 95 : GetResultingTransformMatrixInternal(props,
8144 0 : nsPoint(0, 0),
8145 : aAppUnitsPerPixel, flags,
8146 : nullptr);
8147 95 : result = result * parent;
8148 : }
8149 :
8150 : if (aFlags & OFFSET_BY_ORIGIN) {
8151 0 : nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, !hasSVGTransforms);
8152 : }
8153 0 :
8154 : return result;
8155 : }
8156 :
8157 : bool
8158 0 : nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
8159 0 : {
8160 0 : if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity)) {
8161 : return true;
8162 0 : }
8163 :
8164 : EffectCompositor::SetPerformanceWarning(
8165 : mFrame, eCSSProperty_opacity,
8166 0 : AnimationPerformanceWarning(
8167 : AnimationPerformanceWarning::Type::OpacityFrameInactive));
8168 0 :
8169 : return false;
8170 : }
8171 :
8172 0 : bool
8173 : nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
8174 : {
8175 : return mAllowAsyncAnimation;
8176 : }
8177 :
8178 : /* static */ auto
8179 : nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
8180 22 : nsIFrame* aFrame,
8181 0 : nsRect* aDirtyRect) -> PrerenderDecision
8182 : {
8183 : // Elements whose transform has been modified recently, or which
8184 : // have a compositor-animated transform, can be prerendered. An element
8185 0 : // might have only just had its transform animated in which case
8186 11 : // the ActiveLayerManager may not have been notified yet.
8187 : if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
8188 11 : !EffectCompositor::HasAnimationsForCompositor(aFrame,
8189 : eCSSProperty_transform)) {
8190 : EffectCompositor::SetPerformanceWarning(
8191 : aFrame, eCSSProperty_transform,
8192 : AnimationPerformanceWarning(
8193 : AnimationPerformanceWarning::Type::TransformFrameInactive));
8194 :
8195 : return NoPrerender;
8196 : }
8197 :
8198 : // We should not allow prerender if any ancestor container element has
8199 : // mask/clip-path effects.
8200 : //
8201 : // With prerender and async transform animation, we do not need to restyle an
8202 : // animated element to respect position changes, since that transform is done
8203 : // by layer animation. As a result, the container element is not aware of
8204 : // position change of that containing element and loses the chance to update
8205 : // the content of mask/clip-path.
8206 : //
8207 : // Why do we need to update a mask? This is relative to how we generate a
8208 : // mask layer in ContainerState::SetupMaskLayerForCSSMask. While creating a
8209 0 : // mask layer, to reduce memory usage, we did not choose the size of the
8210 0 : // masked element as mask size. Instead, we read the union of bounds of all
8211 0 : // children display items by nsDisplayWrapList::GetBounds, which is smaller
8212 0 : // than or equal to the masked element's boundary, and use it as the position
8213 : // size of the mask layer. That union bounds is actually affected by the
8214 : // geometry of the animated element. To keep the content of mask up to date,
8215 : // forbidding of prerender is required.
8216 : for (nsIFrame* container = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
8217 : container; container = nsLayoutUtils::GetCrossDocParentFrame(container)) {
8218 : const nsStyleSVGReset *svgReset = container->StyleSVGReset();
8219 0 : if (svgReset->HasMask() || svgReset->HasClipPath()) {
8220 0 : return NoPrerender;
8221 : }
8222 : }
8223 :
8224 0 : // If the incoming dirty rect already contains the entire overflow area,
8225 0 : // we are already rendering the entire content.
8226 0 : nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
8227 0 : if (aDirtyRect->Contains(overflow)) {
8228 0 : return FullPrerender;
8229 : }
8230 :
8231 : float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
8232 0 : float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
8233 0 : uint32_t absoluteLimitX = gfxPrefs::AnimationPrerenderAbsoluteLimitX();
8234 : uint32_t absoluteLimitY = gfxPrefs::AnimationPrerenderAbsoluteLimitY();
8235 0 : nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
8236 0 : // Only prerender if the transformed frame's size is <= a multiple of the
8237 : // reference frame size (~viewport), and less than an absolute limit.
8238 : // Both the ratio and the absolute limit are configurable.
8239 0 : nsSize relativeLimit(nscoord(refSize.width * viewportRatioX),
8240 : nscoord(refSize.height * viewportRatioY));
8241 0 : nsSize absoluteLimit(aFrame->PresContext()->DevPixelsToAppUnits(absoluteLimitX),
8242 0 : aFrame->PresContext()->DevPixelsToAppUnits(absoluteLimitY));
8243 0 : nsSize maxSize = Min(relativeLimit, absoluteLimit);
8244 :
8245 0 : const auto transform = nsLayoutUtils::GetTransformToAncestor(aFrame,
8246 0 : nsLayoutUtils::GetDisplayRootFrame(aFrame));
8247 0 : const gfxRect transformedBounds = transform.TransformAndClipBounds(
8248 0 : gfxRect(overflow.x, overflow.y, overflow.width, overflow.height),
8249 0 : gfxRect::MaxIntRect());
8250 0 : const nsSize frameSize = nsSize(transformedBounds.width, transformedBounds.height);
8251 0 :
8252 0 : uint64_t maxLimitArea = uint64_t(maxSize.width) * maxSize.height;
8253 : uint64_t frameArea = uint64_t(frameSize.width) * frameSize.height;
8254 : if (frameArea <= maxLimitArea && frameSize <= absoluteLimit) {
8255 0 : *aDirtyRect = overflow;
8256 0 : return FullPrerender;
8257 : } else if (gfxPrefs::PartiallyPrerenderAnimatedContent()) {
8258 : *aDirtyRect = nsLayoutUtils::ComputePartialPrerenderArea(*aDirtyRect, overflow, maxSize);
8259 0 : return PartialPrerender;
8260 : }
8261 :
8262 0 : if (frameArea > maxLimitArea) {
8263 0 : uint64_t appUnitsPerPixel = nsPresContext::AppUnitsPerCSSPixel();
8264 0 : EffectCompositor::SetPerformanceWarning(
8265 : aFrame, eCSSProperty_transform,
8266 : AnimationPerformanceWarning(
8267 : AnimationPerformanceWarning::Type::ContentTooLargeArea,
8268 0 : {
8269 : int(frameArea / (appUnitsPerPixel * appUnitsPerPixel)),
8270 : int(maxLimitArea / (appUnitsPerPixel * appUnitsPerPixel)),
8271 0 : }));
8272 0 : } else {
8273 0 : EffectCompositor::SetPerformanceWarning(
8274 0 : aFrame, eCSSProperty_transform,
8275 0 : AnimationPerformanceWarning(
8276 0 : AnimationPerformanceWarning::Type::ContentTooLarge,
8277 0 : {
8278 : nsPresContext::AppUnitsToIntCSSPixels(frameSize.width),
8279 : nsPresContext::AppUnitsToIntCSSPixels(frameSize.height),
8280 : nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.width),
8281 : nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.height),
8282 : nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.width),
8283 : nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.height),
8284 0 : }));
8285 : }
8286 0 :
8287 : return NoPrerender;
8288 : }
8289 0 :
8290 : /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
8291 : static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix)
8292 0 : {
8293 : if (aMatrix.IsSingular()) {
8294 : return false;
8295 : }
8296 33 : if (aFrame->BackfaceIsHidden() && aMatrix.IsBackfaceVisible()) {
8297 : return false;
8298 66 : }
8299 22 : return true;
8300 : }
8301 :
8302 0 : const Matrix4x4Flagged&
8303 : nsDisplayTransform::GetTransform() const
8304 0 : {
8305 0 : if (mTransform) {
8306 : return *mTransform;
8307 0 : }
8308 0 :
8309 0 : float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
8310 0 :
8311 0 : if (mTransformGetter) {
8312 : mTransform.emplace(mTransformGetter(mFrame, scale));
8313 0 : Point3D newOrigin =
8314 33 : Point3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale),
8315 0 : NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale),
8316 11 : 0.0f);
8317 22 : mTransform->ChangeBasis(newOrigin.x, newOrigin.y, newOrigin.z);
8318 0 : } else if (!mIsTransformSeparator) {
8319 : DebugOnly<bool> isReference =
8320 : mFrame->IsTransformed() ||
8321 0 : mFrame->Combines3DTransformWithAncestors() || mFrame->Extend3DContext();
8322 : MOZ_ASSERT(isReference);
8323 : mTransform.emplace(
8324 11 : GetResultingTransformMatrix(mFrame, ToReferenceFrame(),
8325 : scale, INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN));
8326 : } else {
8327 : // Use identity matrix
8328 0 : mTransform.emplace();
8329 : }
8330 0 :
8331 0 : return *mTransform;
8332 : }
8333 :
8334 0 : const Matrix4x4Flagged&
8335 : nsDisplayTransform::GetInverseTransform() const
8336 0 : {
8337 : if (mInverseTransform) {
8338 0 : return *mInverseTransform;
8339 : }
8340 :
8341 : MOZ_ASSERT(!GetTransform().IsSingular());
8342 11 :
8343 : mInverseTransform.emplace(GetTransform().Inverse());
8344 0 :
8345 11 : return *mInverseTransform;
8346 : }
8347 :
8348 : Matrix4x4
8349 : nsDisplayTransform::GetTransformForRendering(LayoutDevicePoint* aOutOrigin)
8350 0 : {
8351 0 : if (!mFrame->HasPerspective() || mTransformGetter || mIsTransformSeparator) {
8352 0 : if (!mTransformGetter && !mIsTransformSeparator && aOutOrigin) {
8353 : // If aOutOrigin is provided, put the offset to origin into it, because
8354 0 : // we need to keep it separate for webrender. The combination of
8355 : // *aOutOrigin and the returned matrix here should always be equivalent
8356 0 : // to what GetTransform() would have returned.
8357 : float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
8358 0 : *aOutOrigin = LayoutDevicePoint::FromAppUnits(ToReferenceFrame(), scale);
8359 : return GetResultingTransformMatrix(mFrame, nsPoint(0, 0), scale, INCLUDE_PERSPECTIVE);
8360 : }
8361 0 : return GetTransform().GetMatrix();
8362 : }
8363 : MOZ_ASSERT(!mTransformGetter);
8364 :
8365 0 : float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
8366 : // Don't include perspective transform, or the offset to origin, since
8367 0 : // nsDisplayPerspective will handle both of those.
8368 : return GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale, 0);
8369 0 : }
8370 0 :
8371 0 : const Matrix4x4&
8372 0 : nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBuilder)
8373 0 : {
8374 : MOZ_ASSERT(!mFrame->Extend3DContext() || IsLeafOf3DContext());
8375 : // XXX: should go back to fix mTransformGetter.
8376 : if (!mTransformPreserves3DInited) {
8377 0 : mTransformPreserves3DInited = true;
8378 0 : if (!IsLeafOf3DContext()) {
8379 : mTransformPreserves3D = GetTransform().GetMatrix();
8380 : return mTransformPreserves3D;
8381 : }
8382 0 :
8383 : const nsIFrame* establisher; // Establisher of the 3D rendering context.
8384 0 : for (establisher = mFrame;
8385 0 : establisher && establisher->Combines3DTransformWithAncestors();
8386 0 : establisher = establisher->GetInFlowParent()) {
8387 0 : }
8388 0 : const nsIFrame* establisherReference =
8389 : aBuilder->FindReferenceFrameFor(nsLayoutUtils::GetCrossDocParentFrame(establisher));
8390 0 :
8391 : nsPoint offset = establisher->GetOffsetToCrossDoc(establisherReference);
8392 : float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
8393 : uint32_t flags = INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN;
8394 0 : mTransformPreserves3D =
8395 : GetResultingTransformMatrix(mFrame, offset, scale, flags);
8396 : }
8397 : return mTransformPreserves3D;
8398 : }
8399 0 :
8400 : bool
8401 : nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
8402 : {
8403 0 : // The visible rect of a Preserves-3D frame is just an intermediate
8404 : // result. It should always build a layer to make sure it is
8405 : // rendering correctly.
8406 : return MayBeAnimated(aBuilder) || mFrame->Combines3DTransformWithAncestors();
8407 : }
8408 :
8409 : bool
8410 : nsDisplayTransform::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
8411 : mozilla::wr::IpcResourceUpdateQueue& aResources,
8412 : const StackingContextHelper& aSc,
8413 : WebRenderLayerManager* aManager,
8414 0 : nsDisplayListBuilder* aDisplayListBuilder)
8415 0 : {
8416 : // We want to make sure we don't pollute the transform property in the WR
8417 0 : // stacking context by including the position of this frame (relative to the
8418 0 : // parent reference frame). We need to keep those separate; the position of
8419 : // this frame goes into the stacking context bounds while the transform goes
8420 : // into the transform.
8421 : LayoutDevicePoint position;
8422 0 : Matrix4x4 newTransformMatrix = GetTransformForRendering(&position);
8423 :
8424 : gfx::Matrix4x4* transformForSC = &newTransformMatrix;
8425 0 : if (newTransformMatrix.IsIdentity()) {
8426 : // If the transform is an identity transform, strip it out so that WR
8427 0 : // doesn't turn this stacking context into a reference frame, as it
8428 0 : // affects positioning. Bug 1345577 tracks a better fix.
8429 : transformForSC = nullptr;
8430 0 : }
8431 0 :
8432 : RefPtr<WebRenderAnimationData> animationData = aManager->CommandBuilder().CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(this);
8433 :
8434 : AnimationInfo& animationInfo = animationData->GetAnimationInfo();
8435 0 : AddAnimationsForProperty(Frame(), aDisplayListBuilder,
8436 : this, eCSSProperty_transform,
8437 0 : animationInfo, false, true);
8438 0 : animationInfo.StartPendingAnimations(aManager->GetAnimationReadyTime());
8439 0 :
8440 : // Note that animationsId can be 0 (uninitialized in AnimationInfo) if there
8441 : // are no active animations.
8442 0 : uint64_t animationsId = animationInfo.GetCompositorAnimationsId();
8443 0 : wr::WrAnimationProperty prop;
8444 0 : if (!animationInfo.GetAnimations().IsEmpty()) {
8445 0 : prop.id = animationsId;
8446 0 : prop.effect_type = wr::WrAnimationType::Transform;
8447 0 :
8448 : OpAddCompositorAnimations
8449 : anim(CompositorAnimations(animationInfo.GetAnimations(), animationsId));
8450 0 : aManager->WrBridge()->AddWebRenderParentCommand(anim);
8451 0 : aManager->AddActiveCompositorAnimationId(animationsId);
8452 0 : } else if (animationsId) {
8453 : aManager->AddCompositorAnimationsIdForDiscard(animationsId);
8454 : animationsId = 0;
8455 : }
8456 :
8457 : nsTArray<mozilla::wr::WrFilterOp> filters;
8458 0 : Maybe<nsDisplayTransform*> deferredTransformItem;
8459 : if (!mFrame->HasPerspective()) {
8460 : // If it has perspective, we create a new scroll data via the
8461 : // UpdateScrollData call because that scenario is more complex. Otherwise
8462 : // we can just stash the transform on the StackingContextHelper and
8463 0 : // apply it to any scroll data that are created inside this
8464 0 : // nsDisplayTransform.
8465 : deferredTransformItem = Some(this);
8466 : }
8467 :
8468 : // If it looks like we're animated, we should rasterize in local space
8469 0 : // (disabling subpixel-aa and global pixel snapping)
8470 : bool rasterizeLocally = ActiveLayerTracker::IsStyleMaybeAnimated(
8471 : Frame(), eCSSProperty_transform);
8472 :
8473 : StackingContextHelper sc(aSc,
8474 : aBuilder,
8475 : filters,
8476 0 : LayoutDeviceRect(position, LayoutDeviceSize()),
8477 0 : &newTransformMatrix,
8478 : animationsId ? &prop : nullptr,
8479 : nullptr,
8480 0 : transformForSC,
8481 : nullptr,
8482 0 : gfx::CompositionOp::OP_OVER,
8483 0 : !BackfaceIsHidden(),
8484 : mFrame->Extend3DContext() && !mNoExtendContext,
8485 : deferredTransformItem,
8486 : nullptr,
8487 0 : rasterizeLocally);
8488 :
8489 : return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc,
8490 0 : aManager, aDisplayListBuilder);
8491 : }
8492 :
8493 : bool
8494 : nsDisplayTransform::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
8495 0 : mozilla::layers::WebRenderLayerScrollData* aLayerData)
8496 0 : {
8497 : if (!mFrame->HasPerspective()) {
8498 : // This case is handled in CreateWebRenderCommands by stashing the transform
8499 : // on the stacking context.
8500 : return false;
8501 : }
8502 11 : if (aLayerData) {
8503 : aLayerData->SetTransform(GetTransform().GetMatrix());
8504 : aLayerData->SetTransformIsPerspective(true);
8505 : }
8506 : return true;
8507 : }
8508 :
8509 0 : already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
8510 0 : LayerManager *aManager,
8511 : const ContainerLayerParameters& aContainerParameters)
8512 : {
8513 : // While generating a glyph mask, the transform vector of the root frame had
8514 : // been applied into the target context, so stop applying it again here.
8515 : const bool shouldSkipTransform =
8516 : (aBuilder->RootReferenceFrame() == mFrame) &&
8517 0 : (aBuilder->IsForGenerateGlyphMask() || aBuilder->IsForPaintingSelectionBG());
8518 :
8519 11 : /* For frames without transform, it would not be removed for
8520 : * backface hidden here. But, it would be removed by the init
8521 0 : * function of nsDisplayTransform.
8522 0 : */
8523 : const Matrix4x4 newTransformMatrix =
8524 0 : shouldSkipTransform ? Matrix4x4(): GetTransformForRendering();
8525 :
8526 : uint32_t flags = FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR;
8527 : RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
8528 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mStoredList.GetChildren(),
8529 : aContainerParameters, &newTransformMatrix, flags);
8530 11 :
8531 0 : if (!container) {
8532 : return nullptr;
8533 22 : }
8534 :
8535 : // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
8536 11 : // so we never need to explicitely unset this flag.
8537 0 : if (mFrame->Extend3DContext() && !mNoExtendContext) {
8538 : container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_EXTEND_3D_CONTEXT);
8539 : } else {
8540 1 : container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_EXTEND_3D_CONTEXT);
8541 : }
8542 1 :
8543 11 : if (mAllowAsyncAnimation) {
8544 : mFrame->SetProperty(nsIFrame::RefusedAsyncAnimationProperty(), false);
8545 : }
8546 :
8547 0 : nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
8548 0 : this, mFrame,
8549 0 : eCSSProperty_transform);
8550 : if (mAllowAsyncAnimation && MayBeAnimated(aBuilder)) {
8551 0 : // Only allow async updates to the transform if we're an animated layer, since that's what
8552 22 : // triggers us to set the correct AGR in the constructor and makes sure FrameLayerBuilder
8553 : // won't compute occlusions for this layer.
8554 22 : container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
8555 : /*the value is irrelevant*/nullptr);
8556 : container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM);
8557 : } else {
8558 22 : container->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
8559 : container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM);
8560 : }
8561 : return container.forget();
8562 : }
8563 :
8564 : bool
8565 : nsDisplayTransform::MayBeAnimated(nsDisplayListBuilder* aBuilder) const
8566 : {
8567 0 : // If EffectCompositor::HasAnimationsForCompositor() is true then we can
8568 0 : // completely bypass the main thread for this animation, so it is always
8569 22 : // worthwhile.
8570 22 : // For ActiveLayerTracker::IsStyleAnimated() cases the main thread is
8571 0 : // already involved so there is less to be gained.
8572 0 : // Therefore we check that the *post-transform* bounds of this item are
8573 : // big enough to justify an active layer.
8574 : if (EffectCompositor::HasAnimationsForCompositor(mFrame,
8575 0 : eCSSProperty_transform) ||
8576 : (ActiveLayerTracker::IsStyleAnimated(aBuilder,
8577 : mFrame,
8578 : eCSSProperty_transform) &&
8579 11 : !IsItemTooSmallForActiveLayer(mFrame))) {
8580 : return true;
8581 : }
8582 : return false;
8583 : }
8584 :
8585 : nsDisplayItem::LayerState
8586 : nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
8587 44 : LayerManager* aManager,
8588 33 : const ContainerLayerParameters& aParameters) {
8589 : // If the transform is 3d, the layer takes part in preserve-3d
8590 : // sorting, or the layer is a separator then we *always* want this
8591 : // to be an active layer.
8592 11 : // Checking HasPerspective() is needed to handle perspective value 0 when
8593 : // the transform is 2D.
8594 : if (!GetTransform().Is2D() || mFrame->Combines3DTransformWithAncestors() ||
8595 : mIsTransformSeparator || mFrame->HasPerspective()) {
8596 : return LAYER_ACTIVE_FORCE;
8597 : }
8598 :
8599 : if (MayBeAnimated(aBuilder)) {
8600 : // Returns LAYER_ACTIVE_FORCE to avoid flatterning the layer for async
8601 : // animations.
8602 33 : return LAYER_ACTIVE_FORCE;
8603 33 : }
8604 :
8605 : // Expect the child display items to have this frame as their animated
8606 0 : // geometry root (since it will be their reference frame). If they have a
8607 : // different animated geometry root, we'll make this an active layer so the
8608 : // animation can be accelerated.
8609 : return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
8610 : *mStoredList.GetChildren(), mAnimatedGeometryRootForChildren);
8611 : }
8612 :
8613 0 : bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
8614 : nsRegion *aVisibleRegion)
8615 : {
8616 : // nsDisplayTransform::GetBounds() returns an empty rect in nested 3d context.
8617 : // Calling mStoredList.RecomputeVisibility below for such transform causes the
8618 : // child display items to end up with empty visible rect.
8619 : // We avoid this by bailing out always if we are dealing with a 3d context.
8620 : if (mFrame->Extend3DContext() || mFrame->Combines3DTransformWithAncestors()) {
8621 0 : return true;
8622 0 : }
8623 :
8624 0 : /* As we do this, we need to be sure to
8625 : * untransform the visible rect, since we want everything that's painting to
8626 0 : * think that it's painting in its original rectangular coordinate space.
8627 : * If we can't untransform, take the entire overflow rect */
8628 : nsRect untransformedVisibleRect;
8629 : if (!UntransformPaintRect(aBuilder, &untransformedVisibleRect))
8630 0 : {
8631 : untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf();
8632 : }
8633 : nsRegion untransformedVisible = untransformedVisibleRect;
8634 : // Call RecomputeVisiblity instead of ComputeVisibility since
8635 : // nsDisplayItem::ComputeVisibility should only be called from
8636 : // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
8637 : mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
8638 : return true;
8639 0 : }
8640 :
8641 : #ifdef DEBUG_HIT
8642 : #include <time.h>
8643 : #endif
8644 0 :
8645 0 : /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
8646 0 : void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
8647 : const nsRect& aRect,
8648 : HitTestState *aState,
8649 : nsTArray<nsIFrame*> *aOutFrames)
8650 : {
8651 : if (aState->mInPreserves3D) {
8652 : mStoredList.HitTest(aBuilder, aRect, aState, aOutFrames);
8653 : return;
8654 : }
8655 :
8656 : /* Here's how this works:
8657 0 : * 1. Get the matrix. If it's singular, abort (clearly we didn't hit
8658 0 : * anything).
8659 : * 2. Invert the matrix.
8660 0 : * 3. Use it to transform the rect into the correct space.
8661 : * 4. Pass that rect down through to the list's version of HitTest.
8662 : */
8663 : // GetTransform always operates in dev pixels.
8664 : float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
8665 : Matrix4x4 matrix = GetAccumulatedPreserved3DTransform(aBuilder);
8666 :
8667 : if (!IsFrameVisible(mFrame, matrix)) {
8668 : return;
8669 : }
8670 0 :
8671 0 : /* We want to go from transformed-space to regular space.
8672 0 : * Thus we have to invert the matrix, which normally does
8673 : * the reverse operation (e.g. regular->transformed)
8674 0 : */
8675 0 :
8676 0 : /* Now, apply the transform and pass it down the channel. */
8677 0 : matrix.Invert();
8678 : nsRect resultingRect;
8679 : if (aRect.width == 1 && aRect.height == 1) {
8680 0 : // Magic width/height indicating we're hit testing a point, not a rect
8681 : Point4D point = matrix.ProjectPoint(Point(NSAppUnitsToFloatPixels(aRect.x, factor),
8682 0 : NSAppUnitsToFloatPixels(aRect.y, factor)));
8683 0 : if (!point.HasPositiveWCoord()) {
8684 0 : return;
8685 : }
8686 :
8687 0 : Point point2d = point.As2DPoint();
8688 0 :
8689 0 : resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point2d.x), factor),
8690 0 : NSFloatPixelsToAppUnits(float(point2d.y), factor),
8691 : 1, 1);
8692 :
8693 : } else {
8694 0 : Rect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
8695 : NSAppUnitsToFloatPixels(aRect.y, factor),
8696 : NSAppUnitsToFloatPixels(aRect.width, factor),
8697 : NSAppUnitsToFloatPixels(aRect.height, factor));
8698 0 :
8699 :
8700 0 : bool snap;
8701 : nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
8702 0 : Rect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
8703 : NSAppUnitsToFloatPixels(childBounds.y, factor),
8704 : NSAppUnitsToFloatPixels(childBounds.width, factor),
8705 : NSAppUnitsToFloatPixels(childBounds.height, factor));
8706 :
8707 : Rect rect = matrix.ProjectRectBounds(originalRect, childGfxBounds);
8708 0 :
8709 : resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
8710 : NSFloatPixelsToAppUnits(float(rect.Y()), factor),
8711 : NSFloatPixelsToAppUnits(float(rect.Width()), factor),
8712 : NSFloatPixelsToAppUnits(float(rect.Height()), factor));
8713 : }
8714 :
8715 : if (resultingRect.IsEmpty()) {
8716 : return;
8717 : }
8718 :
8719 0 :
8720 : #ifdef DEBUG_HIT
8721 : printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
8722 : printf(" Untransformed point: (%f, %f)\n", resultingRect.X(), resultingRect.Y());
8723 : uint32_t originalFrameCount = aOutFrames.Length();
8724 : #endif
8725 :
8726 : mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames);
8727 :
8728 : #ifdef DEBUG_HIT
8729 : if (originalFrameCount != aOutFrames.Length())
8730 : printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
8731 0 : dynamic_cast<void *>(aOutFrames.ElementAt(0)));
8732 : printf("=== end of hit test ===\n");
8733 : #endif
8734 0 :
8735 0 : }
8736 :
8737 0 : float
8738 : nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint)
8739 : {
8740 0 : // GetTransform always operates in dev pixels.
8741 0 : float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
8742 0 : Matrix4x4 matrix = GetAccumulatedPreserved3DTransform(aBuilder);
8743 0 :
8744 : NS_ASSERTION(IsFrameVisible(mFrame, matrix),
8745 0 : "We can't have hit a frame that isn't visible!");
8746 :
8747 0 : Matrix4x4 inverse = matrix;
8748 0 : inverse.Invert();
8749 : Point4D point = inverse.ProjectPoint(Point(NSAppUnitsToFloatPixels(aPoint.x, factor),
8750 : NSAppUnitsToFloatPixels(aPoint.y, factor)));
8751 :
8752 : Point point2d = point.As2DPoint();
8753 :
8754 : Point3D transformed = matrix.TransformPoint(Point3D(point2d.x, point2d.y, 0));
8755 0 : return transformed.z;
8756 : }
8757 :
8758 0 : /* The bounding rectangle for the object is the overflow rectangle translated
8759 : * by the reference point.
8760 22 : */
8761 0 : nsRect
8762 : nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
8763 : bool* aSnap) const
8764 11 : {
8765 0 : *aSnap = false;
8766 :
8767 : if (mHasBounds) {
8768 33 : return mBounds;
8769 : }
8770 22 :
8771 11 : if (mFrame->Extend3DContext() && !mIsTransformSeparator) {
8772 11 : return nsRect();
8773 : }
8774 0 :
8775 11 : nsRect untransformedBounds = mStoredList.GetBounds(aBuilder, aSnap);
8776 : // GetTransform always operates in dev pixels.
8777 : float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
8778 : mBounds = nsLayoutUtils::MatrixTransformRect(untransformedBounds,
8779 0 : GetTransform(),
8780 : factor);
8781 0 : mHasBounds = true;
8782 : return mBounds;
8783 : }
8784 :
8785 : void
8786 : nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder)
8787 : {
8788 : MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
8789 :
8790 : /* For some cases, the transform would make an empty bounds, but it
8791 0 : * may be turned back again to get a non-empty bounds. We should
8792 : * not depend on transforming bounds level by level.
8793 0 : *
8794 : * Here, it applies accumulated transforms on the leaf frames of the
8795 0 : * 3d rendering context, and track and accmulate bounds at
8796 : * nsDisplayListBuilder.
8797 0 : */
8798 : nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
8799 :
8800 : accTransform.Accumulate(GetTransform().GetMatrix());
8801 :
8802 : if (!IsLeafOf3DContext()) {
8803 : // Do not dive into another 3D context.
8804 : mStoredList.DoUpdateBoundsPreserves3D(aBuilder);
8805 0 : }
8806 :
8807 0 : /* For Preserves3D, it is bounds of only children as leaf frames.
8808 : * For non-leaf frames, their bounds are accumulated and kept at
8809 : * nsDisplayListBuilder.
8810 0 : */
8811 0 : bool snap;
8812 : nsRect untransformedBounds = mStoredList.GetBounds(aBuilder, &snap);
8813 0 : // GetTransform always operates in dev pixels.
8814 0 : float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
8815 : nsRect rect =
8816 : nsLayoutUtils::MatrixTransformRect(untransformedBounds,
8817 : accTransform.GetCurrentTransform(),
8818 : factor);
8819 :
8820 : aBuilder->AccumulateRect(rect);
8821 : }
8822 :
8823 : /* The transform is opaque iff the transform consists solely of scales and
8824 : * translations and if the underlying content is opaque. Thus if the transform
8825 : * is of the form
8826 : *
8827 : * |a c e|
8828 : * |b d f|
8829 : * |0 0 1|
8830 : *
8831 : * We need b and c to be zero.
8832 : *
8833 0 : * We also need to check whether the underlying opaque content completely fills
8834 : * our visible rect. We use UntransformRect which expands to the axis-aligned
8835 : * bounding rect, but that's OK since if
8836 0 : * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
8837 0 : * certainly contains the actual (non-axis-aligned) untransformed rect.
8838 0 : */
8839 0 : nsRegion
8840 : nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
8841 : bool* aSnap) const
8842 0 : {
8843 : *aSnap = false;
8844 0 : nsRect untransformedVisible;
8845 0 : if (!UntransformBuildingRect(aBuilder, &untransformedVisible)) {
8846 : return nsRegion();
8847 0 : }
8848 0 :
8849 0 : const Matrix4x4Flagged& matrix = GetTransform();
8850 0 :
8851 : nsRegion result;
8852 0 : Matrix matrix2d;
8853 : bool tmpSnap;
8854 : if (matrix.Is2D(&matrix2d) &&
8855 : matrix2d.PreservesAxisAlignedRectangles() &&
8856 : mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) {
8857 : result = GetBuildingRect().Intersect(GetBounds(aBuilder, &tmpSnap));
8858 : }
8859 : return result;
8860 : }
8861 :
8862 : /* TransformRect takes in as parameters a rectangle (in app space) and returns
8863 : * the smallest rectangle (in app space) containing the transformed image of
8864 : * that rectangle. That is, it takes the four corners of the rectangle,
8865 : * transforms them according to the matrix associated with the specified frame,
8866 : * then returns the smallest rectangle containing the four transformed points.
8867 : *
8868 : * @param aUntransformedBounds The rectangle (in app units) to transform.
8869 0 : * @param aFrame The frame whose transformation should be applied.
8870 : * @param aOrigin The delta from the frame origin to the coordinate space origin
8871 : * @param aBoundsOverride (optional) Force the frame bounds to be the
8872 : * specified bounds.
8873 0 : * @return The smallest rectangle containing the image of the transformed
8874 : * rectangle.
8875 0 : */
8876 : nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
8877 62 : const nsIFrame* aFrame,
8878 : const nsRect* aBoundsOverride)
8879 : {
8880 0 : MOZ_ASSERT(aFrame, "Can't take the transform based on a null frame!");
8881 124 :
8882 : float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
8883 :
8884 0 : uint32_t flags = INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN|INCLUDE_PRESERVE3D_ANCESTORS;
8885 : return nsLayoutUtils::MatrixTransformRect
8886 : (aUntransformedBounds,
8887 : GetResultingTransformMatrix(aFrame, nsPoint(0, 0), factor, flags, aBoundsOverride),
8888 : factor);
8889 22 : }
8890 :
8891 44 : bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds,
8892 : const nsRect &aChildBounds,
8893 22 : const nsIFrame* aFrame,
8894 : nsRect *aOutRect)
8895 22 : {
8896 22 : MOZ_ASSERT(aFrame, "Can't take the transform based on a null frame!");
8897 :
8898 : float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
8899 :
8900 44 : uint32_t flags = INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN|INCLUDE_PRESERVE3D_ANCESTORS;
8901 44 :
8902 44 : Matrix4x4 transform = GetResultingTransformMatrix(aFrame, nsPoint(0, 0), factor, flags);
8903 132 : if (transform.IsSingular()) {
8904 : return false;
8905 0 : }
8906 44 :
8907 44 : RectDouble result(NSAppUnitsToFloatPixels(aTransformedBounds.x, factor),
8908 132 : NSAppUnitsToFloatPixels(aTransformedBounds.y, factor),
8909 : NSAppUnitsToFloatPixels(aTransformedBounds.width, factor),
8910 22 : NSAppUnitsToFloatPixels(aTransformedBounds.height, factor));
8911 22 :
8912 22 : RectDouble childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds.x, factor),
8913 : NSAppUnitsToFloatPixels(aChildBounds.y, factor),
8914 : NSAppUnitsToFloatPixels(aChildBounds.width, factor),
8915 0 : NSAppUnitsToFloatPixels(aChildBounds.height, factor));
8916 :
8917 : result = transform.Inverse().ProjectRectBounds(result, childGfxBounds);
8918 : *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result), factor);
8919 0 : return true;
8920 : }
8921 :
8922 : bool nsDisplayTransform::UntransformRect(nsDisplayListBuilder* aBuilder,
8923 : const nsRect& aRect,
8924 0 : nsRect *aOutRect) const
8925 0 : {
8926 0 : if (GetTransform().IsSingular()) {
8927 0 : return false;
8928 0 : }
8929 :
8930 : // GetTransform always operates in dev pixels.
8931 0 : float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
8932 0 : RectDouble result(NSAppUnitsToFloatPixels(aRect.x, factor),
8933 0 : NSAppUnitsToFloatPixels(aRect.y, factor),
8934 0 : NSAppUnitsToFloatPixels(aRect.width, factor),
8935 0 : NSAppUnitsToFloatPixels(aRect.height, factor));
8936 :
8937 : bool snap;
8938 0 : nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
8939 : RectDouble childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
8940 0 : NSAppUnitsToFloatPixels(childBounds.y, factor),
8941 : NSAppUnitsToFloatPixels(childBounds.width, factor),
8942 : NSAppUnitsToFloatPixels(childBounds.height, factor));
8943 :
8944 : /* We want to untransform the matrix, so invert the transformation first! */
8945 : result = GetInverseTransform().ProjectRectBounds(result, childGfxBounds);
8946 0 :
8947 : *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result), factor);
8948 0 :
8949 0 : return true;
8950 0 : }
8951 :
8952 0 : void
8953 0 : nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream)
8954 : {
8955 0 : AppendToString(aStream, GetTransform().GetMatrix());
8956 0 : if (IsTransformSeparator()) {
8957 : aStream << " transform-separator";
8958 0 : }
8959 0 : if (IsLeafOf3DContext()) {
8960 : aStream << " 3d-context-leaf";
8961 0 : }
8962 : if (mFrame->Extend3DContext()) {
8963 0 : aStream << " extends-3d-context";
8964 : }
8965 0 : if (mFrame->Combines3DTransformWithAncestors()) {
8966 : aStream << " combines-3d-with-ancestors";
8967 0 : }
8968 : }
8969 0 :
8970 0 : nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder,
8971 0 : nsIFrame* aFrame,
8972 0 : nsDisplayList* aList)
8973 : : nsDisplayItem(aBuilder, aFrame)
8974 : , mList(aBuilder, aFrame, aList, true)
8975 0 : {
8976 : MOZ_ASSERT(mList.GetChildren()->Count() == 1);
8977 : MOZ_ASSERT(mList.GetChildren()->GetTop()->GetType() == DisplayItemType::TYPE_TRANSFORM);
8978 : mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(mFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME));
8979 0 : }
8980 :
8981 0 : already_AddRefed<Layer>
8982 : nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder,
8983 0 : LayerManager *aManager,
8984 0 : const ContainerLayerParameters& aContainerParameters)
8985 0 : {
8986 : float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
8987 :
8988 : Matrix4x4 perspectiveMatrix;
8989 : DebugOnly<bool> hasPerspective =
8990 0 : nsDisplayTransform::ComputePerspectiveMatrix(mFrame, appUnitsPerPixel,
8991 : perspectiveMatrix);
8992 : MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?");
8993 :
8994 : /*
8995 : * ClipListToRange can remove our child after we were created.
8996 : */
8997 : if (!mList.GetChildren()->GetTop()) {
8998 : return nullptr;
8999 0 : }
9000 :
9001 : /*
9002 0 : * The resulting matrix is still in the coordinate space of the transformed
9003 0 : * frame. Append a translation to the reference frame coordinates.
9004 0 : */
9005 0 : nsDisplayTransform* transform =
9006 0 : static_cast<nsDisplayTransform*>(mList.GetChildren()->GetTop());
9007 0 :
9008 : Point3D newOrigin =
9009 0 : Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x, appUnitsPerPixel),
9010 : NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y, appUnitsPerPixel),
9011 : 0.0f);
9012 0 : Point3D roundedOrigin(NS_round(newOrigin.x),
9013 0 : NS_round(newOrigin.y),
9014 : 0);
9015 0 :
9016 : perspectiveMatrix.PostTranslate(roundedOrigin);
9017 :
9018 : RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
9019 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList.GetChildren(),
9020 : aContainerParameters, &perspectiveMatrix, 0);
9021 :
9022 0 : if (!container) {
9023 0 : return nullptr;
9024 : }
9025 0 :
9026 : // Sort of a lie, but we want to pretend that the perspective layer extends a 3d context
9027 : // so that it gets its transform combined with children. Might need a better name that reflects
9028 : // this use case and isn't specific to preserve-3d.
9029 0 : container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_EXTEND_3D_CONTEXT);
9030 : container->SetTransformIsPerspective(true);
9031 :
9032 : return container.forget();
9033 0 : }
9034 :
9035 : LayerState
9036 : nsDisplayPerspective::GetLayerState(nsDisplayListBuilder* aBuilder,
9037 0 : LayerManager* aManager,
9038 : const ContainerLayerParameters& aParameters)
9039 : {
9040 : return LAYER_ACTIVE_FORCE;
9041 : }
9042 :
9043 0 : bool
9044 0 : nsDisplayPerspective::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
9045 : mozilla::wr::IpcResourceUpdateQueue& aResources,
9046 0 : const StackingContextHelper& aSc,
9047 0 : WebRenderLayerManager* aManager,
9048 0 : nsDisplayListBuilder* aDisplayListBuilder)
9049 : {
9050 : float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
9051 : Matrix4x4 perspectiveMatrix;
9052 : DebugOnly<bool> hasPerspective =
9053 0 : nsDisplayTransform::ComputePerspectiveMatrix(mFrame, appUnitsPerPixel,
9054 : perspectiveMatrix);
9055 : MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?");
9056 :
9057 : /*
9058 : * ClipListToRange can remove our child after we were created.
9059 : */
9060 : if (!mList.GetChildren()->GetTop()) {
9061 : return false;
9062 0 : }
9063 :
9064 : /*
9065 0 : * The resulting matrix is still in the coordinate space of the transformed
9066 0 : * frame. Append a translation to the reference frame coordinates.
9067 0 : */
9068 0 : nsDisplayTransform* transform =
9069 0 : static_cast<nsDisplayTransform*>(mList.GetChildren()->GetTop());
9070 0 :
9071 : Point3D newOrigin =
9072 0 : Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x, appUnitsPerPixel),
9073 : NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y, appUnitsPerPixel),
9074 0 : 0.0f);
9075 : Point3D roundedOrigin(NS_round(newOrigin.x),
9076 : NS_round(newOrigin.y),
9077 : 0);
9078 0 :
9079 : gfx::Matrix4x4 transformForSC = gfx::Matrix4x4::Translation(roundedOrigin);
9080 :
9081 : nsTArray<mozilla::wr::WrFilterOp> filters;
9082 : StackingContextHelper sc(aSc,
9083 : aBuilder,
9084 : filters,
9085 0 : LayoutDeviceRect(),
9086 0 : nullptr,
9087 : nullptr,
9088 0 : nullptr,
9089 0 : &transformForSC,
9090 : &perspectiveMatrix,
9091 : gfx::CompositionOp::OP_OVER,
9092 : !BackfaceIsHidden(),
9093 0 : true);
9094 :
9095 0 : return mList.CreateWebRenderCommands(aBuilder, aResources, sc,
9096 : aManager, aDisplayListBuilder);
9097 : }
9098 :
9099 0 : nsDisplayItemGeometry*
9100 : nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder* aBuilder)
9101 : {
9102 : return new nsCharClipGeometry(this, aBuilder);
9103 0 : }
9104 :
9105 : void
9106 0 : nsCharClipDisplayItem::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
9107 0 : const nsDisplayItemGeometry* aGeometry,
9108 0 : nsRegion* aInvalidRegion) const
9109 0 : {
9110 0 : const nsCharClipGeometry* geometry = static_cast<const nsCharClipGeometry*>(aGeometry);
9111 0 :
9112 0 : bool snap;
9113 : nsRect newRect = geometry->mBounds;
9114 0 : nsRect oldRect = GetBounds(aBuilder, &snap);
9115 : if (mVisIStartEdge != geometry->mVisIStartEdge ||
9116 0 : mVisIEndEdge != geometry->mVisIEndEdge ||
9117 : !oldRect.IsEqualInterior(newRect) ||
9118 : !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
9119 : aInvalidRegion->Or(oldRect, newRect);
9120 0 : }
9121 : }
9122 0 :
9123 : nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
9124 0 : nsIFrame* aFrame, nsDisplayList* aList,
9125 0 : bool aHandleOpacity,
9126 : const ActiveScrolledRoot* aActiveScrolledRoot,
9127 0 : bool aClearClipChain)
9128 : : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, aClearClipChain)
9129 0 : , mHandleOpacity(aHandleOpacity)
9130 : {
9131 0 : MOZ_COUNT_CTOR(nsDisplaySVGEffects);
9132 : }
9133 0 :
9134 0 : nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
9135 : nsIFrame* aFrame, nsDisplayList* aList,
9136 : bool aHandleOpacity)
9137 0 : : nsDisplayWrapList(aBuilder, aFrame, aList)
9138 : , mHandleOpacity(aHandleOpacity)
9139 0 : {
9140 0 : MOZ_COUNT_CTOR(nsDisplaySVGEffects);
9141 : }
9142 :
9143 0 : #ifdef NS_BUILD_REFCNT_LOGGING
9144 : nsDisplaySVGEffects::~nsDisplaySVGEffects()
9145 : {
9146 0 : MOZ_COUNT_DTOR(nsDisplaySVGEffects);
9147 0 : }
9148 : #endif
9149 :
9150 : nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
9151 0 : bool* aSnap) const
9152 : {
9153 : *aSnap = false;
9154 0 : return nsRegion();
9155 0 : }
9156 0 :
9157 0 : void
9158 : nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
9159 0 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
9160 : {
9161 : nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
9162 0 : if (nsSVGIntegrationUtils::HitTestFrameForEffects(mFrame,
9163 : rectCenter - ToReferenceFrame())) {
9164 0 : mList.HitTest(aBuilder, aRect, aState, aOutFrames);
9165 : }
9166 : }
9167 :
9168 0 : gfxRect
9169 : nsDisplaySVGEffects::BBoxInUserSpace() const
9170 0 : {
9171 : return nsSVGUtils::GetBBox(mFrame);
9172 : }
9173 :
9174 0 : gfxPoint
9175 : nsDisplaySVGEffects::UserSpaceOffset() const
9176 : {
9177 : return nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame);
9178 : }
9179 0 :
9180 : void
9181 0 : nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
9182 0 : const nsDisplayItemGeometry* aGeometry,
9183 0 : nsRegion* aInvalidRegion) const
9184 0 : {
9185 : const nsDisplaySVGEffectGeometry* geometry =
9186 : static_cast<const nsDisplaySVGEffectGeometry*>(aGeometry);
9187 : bool snap;
9188 : nsRect bounds = GetBounds(aBuilder, &snap);
9189 : if (geometry->mFrameOffsetToReferenceFrame != ToReferenceFrame() ||
9190 : geometry->mUserSpaceOffset != UserSpaceOffset() ||
9191 0 : !geometry->mBBox.IsEqualInterior(BBoxInUserSpace())) {
9192 : // Filter and mask output can depend on the location of the frame's user
9193 0 : // space and on the frame's BBox. We need to invalidate if either of these
9194 : // change relative to the reference frame.
9195 0 : // Invalidations from our inactive layer manager are not enough to catch
9196 : // some of these cases because filters can produce output even if there's
9197 0 : // nothing in the filter input.
9198 0 : aInvalidRegion->Or(bounds, geometry->mBounds);
9199 0 : }
9200 0 : }
9201 0 :
9202 0 : bool nsDisplaySVGEffects::ValidateSVGFrame()
9203 0 : {
9204 : const nsIContent* content = mFrame->GetContent();
9205 0 : bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
9206 : if (hasSVGLayout) {
9207 : nsSVGDisplayableFrame* svgFrame = do_QueryFrame(mFrame);
9208 : if (!svgFrame || !mFrame->GetContent()->IsSVGElement()) {
9209 : NS_ASSERTION(false, "why?");
9210 : return false;
9211 : }
9212 : if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
9213 : return false; // The SVG spec says not to draw filters for this
9214 0 : }
9215 : }
9216 :
9217 : return true;
9218 0 : }
9219 0 :
9220 : static IntRect
9221 0 : ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
9222 0 : {
9223 0 : // Get the clip extents in device space.
9224 0 : gfxRect clippedFrameSurfaceRect =
9225 : aCtx.GetClipExtents(gfxContext::eDeviceSpace);
9226 : clippedFrameSurfaceRect.RoundOut();
9227 :
9228 : IntRect result;
9229 : ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
9230 0 : return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
9231 : : IntRect();
9232 : }
9233 :
9234 : typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
9235 0 :
9236 : static void
9237 0 : ComputeMaskGeometry(PaintFramesParams& aParams)
9238 : {
9239 : // Properties are added lazily and may have been removed by a restyle, so
9240 0 : // make sure all applicable ones are set again.
9241 0 : nsIFrame* firstFrame =
9242 : nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParams.frame);
9243 0 :
9244 0 : const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
9245 :
9246 : SVGObserverUtils::EffectProperties effectProperties =
9247 0 : SVGObserverUtils::GetEffectProperties(firstFrame);
9248 0 : nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
9249 :
9250 : if (maskFrames.Length() == 0) {
9251 0 : return;
9252 : }
9253 :
9254 : gfxContext& ctx = aParams.ctx;
9255 0 : nsIFrame* frame = aParams.frame;
9256 :
9257 0 : nsPoint offsetToUserSpace =
9258 0 : nsLayoutUtils::ComputeOffsetToUserSpace(aParams.builder, aParams.frame);
9259 :
9260 : gfxPoint devPixelOffsetToUserSpace =
9261 0 : nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
9262 0 : frame->PresContext()->AppUnitsPerDevPixel());
9263 0 :
9264 : gfxContextMatrixAutoSaveRestore matSR(&ctx);
9265 : ctx.SetMatrixDouble(ctx.CurrentMatrixDouble().PreTranslate(devPixelOffsetToUserSpace));
9266 0 :
9267 0 : // Convert boaderArea and dirtyRect to user space.
9268 0 : int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
9269 0 : nsRect userSpaceBorderArea = aParams.borderArea - offsetToUserSpace;
9270 : nsRect userSpaceDirtyRect = aParams.dirtyRect - offsetToUserSpace;
9271 0 :
9272 0 : // Union all mask layer rectangles in user space.
9273 : gfxRect maskInUserSpace;
9274 0 : for (size_t i = 0; i < maskFrames.Length() ; i++) {
9275 0 : nsSVGMaskFrame* maskFrame = maskFrames[i];
9276 : gfxRect currentMaskSurfaceRect;
9277 0 :
9278 : if (maskFrame) {
9279 : currentMaskSurfaceRect = maskFrame->GetMaskArea(aParams.frame);
9280 : } else {
9281 : nsCSSRendering::ImageLayerClipState clipState;
9282 0 : nsCSSRendering::GetImageLayerClip(svgReset->mMask.mLayers[i],
9283 0 : frame,
9284 : *frame->StyleBorder(),
9285 : userSpaceBorderArea,
9286 0 : userSpaceDirtyRect,
9287 : false, /* aWillPaintBorder */
9288 : appUnitsPerDevPixel,
9289 0 : &clipState);
9290 : currentMaskSurfaceRect = clipState.mDirtyRectInDevPx;
9291 0 : }
9292 0 :
9293 0 : maskInUserSpace = maskInUserSpace.Union(currentMaskSurfaceRect);
9294 : }
9295 :
9296 0 : gfxContextAutoSaveRestore autoSR;
9297 0 :
9298 : if (!maskInUserSpace.IsEmpty()) {
9299 : autoSR.SetContext(&ctx);
9300 0 : ctx.Clip(maskInUserSpace);
9301 : }
9302 :
9303 0 : IntRect result = ComputeClipExtsInDeviceSpace(ctx);
9304 0 : aParams.maskRect = result;
9305 : }
9306 0 :
9307 : nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
9308 0 : nsIFrame* aFrame, nsDisplayList* aList,
9309 0 : bool aHandleOpacity,
9310 0 : const ActiveScrolledRoot* aActiveScrolledRoot)
9311 0 : : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity, aActiveScrolledRoot, true)
9312 0 : {
9313 0 : MOZ_COUNT_CTOR(nsDisplayMask);
9314 0 :
9315 : nsPresContext* presContext = mFrame->PresContext();
9316 : uint32_t flags = aBuilder->GetBackgroundPaintFlags() |
9317 : nsCSSRendering::PAINTBG_MASK_IMAGE;
9318 : const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
9319 0 : NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
9320 0 : if (!svgReset->mMask.mLayers[i].mImage.IsResolved()) {
9321 : continue;
9322 0 : }
9323 0 : bool isTransformedFixed;
9324 : nsBackgroundLayerState state =
9325 0 : nsCSSRendering::PrepareImageLayer(presContext, aFrame, flags,
9326 : mFrame->GetRectRelativeToSelf(),
9327 : mFrame->GetRectRelativeToSelf(),
9328 0 : svgReset->mMask.mLayers[i],
9329 : &isTransformedFixed);
9330 0 : mDestRects.AppendElement(state.mDestArea);
9331 0 : }
9332 : }
9333 :
9334 : #ifdef NS_BUILD_REFCNT_LOGGING
9335 0 : nsDisplayMask::~nsDisplayMask()
9336 : {
9337 : MOZ_COUNT_DTOR(nsDisplayMask);
9338 : }
9339 0 : #endif
9340 :
9341 : static bool
9342 : CanMergeDisplayMaskFrame(nsIFrame* aFrame)
9343 : {
9344 : // Do not merge items for box-decoration-break:clone elements,
9345 : // since each box should have its own mask in that case.
9346 0 : if (aFrame->StyleBorder()->mBoxDecorationBreak ==
9347 : mozilla::StyleBoxDecorationBreak::Clone) {
9348 : return false;
9349 : }
9350 0 :
9351 : // Do not merge if either frame has a mask. Continuation frames should apply
9352 : // the mask independently (just like nsDisplayBackgroundImage).
9353 : if (aFrame->StyleSVGReset()->HasMask()) {
9354 0 : return false;
9355 : }
9356 :
9357 : return true;
9358 0 : }
9359 :
9360 : bool
9361 : nsDisplayMask::CanMerge(const nsDisplayItem* aItem) const
9362 0 : {
9363 0 : // Items for the same content element should be merged into a single
9364 : // compositing group.
9365 : if (!HasSameTypeAndClip(aItem) || !HasSameContent(aItem)) {
9366 : return false;
9367 0 : }
9368 :
9369 : return CanMergeDisplayMaskFrame(mFrame) &&
9370 : CanMergeDisplayMaskFrame(aItem->Frame());
9371 0 : }
9372 :
9373 : already_AddRefed<Layer>
9374 : nsDisplayMask::BuildLayer(nsDisplayListBuilder* aBuilder,
9375 0 : LayerManager* aManager,
9376 : const ContainerLayerParameters& aContainerParameters)
9377 : {
9378 : if (!ValidateSVGFrame()) {
9379 : return nullptr;
9380 0 : }
9381 :
9382 0 : if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) {
9383 : return nullptr;
9384 0 : }
9385 0 :
9386 : nsIFrame* firstFrame =
9387 : nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
9388 : SVGObserverUtils::EffectProperties effectProperties =
9389 : SVGObserverUtils::GetEffectProperties(firstFrame);
9390 0 :
9391 0 : if (effectProperties.HasInvalidClipPath() ||
9392 : effectProperties.HasInvalidMask()) {
9393 0 : return nullptr;
9394 : }
9395 :
9396 : RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
9397 0 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
9398 : aContainerParameters, nullptr);
9399 :
9400 0 : return container.forget();
9401 : }
9402 0 :
9403 : bool
9404 0 : nsDisplayMask::PaintMask(nsDisplayListBuilder* aBuilder,
9405 0 : gfxContext* aMaskContext)
9406 : {
9407 : MOZ_ASSERT(aMaskContext->GetDrawTarget()->GetFormat() == SurfaceFormat::A8);
9408 :
9409 : imgDrawingParams imgParmas(aBuilder->ShouldSyncDecodeImages()
9410 0 : ? imgIContainer::FLAG_SYNC_DECODE
9411 0 : : imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
9412 0 : nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
9413 : nsSVGIntegrationUtils::PaintFramesParams params(*aMaskContext,
9414 0 : mFrame, GetBuildingRect(),
9415 : borderArea, aBuilder,
9416 0 : nullptr,
9417 : mHandleOpacity, imgParmas);
9418 : ComputeMaskGeometry(params);
9419 : nsSVGIntegrationUtils::PaintMask(params);
9420 0 :
9421 : nsDisplayMaskGeometry::UpdateDrawResult(this, imgParmas.result);
9422 :
9423 : return imgParmas.result == mozilla::image::ImgDrawResult::SUCCESS;
9424 0 : }
9425 0 :
9426 0 : LayerState
9427 : nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
9428 : LayerManager* aManager,
9429 : const ContainerLayerParameters& aParameters)
9430 : {
9431 : if (CanPaintOnMaskLayer(aManager)) {
9432 0 : LayerState result = RequiredLayerStateForChildren(aBuilder, aManager,
9433 : aParameters, mList, GetAnimatedGeometryRoot());
9434 : // When we're not active, FrameLayerBuilder will call PaintAsLayer()
9435 : // on us during painting. In that case we don't want a mask layer to
9436 : // be created, because PaintAsLayer() takes care of applying the mask.
9437 : // So we return LAYER_SVG_EFFECTS instead of LAYER_INACTIVE so that
9438 0 : // FrameLayerBuilder doesn't set a mask layer on our layer.
9439 : return result == LAYER_INACTIVE ? LAYER_SVG_EFFECTS : result;
9440 0 : }
9441 :
9442 : return LAYER_SVG_EFFECTS;
9443 : }
9444 0 :
9445 : bool nsDisplayMask::CanPaintOnMaskLayer(LayerManager* aManager)
9446 : {
9447 : if (!nsSVGIntegrationUtils::IsMaskResourceReady(mFrame)) {
9448 0 : return false;
9449 : }
9450 :
9451 0 : if (gfxPrefs::DrawMaskLayer()) {
9452 : return false;
9453 : }
9454 :
9455 : return true;
9456 0 : }
9457 0 :
9458 0 : bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
9459 0 : nsRegion* aVisibleRegion)
9460 : {
9461 : // Our children may be made translucent or arbitrarily deformed so we should
9462 : // not allow them to subtract area from aVisibleRegion.
9463 0 : nsRegion childrenVisible(GetPaintRect());
9464 : nsRect r = GetPaintRect().Intersect(mList.GetBounds(aBuilder));
9465 : mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
9466 : return true;
9467 0 : }
9468 0 :
9469 : void
9470 : nsDisplayMask::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
9471 0 : const nsDisplayItemGeometry* aGeometry,
9472 : nsRegion* aInvalidRegion) const
9473 0 : {
9474 : nsDisplaySVGEffects::ComputeInvalidationRegion(aBuilder, aGeometry,
9475 0 : aInvalidRegion);
9476 0 :
9477 0 : const nsDisplayMaskGeometry* geometry =
9478 : static_cast<const nsDisplayMaskGeometry*>(aGeometry);
9479 : bool snap;
9480 0 : nsRect bounds = GetBounds(aBuilder, &snap);
9481 0 :
9482 : if (mFrame->StyleEffects()->mOpacity != geometry->mOpacity ||
9483 0 : mHandleOpacity != geometry->mHandleOpacity) {
9484 0 : aInvalidRegion->Or(*aInvalidRegion, bounds);
9485 0 : }
9486 0 :
9487 : if (mDestRects.Length() != geometry->mDestRects.Length()) {
9488 : aInvalidRegion->Or(bounds, geometry->mBounds);
9489 : } else {
9490 : for (size_t i = 0; i < mDestRects.Length(); i++) {
9491 0 : if (!mDestRects[i].IsEqualInterior(geometry->mDestRects[i])) {
9492 0 : aInvalidRegion->Or(bounds, geometry->mBounds);
9493 0 : break;
9494 0 : }
9495 0 : }
9496 0 : }
9497 0 :
9498 0 : if (aBuilder->ShouldSyncDecodeImages() &&
9499 : geometry->ShouldInvalidateToSyncDecodeImages()) {
9500 : const nsStyleSVGReset *svgReset = mFrame->StyleSVGReset();
9501 : NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
9502 0 : const nsStyleImage& image = svgReset->mMask.mLayers[i].mImage;
9503 : if (image.GetType() == eStyleImageType_Image ) {
9504 : aInvalidRegion->Or(*aInvalidRegion, bounds);
9505 0 : break;
9506 : }
9507 : }
9508 : }
9509 : }
9510 :
9511 0 : void
9512 : nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder,
9513 : gfxContext* aCtx,
9514 0 : LayerManager* aManager)
9515 0 : {
9516 0 : // Clip the drawing target by mVisibleRect, which contains the visible
9517 : // region of the target frame and its out-of-flow and inflow descendants.
9518 0 : gfxContext* context = aCtx;
9519 :
9520 0 : Rect bounds =
9521 0 : NSRectToRect(GetPaintRect(), mFrame->PresContext()->AppUnitsPerDevPixel());
9522 : bounds.RoundOut();
9523 : context->Clip(bounds);
9524 :
9525 : imgDrawingParams imgParams(aBuilder->ShouldSyncDecodeImages()
9526 0 : ? imgIContainer::FLAG_SYNC_DECODE
9527 : : imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
9528 0 : nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
9529 : nsSVGIntegrationUtils::PaintFramesParams params(*aCtx,
9530 0 : mFrame, GetPaintRect(),
9531 : borderArea, aBuilder,
9532 0 : aManager,
9533 : mHandleOpacity, imgParams);
9534 0 :
9535 0 : ComputeMaskGeometry(params);
9536 :
9537 : nsSVGIntegrationUtils::PaintMaskAndClipPath(params);
9538 0 :
9539 : context->PopClip();
9540 :
9541 : nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
9542 : }
9543 :
9544 : bool
9545 0 : nsDisplayMask::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
9546 0 : mozilla::wr::IpcResourceUpdateQueue& aResources,
9547 0 : const StackingContextHelper& aSc,
9548 : mozilla::layers::WebRenderLayerManager* aManager,
9549 0 : nsDisplayListBuilder* aDisplayListBuilder)
9550 : {
9551 0 : bool snap;
9552 0 : float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
9553 0 : nsRect displayBound = GetBounds(aDisplayListBuilder, &snap);
9554 0 : LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(displayBound, appUnitsPerDevPixel);
9555 0 :
9556 : Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(this, aBuilder, aResources,
9557 0 : aSc, aDisplayListBuilder,
9558 : bounds);
9559 : Maybe<StackingContextHelper> layer;
9560 : const StackingContextHelper* sc = &aSc;
9561 : if (mask) {
9562 : auto layoutBounds = wr::ToRoundedLayoutRect(bounds);
9563 0 : wr::WrClipId clipId = aBuilder.DefineClip(Nothing(),
9564 : layoutBounds, nullptr, mask.ptr());
9565 0 :
9566 : // Create a new stacking context to attach the mask to, ensuring the mask is
9567 0 : // applied to the aggregate, and not the individual elements.
9568 :
9569 : // The stacking context shouldn't have any offset.
9570 : bounds.MoveTo(0, 0);
9571 :
9572 : layer.emplace(aSc,
9573 : aBuilder,
9574 : /*aFilters: */ nsTArray<wr::WrFilterOp>(),
9575 : /*aBounds: */ bounds,
9576 : /*aBoundTransform: */ nullptr,
9577 : /*aAnimation: */ nullptr,
9578 0 : /*aOpacity: */ nullptr,
9579 0 : /*aTransform: */ nullptr,
9580 0 : /*aPerspective: */ nullptr,
9581 : /*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
9582 : /*aBackfaceVisible: */ true,
9583 0 : /*aIsPreserve3D: */ false,
9584 : /*aTransformForScrollData: */ Nothing(),
9585 0 : /*aClipNodeId: */ &clipId);
9586 0 : sc = layer.ptr();
9587 : aManager->CommandBuilder().PushOverrideForASR(GetActiveScrolledRoot(), Some(clipId));
9588 : }
9589 0 :
9590 : nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, *sc, aManager, aDisplayListBuilder);
9591 :
9592 : if (mask) {
9593 0 : aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
9594 : }
9595 :
9596 0 : return true;
9597 0 : }
9598 :
9599 : Maybe<nsRect>
9600 : nsDisplayMask::GetClipWithRespectToASR(nsDisplayListBuilder* aBuilder,
9601 : const ActiveScrolledRoot* aASR) const
9602 0 : {
9603 0 : if (const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(GetClipChain(), aASR)) {
9604 0 : return Some(clip->GetClipRect());
9605 : }
9606 : // This item does not have a clip with respect to |aASR|. However, we
9607 0 : // might still have finite bounds with respect to |aASR|. Check our
9608 0 : // children.
9609 : nsDisplayList* childList = GetSameCoordinateSystemChildren();
9610 : if (childList) {
9611 : return Some(childList->GetClippedBoundsWithRespectToASR(aBuilder, aASR));
9612 : }
9613 : #ifdef DEBUG
9614 : if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
9615 : MOZ_ASSERT(false, "item should have finite clip with respect to aASR");
9616 : }
9617 : #endif
9618 0 : return Nothing();
9619 : }
9620 :
9621 0 :
9622 :
9623 0 : #ifdef MOZ_DUMP_PAINTING
9624 0 : void
9625 0 : nsDisplayMask::PrintEffects(nsACString& aTo)
9626 0 : {
9627 0 : nsIFrame* firstFrame =
9628 0 : nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
9629 0 : SVGObserverUtils::EffectProperties effectProperties =
9630 : SVGObserverUtils::GetEffectProperties(firstFrame);
9631 0 : nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
9632 0 : bool first = true;
9633 0 : aTo += " effects=(";
9634 : if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
9635 0 : first = false;
9636 0 : aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
9637 : }
9638 0 : if (clipPathFrame) {
9639 0 : if (!first) {
9640 0 : aTo += ", ";
9641 0 : }
9642 : aTo += nsPrintfCString("clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
9643 0 : first = false;
9644 0 : }
9645 : const nsStyleSVGReset *style = mFrame->StyleSVGReset();
9646 : if (style->HasClipPath() && !clipPathFrame) {
9647 0 : if (!first) {
9648 0 : aTo += ", ";
9649 0 : }
9650 0 : aTo += "clip(basic-shape)";
9651 : first = false;
9652 0 : }
9653 :
9654 0 : nsTArray<nsSVGMaskFrame*> masks = effectProperties.GetMaskFrames();
9655 0 : if (!masks.IsEmpty() && masks[0]) {
9656 : if (!first) {
9657 : aTo += ", ";
9658 0 : }
9659 : aTo += "mask";
9660 0 : }
9661 : aTo += ")";
9662 0 : }
9663 : #endif
9664 0 :
9665 0 : nsDisplayFilter::nsDisplayFilter(nsDisplayListBuilder* aBuilder,
9666 : nsIFrame* aFrame, nsDisplayList* aList,
9667 : bool aHandleOpacity)
9668 0 : : nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity),
9669 : mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
9670 0 : {
9671 0 : MOZ_COUNT_CTOR(nsDisplayFilter);
9672 : }
9673 :
9674 : #ifdef NS_BUILD_REFCNT_LOGGING
9675 0 : nsDisplayFilter::~nsDisplayFilter()
9676 : {
9677 : MOZ_COUNT_DTOR(nsDisplayFilter);
9678 : }
9679 0 : #endif
9680 :
9681 : already_AddRefed<Layer>
9682 : nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder,
9683 0 : LayerManager* aManager,
9684 : const ContainerLayerParameters& aContainerParameters)
9685 : {
9686 : if (!ValidateSVGFrame()) {
9687 : return nullptr;
9688 0 : }
9689 :
9690 0 : if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) {
9691 : return nullptr;
9692 0 : }
9693 :
9694 : nsIFrame* firstFrame =
9695 : nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
9696 0 : SVGObserverUtils::EffectProperties effectProperties =
9697 : SVGObserverUtils::GetEffectProperties(firstFrame);
9698 :
9699 0 : if (effectProperties.HasInvalidFilter()) {
9700 0 : return nullptr;
9701 : }
9702 :
9703 0 : MOZ_ASSERT(effectProperties.mFilter && mFrame->StyleEffects()->HasFilters(),
9704 0 : "By getting here, we must have valid CSS filters.");
9705 0 :
9706 : ContainerLayerParameters newContainerParameters = aContainerParameters;
9707 : newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
9708 :
9709 0 : RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
9710 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
9711 : newContainerParameters, nullptr);
9712 : return container.forget();
9713 0 : }
9714 :
9715 : LayerState
9716 : nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
9717 0 : LayerManager* aManager,
9718 : const ContainerLayerParameters& aParameters)
9719 : {
9720 0 : return LAYER_SVG_EFFECTS;
9721 : }
9722 0 :
9723 0 : bool
9724 0 : nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
9725 : nsRegion* aVisibleRegion)
9726 : {
9727 : nsPoint offset = ToReferenceFrame();
9728 0 : nsRect dirtyRect =
9729 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
9730 0 : GetPaintRect() - offset) +
9731 0 : offset;
9732 0 :
9733 : // Our children may be made translucent or arbitrarily deformed so we should
9734 : // not allow them to subtract area from aVisibleRegion.
9735 : nsRegion childrenVisible(dirtyRect);
9736 0 : nsRect r = dirtyRect.Intersect(
9737 : mList.GetClippedBoundsWithRespectToASR(aBuilder, mActiveScrolledRoot));
9738 : mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
9739 : return true;
9740 0 : }
9741 0 :
9742 : void
9743 : nsDisplayFilter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
9744 0 : const nsDisplayItemGeometry* aGeometry,
9745 : nsRegion* aInvalidRegion) const
9746 0 : {
9747 0 : nsDisplaySVGEffects::ComputeInvalidationRegion(aBuilder, aGeometry,
9748 : aInvalidRegion);
9749 0 :
9750 0 : const nsDisplayFilterGeometry* geometry =
9751 : static_cast<const nsDisplayFilterGeometry*>(aGeometry);
9752 0 :
9753 : if (aBuilder->ShouldSyncDecodeImages() &&
9754 : geometry->ShouldInvalidateToSyncDecodeImages()) {
9755 0 : bool snap;
9756 : nsRect bounds = GetBounds(aBuilder, &snap);
9757 : aInvalidRegion->Or(*aInvalidRegion, bounds);
9758 : }
9759 0 : }
9760 :
9761 0 : void
9762 0 : nsDisplayFilter::PaintAsLayer(nsDisplayListBuilder* aBuilder,
9763 : gfxContext* aCtx,
9764 : LayerManager* aManager)
9765 : {
9766 : imgDrawingParams imgParams(aBuilder->ShouldSyncDecodeImages()
9767 0 : ? imgIContainer::FLAG_SYNC_DECODE
9768 0 : : imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
9769 0 : nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
9770 0 : nsSVGIntegrationUtils::PaintFramesParams params(*aCtx,
9771 : mFrame, GetPaintRect(),
9772 : borderArea, aBuilder,
9773 0 : aManager,
9774 : mHandleOpacity, imgParams);
9775 : nsSVGIntegrationUtils::PaintFilter(params);
9776 0 : nsDisplayFilterGeometry::UpdateDrawResult(this, imgParams.result);
9777 : }
9778 :
9779 : static float
9780 0 : ClampStdDeviation(float aStdDeviation)
9781 : {
9782 : // Cap software blur radius for performance reasons.
9783 : return std::min(std::max(0.0f, aStdDeviation), 100.0f);
9784 : }
9785 :
9786 0 : bool
9787 : nsDisplayFilter::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
9788 : mozilla::wr::IpcResourceUpdateQueue& aResources,
9789 : const StackingContextHelper& aSc,
9790 : mozilla::layers::WebRenderLayerManager* aManager,
9791 : nsDisplayListBuilder* aDisplayListBuilder)
9792 : {
9793 0 : if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
9794 0 : return false;
9795 0 : }
9796 0 :
9797 : // Due to differences in the way that WebRender filters operate
9798 : // only the brightness and contrast filters use that path. We
9799 : // can gradually enable more filters as WebRender bugs are fixed.
9800 : nsTArray<mozilla::wr::WrFilterOp> wrFilters;
9801 : const nsTArray<nsStyleFilter>& filters = mFrame->StyleEffects()->mFilters;
9802 : for (const nsStyleFilter& filter : filters) {
9803 : switch (filter.GetType()) {
9804 : case NS_STYLE_FILTER_BRIGHTNESS:
9805 0 : case NS_STYLE_FILTER_CONTRAST:
9806 0 : case NS_STYLE_FILTER_GRAYSCALE:
9807 0 : case NS_STYLE_FILTER_INVERT:
9808 0 : case NS_STYLE_FILTER_OPACITY:
9809 : case NS_STYLE_FILTER_SATURATE:
9810 : case NS_STYLE_FILTER_SEPIA: {
9811 : mozilla::wr::WrFilterOp filterOp = {
9812 : wr::ToWrFilterOpType(filter.GetType()),
9813 0 : filter.GetFilterParameter().GetFactorOrPercentValue(),
9814 0 : };
9815 0 : wrFilters.AppendElement(filterOp);
9816 0 : break;
9817 : }
9818 : case NS_STYLE_FILTER_HUE_ROTATE: {
9819 : mozilla::wr::WrFilterOp filterOp = {
9820 0 : wr::ToWrFilterOpType(filter.GetType()),
9821 : (float)filter.GetFilterParameter().GetAngleValueInDegrees(),
9822 0 : };
9823 0 : wrFilters.AppendElement(filterOp);
9824 : break;
9825 0 : }
9826 : case NS_STYLE_FILTER_BLUR: {
9827 0 : float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
9828 0 : mozilla::wr::WrFilterOp filterOp = {
9829 : wr::ToWrFilterOpType(filter.GetType()),
9830 : ClampStdDeviation(
9831 : NSAppUnitsToFloatPixels(
9832 0 : filter.GetFilterParameter().GetCoordValue(),
9833 0 : appUnitsPerDevPixel)),
9834 0 : };
9835 0 : wrFilters.AppendElement(filterOp);
9836 0 : break;
9837 : }
9838 : case NS_STYLE_FILTER_DROP_SHADOW: {
9839 0 : float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
9840 0 : nsCSSShadowArray* shadows = filter.GetDropShadow();
9841 0 : if (!shadows || shadows->Length() != 1) {
9842 0 : NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
9843 : return false;
9844 : }
9845 :
9846 0 : nsCSSShadowItem* shadow = shadows->ShadowAt(0);
9847 0 : nscolor color = shadow->mColor;
9848 : if (!shadow->mHasColor) {
9849 0 : color = mFrame->StyleColor()->mColor;
9850 0 : }
9851 :
9852 : mozilla::wr::WrFilterOp filterOp = {
9853 0 : wr::ToWrFilterOpType(filter.GetType()),
9854 0 : NSAppUnitsToFloatPixels(shadow->mRadius, appUnitsPerDevPixel),
9855 0 : {
9856 0 : NSAppUnitsToFloatPixels(shadow->mXOffset, appUnitsPerDevPixel),
9857 : NSAppUnitsToFloatPixels(shadow->mYOffset, appUnitsPerDevPixel),
9858 0 : },
9859 : {
9860 0 : NS_GET_R(color) / 255.0f,
9861 0 : NS_GET_G(color) / 255.0f,
9862 : NS_GET_B(color) / 255.0f,
9863 : NS_GET_A(color) / 255.0f,
9864 : }
9865 : };
9866 :
9867 : wrFilters.AppendElement(filterOp);
9868 0 : break;
9869 0 : }
9870 0 : default:
9871 : return false;
9872 0 : }
9873 : }
9874 :
9875 : float opacity = mFrame->StyleEffects()->mOpacity;
9876 : StackingContextHelper sc(aSc, aBuilder, wrFilters, LayoutDeviceRect(), nullptr,
9877 : nullptr, opacity != 1.0f && mHandleOpacity ? &opacity : nullptr);
9878 0 :
9879 : nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, sc, aManager, aDisplayListBuilder);
9880 : return true;
9881 0 : }
9882 :
9883 0 : #ifdef MOZ_DUMP_PAINTING
9884 0 : void
9885 0 : nsDisplayFilter::PrintEffects(nsACString& aTo)
9886 0 : {
9887 0 : nsIFrame* firstFrame =
9888 0 : nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
9889 : SVGObserverUtils::EffectProperties effectProperties =
9890 0 : SVGObserverUtils::GetEffectProperties(firstFrame);
9891 0 : bool first = true;
9892 0 : aTo += " effects=(";
9893 : if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
9894 0 : first = false;
9895 : aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
9896 0 : }
9897 0 : if (effectProperties.HasValidFilter()) {
9898 : if (!first) {
9899 : aTo += ", ";
9900 11 : }
9901 0 : aTo += "filter";
9902 11 : }
9903 : aTo += ")";
9904 11 : }
9905 0 : #endif
9906 :
9907 : nsDisplaySVGWrapper::nsDisplaySVGWrapper(nsDisplayListBuilder* aBuilder,
9908 0 : nsIFrame* aFrame, nsDisplayList* aList)
9909 0 : : nsDisplayWrapList(aBuilder, aFrame, aList)
9910 11 : {
9911 : MOZ_COUNT_CTOR(nsDisplaySVGWrapper);
9912 : }
9913 :
9914 0 : #ifdef NS_BUILD_REFCNT_LOGGING
9915 : nsDisplaySVGWrapper::~nsDisplaySVGWrapper() {
9916 : MOZ_COUNT_DTOR(nsDisplaySVGWrapper);
9917 : }
9918 0 : #endif
9919 11 :
9920 : LayerState
9921 : nsDisplaySVGWrapper::GetLayerState(nsDisplayListBuilder* aBuilder,
9922 0 : LayerManager* aManager,
9923 : const ContainerLayerParameters& aParameters)
9924 : {
9925 : RefPtr<LayerManager> layerManager = aBuilder->GetWidgetLayerManager();
9926 0 : if (layerManager && layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
9927 : return LAYER_ACTIVE_FORCE;
9928 22 : }
9929 0 : return LAYER_NONE;
9930 : }
9931 :
9932 0 : bool
9933 : nsDisplaySVGWrapper::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
9934 : {
9935 : RefPtr<LayerManager> layerManager = aBuilder->GetWidgetLayerManager();
9936 0 : if (layerManager && layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
9937 : return false;
9938 : }
9939 : return true;
9940 0 : }
9941 0 :
9942 : already_AddRefed<Layer>
9943 : nsDisplaySVGWrapper::BuildLayer(nsDisplayListBuilder* aBuilder,
9944 0 : LayerManager* aManager,
9945 0 : const ContainerLayerParameters& aContainerParameters)
9946 : {
9947 0 : ContainerLayerParameters newContainerParameters = aContainerParameters;
9948 : newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
9949 :
9950 : RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
9951 0 : BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
9952 : newContainerParameters, nullptr);
9953 :
9954 : return container.forget();
9955 : }
9956 :
9957 0 : bool
9958 0 : nsDisplaySVGWrapper::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
9959 : mozilla::wr::IpcResourceUpdateQueue& aResources,
9960 : const StackingContextHelper& aSc,
9961 : mozilla::layers::WebRenderLayerManager* aManager,
9962 0 : nsDisplayListBuilder* aDisplayListBuilder)
9963 : {
9964 : if (gfxPrefs::WebRenderBlobInvalidation()) {
9965 : return nsDisplayWrapList::CreateWebRenderCommands(aBuilder,
9966 : aResources,
9967 : aSc,
9968 : aManager,
9969 : aDisplayListBuilder);
9970 : } else {
9971 : return false;
9972 : }
9973 : }
9974 :
9975 : namespace mozilla {
9976 0 :
9977 : uint32_t PaintTelemetry::sPaintLevel = 0;
9978 : uint32_t PaintTelemetry::sMetricLevel = 0;
9979 0 : EnumeratedArray<PaintTelemetry::Metric,
9980 : PaintTelemetry::Metric::COUNT,
9981 : double> PaintTelemetry::sMetrics;
9982 :
9983 : PaintTelemetry::AutoRecordPaint::AutoRecordPaint()
9984 147 : {
9985 1 : // Don't record nested paints.
9986 : if (sPaintLevel++ > 0) {
9987 21 : return;
9988 : }
9989 :
9990 21 : // Reset metrics for a new paint.
9991 : for (auto& metric : sMetrics) {
9992 21 : metric = 0.0;
9993 21 : }
9994 : mStart = TimeStamp::Now();
9995 : }
9996 :
9997 : PaintTelemetry::AutoRecordPaint::~AutoRecordPaint()
9998 : {
9999 21 : MOZ_ASSERT(sPaintLevel != 0);
10000 : if (--sPaintLevel > 0) {
10001 : return;
10002 : }
10003 0 :
10004 : // If we're in multi-process mode, don't include paint times for the parent
10005 : // process.
10006 0 : if (gfxVars::BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) {
10007 : return;
10008 : }
10009 0 :
10010 0 : double totalMs = (TimeStamp::Now() - mStart).ToMilliseconds();
10011 0 :
10012 0 : // Record the total time.
10013 0 : Telemetry::Accumulate(Telemetry::CONTENT_PAINT_TIME, static_cast<uint32_t>(totalMs));
10014 0 :
10015 0 : // Helpers for recording large/small paints.
10016 0 : auto recordLarge = [=](const nsCString& aKey, double aDurationMs) -> void {
10017 0 : MOZ_ASSERT(aDurationMs <= totalMs);
10018 0 : uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0);
10019 : Telemetry::Accumulate(Telemetry::CONTENT_LARGE_PAINT_PHASE_WEIGHT, aKey, amount);
10020 0 : };
10021 0 : auto recordSmall = [=](const nsCString& aKey, double aDurationMs) -> void {
10022 0 : MOZ_ASSERT(aDurationMs <= totalMs);
10023 : uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0);
10024 : Telemetry::Accumulate(Telemetry::CONTENT_SMALL_PAINT_PHASE_WEIGHT, aKey, amount);
10025 : };
10026 0 :
10027 0 : double dlMs = sMetrics[Metric::DisplayList];
10028 0 : double flbMs = sMetrics[Metric::Layerization];
10029 0 : double rMs = sMetrics[Metric::Rasterization];
10030 :
10031 0 : // If the total time was >= 16ms, then it's likely we missed a frame due to
10032 0 : // painting. We bucket these metrics separately.
10033 0 : if (totalMs >= 16.0) {
10034 : recordLarge(NS_LITERAL_CSTRING("dl"), dlMs);
10035 21 : recordLarge(NS_LITERAL_CSTRING("flb"), flbMs);
10036 : recordLarge(NS_LITERAL_CSTRING("r"), rMs);
10037 1 : } else {
10038 92 : recordSmall(NS_LITERAL_CSTRING("dl"), dlMs);
10039 : recordSmall(NS_LITERAL_CSTRING("flb"), flbMs);
10040 : recordSmall(NS_LITERAL_CSTRING("r"), rMs);
10041 1 : }
10042 : }
10043 :
10044 : PaintTelemetry::AutoRecord::AutoRecord(Metric aMetric)
10045 : : mMetric(aMetric)
10046 24 : {
10047 : // Don't double-record anything nested.
10048 : if (sMetricLevel++ > 0) {
10049 : return;
10050 1 : }
10051 :
10052 : // Don't record inside nested paints, or outside of paints.
10053 70 : if (sPaintLevel != 1) {
10054 : return;
10055 1 : }
10056 :
10057 46 : mStart = TimeStamp::Now();
10058 1 : }
10059 :
10060 : PaintTelemetry::AutoRecord::~AutoRecord()
10061 : {
10062 1 : MOZ_ASSERT(sMetricLevel != 0);
10063 1 :
10064 : sMetricLevel--;
10065 : if (mStart.IsNull()) {
10066 : return;
10067 : }
10068 :
10069 : sMetrics[mMetric] += (TimeStamp::Now() - mStart).ToMilliseconds();
10070 : }
10071 :
10072 : } // namespace mozilla
|