Coverage Report

Created: 2018-09-25 14:53

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