Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/painting/FrameLayerBuilder.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
#include "mozilla/DebugOnly.h"
8
9
#include "FrameLayerBuilder.h"
10
11
#include "gfxContext.h"
12
#include "mozilla/LookAndFeel.h"
13
#include "mozilla/Maybe.h"
14
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
15
#include "mozilla/gfx/Matrix.h"
16
#include "ActiveLayerTracker.h"
17
#include "BasicLayers.h"
18
#include "ImageContainer.h"
19
#include "ImageLayers.h"
20
#include "LayerTreeInvalidation.h"
21
#include "Layers.h"
22
#include "LayerUserData.h"
23
#include "MatrixStack.h"
24
#include "MaskLayerImageCache.h"
25
#include "UnitTransforms.h"
26
#include "Units.h"
27
#include "gfx2DGlue.h"
28
#include "gfxEnv.h"
29
#include "gfxUtils.h"
30
#include "nsAutoPtr.h"
31
#include "nsAnimationManager.h"
32
#include "nsDisplayList.h"
33
#include "nsDocShell.h"
34
#include "nsIScrollableFrame.h"
35
#include "nsImageFrame.h"
36
#include "nsLayoutUtils.h"
37
#include "nsPresContext.h"
38
#include "nsPrintfCString.h"
39
#include "nsSVGIntegrationUtils.h"
40
#include "nsTransitionManager.h"
41
#include "mozilla/LayerTimelineMarker.h"
42
43
#include "mozilla/EffectCompositor.h"
44
#include "mozilla/Move.h"
45
#include "mozilla/ReverseIterator.h"
46
#include "mozilla/gfx/2D.h"
47
#include "mozilla/gfx/Tools.h"
48
#include "mozilla/layers/ShadowLayers.h"
49
#include "mozilla/layers/TextureClient.h"
50
#include "mozilla/layers/TextureWrapperImage.h"
51
#include "mozilla/layers/WebRenderUserData.h"
52
#include "mozilla/Unused.h"
53
#include "GeckoProfiler.h"
54
#include "LayersLogging.h"
55
#include "gfxPrefs.h"
56
57
#include <algorithm>
58
#include <functional>
59
#include <deque>
60
61
using namespace mozilla::layers;
62
using namespace mozilla::gfx;
63
64
// PaintedLayerData::mAssignedDisplayItems is a std::vector, which is
65
// non-memmovable
66
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::PaintedLayerData);
67
68
namespace mozilla {
69
70
class PaintedDisplayItemLayerUserData;
71
72
static nsTHashtable<nsPtrHashKey<DisplayItemData>>* sAliveDisplayItemDatas;
73
74
/**
75
 * The address of gPaintedDisplayItemLayerUserData is used as the user
76
 * data key for PaintedLayers created by FrameLayerBuilder.
77
 * It identifies PaintedLayers used to draw non-layer content, which are
78
 * therefore eligible for recycling. We want display items to be able to
79
 * create their own dedicated PaintedLayers in BuildLayer, if necessary,
80
 * and we wouldn't want to accidentally recycle those.
81
 * The user data is a PaintedDisplayItemLayerUserData.
82
 */
83
uint8_t gPaintedDisplayItemLayerUserData;
84
/**
85
 * The address of gColorLayerUserData is used as the user
86
 * data key for ColorLayers created by FrameLayerBuilder.
87
 * The user data is null.
88
 */
89
uint8_t gColorLayerUserData;
90
/**
91
 * The address of gImageLayerUserData is used as the user
92
 * data key for ImageLayers created by FrameLayerBuilder.
93
 * The user data is null.
94
 */
95
uint8_t gImageLayerUserData;
96
/**
97
 * The address of gLayerManagerUserData is used as the user
98
 * data key for retained LayerManagers managed by FrameLayerBuilder.
99
 * The user data is a LayerManagerData.
100
 */
101
uint8_t gLayerManagerUserData;
102
/**
103
 * The address of gMaskLayerUserData is used as the user
104
 * data key for mask layers managed by FrameLayerBuilder.
105
 * The user data is a MaskLayerUserData.
106
 */
107
uint8_t gMaskLayerUserData;
108
/**
109
 * The address of gCSSMaskLayerUserData is used as the user
110
 * data key for mask layers of css masking managed by FrameLayerBuilder.
111
 * The user data is a CSSMaskLayerUserData.
112
 */
113
uint8_t gCSSMaskLayerUserData;
114
115
// a global cache of image containers used for mask layers
116
static MaskLayerImageCache* gMaskLayerImageCache = nullptr;
117
118
static inline MaskLayerImageCache*
119
GetMaskLayerImageCache()
120
0
{
121
0
  if (!gMaskLayerImageCache) {
122
0
    gMaskLayerImageCache = new MaskLayerImageCache();
123
0
  }
124
0
125
0
  return gMaskLayerImageCache;
126
0
}
127
128
struct DisplayItemEntry
129
{
130
  DisplayItemEntry(nsDisplayItem* aItem, DisplayItemEntryType aType)
131
    : mItem(aItem)
132
    , mType(aType)
133
0
  {
134
0
  }
135
136
  nsDisplayItem* mItem;
137
  DisplayItemEntryType mType;
138
};
139
140
/**
141
 * Returns true if the given |aType| is an effect start marker.
142
 */
143
static bool
144
IsEffectStartMarker(DisplayItemEntryType aType)
145
0
{
146
0
  return aType == DisplayItemEntryType::PUSH_OPACITY ||
147
0
         aType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG ||
148
0
         aType == DisplayItemEntryType::PUSH_TRANSFORM;
149
0
}
150
151
/**
152
 * Returns true if the given |aType| is an effect end marker.
153
 */
154
static bool
155
IsEffectEndMarker(DisplayItemEntryType aType)
156
0
{
157
0
  return aType == DisplayItemEntryType::POP_OPACITY ||
158
0
         aType == DisplayItemEntryType::POP_TRANSFORM;
159
0
}
160
161
enum class MarkerType
162
{
163
  StartMarker,
164
  EndMarker
165
};
166
167
/**
168
 * Adds the effect marker to |aMarkers| based on the type of |aItem| and whether
169
 * |markerType| is a start or end marker.
170
 */
171
template<MarkerType markerType>
172
static bool
173
AddMarkerIfNeeded(nsDisplayItem* aItem, std::deque<DisplayItemEntry>& aMarkers)
174
0
{
175
0
  const DisplayItemType type = aItem->GetType();
176
0
  if (type != DisplayItemType::TYPE_OPACITY &&
177
0
      type != DisplayItemType::TYPE_TRANSFORM) {
178
0
    return false;
179
0
  }
180
0
181
0
  DisplayItemEntryType marker;
182
0
183
0
// Just a fancy way to avoid writing two separate functions to select between
184
0
// PUSH and POP markers. This is done during compile time based on |markerType|.
185
0
#define GET_MARKER(start_marker, end_marker)                                   \
186
0
  std::conditional<                                                            \
187
0
    markerType == MarkerType::StartMarker,                                     \
188
0
    std::integral_constant<DisplayItemEntryType, start_marker>,                \
189
0
    std::integral_constant<DisplayItemEntryType, end_marker>>::type::value;
190
0
191
0
  switch (type) {
192
0
    case DisplayItemType::TYPE_OPACITY:
193
0
      marker = GET_MARKER(DisplayItemEntryType::PUSH_OPACITY,
194
0
                          DisplayItemEntryType::POP_OPACITY);
195
0
      break;
196
0
    case DisplayItemType::TYPE_TRANSFORM:
197
0
      marker = GET_MARKER(DisplayItemEntryType::PUSH_TRANSFORM,
198
0
                          DisplayItemEntryType::POP_TRANSFORM);
199
0
      break;
200
0
    default:
201
0
      MOZ_ASSERT_UNREACHABLE("Invalid display item type!");
202
0
      break;
203
0
  }
204
0
205
0
  aMarkers.emplace_back(aItem, marker);
206
0
  return true;
207
0
}
Unexecuted instantiation: Unified_cpp_layout_painting0.cpp:bool mozilla::AddMarkerIfNeeded<(mozilla::MarkerType)1>(nsDisplayItem*, std::__1::deque<mozilla::DisplayItemEntry, std::__1::allocator<mozilla::DisplayItemEntry> >&)
Unexecuted instantiation: Unified_cpp_layout_painting0.cpp:bool mozilla::AddMarkerIfNeeded<(mozilla::MarkerType)0>(nsDisplayItem*, std::__1::deque<mozilla::DisplayItemEntry, std::__1::allocator<mozilla::DisplayItemEntry> >&)
208
209
class FLBDisplayItemIterator : protected FlattenedDisplayItemIterator
210
{
211
public:
212
  FLBDisplayItemIterator(nsDisplayListBuilder* aBuilder,
213
                         nsDisplayList* aList,
214
                         ContainerState* aState)
215
    : FlattenedDisplayItemIterator(aBuilder, aList, false)
216
    , mState(aState)
217
    , mStoreMarker(false)
218
0
  {
219
0
    MOZ_ASSERT(mState);
220
0
    ResolveFlattening();
221
0
  }
222
223
  DisplayItemEntry GetNextEntry()
224
0
  {
225
0
    if (!mMarkers.empty()) {
226
0
      DisplayItemEntry entry = mMarkers.front();
227
0
      mMarkers.pop_front();
228
0
      return entry;
229
0
    }
230
0
231
0
    nsDisplayItem* next = GetNext();
232
0
    return DisplayItemEntry{ next, DisplayItemEntryType::ITEM };
233
0
  }
234
235
  nsDisplayItem* GetNext();
236
237
  bool HasNext() const
238
0
  {
239
0
    return FlattenedDisplayItemIterator::HasNext() || !mMarkers.empty();
240
0
  }
241
242
0
  nsDisplayItem* PeekNext() { return mNext; }
243
244
private:
245
  bool ShouldFlattenNextItem() override;
246
247
  void StartNested(nsDisplayItem* aItem) override
248
0
  {
249
0
    if (!mStoreMarker) {
250
0
      return;
251
0
    }
252
0
253
0
    if (AddMarkerIfNeeded<MarkerType::StartMarker>(aItem, mMarkers)) {
254
0
      mActiveMarkers.AppendElement(aItem);
255
0
    }
256
0
257
0
    mStoreMarker = false;
258
0
  }
259
260
  void EndNested(nsDisplayItem* aItem) override
261
0
  {
262
0
    if (mActiveMarkers.IsEmpty() || mActiveMarkers.LastElement() != aItem) {
263
0
      // Do not emit an end marker if this item did not emit a start marker.
264
0
      return;
265
0
    }
266
0
267
0
    if (AddMarkerIfNeeded<MarkerType::EndMarker>(aItem, mMarkers)) {
268
0
      mActiveMarkers.RemoveLastElement();
269
0
    }
270
0
  }
271
272
  bool NextItemWantsInactiveLayer();
273
274
  std::deque<DisplayItemEntry> mMarkers;
275
  AutoTArray<nsDisplayItem*, 4> mActiveMarkers;
276
  ContainerState* mState;
277
  bool mStoreMarker;
278
};
279
280
DisplayItemData::DisplayItemData(LayerManagerData* aParent,
281
                                 uint32_t aKey,
282
                                 Layer* aLayer,
283
                                 nsIFrame* aFrame)
284
285
  : mRefCnt(0)
286
  , mParent(aParent)
287
  , mLayer(aLayer)
288
  , mDisplayItemKey(aKey)
289
  , mItem(nullptr)
290
  , mUsed(true)
291
  , mIsInvalid(false)
292
  , mReusedItem(false)
293
0
{
294
0
  MOZ_COUNT_CTOR(DisplayItemData);
295
0
296
0
  if (!sAliveDisplayItemDatas) {
297
0
    sAliveDisplayItemDatas = new nsTHashtable<nsPtrHashKey<DisplayItemData>>();
298
0
  }
299
0
  MOZ_RELEASE_ASSERT(!sAliveDisplayItemDatas->Contains(this));
300
0
  sAliveDisplayItemDatas->PutEntry(this);
301
0
302
0
  MOZ_RELEASE_ASSERT(mLayer);
303
0
  if (aFrame) {
304
0
    AddFrame(aFrame);
305
0
  }
306
0
}
307
308
void
309
DisplayItemData::AddFrame(nsIFrame* aFrame)
310
0
{
311
0
  MOZ_RELEASE_ASSERT(mLayer);
312
0
  MOZ_RELEASE_ASSERT(!mFrameList.Contains(aFrame));
313
0
  mFrameList.AppendElement(aFrame);
314
0
315
0
  SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
316
0
  array.AppendElement(this);
317
0
}
318
319
void
320
DisplayItemData::RemoveFrame(nsIFrame* aFrame)
321
0
{
322
0
  MOZ_RELEASE_ASSERT(mLayer);
323
0
  bool result = mFrameList.RemoveElement(aFrame);
324
0
  MOZ_RELEASE_ASSERT(result, "Can't remove a frame that wasn't added!");
325
0
326
0
  SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
327
0
  array.RemoveElement(this);
328
0
}
329
330
void
331
DisplayItemData::EndUpdate()
332
0
{
333
0
  MOZ_RELEASE_ASSERT(mLayer);
334
0
  mIsInvalid = false;
335
0
  mUsed = false;
336
0
  mReusedItem = false;
337
0
  mOldTransform = nullptr;
338
0
}
339
340
void
341
DisplayItemData::EndUpdate(nsAutoPtr<nsDisplayItemGeometry> aGeometry)
342
0
{
343
0
  MOZ_RELEASE_ASSERT(mLayer);
344
0
  MOZ_ASSERT(mItem);
345
0
  MOZ_ASSERT(mGeometry || aGeometry);
346
0
347
0
  if (aGeometry) {
348
0
    mGeometry = aGeometry;
349
0
  }
350
0
  mClip = mItem->GetClip();
351
0
  mChangedFrameInvalidations.SetEmpty();
352
0
353
0
  EndUpdate();
354
0
}
355
356
void
357
DisplayItemData::BeginUpdate(Layer* aLayer,
358
                             LayerState aState,
359
                             bool aFirstUpdate,
360
                             nsDisplayItem* aItem /* = nullptr */)
361
0
{
362
0
  BeginUpdate(aLayer,
363
0
              aState,
364
0
              aItem,
365
0
              (aItem && !aFirstUpdate) ? aItem->IsReused() : false,
366
0
              aItem ? aItem->HasMergedFrames() : false);
367
0
}
368
369
void
370
DisplayItemData::BeginUpdate(Layer* aLayer,
371
                             LayerState aState,
372
                             nsDisplayItem* aItem,
373
                             bool aIsReused,
374
                             bool aIsMerged)
375
0
{
376
0
  MOZ_RELEASE_ASSERT(mLayer);
377
0
  MOZ_RELEASE_ASSERT(aLayer);
378
0
  mLayer = aLayer;
379
0
  mOptLayer = nullptr;
380
0
  mInactiveManager = nullptr;
381
0
  mLayerState = aState;
382
0
  mUsed = true;
383
0
384
0
  if (aLayer->AsPaintedLayer()) {
385
0
    if (aItem != mItem) {
386
0
      aItem->SetDisplayItemData(this, aLayer->Manager());
387
0
    } else {
388
0
      MOZ_ASSERT(aItem->GetDisplayItemData() == this);
389
0
    }
390
0
    mReusedItem = aIsReused;
391
0
  }
392
0
393
0
  if (!aItem) {
394
0
    return;
395
0
  }
396
0
397
0
  if (!aIsMerged && mFrameList.Length() == 1) {
398
0
    MOZ_ASSERT(mFrameList[0] == aItem->Frame());
399
0
    return;
400
0
  }
401
0
402
0
  // We avoid adding or removing element unnecessarily
403
0
  // since we have to modify userdata each time
404
0
  AutoTArray<nsIFrame*, 4> copy(mFrameList);
405
0
  if (!copy.RemoveElement(aItem->Frame())) {
406
0
    AddFrame(aItem->Frame());
407
0
    mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
408
0
                                  aItem->Frame()->GetVisualOverflowRect());
409
0
  }
410
0
411
0
  AutoTArray<nsIFrame*, 4> mergedFrames;
412
0
  aItem->GetMergedFrames(&mergedFrames);
413
0
  for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
414
0
    if (!copy.RemoveElement(mergedFrames[i])) {
415
0
      AddFrame(mergedFrames[i]);
416
0
      mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
417
0
                                    mergedFrames[i]->GetVisualOverflowRect());
418
0
    }
419
0
  }
420
0
421
0
  for (uint32_t i = 0; i < copy.Length(); i++) {
422
0
    RemoveFrame(copy[i]);
423
0
    mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
424
0
                                  copy[i]->GetVisualOverflowRect());
425
0
  }
426
0
}
427
428
static const nsIFrame* sDestroyedFrame = nullptr;
429
DisplayItemData::~DisplayItemData()
430
0
{
431
0
  MOZ_COUNT_DTOR(DisplayItemData);
432
0
433
0
  if (mItem) {
434
0
    MOZ_ASSERT(mItem->GetDisplayItemData() == this);
435
0
    mItem->SetDisplayItemData(nullptr, nullptr);
436
0
  }
437
0
438
0
  for (uint32_t i = 0; i < mFrameList.Length(); i++) {
439
0
    nsIFrame* frame = mFrameList[i];
440
0
    if (frame == sDestroyedFrame) {
441
0
      continue;
442
0
    }
443
0
444
0
    SmallPointerArray<DisplayItemData>& array = frame->DisplayItemData();
445
0
    array.RemoveElement(this);
446
0
  }
447
0
448
0
  MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas);
449
0
  nsPtrHashKey<mozilla::DisplayItemData>* entry =
450
0
    sAliveDisplayItemDatas->GetEntry(this);
451
0
  MOZ_RELEASE_ASSERT(entry);
452
0
453
0
  sAliveDisplayItemDatas->RemoveEntry(entry);
454
0
455
0
  if (sAliveDisplayItemDatas->Count() == 0) {
456
0
    delete sAliveDisplayItemDatas;
457
0
    sAliveDisplayItemDatas = nullptr;
458
0
  }
459
0
}
460
461
void
462
DisplayItemData::ClearAnimationCompositorState()
463
0
{
464
0
  if (mDisplayItemKey !=
465
0
        static_cast<uint32_t>(DisplayItemType::TYPE_TRANSFORM) &&
466
0
      mDisplayItemKey != static_cast<uint32_t>(DisplayItemType::TYPE_OPACITY)) {
467
0
    return;
468
0
  }
469
0
470
0
  for (nsIFrame* frame : mFrameList) {
471
0
    nsCSSPropertyID prop =
472
0
      mDisplayItemKey == static_cast<uint32_t>(DisplayItemType::TYPE_TRANSFORM)
473
0
        ? eCSSProperty_transform
474
0
        : eCSSProperty_opacity;
475
0
    EffectCompositor::ClearIsRunningOnCompositor(frame, prop);
476
0
  }
477
0
}
478
479
const nsRegion&
480
DisplayItemData::GetChangedFrameInvalidations()
481
0
{
482
0
  return mChangedFrameInvalidations;
483
0
}
484
485
DisplayItemData*
486
DisplayItemData::AssertDisplayItemData(DisplayItemData* aData)
487
0
{
488
0
  MOZ_RELEASE_ASSERT(aData);
489
0
  MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas &&
490
0
                     sAliveDisplayItemDatas->Contains(aData));
491
0
  MOZ_RELEASE_ASSERT(aData->mLayer);
492
0
  return aData;
493
0
}
494
495
/**
496
 * This is the userdata we associate with a layer manager.
497
 */
498
class LayerManagerData : public LayerUserData
499
{
500
public:
501
  explicit LayerManagerData(LayerManager* aManager)
502
    : mLayerManager(aManager)
503
#ifdef DEBUG_DISPLAY_ITEM_DATA
504
    , mParent(nullptr)
505
#endif
506
    , mInvalidateAllLayers(false)
507
0
  {
508
0
    MOZ_COUNT_CTOR(LayerManagerData);
509
0
  }
510
0
  ~LayerManagerData() override { MOZ_COUNT_DTOR(LayerManagerData); }
511
512
#ifdef DEBUG_DISPLAY_ITEM_DATA
513
  void Dump(const char* aPrefix = "")
514
  {
515
    printf_stderr("%sLayerManagerData %p\n", aPrefix, this);
516
517
    for (auto& data : mDisplayItems) {
518
      nsAutoCString prefix;
519
      prefix += aPrefix;
520
      prefix += "  ";
521
522
      const char* layerState;
523
      switch (data->mLayerState) {
524
        case LAYER_NONE:
525
          layerState = "LAYER_NONE";
526
          break;
527
        case LAYER_INACTIVE:
528
          layerState = "LAYER_INACTIVE";
529
          break;
530
        case LAYER_ACTIVE:
531
          layerState = "LAYER_ACTIVE";
532
          break;
533
        case LAYER_ACTIVE_FORCE:
534
          layerState = "LAYER_ACTIVE_FORCE";
535
          break;
536
        case LAYER_ACTIVE_EMPTY:
537
          layerState = "LAYER_ACTIVE_EMPTY";
538
          break;
539
        case LAYER_SVG_EFFECTS:
540
          layerState = "LAYER_SVG_EFFECTS";
541
          break;
542
      }
543
      uint32_t mask = (1 << TYPE_BITS) - 1;
544
545
      nsAutoCString str;
546
      str += prefix;
547
      str += nsPrintfCString("Frame %p ", data->mFrameList[0]);
548
      str += nsDisplayItem::DisplayItemTypeName(
549
        static_cast<nsDisplayItem::Type>(data->mDisplayItemKey & mask));
550
      if ((data->mDisplayItemKey >> TYPE_BITS)) {
551
        str += nsPrintfCString("(%i)", data->mDisplayItemKey >> TYPE_BITS);
552
      }
553
      str += nsPrintfCString(", %s, Layer %p", layerState, data->mLayer.get());
554
      if (data->mOptLayer) {
555
        str += nsPrintfCString(", OptLayer %p", data->mOptLayer.get());
556
      }
557
      if (data->mInactiveManager) {
558
        str += nsPrintfCString(", InactiveLayerManager %p",
559
                               data->mInactiveManager.get());
560
      }
561
      str += "\n";
562
563
      printf_stderr("%s", str.get());
564
565
      if (data->mInactiveManager) {
566
        prefix += "  ";
567
        printf_stderr("%sDumping inactive layer info:\n", prefix.get());
568
        LayerManagerData* lmd = static_cast<LayerManagerData*>(
569
          data->mInactiveManager->GetUserData(&gLayerManagerUserData));
570
        lmd->Dump(prefix.get());
571
      }
572
    }
573
  }
574
#endif
575
576
  /**
577
   * Tracks which frames have layers associated with them.
578
   */
579
  LayerManager* mLayerManager;
580
#ifdef DEBUG_DISPLAY_ITEM_DATA
581
  LayerManagerData* mParent;
582
#endif
583
  std::vector<RefPtr<DisplayItemData>> mDisplayItems;
584
  bool mInvalidateAllLayers;
585
};
586
587
/* static */ void
588
FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
589
0
{
590
0
  RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
591
0
  aFrame->DisplayItemData().Clear();
592
0
  aFrame->DeleteProperty(WebRenderUserDataProperty::Key());
593
0
}
594
595
/**
596
 * We keep a stack of these to represent the PaintedLayers that are
597
 * currently available to have display items added to.
598
 * We use a stack here because as much as possible we want to
599
 * assign display items to existing PaintedLayers, and to the lowest
600
 * PaintedLayer in z-order. This reduces the number of layers and
601
 * makes it more likely a display item will be rendered to an opaque
602
 * layer, giving us the best chance of getting subpixel AA.
603
 */
604
class PaintedLayerData
605
{
606
public:
607
  PaintedLayerData()
608
    : mAnimatedGeometryRoot(nullptr)
609
    , mASR(nullptr)
610
    , mClipChain(nullptr)
611
    , mReferenceFrame(nullptr)
612
    , mLayer(nullptr)
613
    , mSolidColor(NS_RGBA(0, 0, 0, 0))
614
    , mIsSolidColorInVisibleRegion(false)
615
    , mNeedComponentAlpha(false)
616
    , mForceTransparentSurface(false)
617
    , mHideAllLayersBelow(false)
618
    , mOpaqueForAnimatedGeometryRootParent(false)
619
    , mDisableFlattening(false)
620
    , mBackfaceHidden(false)
621
    , mShouldPaintOnContentSide(false)
622
    , mDTCRequiresTargetConfirmation(false)
623
    , mImage(nullptr)
624
    , mItemClip(nullptr)
625
    , mNewChildLayersIndex(-1)
626
#ifdef DEBUG
627
    , mTransformLevel(0)
628
#endif
629
0
  {
630
0
  }
631
632
0
  ~PaintedLayerData() { MOZ_ASSERT(mTransformLevel == 0); }
633
634
#ifdef MOZ_DUMP_PAINTING
635
  /**
636
   * Keep track of important decisions for debugging.
637
   */
638
  nsCString mLog;
639
640
#define FLB_LOG_PAINTED_LAYER_DECISION(pld, ...)                               \
641
  if (gfxPrefs::LayersDumpDecision()) {                                        \
642
    pld->mLog.AppendPrintf("\t\t\t\t");                                        \
643
    pld->mLog.AppendPrintf(__VA_ARGS__);                                       \
644
  }
645
#else
646
#define FLB_LOG_PAINTED_LAYER_DECISION(...)
647
#endif
648
649
  /**
650
   * Record that an item has been added to the PaintedLayer, so we
651
   * need to update our regions.
652
   * @param aVisibleRect the area of the item that's visible
653
   * @param aSolidColor if non-null, the visible area of the item is
654
   * a constant color given by *aSolidColor
655
   */
656
  void Accumulate(ContainerState* aState,
657
                  nsDisplayItem* aItem,
658
                  const nsIntRect& aVisibleRect,
659
                  const nsRect& aContentRect,
660
                  const DisplayItemClip& aClip,
661
                  LayerState aLayerState,
662
                  nsDisplayList* aList,
663
                  DisplayItemEntryType aType,
664
                  nsTArray<size_t>& aOpacityIndices,
665
                  const RefPtr<TransformClipNode>& aTransform);
666
667
  /**
668
   * Updates the status of |mTransform| and |aOpacityIndices|, based on |aType|.
669
   */
670
  void UpdateEffectStatus(DisplayItemEntryType aType,
671
                          nsTArray<size_t>& aOpacityIndices);
672
673
  AnimatedGeometryRoot* GetAnimatedGeometryRoot()
674
0
  {
675
0
    return mAnimatedGeometryRoot;
676
0
  }
677
678
  /**
679
   * A region including the horizontal pan, vertical pan, and no action regions.
680
   */
681
  nsRegion CombinedTouchActionRegion();
682
683
  /**
684
   * Add the given hit test info to the hit regions for this PaintedLayer.
685
   */
686
  void AccumulateHitTestInfo(ContainerState* aState,
687
                             nsDisplayCompositorHitTestInfo* aItem,
688
                             TransformClipNode* aTransform);
689
690
  /**
691
   * If this represents only a nsDisplayImage, and the image type supports being
692
   * optimized to an ImageLayer, returns true.
693
   */
694
  bool CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
695
696
  /**
697
   * If this represents only a nsDisplayImage, and the image type supports being
698
   * optimized to an ImageLayer, returns an ImageContainer for the underlying
699
   * image if one is available.
700
   */
701
  already_AddRefed<ImageContainer> GetContainerForImageLayer(
702
    nsDisplayListBuilder* aBuilder);
703
704
  bool VisibleAboveRegionIntersects(const nsIntRegion& aRegion) const
705
0
  {
706
0
    return !mVisibleAboveRegion.Intersect(aRegion).IsEmpty();
707
0
  }
708
  bool VisibleRegionIntersects(const nsIntRegion& aRegion) const
709
0
  {
710
0
    return !mVisibleRegion.Intersect(aRegion).IsEmpty();
711
0
  }
712
713
  /**
714
   * The region of visible content in the layer, relative to the
715
   * container layer (which is at the snapped top-left of the display
716
   * list reference frame).
717
   */
718
  nsIntRegion mVisibleRegion;
719
  /**
720
   * The region of visible content in the layer that is opaque.
721
   * Same coordinate system as mVisibleRegion.
722
   */
723
  nsIntRegion mOpaqueRegion;
724
  /**
725
   * The definitely-hit region for this PaintedLayer.
726
   */
727
  nsRegion mHitRegion;
728
  /**
729
   * The maybe-hit region for this PaintedLayer.
730
   */
731
  nsRegion mMaybeHitRegion;
732
  /**
733
   * The dispatch-to-content hit region for this PaintedLayer.
734
   */
735
  nsRegion mDispatchToContentHitRegion;
736
  /**
737
   * The region for this PaintedLayer that is sensitive to events
738
   * but disallows panning and zooming. This is an approximation
739
   * and any deviation from the true region will be part of the
740
   * mDispatchToContentHitRegion.
741
   */
742
  nsRegion mNoActionRegion;
743
  /**
744
   * The region for this PaintedLayer that is sensitive to events and
745
   * allows horizontal panning but not zooming. This is an approximation
746
   * and any deviation from the true region will be part of the
747
   * mDispatchToContentHitRegion.
748
   */
749
  nsRegion mHorizontalPanRegion;
750
  /**
751
   * The region for this PaintedLayer that is sensitive to events and
752
   * allows vertical panning but not zooming. This is an approximation
753
   * and any deviation from the true region will be part of the
754
   * mDispatchToContentHitRegion.
755
   */
756
  nsRegion mVerticalPanRegion;
757
758
  bool mCollapsedTouchActions = false;
759
  /**
760
   * Scaled versions of the bounds of mHitRegion and mMaybeHitRegion.
761
   * We store these because FindPaintedLayerFor() needs to consume them
762
   * in this form, and it's a hot code path so we don't want to scale
763
   * them inside that function.
764
   */
765
  nsIntRect mScaledHitRegionBounds;
766
  nsIntRect mScaledMaybeHitRegionBounds;
767
  /**
768
   * The "active scrolled root" for all content in the layer. Must
769
   * be non-null; all content in a PaintedLayer must have the same
770
   * active scrolled root.
771
   */
772
  AnimatedGeometryRoot* mAnimatedGeometryRoot;
773
  const ActiveScrolledRoot* mASR;
774
  /**
775
   * The chain of clips that should apply to this layer.
776
   */
777
  const DisplayItemClipChain* mClipChain;
778
  /**
779
   * The offset between mAnimatedGeometryRoot and the reference frame.
780
   */
781
  nsPoint mAnimatedGeometryRootOffset;
782
  /**
783
   * If non-null, the frame from which we'll extract "fixed positioning"
784
   * metadata for this layer. This can be a position:fixed frame or a viewport
785
   * frame; the latter case is used for background-attachment:fixed content.
786
   */
787
  const nsIFrame* mReferenceFrame;
788
  PaintedLayer* mLayer;
789
  /**
790
   * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
791
   * region.
792
   */
793
  nscolor mSolidColor;
794
  /**
795
   * True if every pixel in mVisibleRegion will have color mSolidColor.
796
   */
797
  bool mIsSolidColorInVisibleRegion;
798
  /**
799
   * True if there is any text visible in the layer that's over
800
   * transparent pixels in the layer.
801
   */
802
  bool mNeedComponentAlpha;
803
  /**
804
   * Set if the layer should be treated as transparent, even if its entire
805
   * area is covered by opaque display items. For example, this needs to
806
   * be set if something is going to "punch holes" in the layer by clearing
807
   * part of its surface.
808
   */
809
  bool mForceTransparentSurface;
810
  /**
811
   * Set if all layers below this PaintedLayer should be hidden.
812
   */
813
  bool mHideAllLayersBelow;
814
  /**
815
   * Set if the opaque region for this layer can be applied to the parent
816
   * animated geometry root of this layer's animated geometry root.
817
   * We set this when a PaintedLayer's animated geometry root is a scrollframe
818
   * and the PaintedLayer completely fills the displayport of the scrollframe.
819
   */
820
  bool mOpaqueForAnimatedGeometryRootParent;
821
  /**
822
   * Set if there is content in the layer that must avoid being flattened.
823
   */
824
  bool mDisableFlattening;
825
  /**
826
   * Set if the backface of this region is hidden to the user.
827
   * Content that backface is hidden should not be draw on the layer
828
   * with visible backface.
829
   */
830
  bool mBackfaceHidden;
831
  /**
832
   * Set if it is better to render this layer on the content process, for
833
   * example if it contains native theme widgets.
834
   */
835
  bool mShouldPaintOnContentSide;
836
  /**
837
   * Set to true if events targeting the dispatch-to-content region
838
   * require target confirmation.
839
   * See CompositorHitTestFlags::eRequiresTargetConfirmation and
840
   * EventRegions::mDTCRequiresTargetConfirmation.
841
   */
842
  bool mDTCRequiresTargetConfirmation;
843
  /**
844
   * Stores the pointer to the nsDisplayImage if we want to
845
   * convert this to an ImageLayer.
846
   */
847
  nsDisplayImageContainer* mImage;
848
  /**
849
   * Stores the clip that we need to apply to the image or, if there is no
850
   * image, a clip for SOME item in the layer. There is no guarantee which
851
   * item's clip will be stored here and mItemClip should not be used to clip
852
   * the whole layer - only some part of the clip should be used, as determined
853
   * by PaintedDisplayItemLayerUserData::GetCommonClipCount() - which may even
854
   * be no part at all.
855
   */
856
  const DisplayItemClip* mItemClip;
857
  /**
858
   * Index of this layer in mNewChildLayers.
859
   */
860
  int32_t mNewChildLayersIndex;
861
  /**
862
   * The region of visible content above the layer and below the
863
   * next PaintedLayerData currently in the stack, if any.
864
   * This is a conservative approximation: it contains the true region.
865
   */
866
  nsIntRegion mVisibleAboveRegion;
867
  /**
868
   * All the display items that have been assigned to this painted layer.
869
   * These items get added by Accumulate().
870
   */
871
  std::vector<AssignedDisplayItem> mAssignedDisplayItems;
872
873
#ifdef DEBUG
874
  /**
875
   * Tracks the level of transform to ensure balanced PUSH/POP markers.
876
   */
877
  int mTransformLevel;
878
#endif
879
};
880
881
struct NewLayerEntry
882
{
883
  NewLayerEntry()
884
    : mAnimatedGeometryRoot(nullptr)
885
    , mASR(nullptr)
886
    , mClipChain(nullptr)
887
    , mScrollMetadataASR(nullptr)
888
    , mLayerContentsVisibleRect(0, 0, -1, -1)
889
    , mLayerState(LAYER_INACTIVE)
890
    , mHideAllLayersBelow(false)
891
    , mOpaqueForAnimatedGeometryRootParent(false)
892
    , mPropagateComponentAlphaFlattening(true)
893
    , mUntransformedVisibleRegion(false)
894
    , mIsFixedToRootScrollFrame(false)
895
0
  {
896
0
  }
897
  // mLayer is null if the previous entry is for a PaintedLayer that hasn't
898
  // been optimized to some other form (yet).
899
  RefPtr<Layer> mLayer;
900
  AnimatedGeometryRoot* mAnimatedGeometryRoot;
901
  const ActiveScrolledRoot* mASR;
902
  const DisplayItemClipChain* mClipChain;
903
  const ActiveScrolledRoot* mScrollMetadataASR;
904
  // If non-null, this ScrollMetadata is set to the be the first ScrollMetadata
905
  // on the layer.
906
  UniquePtr<ScrollMetadata> mBaseScrollMetadata;
907
  // The following are only used for retained layers (for occlusion
908
  // culling of those layers). These regions are all relative to the
909
  // container reference frame.
910
  nsIntRegion mVisibleRegion;
911
  nsIntRegion mOpaqueRegion;
912
  // This rect is in the layer's own coordinate space. The computed visible
913
  // region for the layer cannot extend beyond this rect.
914
  nsIntRect mLayerContentsVisibleRect;
915
  LayerState mLayerState;
916
  bool mHideAllLayersBelow;
917
  // When mOpaqueForAnimatedGeometryRootParent is true, the opaque region of
918
  // this layer is opaque in the same position even subject to the animation of
919
  // geometry of mAnimatedGeometryRoot. For example when mAnimatedGeometryRoot
920
  // is a scrolled frame and the scrolled content is opaque everywhere in the
921
  // displayport, we can set this flag.
922
  // When this flag is set, we can treat this opaque region as covering
923
  // content whose animated geometry root is the animated geometry root for
924
  // mAnimatedGeometryRoot->GetParent().
925
  bool mOpaqueForAnimatedGeometryRootParent;
926
927
  // If true, then the content flags for this layer should contribute
928
  // to our decision to flatten component alpha layers, false otherwise.
929
  bool mPropagateComponentAlphaFlattening;
930
  // mVisibleRegion is relative to the associated frame before
931
  // transform.
932
  bool mUntransformedVisibleRegion;
933
  bool mIsFixedToRootScrollFrame;
934
};
935
936
class PaintedLayerDataTree;
937
938
/**
939
 * This is tree node type for PaintedLayerDataTree.
940
 * Each node corresponds to a different animated geometry root, and contains
941
 * a stack of PaintedLayerDatas, in bottom-to-top order.
942
 * There is at most one node per animated geometry root. The ancestor and
943
 * descendant relations in PaintedLayerDataTree tree mirror those in the frame
944
 * tree.
945
 * Each node can have clip that describes the potential extents that items in
946
 * this node can cover. If mHasClip is false, it means that the node's contents
947
 * can move anywhere.
948
 * Testing against the clip instead of the node's actual contents has the
949
 * advantage that the node's contents can move or animate without affecting
950
 * content in other nodes. So we don't need to re-layerize during animations
951
 * (sync or async), and during async animations everything is guaranteed to
952
 * look correct.
953
 * The contents of a node's PaintedLayerData stack all share the node's
954
 * animated geometry root. The child nodes are on top of the PaintedLayerData
955
 * stack, in z-order, and the clip rects of the child nodes are allowed to
956
 * intersect with the visible region or visible above region of their parent
957
 * node's PaintedLayerDatas.
958
 */
959
class PaintedLayerDataNode
960
{
961
public:
962
  PaintedLayerDataNode(PaintedLayerDataTree& aTree,
963
                       PaintedLayerDataNode* aParent,
964
                       AnimatedGeometryRoot* aAnimatedGeometryRoot);
965
  ~PaintedLayerDataNode();
966
967
  AnimatedGeometryRoot* GetAnimatedGeometryRoot() const
968
0
  {
969
0
    return mAnimatedGeometryRoot;
970
0
  }
971
972
  /**
973
   * Whether this node's contents can potentially intersect aRect.
974
   * aRect is in our tree's ContainerState's coordinate space.
975
   */
976
  bool Intersects(const nsIntRect& aRect) const
977
0
  {
978
0
    return !mHasClip || mClipRect.Intersects(aRect);
979
0
  }
980
981
  /**
982
   * Create a PaintedLayerDataNode for aAnimatedGeometryRoot, add it to our
983
   * children, and return it.
984
   */
985
  PaintedLayerDataNode* AddChildNodeFor(
986
    AnimatedGeometryRoot* aAnimatedGeometryRoot);
987
988
  /**
989
   * Find a PaintedLayerData in our mPaintedLayerDataStack that aItem can be
990
   * added to. Creates a new PaintedLayerData by calling
991
   * aNewPaintedLayerCallback if necessary.
992
   */
993
  template<typename NewPaintedLayerCallbackType>
994
  PaintedLayerData* FindPaintedLayerFor(
995
    const nsIntRect& aVisibleRect,
996
    bool aBackfaceHidden,
997
    const ActiveScrolledRoot* aASR,
998
    const DisplayItemClipChain* aClipChain,
999
    NewPaintedLayerCallbackType aNewPaintedLayerCallback);
1000
1001
  /**
1002
   * Find an opaque background color for aRegion. Pulls a color from the parent
1003
   * geometry root if appropriate, but only if that color is present underneath
1004
   * the whole clip of this node, so that this node's contents can animate or
1005
   * move (possibly async) without having to change the background color.
1006
   * @param aUnderIndex Searching will start in mPaintedLayerDataStack right
1007
   *                    below aUnderIndex.
1008
   */
1009
  enum
1010
  {
1011
    ABOVE_TOP = -1
1012
  };
1013
  nscolor FindOpaqueBackgroundColor(const nsIntRegion& aRegion,
1014
                                    int32_t aUnderIndex = ABOVE_TOP) const;
1015
  /**
1016
   * Same as FindOpaqueBackgroundColor, but only returns a color if absolutely
1017
   * nothing is in between, so that it can be used for a layer that can move
1018
   * anywhere inside our clip.
1019
   */
1020
  nscolor FindOpaqueBackgroundColorCoveringEverything() const;
1021
1022
  /**
1023
   * Adds aRect to this node's top PaintedLayerData's mVisibleAboveRegion,
1024
   * or mVisibleAboveBackgroundRegion if mPaintedLayerDataStack is empty.
1025
   */
1026
  void AddToVisibleAboveRegion(const nsIntRect& aRect);
1027
  /**
1028
   * Call this if all of our existing content can potentially be covered, so
1029
   * nothing can merge with it and all new content needs to create new items
1030
   * on top. This will finish all of our children and pop our whole
1031
   * mPaintedLayerDataStack.
1032
   */
1033
  void SetAllDrawingAbove();
1034
1035
  /**
1036
   * Finish this node: Finish all children, finish our PaintedLayer contents,
1037
   * and (if requested) adjust our parent's visible above region to include
1038
   * our clip.
1039
   */
1040
  void Finish(bool aParentNeedsAccurateVisibleAboveRegion);
1041
1042
  /**
1043
   * Finish any children that intersect aRect.
1044
   */
1045
  void FinishChildrenIntersecting(const nsIntRect& aRect);
1046
1047
  /**
1048
   * Finish all children.
1049
   */
1050
0
  void FinishAllChildren() { FinishAllChildren(true); }
1051
1052
protected:
1053
  /**
1054
   * Finish all items in mPaintedLayerDataStack and clear the stack.
1055
   */
1056
  void PopAllPaintedLayerData();
1057
  /**
1058
   * Finish all of our child nodes, but don't touch mPaintedLayerDataStack.
1059
   */
1060
  void FinishAllChildren(bool aThisNodeNeedsAccurateVisibleAboveRegion);
1061
  /**
1062
   * Pass off opaque background color searching to our parent node, if we have
1063
   * one.
1064
   */
1065
  nscolor FindOpaqueBackgroundColorInParentNode() const;
1066
1067
  PaintedLayerDataTree& mTree;
1068
  PaintedLayerDataNode* mParent;
1069
  AnimatedGeometryRoot* mAnimatedGeometryRoot;
1070
1071
  /**
1072
   * Our contents: a PaintedLayerData stack and our child nodes.
1073
   */
1074
  AutoTArray<PaintedLayerData, 3> mPaintedLayerDataStack;
1075
1076
  /**
1077
   * UniquePtr is used here in the sense of "unique ownership", i.e. there is
1078
   * only one owner. Not in the sense of "this is the only pointer to the
1079
   * node": There are two other, non-owning, pointers to our child nodes: The
1080
   * node's respective children point to their parent node with their mParent
1081
   * pointer, and the tree keeps a map of animated geometry root to node in its
1082
   * mNodes member. These outside pointers are the reason that mChildren isn't
1083
   * just an nsTArray<PaintedLayerDataNode> (since the pointers would become
1084
   * invalid whenever the array expands its capacity).
1085
   */
1086
  nsTArray<UniquePtr<PaintedLayerDataNode>> mChildren;
1087
1088
  /**
1089
   * The region that's covered between our "background" and the bottom of
1090
   * mPaintedLayerDataStack. This is used to indicate whether we can pull
1091
   * a background color from our parent node. If mVisibleAboveBackgroundRegion
1092
   * should be considered infinite, mAllDrawingAboveBackground will be true and
1093
   * the value of mVisibleAboveBackgroundRegion will be meaningless.
1094
   */
1095
  nsIntRegion mVisibleAboveBackgroundRegion;
1096
1097
  /**
1098
   * Our clip, if we have any. If not, that means we can move anywhere, and
1099
   * mHasClip will be false and mClipRect will be meaningless.
1100
   */
1101
  nsIntRect mClipRect;
1102
  bool mHasClip;
1103
1104
  /**
1105
   * Whether mVisibleAboveBackgroundRegion should be considered infinite.
1106
   */
1107
  bool mAllDrawingAboveBackground;
1108
};
1109
1110
class ContainerState;
1111
1112
/**
1113
 * A tree of PaintedLayerDataNodes. At any point in time, the tree only
1114
 * contains nodes for animated geometry roots that new items can potentially
1115
 * merge into. Any time content is added on top that overlaps existing things
1116
 * in such a way that we no longer want to merge new items with some existing
1117
 * content, that existing content gets "finished".
1118
 * The public-facing methods of this class are FindPaintedLayerFor,
1119
 * AddingOwnLayer, and Finish. The other public methods are for
1120
 * PaintedLayerDataNode.
1121
 * The tree calls out to its containing ContainerState for some things.
1122
 * All coordinates / rects in the tree or the tree nodes are in the
1123
 * ContainerState's coordinate space, i.e. relative to the reference frame and
1124
 * in layer pixels.
1125
 * The clip rects of sibling nodes never overlap. This is ensured by finishing
1126
 * existing nodes before adding new ones, if this property were to be violated.
1127
 * The root tree node doesn't get finished until the ContainerState is
1128
 * finished.
1129
 * The tree's root node is always the root reference frame of the builder. We
1130
 * don't stop at the container state's mContainerAnimatedGeometryRoot because
1131
 * some of our contents can have animated geometry roots that are not
1132
 * descendants of the container's animated geometry root. Every animated
1133
 * geometry root we encounter for our contents needs to have a defined place in
1134
 * the tree.
1135
 */
1136
class PaintedLayerDataTree
1137
{
1138
public:
1139
  PaintedLayerDataTree(ContainerState& aContainerState,
1140
                       nscolor& aBackgroundColor)
1141
    : mContainerState(aContainerState)
1142
    , mContainerUniformBackgroundColor(aBackgroundColor)
1143
    , mForInactiveLayer(false)
1144
0
  {
1145
0
  }
1146
1147
  ~PaintedLayerDataTree()
1148
0
  {
1149
0
    MOZ_ASSERT(!mRoot);
1150
0
    MOZ_ASSERT(mNodes.Count() == 0);
1151
0
  }
1152
1153
  void InitializeForInactiveLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1154
1155
  /**
1156
   * Notify our contents that some non-PaintedLayer content has been added.
1157
   * *aRect needs to be a rectangle that doesn't move with respect to
1158
   * aAnimatedGeometryRoot and that contains the added item.
1159
   * If aRect is null, the extents will be considered infinite.
1160
   * If aOutUniformBackgroundColor is non-null, it will be set to an opaque
1161
   * color that can be pulled into the background of the added content, or
1162
   * transparent if that is not possible.
1163
   */
1164
  void AddingOwnLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1165
                      const nsIntRect* aRect,
1166
                      nscolor* aOutUniformBackgroundColor);
1167
1168
  /**
1169
   * Find a PaintedLayerData for aItem. This can either be an existing
1170
   * PaintedLayerData from inside a node in our tree, or a new one that gets
1171
   * created by a call out to aNewPaintedLayerCallback.
1172
   */
1173
  template<typename NewPaintedLayerCallbackType>
1174
  PaintedLayerData* FindPaintedLayerFor(
1175
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1176
    const ActiveScrolledRoot* aASR,
1177
    const DisplayItemClipChain* aClipChain,
1178
    const nsIntRect& aVisibleRect,
1179
    const bool aBackfaceHidden,
1180
    NewPaintedLayerCallbackType aNewPaintedLayerCallback);
1181
1182
  /**
1183
   * Finish everything.
1184
   */
1185
  void Finish();
1186
1187
  /**
1188
   * Get the parent animated geometry root of aAnimatedGeometryRoot.
1189
   * That's either aAnimatedGeometryRoot's animated geometry root, or, if
1190
   * that's aAnimatedGeometryRoot itself, then it's the animated geometry
1191
   * root for aAnimatedGeometryRoot's cross-doc parent frame.
1192
   */
1193
  AnimatedGeometryRoot* GetParentAnimatedGeometryRoot(
1194
    AnimatedGeometryRoot* aAnimatedGeometryRoot);
1195
1196
  /**
1197
   * Whether aAnimatedGeometryRoot has an intrinsic clip that doesn't move with
1198
   * respect to aAnimatedGeometryRoot's parent animated geometry root.
1199
   * If aAnimatedGeometryRoot is a scroll frame, this will be the scroll frame's
1200
   * scroll port, otherwise there is no clip.
1201
   * This method doesn't have much to do with PaintedLayerDataTree, but this is
1202
   * where we have easy access to a display list builder, which we use to get
1203
   * the clip rect result into the right coordinate space.
1204
   */
1205
  bool IsClippedWithRespectToParentAnimatedGeometryRoot(
1206
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1207
    nsIntRect* aOutClip);
1208
1209
  /**
1210
   * Called by PaintedLayerDataNode when it is finished, so that we can drop
1211
   * our pointers to it.
1212
   */
1213
  void NodeWasFinished(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1214
1215
  nsDisplayListBuilder* Builder() const;
1216
0
  ContainerState& ContState() const { return mContainerState; }
1217
  nscolor UniformBackgroundColor() const
1218
0
  {
1219
0
    return mContainerUniformBackgroundColor;
1220
0
  }
1221
1222
protected:
1223
  /**
1224
   * Finish all nodes that potentially intersect *aRect, where *aRect is a rect
1225
   * that doesn't move with respect to aAnimatedGeometryRoot.
1226
   * If aRect is null, *aRect will be considered infinite.
1227
   */
1228
  void FinishPotentiallyIntersectingNodes(
1229
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1230
    const nsIntRect* aRect);
1231
1232
  /**
1233
   * Make sure that there is a node for aAnimatedGeometryRoot and all of its
1234
   * ancestor geometry roots. Return the node for aAnimatedGeometryRoot.
1235
   */
1236
  PaintedLayerDataNode* EnsureNodeFor(
1237
    AnimatedGeometryRoot* aAnimatedGeometryRoot);
1238
1239
  /**
1240
   * Find an existing node in the tree for an ancestor of aAnimatedGeometryRoot.
1241
   * *aOutAncestorChild will be set to the last ancestor that was encountered
1242
   * in the search up from aAnimatedGeometryRoot; it will be a child animated
1243
   * geometry root of the result, if neither are null.
1244
   */
1245
  PaintedLayerDataNode* FindNodeForAncestorAnimatedGeometryRoot(
1246
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1247
    AnimatedGeometryRoot** aOutAncestorChild);
1248
1249
  ContainerState& mContainerState;
1250
  Maybe<PaintedLayerDataNode> mRoot;
1251
1252
  /**
1253
   * The uniform opaque color from behind this container layer, or
1254
   * NS_RGBA(0,0,0,0) if the background behind this container layer is not
1255
   * uniform and opaque. This color can be pulled into PaintedLayers that are
1256
   * directly above the background.
1257
   */
1258
  nscolor mContainerUniformBackgroundColor;
1259
1260
  /**
1261
   * A hash map for quick access the node belonging to a particular animated
1262
   * geometry root.
1263
   */
1264
  nsDataHashtable<nsPtrHashKey<AnimatedGeometryRoot>, PaintedLayerDataNode*>
1265
    mNodes;
1266
1267
  bool mForInactiveLayer;
1268
};
1269
1270
/**
1271
 * This is a helper object used to build up the layer children for
1272
 * a ContainerLayer.
1273
 */
1274
class ContainerState
1275
{
1276
public:
1277
  ContainerState(nsDisplayListBuilder* aBuilder,
1278
                 LayerManager* aManager,
1279
                 FrameLayerBuilder* aLayerBuilder,
1280
                 nsIFrame* aContainerFrame,
1281
                 nsDisplayItem* aContainerItem,
1282
                 const nsRect& aContainerBounds,
1283
                 ContainerLayer* aContainerLayer,
1284
                 const ContainerLayerParameters& aParameters,
1285
                 nscolor aBackgroundColor,
1286
                 const ActiveScrolledRoot* aContainerASR,
1287
                 const ActiveScrolledRoot* aContainerScrollMetadataASR,
1288
                 const ActiveScrolledRoot* aContainerCompositorASR)
1289
    : mBuilder(aBuilder)
1290
    , mManager(aManager)
1291
    , mLayerBuilder(aLayerBuilder)
1292
    , mContainerFrame(aContainerFrame)
1293
    , mContainerLayer(aContainerLayer)
1294
    , mContainerBounds(aContainerBounds)
1295
    , mContainerASR(aContainerASR)
1296
    , mContainerScrollMetadataASR(aContainerScrollMetadataASR)
1297
    , mContainerCompositorASR(aContainerCompositorASR)
1298
    , mParameters(aParameters)
1299
    , mPaintedLayerDataTree(*this, aBackgroundColor)
1300
    , mLastDisplayPortAGR(nullptr)
1301
0
  {
1302
0
    nsPresContext* presContext = aContainerFrame->PresContext();
1303
0
    mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
1304
0
    mContainerReferenceFrame = const_cast<nsIFrame*>(
1305
0
      aContainerItem ? aContainerItem->ReferenceFrameForChildren()
1306
0
                     : mBuilder->FindReferenceFrameFor(mContainerFrame));
1307
0
    bool isAtRoot = !aContainerItem ||
1308
0
                    (aContainerItem->Frame() == mBuilder->RootReferenceFrame());
1309
0
    MOZ_ASSERT(!isAtRoot ||
1310
0
               mContainerReferenceFrame == mBuilder->RootReferenceFrame());
1311
0
    mContainerAnimatedGeometryRoot =
1312
0
      isAtRoot ? aBuilder->GetRootAnimatedGeometryRoot()
1313
0
               : aContainerItem->GetAnimatedGeometryRoot();
1314
0
    MOZ_ASSERT(
1315
0
      !mBuilder->IsPaintingToWindow() ||
1316
0
      nsLayoutUtils::IsAncestorFrameCrossDoc(mBuilder->RootReferenceFrame(),
1317
0
                                             *mContainerAnimatedGeometryRoot));
1318
0
    // When AllowResidualTranslation is false, display items will be drawn
1319
0
    // scaled with a translation by integer pixels, so we know how the snapping
1320
0
    // will work.
1321
0
    mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
1322
0
                       !mParameters.AllowResidualTranslation();
1323
0
    CollectOldLayers();
1324
0
  }
1325
1326
  /**
1327
   * This is the method that actually walks a display list and builds
1328
   * the child layers.
1329
   */
1330
  void ProcessDisplayItems(nsDisplayList* aList);
1331
  /**
1332
   * This finalizes all the open PaintedLayers by popping every element off
1333
   * mPaintedLayerDataStack, then sets the children of the container layer
1334
   * to be all the layers in mNewChildLayers in that order and removes any
1335
   * layers as children of the container that aren't in mNewChildLayers.
1336
   * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
1337
   * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
1338
   */
1339
  void Finish(uint32_t* aTextContentFlags,
1340
              const nsIntRect& aContainerPixelBounds,
1341
              nsDisplayList* aChildItems);
1342
1343
0
  nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
1344
1345
  nsIntRect ScaleToNearestPixels(const nsRect& aRect) const
1346
0
  {
1347
0
    return aRect.ScaleToNearestPixels(
1348
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1349
0
  }
1350
  nsIntRegion ScaleRegionToNearestPixels(const nsRegion& aRegion) const
1351
0
  {
1352
0
    return aRegion.ScaleToNearestPixels(
1353
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1354
0
  }
1355
  nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap = false) const
1356
0
  {
1357
0
    if (aSnap && mSnappingEnabled) {
1358
0
      return ScaleToNearestPixels(aRect);
1359
0
    }
1360
0
    return aRect.ScaleToOutsidePixels(
1361
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1362
0
  }
1363
  nsIntRegion ScaleToOutsidePixels(const nsRegion& aRegion,
1364
                                   bool aSnap = false) const
1365
0
  {
1366
0
    if (aSnap && mSnappingEnabled) {
1367
0
      return ScaleRegionToNearestPixels(aRegion);
1368
0
    }
1369
0
    return aRegion.ScaleToOutsidePixels(
1370
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1371
0
  }
1372
  nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap = false) const
1373
0
  {
1374
0
    if (aSnap && mSnappingEnabled) {
1375
0
      return ScaleToNearestPixels(aRect);
1376
0
    }
1377
0
    return aRect.ScaleToInsidePixels(
1378
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1379
0
  }
1380
1381
  nsIntRegion ScaleRegionToInsidePixels(const nsRegion& aRegion,
1382
                                        bool aSnap = false) const
1383
0
  {
1384
0
    if (aSnap && mSnappingEnabled) {
1385
0
      return ScaleRegionToNearestPixels(aRegion);
1386
0
    }
1387
0
    return aRegion.ScaleToInsidePixels(
1388
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1389
0
  }
1390
1391
  nsIntRegion ScaleRegionToOutsidePixels(const nsRegion& aRegion,
1392
                                         bool aSnap = false) const
1393
0
  {
1394
0
    if (aSnap && mSnappingEnabled) {
1395
0
      return ScaleRegionToNearestPixels(aRegion);
1396
0
    }
1397
0
    return aRegion.ScaleToOutsidePixels(
1398
0
      mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
1399
0
  }
1400
1401
0
  nsIFrame* GetContainerFrame() const { return mContainerFrame; }
1402
0
  nsDisplayListBuilder* Builder() const { return mBuilder; }
1403
1404
  /**
1405
   * Check if we are currently inside an inactive layer.
1406
   */
1407
  bool IsInInactiveLayer() const
1408
0
  {
1409
0
    return mLayerBuilder->GetContainingPaintedLayerData();
1410
0
  }
1411
1412
  /**
1413
   * Sets aOuterVisibleRegion as aLayer's visible region.
1414
   * @param aOuterVisibleRegion
1415
   *   is in the coordinate space of the container reference frame.
1416
   * @param aLayerContentsVisibleRect, if non-null, is in the layer's own
1417
   *   coordinate system.
1418
   * @param aOuterUntransformed is true if the given aOuterVisibleRegion
1419
   *   is already untransformed with the matrix of the layer.
1420
   */
1421
  void SetOuterVisibleRegionForLayer(
1422
    Layer* aLayer,
1423
    const nsIntRegion& aOuterVisibleRegion,
1424
    const nsIntRect* aLayerContentsVisibleRect = nullptr,
1425
    bool aOuterUntransformed = false) const;
1426
1427
  /**
1428
   * Try to determine whether the PaintedLayer aData has a single opaque color
1429
   * covering aRect. If successful, return that color, otherwise return
1430
   * NS_RGBA(0,0,0,0).
1431
   * If aRect turns out not to intersect any content in the layer,
1432
   * *aOutIntersectsLayer will be set to false.
1433
   */
1434
  nscolor FindOpaqueBackgroundColorInLayer(const PaintedLayerData* aData,
1435
                                           const nsIntRect& aRect,
1436
                                           bool* aOutIntersectsLayer) const;
1437
1438
  /**
1439
   * Indicate that we are done adding items to the PaintedLayer represented by
1440
   * aData. Make sure that a real PaintedLayer exists for it, and set the final
1441
   * visible region and opaque-content.
1442
   */
1443
  template<typename FindOpaqueBackgroundColorCallbackType>
1444
  void FinishPaintedLayerData(
1445
    PaintedLayerData& aData,
1446
    FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor);
1447
1448
protected:
1449
  friend class PaintedLayerData;
1450
  friend class FLBDisplayItemIterator;
1451
1452
  LayerManager::PaintedLayerCreationHint GetLayerCreationHint(
1453
    AnimatedGeometryRoot* aAnimatedGeometryRoot);
1454
1455
  /**
1456
   * Creates a new PaintedLayer and sets up the transform on the PaintedLayer
1457
   * to account for scrolling.
1458
   */
1459
  already_AddRefed<PaintedLayer> CreatePaintedLayer(PaintedLayerData* aData);
1460
1461
  /**
1462
   * Find a PaintedLayer for recycling, recycle it and prepare it for use, or
1463
   * return null if no suitable layer was found.
1464
   */
1465
  already_AddRefed<PaintedLayer> AttemptToRecyclePaintedLayer(
1466
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1467
    nsDisplayItem* aItem,
1468
    const nsPoint& aTopLeft,
1469
    const nsIFrame* aReferenceFrame);
1470
  /**
1471
   * Recycle aLayer and do any necessary invalidation.
1472
   */
1473
  PaintedDisplayItemLayerUserData* RecyclePaintedLayer(
1474
    PaintedLayer* aLayer,
1475
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1476
    bool& didResetScrollPositionForLayerPixelAlignment);
1477
1478
  /**
1479
   * Perform the last step of CreatePaintedLayer / AttemptToRecyclePaintedLayer:
1480
   * Initialize aData, set up the layer's transform for scrolling, and
1481
   * invalidate the layer for layer pixel alignment changes if necessary.
1482
   */
1483
  void PreparePaintedLayerForUse(
1484
    PaintedLayer* aLayer,
1485
    PaintedDisplayItemLayerUserData* aData,
1486
    AnimatedGeometryRoot* aAnimatedGeometryRoot,
1487
    const nsIFrame* aReferenceFrame,
1488
    const nsPoint& aTopLeft,
1489
    bool aDidResetScrollPositionForLayerPixelAlignment);
1490
1491
  /**
1492
   * Attempt to prepare an ImageLayer based upon the provided PaintedLayerData.
1493
   * Returns nullptr on failure.
1494
   */
1495
  already_AddRefed<Layer> PrepareImageLayer(PaintedLayerData* aData);
1496
1497
  /**
1498
   * Attempt to prepare a ColorLayer based upon the provided PaintedLayerData.
1499
   * Returns nullptr on failure.
1500
   */
1501
  already_AddRefed<Layer> PrepareColorLayer(PaintedLayerData* aData);
1502
1503
  /**
1504
   * Grab the next recyclable ColorLayer, or create one if there are no
1505
   * more recyclable ColorLayers.
1506
   */
1507
  already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(
1508
    PaintedLayer* aPainted);
1509
  /**
1510
   * Grab the next recyclable ImageLayer, or create one if there are no
1511
   * more recyclable ImageLayers.
1512
   */
1513
  already_AddRefed<ImageLayer> CreateOrRecycleImageLayer(
1514
    PaintedLayer* aPainted);
1515
  /**
1516
   * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a
1517
   * mask layer which has been used for aLayer before), or create one if such
1518
   * a layer doesn't exist.
1519
   *
1520
   * Since mask layers can exist either on the layer directly, or as a side-
1521
   * attachment to FrameMetrics (for ancestor scrollframe clips), we key the
1522
   * recycle operation on both the originating layer and the mask layer's
1523
   * index in the layer, if any.
1524
   */
1525
  struct MaskLayerKey;
1526
  template<typename UserData>
1527
  already_AddRefed<ImageLayer> CreateOrRecycleMaskImageLayerFor(
1528
    const MaskLayerKey& aKey,
1529
    UserData* (*aGetUserData)(Layer* aLayer),
1530
    void (*aSetDefaultUserData)(Layer* aLayer));
1531
  /**
1532
   * Grabs all PaintedLayers and ColorLayers from the ContainerLayer and makes
1533
   * them available for recycling.
1534
   */
1535
  void CollectOldLayers();
1536
  /**
1537
   * If aItem used to belong to a PaintedLayer, invalidates the area of
1538
   * aItem in that layer. If aNewLayer is a PaintedLayer, invalidates the area
1539
   * of aItem in that layer.
1540
   */
1541
  void InvalidateForLayerChange(nsDisplayItem* aItem,
1542
                                PaintedLayer* aNewLayer,
1543
                                DisplayItemData* aData);
1544
  /**
1545
   * Returns true if aItem's opaque area (in aOpaque) covers the entire
1546
   * scrollable area of its presshell.
1547
   */
1548
  bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
1549
1550
  /**
1551
   * Set ScrollMetadata and scroll-induced clipping on aEntry's layer.
1552
   */
1553
  void SetupScrollingMetadata(NewLayerEntry* aEntry);
1554
1555
  /**
1556
   * Applies occlusion culling.
1557
   * For each layer in mNewChildLayers, remove from its visible region the
1558
   * opaque regions of the layers at higher z-index, but only if they have
1559
   * the same animated geometry root and fixed-pos frame ancestor.
1560
   * The opaque region for the child layers that share the same animated
1561
   * geometry root as the container frame is returned in
1562
   * *aOpaqueRegionForContainer.
1563
   *
1564
   * Also sets scroll metadata on the layers.
1565
   */
1566
  void PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer);
1567
1568
  /**
1569
   * Computes the snapped opaque area of aItem. Sets aList's opaque flag
1570
   * if it covers the entire list bounds. Sets *aHideAllLayersBelow to true
1571
   * this item covers the entire viewport so that all layers below are
1572
   * permanently invisible.
1573
   */
1574
  nsIntRegion ComputeOpaqueRect(nsDisplayItem* aItem,
1575
                                AnimatedGeometryRoot* aAnimatedGeometryRoot,
1576
                                const ActiveScrolledRoot* aASR,
1577
                                const DisplayItemClip& aClip,
1578
                                nsDisplayList* aList,
1579
                                bool* aHideAllLayersBelow,
1580
                                bool* aOpaqueForAnimatedGeometryRootParent);
1581
1582
  /**
1583
   * Fills a PaintedLayerData object that is initialized for a layer that the
1584
   * current item will be assigned to. Also creates mNewChildLayers entries.
1585
   * @param  aData                 The PaintedLayerData that will be filled.
1586
   * @param  aVisibleRect          The visible rect of the item.
1587
   * @param  aAnimatedGeometryRoot The item's animated geometry root.
1588
   * @param  aASR                  The active scrolled root that moves this
1589
   * PaintedLayer.
1590
   * @param  aClipChain            The clip chain that the compositor needs to
1591
   *                               apply to this layer.
1592
   * @param  aScrollMetadataASR    The leaf ASR for which scroll metadata needs
1593
   * to be set on the layer, because either the layer itself or its scrolled
1594
   * clip need to move with that ASR.
1595
   * @param  aTopLeft              The offset between aAnimatedGeometryRoot and
1596
   *                               the reference frame.
1597
   * @param  aReferenceFrame       The reference frame for the item.
1598
   * @param  aBackfaceHidden       The backface visibility for the item frame.
1599
   */
1600
  void NewPaintedLayerData(PaintedLayerData* aData,
1601
                           AnimatedGeometryRoot* aAnimatedGeometryRoot,
1602
                           const ActiveScrolledRoot* aASR,
1603
                           const DisplayItemClipChain* aClipChain,
1604
                           const ActiveScrolledRoot* aScrollMetadataASR,
1605
                           const nsPoint& aTopLeft,
1606
                           const nsIFrame* aReferenceFrame,
1607
                           const bool aBackfaceHidden);
1608
1609
  /* Build a mask layer to represent the clipping region. Will return null if
1610
   * there is no clipping specified or a mask layer cannot be built.
1611
   * Builds an ImageLayer for the appropriate backend; the mask is relative to
1612
   * aLayer's visible region.
1613
   * aLayer is the layer to be clipped.
1614
   * relative to the container reference frame
1615
   * aRoundedRectClipCount is used when building mask layers for PaintedLayers,
1616
   */
1617
  void SetupMaskLayer(Layer* aLayer, const DisplayItemClip& aClip);
1618
1619
  /**
1620
   * If |aClip| has rounded corners, create a mask layer for them, and
1621
   * add it to |aLayer|'s ancestor mask layers, returning an index into
1622
   * the array of ancestor mask layers. Returns an empty Maybe if
1623
   * |aClip| does not have rounded corners, or if no mask layer could
1624
   * be created.
1625
   */
1626
  Maybe<size_t> SetupMaskLayerForScrolledClip(Layer* aLayer,
1627
                                              const DisplayItemClip& aClip);
1628
1629
  /*
1630
   * Create/find a mask layer with suitable size for aMaskItem to paint
1631
   * css-positioned-masking onto.
1632
   */
1633
  void SetupMaskLayerForCSSMask(Layer* aLayer, nsDisplayMask* aMaskItem);
1634
1635
  already_AddRefed<Layer> CreateMaskLayer(
1636
    Layer* aLayer,
1637
    const DisplayItemClip& aClip,
1638
    const Maybe<size_t>& aForAncestorMaskLayer);
1639
1640
  /**
1641
   * Get the display port for an AGR.
1642
   * The result would be cached for later reusing.
1643
   */
1644
  nsRect GetDisplayPortForAnimatedGeometryRoot(
1645
    AnimatedGeometryRoot* aAnimatedGeometryRoot);
1646
1647
  nsDisplayListBuilder* mBuilder;
1648
  LayerManager* mManager;
1649
  FrameLayerBuilder* mLayerBuilder;
1650
  nsIFrame* mContainerFrame;
1651
  nsIFrame* mContainerReferenceFrame;
1652
  AnimatedGeometryRoot* mContainerAnimatedGeometryRoot;
1653
  ContainerLayer* mContainerLayer;
1654
  nsRect mContainerBounds;
1655
1656
  // Due to the way we store scroll annotations in the layer tree, we need to
1657
  // keep track of three (possibly different) ASRs here.
1658
  // mContainerASR is the ASR of the container display item that this
1659
  // ContainerState was created for.
1660
  // mContainerScrollMetadataASR is the ASR of the leafmost scroll metadata
1661
  // that's in effect on mContainerLayer.
1662
  // mContainerCompositorASR is the ASR that mContainerLayer moves with on
1663
  // the compositor / APZ side, taking into account both the scroll meta data
1664
  // and the fixed position annotation on itself and its ancestors.
1665
  const ActiveScrolledRoot* mContainerASR;
1666
  const ActiveScrolledRoot* mContainerScrollMetadataASR;
1667
  const ActiveScrolledRoot* mContainerCompositorASR;
1668
#ifdef DEBUG
1669
  nsRect mAccumulatedChildBounds;
1670
#endif
1671
  ContainerLayerParameters mParameters;
1672
  /**
1673
   * The region of PaintedLayers that should be invalidated every time
1674
   * we recycle one.
1675
   */
1676
  nsIntRegion mInvalidPaintedContent;
1677
  PaintedLayerDataTree mPaintedLayerDataTree;
1678
  /**
1679
   * We collect the list of children in here. During ProcessDisplayItems,
1680
   * the layers in this array either have mContainerLayer as their parent,
1681
   * or no parent.
1682
   * PaintedLayers have two entries in this array: the second one is used only
1683
   * if the PaintedLayer is optimized away to a ColorLayer or ImageLayer. It's
1684
   * essential that this array is only appended to, since PaintedLayerData
1685
   * records the index of its PaintedLayer in this array.
1686
   */
1687
  typedef AutoTArray<NewLayerEntry, 1> AutoLayersArray;
1688
  AutoLayersArray mNewChildLayers;
1689
  nsTHashtable<nsRefPtrHashKey<PaintedLayer>>
1690
    mPaintedLayersAvailableForRecycling;
1691
  nscoord mAppUnitsPerDevPixel;
1692
  bool mSnappingEnabled;
1693
1694
  struct MaskLayerKey
1695
  {
1696
    MaskLayerKey()
1697
      : mLayer(nullptr)
1698
0
    {
1699
0
    }
1700
    MaskLayerKey(Layer* aLayer, const Maybe<size_t>& aAncestorIndex)
1701
      : mLayer(aLayer)
1702
      , mAncestorIndex(aAncestorIndex)
1703
0
    {
1704
0
    }
1705
1706
    PLDHashNumber Hash() const
1707
0
    {
1708
0
      // Hash the layer and add the layer index to the hash.
1709
0
      return (NS_PTR_TO_UINT32(mLayer) >> 2) +
1710
0
             (mAncestorIndex ? (*mAncestorIndex + 1) : 0);
1711
0
    }
1712
    bool operator==(const MaskLayerKey& aOther) const
1713
0
    {
1714
0
      return mLayer == aOther.mLayer && mAncestorIndex == aOther.mAncestorIndex;
1715
0
    }
1716
1717
    Layer* mLayer;
1718
    Maybe<size_t> mAncestorIndex;
1719
  };
1720
1721
  nsDataHashtable<nsGenericHashKey<MaskLayerKey>, RefPtr<ImageLayer>>
1722
    mRecycledMaskImageLayers;
1723
  // Keep display port of AGR to avoid wasting time on doing the same
1724
  // thing repeatly.
1725
  AnimatedGeometryRoot* mLastDisplayPortAGR;
1726
  nsRect mLastDisplayPortRect;
1727
1728
  // Cache ScrollMetadata so it doesn't need recomputed if the ASR and clip are
1729
  // unchanged. If mASR == nullptr then mMetadata is not valid.
1730
  struct CachedScrollMetadata
1731
  {
1732
    const ActiveScrolledRoot* mASR;
1733
    const DisplayItemClip* mClip;
1734
    Maybe<ScrollMetadata> mMetadata;
1735
1736
    CachedScrollMetadata()
1737
      : mASR(nullptr)
1738
      , mClip(nullptr)
1739
0
    {
1740
0
    }
1741
  };
1742
  CachedScrollMetadata mCachedScrollMetadata;
1743
};
1744
1745
nsDisplayItem*
1746
FLBDisplayItemIterator::GetNext()
1747
0
{
1748
0
  // This function is only supposed to be called if there are no markers set.
1749
0
  // Breaking this invariant can potentially break effect flattening and/or
1750
0
  // display item merging.
1751
0
  MOZ_ASSERT(mMarkers.empty());
1752
0
1753
0
  nsDisplayItem* next = mNext;
1754
0
1755
0
  // Advance mNext to the following item
1756
0
  if (next) {
1757
0
    nsDisplayItem* peek = next->GetAbove();
1758
0
1759
0
    // Peek ahead to the next item and see if it can be merged with the
1760
0
    // current item.
1761
0
    if (peek && next->CanMerge(peek)) {
1762
0
      // Create a list of consecutive items that can be merged together.
1763
0
      AutoTArray<nsDisplayItem*, 2> mergedItems{ next, peek };
1764
0
      while ((peek = peek->GetAbove())) {
1765
0
        if (!next->CanMerge(peek)) {
1766
0
          break;
1767
0
        }
1768
0
1769
0
        mergedItems.AppendElement(peek);
1770
0
      }
1771
0
1772
0
      // We have items that can be merged together.
1773
0
      // Merge them into a temporary item and process that item immediately.
1774
0
      MOZ_ASSERT(mergedItems.Length() > 1);
1775
0
      next = mState->mBuilder->MergeItems(mergedItems);
1776
0
    }
1777
0
1778
0
    // |mNext| is either the first item that could not be merged with |next|,
1779
0
    // or a nullptr.
1780
0
    mNext = peek;
1781
0
1782
0
    ResolveFlattening();
1783
0
  }
1784
0
1785
0
  return next;
1786
0
}
1787
1788
bool
1789
FLBDisplayItemIterator::NextItemWantsInactiveLayer()
1790
0
{
1791
0
  LayerState layerState = mNext->GetLayerState(
1792
0
    mState->mBuilder, mState->mManager, mState->mParameters);
1793
0
1794
0
  return layerState == LayerState::LAYER_INACTIVE;
1795
0
}
1796
1797
bool
1798
FLBDisplayItemIterator::ShouldFlattenNextItem()
1799
0
{
1800
0
  if (!mNext) {
1801
0
    return false;
1802
0
  }
1803
0
1804
0
  if (!mNext->ShouldFlattenAway(mBuilder)) {
1805
0
    return false;
1806
0
  }
1807
0
1808
0
  const DisplayItemType type = mNext->GetType();
1809
0
  if (type != DisplayItemType::TYPE_OPACITY &&
1810
0
      type != DisplayItemType::TYPE_TRANSFORM) {
1811
0
    return true;
1812
0
  }
1813
0
1814
0
  if (type == DisplayItemType::TYPE_OPACITY) {
1815
0
    nsDisplayOpacity* opacity = static_cast<nsDisplayOpacity*>(mNext);
1816
0
1817
0
    if (opacity->OpacityAppliedToChildren()) {
1818
0
      // This is the previous opacity flattening path, where the opacity has
1819
0
      // been applied to children.
1820
0
      return true;
1821
0
    }
1822
0
  }
1823
0
1824
0
  if (mState->IsInInactiveLayer() || !NextItemWantsInactiveLayer()) {
1825
0
    // Do not flatten nested inactive display items, or display items that want
1826
0
    // an active layer.
1827
0
    return false;
1828
0
  }
1829
0
1830
0
  // Flatten inactive nsDisplayOpacity and nsDisplayTransform.
1831
0
  mStoreMarker = true;
1832
0
  return true;
1833
0
}
1834
1835
class PaintedDisplayItemLayerUserData : public LayerUserData
1836
{
1837
public:
1838
  PaintedDisplayItemLayerUserData()
1839
    : mForcedBackgroundColor(NS_RGBA(0, 0, 0, 0))
1840
    , mXScale(1.f)
1841
    , mYScale(1.f)
1842
    , mAppUnitsPerDevPixel(0)
1843
    , mTranslation(0, 0)
1844
    , mAnimatedGeometryRootPosition(0, 0)
1845
    , mLastItemCount(0)
1846
    , mContainerLayerFrame(nullptr)
1847
    , mHasExplicitLastPaintOffset(false)
1848
    , mDisabledAlpha(false)
1849
0
  {
1850
0
  }
1851
1852
  NS_INLINE_DECL_REFCOUNTING(PaintedDisplayItemLayerUserData);
1853
1854
  /**
1855
   * A color that should be painted over the bounds of the layer's visible
1856
   * region before any other content is painted.
1857
   */
1858
  nscolor mForcedBackgroundColor;
1859
1860
  /**
1861
   * The resolution scale used.
1862
   */
1863
  float mXScale, mYScale;
1864
1865
  /**
1866
   * The appunits per dev pixel for the items in this layer.
1867
   */
1868
  nscoord mAppUnitsPerDevPixel;
1869
1870
  /**
1871
   * The offset from the PaintedLayer's 0,0 to the
1872
   * reference frame. This isn't necessarily the same as the transform
1873
   * set on the PaintedLayer since we might also be applying an extra
1874
   * offset specified by the parent ContainerLayer/
1875
   */
1876
  nsIntPoint mTranslation;
1877
1878
  /**
1879
   * We try to make 0,0 of the PaintedLayer be the top-left of the
1880
   * border-box of the "active scrolled root" frame (i.e. the nearest ancestor
1881
   * frame for the display items that is being actively scrolled). But
1882
   * we force the PaintedLayer transform to be an integer translation, and we
1883
   * may have a resolution scale, so we have to snap the PaintedLayer transform,
1884
   * so 0,0 may not be exactly the top-left of the active scrolled root. Here we
1885
   * store the coordinates in PaintedLayer space of the top-left of the
1886
   * active scrolled root.
1887
   */
1888
  gfxPoint mAnimatedGeometryRootPosition;
1889
1890
  nsIntRegion mRegionToInvalidate;
1891
1892
  // The offset between the active scrolled root of this layer
1893
  // and the root of the container for the previous and current
1894
  // paints respectively.
1895
  nsPoint mLastAnimatedGeometryRootOrigin;
1896
  nsPoint mAnimatedGeometryRootOrigin;
1897
1898
  RefPtr<ColorLayer> mColorLayer;
1899
  RefPtr<ImageLayer> mImageLayer;
1900
1901
  // The region for which display item visibility for this layer has already
1902
  // been calculated. Used to reduce the number of calls to
1903
  // RecomputeVisibilityForItems if it is known in advance that a larger
1904
  // region will be painted during a transaction than in a single call to
1905
  // DrawPaintedLayer, for example when progressive paint is enabled.
1906
  nsIntRegion mVisibilityComputedRegion;
1907
1908
  // The area for which we called RecomputeVisibilityForItems on the
1909
  // previous paint.
1910
  nsRect mPreviousRecomputeVisibilityRect;
1911
1912
  // The number of items assigned to this layer on the previous paint.
1913
  size_t mLastItemCount;
1914
1915
  // The translation set on this PaintedLayer before we started updating the
1916
  // layer tree.
1917
  nsIntPoint mLastPaintOffset;
1918
1919
  // Temporary state only valid during the FrameLayerBuilder's lifetime.
1920
  // FLB's mPaintedLayerItems is responsible for cleaning these up when
1921
  // we finish painting to avoid dangling pointers.
1922
  std::vector<AssignedDisplayItem> mItems;
1923
  nsIFrame* mContainerLayerFrame;
1924
1925
  bool mHasExplicitLastPaintOffset;
1926
1927
  /**
1928
   * This is set when the painted layer has no component alpha.
1929
   */
1930
  bool mDisabledAlpha;
1931
1932
protected:
1933
0
  ~PaintedDisplayItemLayerUserData() override = default;
1934
};
1935
1936
FrameLayerBuilder::FrameLayerBuilder()
1937
  : mRetainingManager(nullptr)
1938
  , mDisplayListBuilder(nullptr)
1939
  , mContainingPaintedLayer(nullptr)
1940
  , mInactiveLayerClip(nullptr)
1941
  , mInvalidateAllLayers(false)
1942
  , mInLayerTreeCompressionMode(false)
1943
  , mIsInactiveLayerManager(false)
1944
0
{
1945
0
  MOZ_COUNT_CTOR(FrameLayerBuilder);
1946
0
}
1947
1948
FrameLayerBuilder::~FrameLayerBuilder()
1949
0
{
1950
0
  GetMaskLayerImageCache()->Sweep();
1951
0
  for (PaintedDisplayItemLayerUserData* userData : mPaintedLayerItems) {
1952
0
    userData->mItems.clear();
1953
0
    userData->mContainerLayerFrame = nullptr;
1954
0
  }
1955
0
  MOZ_COUNT_DTOR(FrameLayerBuilder);
1956
0
}
1957
1958
void
1959
FrameLayerBuilder::AddPaintedLayerItemsEntry(
1960
  PaintedDisplayItemLayerUserData* aData)
1961
0
{
1962
0
  mPaintedLayerItems.AppendElement(aData);
1963
0
}
1964
1965
/*
1966
 * User data for layers which will be used as masks.
1967
 */
1968
struct MaskLayerUserData : public LayerUserData
1969
{
1970
  MaskLayerUserData()
1971
    : mScaleX(-1.0f)
1972
    , mScaleY(-1.0f)
1973
    , mAppUnitsPerDevPixel(-1)
1974
0
  {
1975
0
  }
1976
  MaskLayerUserData(const DisplayItemClip& aClip,
1977
                    int32_t aAppUnitsPerDevPixel,
1978
                    const ContainerLayerParameters& aParams)
1979
    : mScaleX(aParams.mXScale)
1980
    , mScaleY(aParams.mYScale)
1981
    , mOffset(aParams.mOffset)
1982
    , mAppUnitsPerDevPixel(aAppUnitsPerDevPixel)
1983
0
  {
1984
0
    aClip.AppendRoundedRects(&mRoundedClipRects);
1985
0
  }
1986
1987
  void operator=(MaskLayerUserData&& aOther)
1988
0
  {
1989
0
    mScaleX = aOther.mScaleX;
1990
0
    mScaleY = aOther.mScaleY;
1991
0
    mOffset = aOther.mOffset;
1992
0
    mAppUnitsPerDevPixel = aOther.mAppUnitsPerDevPixel;
1993
0
    mRoundedClipRects.SwapElements(aOther.mRoundedClipRects);
1994
0
  }
1995
1996
  bool operator==(const MaskLayerUserData& aOther) const
1997
0
  {
1998
0
    return mRoundedClipRects == aOther.mRoundedClipRects &&
1999
0
           mScaleX == aOther.mScaleX && mScaleY == aOther.mScaleY &&
2000
0
           mOffset == aOther.mOffset &&
2001
0
           mAppUnitsPerDevPixel == aOther.mAppUnitsPerDevPixel;
2002
0
  }
2003
2004
  // Keeps a MaskLayerImageKey alive by managing its mLayerCount member-var
2005
  MaskLayerImageCache::MaskLayerImageKeyRef mImageKey;
2006
  // properties of the mask layer; the mask layer may be re-used if these
2007
  // remain unchanged.
2008
  nsTArray<DisplayItemClip::RoundedRect> mRoundedClipRects;
2009
  // scale from the masked layer which is applied to the mask
2010
  float mScaleX, mScaleY;
2011
  // The ContainerLayerParameters offset which is applied to the mask's
2012
  // transform.
2013
  nsIntPoint mOffset;
2014
  int32_t mAppUnitsPerDevPixel;
2015
};
2016
2017
/*
2018
 * User data for layers which will be used as masks for css positioned mask.
2019
 */
2020
struct CSSMaskLayerUserData : public LayerUserData
2021
{
2022
  CSSMaskLayerUserData()
2023
    : mMaskStyle(nsStyleImageLayers::LayerType::Mask)
2024
0
  {
2025
0
  }
2026
2027
  CSSMaskLayerUserData(nsIFrame* aFrame,
2028
                       const nsIntRect& aMaskBounds,
2029
                       const nsPoint& aMaskLayerOffset)
2030
    : mMaskBounds(aMaskBounds)
2031
    , mMaskStyle(aFrame->StyleSVGReset()->mMask)
2032
    , mMaskLayerOffset(aMaskLayerOffset)
2033
0
  {
2034
0
  }
2035
2036
  void operator=(CSSMaskLayerUserData&& aOther)
2037
0
  {
2038
0
    mMaskBounds = aOther.mMaskBounds;
2039
0
    mMaskStyle = std::move(aOther.mMaskStyle);
2040
0
    mMaskLayerOffset = aOther.mMaskLayerOffset;
2041
0
  }
2042
2043
  bool operator==(const CSSMaskLayerUserData& aOther) const
2044
0
  {
2045
0
    if (!mMaskBounds.IsEqualInterior(aOther.mMaskBounds)) {
2046
0
      return false;
2047
0
    }
2048
0
2049
0
    // Make sure we draw the same portion of the mask onto mask layer.
2050
0
    if (mMaskLayerOffset != aOther.mMaskLayerOffset) {
2051
0
      return false;
2052
0
    }
2053
0
2054
0
    return mMaskStyle == aOther.mMaskStyle;
2055
0
  }
2056
2057
private:
2058
  nsIntRect mMaskBounds;
2059
  nsStyleImageLayers mMaskStyle;
2060
  nsPoint mMaskLayerOffset; // The offset from the origin of mask bounds to
2061
                            // the origin of mask layer.
2062
};
2063
2064
/*
2065
 * A helper object to create a draw target for painting mask and create a
2066
 * image container to hold the drawing result. The caller can then bind this
2067
 * image container with a image mask layer via ImageLayer::SetContainer.
2068
 */
2069
class MaskImageData
2070
{
2071
public:
2072
  MaskImageData(const gfx::IntSize& aSize, LayerManager* aLayerManager)
2073
    : mTextureClientLocked(false)
2074
    , mSize(aSize)
2075
    , mLayerManager(aLayerManager)
2076
0
  {
2077
0
    MOZ_ASSERT(!mSize.IsEmpty());
2078
0
    MOZ_ASSERT(mLayerManager);
2079
0
  }
2080
2081
  ~MaskImageData()
2082
0
  {
2083
0
    if (mTextureClientLocked) {
2084
0
      MOZ_ASSERT(mTextureClient);
2085
0
      // Clear DrawTarget before Unlock.
2086
0
      mDrawTarget = nullptr;
2087
0
      mTextureClient->Unlock();
2088
0
    }
2089
0
  }
2090
2091
  gfx::DrawTarget* CreateDrawTarget()
2092
0
  {
2093
0
    if (mDrawTarget) {
2094
0
      return mDrawTarget;
2095
0
    }
2096
0
2097
0
    if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
2098
0
      mDrawTarget = mLayerManager->CreateOptimalMaskDrawTarget(mSize);
2099
0
      return mDrawTarget;
2100
0
    }
2101
0
2102
0
    MOZ_ASSERT(mLayerManager->GetBackendType() ==
2103
0
                 LayersBackend::LAYERS_CLIENT ||
2104
0
               mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR);
2105
0
2106
0
    KnowsCompositor* knowsCompositor = mLayerManager->AsKnowsCompositor();
2107
0
    if (!knowsCompositor) {
2108
0
      return nullptr;
2109
0
    }
2110
0
    mTextureClient = TextureClient::CreateForDrawing(
2111
0
      knowsCompositor,
2112
0
      SurfaceFormat::A8,
2113
0
      mSize,
2114
0
      BackendSelector::Content,
2115
0
      TextureFlags::DISALLOW_BIGIMAGE,
2116
0
      TextureAllocationFlags::ALLOC_CLEAR_BUFFER);
2117
0
    if (!mTextureClient) {
2118
0
      return nullptr;
2119
0
    }
2120
0
2121
0
    mTextureClientLocked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
2122
0
    if (!mTextureClientLocked) {
2123
0
      return nullptr;
2124
0
    }
2125
0
2126
0
    mDrawTarget = mTextureClient->BorrowDrawTarget();
2127
0
    return mDrawTarget;
2128
0
  }
2129
2130
  already_AddRefed<ImageContainer> CreateImageAndImageContainer()
2131
0
  {
2132
0
    RefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
2133
0
    RefPtr<Image> image = CreateImage();
2134
0
2135
0
    if (!image) {
2136
0
      return nullptr;
2137
0
    }
2138
0
    container->SetCurrentImageInTransaction(image);
2139
0
2140
0
    return container.forget();
2141
0
  }
2142
2143
private:
2144
  already_AddRefed<Image> CreateImage()
2145
0
  {
2146
0
    if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC &&
2147
0
        mDrawTarget) {
2148
0
      RefPtr<SourceSurface> surface = mDrawTarget->Snapshot();
2149
0
      RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(mSize, surface);
2150
0
      // Disallow BIGIMAGE (splitting into multiple textures) for mask
2151
0
      // layer images
2152
0
      image->SetTextureFlags(TextureFlags::DISALLOW_BIGIMAGE);
2153
0
      return image.forget();
2154
0
    }
2155
0
2156
0
    if ((mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
2157
0
         mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR) &&
2158
0
        mTextureClient && mDrawTarget) {
2159
0
      RefPtr<TextureWrapperImage> image = new TextureWrapperImage(
2160
0
        mTextureClient, gfx::IntRect(gfx::IntPoint(0, 0), mSize));
2161
0
      return image.forget();
2162
0
    }
2163
0
2164
0
    return nullptr;
2165
0
  }
2166
2167
  bool mTextureClientLocked;
2168
  gfx::IntSize mSize;
2169
  LayerManager* mLayerManager;
2170
  RefPtr<gfx::DrawTarget> mDrawTarget;
2171
  RefPtr<TextureClient> mTextureClient;
2172
};
2173
2174
static PaintedDisplayItemLayerUserData*
2175
GetPaintedDisplayItemLayerUserData(Layer* aLayer)
2176
0
{
2177
0
  return static_cast<PaintedDisplayItemLayerUserData*>(
2178
0
    aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2179
0
}
2180
2181
/* static */ void
2182
FrameLayerBuilder::Shutdown()
2183
0
{
2184
0
  if (gMaskLayerImageCache) {
2185
0
    delete gMaskLayerImageCache;
2186
0
    gMaskLayerImageCache = nullptr;
2187
0
  }
2188
0
}
2189
2190
void
2191
FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder,
2192
                        LayerManager* aManager,
2193
                        PaintedLayerData* aLayerData,
2194
                        bool aIsInactiveLayerManager,
2195
                        const DisplayItemClip* aInactiveLayerClip)
2196
0
{
2197
0
  mDisplayListBuilder = aBuilder;
2198
0
  mRootPresContext =
2199
0
    aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
2200
0
  mContainingPaintedLayer = aLayerData;
2201
0
  mIsInactiveLayerManager = aIsInactiveLayerManager;
2202
0
  mInactiveLayerClip = aInactiveLayerClip;
2203
0
  aManager->SetUserData(&gLayerManagerLayerBuilder, this);
2204
0
}
2205
2206
void
2207
FrameLayerBuilder::FlashPaint(gfxContext* aContext)
2208
0
{
2209
0
  float r = float(rand()) / RAND_MAX;
2210
0
  float g = float(rand()) / RAND_MAX;
2211
0
  float b = float(rand()) / RAND_MAX;
2212
0
  aContext->SetColor(Color(r, g, b, 0.4f));
2213
0
  aContext->Paint();
2214
0
}
2215
2216
DisplayItemData*
2217
FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey)
2218
0
{
2219
0
  const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
2220
0
  for (uint32_t i = 0; i < array.Length(); i++) {
2221
0
    DisplayItemData* item =
2222
0
      DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
2223
0
    if (item->mDisplayItemKey == aKey &&
2224
0
        item->mLayer->Manager() == mRetainingManager) {
2225
0
      return item;
2226
0
    }
2227
0
  }
2228
0
  return nullptr;
2229
0
}
2230
2231
#ifdef MOZ_DUMP_PAINTING
2232
static nsACString&
2233
AppendToString(nsACString& s,
2234
               const nsIntRect& r,
2235
               const char* pfx = "",
2236
               const char* sfx = "")
2237
{
2238
  s += pfx;
2239
  s += nsPrintfCString("(x=%d, y=%d, w=%d, h=%d)", r.x, r.y, r.width, r.height);
2240
  return s += sfx;
2241
}
2242
2243
static nsACString&
2244
AppendToString(nsACString& s,
2245
               const nsIntRegion& r,
2246
               const char* pfx = "",
2247
               const char* sfx = "")
2248
{
2249
  s += pfx;
2250
2251
  s += "< ";
2252
  for (auto iter = r.RectIter(); !iter.Done(); iter.Next()) {
2253
    AppendToString(s, iter.Get()) += "; ";
2254
  }
2255
  s += ">";
2256
2257
  return s += sfx;
2258
}
2259
#endif // MOZ_DUMP_PAINTING
2260
2261
/**
2262
 * Invalidate aRegion in aLayer. aLayer is in the coordinate system
2263
 * *after* aTranslation has been applied, so we need to
2264
 * apply the inverse of that transform before calling InvalidateRegion.
2265
 */
2266
static void
2267
InvalidatePostTransformRegion(PaintedLayer* aLayer,
2268
                              const nsIntRegion& aRegion,
2269
                              const nsIntPoint& aTranslation)
2270
0
{
2271
0
  // Convert the region from the coordinates of the container layer
2272
0
  // (relative to the snapped top-left of the display list reference frame)
2273
0
  // to the PaintedLayer's own coordinates
2274
0
  nsIntRegion rgn = aRegion;
2275
0
2276
0
  rgn.MoveBy(-aTranslation);
2277
0
  aLayer->InvalidateRegion(rgn);
2278
#ifdef MOZ_DUMP_PAINTING
2279
  if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2280
    nsAutoCString str;
2281
    AppendToString(str, rgn);
2282
    printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
2283
  }
2284
#endif
2285
}
2286
2287
static void
2288
InvalidatePreTransformRect(PaintedLayer* aLayer,
2289
                           const nsRect& aRect,
2290
                           const DisplayItemClip& aClip,
2291
                           const nsIntPoint& aTranslation,
2292
                           TransformClipNode* aTransform)
2293
0
{
2294
0
  PaintedDisplayItemLayerUserData* data =
2295
0
    static_cast<PaintedDisplayItemLayerUserData*>(
2296
0
      aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2297
0
2298
0
  nsRect rect = aClip.ApplyNonRoundedIntersection(aRect);
2299
0
2300
0
  if (aTransform) {
2301
0
    rect = aTransform->TransformRect(rect, data->mAppUnitsPerDevPixel);
2302
0
  }
2303
0
2304
0
  nsIntRect pixelRect = rect.ScaleToOutsidePixels(
2305
0
    data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel);
2306
0
2307
0
  InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation);
2308
0
}
2309
2310
static nsIntPoint
2311
GetTranslationForPaintedLayer(PaintedLayer* aLayer)
2312
0
{
2313
0
  PaintedDisplayItemLayerUserData* data =
2314
0
    static_cast<PaintedDisplayItemLayerUserData*>(
2315
0
      aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2316
0
  NS_ASSERTION(data, "Must be a tracked painted layer!");
2317
0
2318
0
  return data->mTranslation;
2319
0
}
2320
2321
/**
2322
 * Some frames can have multiple, nested, retaining layer managers
2323
 * associated with them (normal manager, inactive managers, SVG effects).
2324
 * In these cases we store the 'outermost' LayerManager data property
2325
 * on the frame since we can walk down the chain from there.
2326
 *
2327
 * If one of these frames has just been destroyed, we will free the inner
2328
 * layer manager when removing the entry from mFramesWithLayers. Destroying
2329
 * the layer manager destroys the LayerManagerData and calls into
2330
 * the DisplayItemData destructor. If the inner layer manager had any
2331
 * items with the same frame, then we attempt to retrieve properties
2332
 * from the deleted frame.
2333
 *
2334
 * Cache the destroyed frame pointer here so we can avoid crashing in this case.
2335
 */
2336
2337
/* static */ void
2338
FrameLayerBuilder::RemoveFrameFromLayerManager(
2339
  const nsIFrame* aFrame,
2340
  SmallPointerArray<DisplayItemData>& aArray)
2341
0
{
2342
0
  MOZ_RELEASE_ASSERT(!sDestroyedFrame);
2343
0
  sDestroyedFrame = aFrame;
2344
0
2345
0
  // Hold a reference to all the items so that they don't get
2346
0
  // deleted from under us.
2347
0
  nsTArray<RefPtr<DisplayItemData>> arrayCopy;
2348
0
  for (DisplayItemData* data : aArray) {
2349
0
    arrayCopy.AppendElement(data);
2350
0
  }
2351
0
2352
#ifdef DEBUG_DISPLAY_ITEM_DATA
2353
  if (aArray->Length()) {
2354
    LayerManagerData* rootData = aArray->ElementAt(0)->mParent;
2355
    while (rootData->mParent) {
2356
      rootData = rootData->mParent;
2357
    }
2358
    printf_stderr("Removing frame %p - dumping display data\n", aFrame);
2359
    rootData->Dump();
2360
  }
2361
#endif
2362
2363
0
  for (DisplayItemData* data : aArray) {
2364
0
    PaintedLayer* t = data->mLayer ? data->mLayer->AsPaintedLayer() : nullptr;
2365
0
    if (t) {
2366
0
      PaintedDisplayItemLayerUserData* paintedData =
2367
0
        static_cast<PaintedDisplayItemLayerUserData*>(
2368
0
          t->GetUserData(&gPaintedDisplayItemLayerUserData));
2369
0
      if (paintedData && data->mGeometry) {
2370
0
        const int32_t appUnitsPerDevPixel = paintedData->mAppUnitsPerDevPixel;
2371
0
        nsRegion rgn = data->mGeometry->ComputeInvalidationRegion();
2372
0
        nsIntRegion pixelRgn = rgn.ToOutsidePixels(appUnitsPerDevPixel);
2373
0
2374
0
        if (data->mTransform) {
2375
0
          pixelRgn =
2376
0
            data->mTransform->TransformRegion(pixelRgn);
2377
0
        }
2378
0
2379
0
        pixelRgn =
2380
0
          pixelRgn.ScaleRoundOut(paintedData->mXScale, paintedData->mYScale);
2381
0
2382
0
        pixelRgn.MoveBy(-GetTranslationForPaintedLayer(t));
2383
0
2384
0
        paintedData->mRegionToInvalidate.Or(paintedData->mRegionToInvalidate,
2385
0
                                            pixelRgn);
2386
0
        paintedData->mRegionToInvalidate.SimplifyOutward(8);
2387
0
      }
2388
0
    }
2389
0
2390
0
    auto it = std::find(data->mParent->mDisplayItems.begin(),
2391
0
                        data->mParent->mDisplayItems.end(),
2392
0
                        data);
2393
0
    MOZ_ASSERT(it != data->mParent->mDisplayItems.end());
2394
0
    std::iter_swap(it, data->mParent->mDisplayItems.end() - 1);
2395
0
    data->mParent->mDisplayItems.pop_back();
2396
0
  }
2397
0
2398
0
  arrayCopy.Clear();
2399
0
  sDestroyedFrame = nullptr;
2400
0
}
2401
2402
void
2403
FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
2404
0
{
2405
0
  mRetainingManager = aManager;
2406
0
  LayerManagerData* data = static_cast<LayerManagerData*>(
2407
0
    aManager->GetUserData(&gLayerManagerUserData));
2408
0
  if (data) {
2409
0
    mInvalidateAllLayers = data->mInvalidateAllLayers;
2410
0
  } else {
2411
0
    data = new LayerManagerData(aManager);
2412
0
    aManager->SetUserData(&gLayerManagerUserData, data);
2413
0
  }
2414
0
}
2415
2416
void
2417
FrameLayerBuilder::DidEndTransaction()
2418
0
{
2419
0
  GetMaskLayerImageCache()->Sweep();
2420
0
}
2421
2422
void
2423
FrameLayerBuilder::WillEndTransaction()
2424
0
{
2425
0
  if (!mRetainingManager) {
2426
0
    return;
2427
0
  }
2428
0
2429
0
  // We need to save the data we'll need to support retaining.
2430
0
  LayerManagerData* data = static_cast<LayerManagerData*>(
2431
0
    mRetainingManager->GetUserData(&gLayerManagerUserData));
2432
0
  NS_ASSERTION(data, "Must have data!");
2433
0
2434
0
  // Update all the frames that used to have layers.
2435
0
  auto iter = data->mDisplayItems.begin();
2436
0
  while (iter != data->mDisplayItems.end()) {
2437
0
    DisplayItemData* did = iter->get();
2438
0
    if (!did->mUsed) {
2439
0
      // This item was visible, but isn't anymore.
2440
0
      PaintedLayer* t = did->mLayer->AsPaintedLayer();
2441
0
      if (t && did->mGeometry) {
2442
#ifdef MOZ_DUMP_PAINTING
2443
        if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2444
          printf_stderr("Invalidating unused display item (%i) belonging to "
2445
                        "frame %p from layer %p\n",
2446
                        did->mDisplayItemKey,
2447
                        did->mFrameList[0],
2448
                        t);
2449
        }
2450
#endif
2451
        InvalidatePreTransformRect(t,
2452
0
                                   did->mGeometry->ComputeInvalidationRegion(),
2453
0
                                   did->mClip,
2454
0
                                   GetLastPaintOffset(t),
2455
0
                                   did->mTransform);
2456
0
      }
2457
0
2458
0
      did->ClearAnimationCompositorState();
2459
0
2460
0
      // Remove this item. Swapping it with the last element first is
2461
0
      // quicker than erasing from the middle.
2462
0
      if (iter != data->mDisplayItems.end() - 1) {
2463
0
        std::iter_swap(iter, data->mDisplayItems.end() - 1);
2464
0
        data->mDisplayItems.pop_back();
2465
0
      } else {
2466
0
        data->mDisplayItems.pop_back();
2467
0
        break;
2468
0
      }
2469
0
2470
0
      // Don't increment iter because we still need to process the item which
2471
0
      // was moved.
2472
0
2473
0
    } else {
2474
0
      ComputeGeometryChangeForItem(did);
2475
0
      iter++;
2476
0
    }
2477
0
  }
2478
0
2479
0
  data->mInvalidateAllLayers = false;
2480
0
}
2481
2482
/* static */ DisplayItemData*
2483
FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem,
2484
                                                LayerManager* aManager)
2485
0
{
2486
0
  const SmallPointerArray<DisplayItemData>& array =
2487
0
    aItem->Frame()->DisplayItemData();
2488
0
  for (uint32_t i = 0; i < array.Length(); i++) {
2489
0
    DisplayItemData* item =
2490
0
      DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
2491
0
    if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
2492
0
        item->mLayer->Manager() == aManager) {
2493
0
      return item;
2494
0
    }
2495
0
  }
2496
0
  return nullptr;
2497
0
}
2498
2499
bool
2500
FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame,
2501
                                      uint32_t aDisplayItemKey)
2502
0
{
2503
0
  const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
2504
0
  for (uint32_t i = 0; i < array.Length(); i++) {
2505
0
    if (DisplayItemData::AssertDisplayItemData(array.ElementAt(i))
2506
0
          ->mDisplayItemKey == aDisplayItemKey) {
2507
0
      return true;
2508
0
    }
2509
0
  }
2510
0
  if (RefPtr<WebRenderUserData> data =
2511
0
        GetWebRenderUserData<WebRenderFallbackData>(aFrame, aDisplayItemKey)) {
2512
0
    return true;
2513
0
  }
2514
0
  return false;
2515
0
}
2516
2517
DisplayItemData*
2518
FrameLayerBuilder::GetOldLayerForFrame(
2519
  nsIFrame* aFrame,
2520
  uint32_t aDisplayItemKey,
2521
  DisplayItemData* aOldData, /* = nullptr */
2522
  LayerManager* aOldLayerManager /* = nullptr */)
2523
0
{
2524
0
  // If we need to build a new layer tree, then just refuse to recycle
2525
0
  // anything.
2526
0
  if (!mRetainingManager || mInvalidateAllLayers)
2527
0
    return nullptr;
2528
0
2529
0
  MOZ_ASSERT(!aOldData || aOldLayerManager,
2530
0
             "You must provide aOldLayerManager to check aOldData's validity.");
2531
0
  MOZ_ASSERT_IF(aOldData, aOldLayerManager == aOldData->mLayer->Manager());
2532
0
2533
0
  DisplayItemData* data = aOldData;
2534
0
  if (!data || aOldLayerManager != mRetainingManager) {
2535
0
    data = GetDisplayItemData(aFrame, aDisplayItemKey);
2536
0
  }
2537
0
2538
0
  MOZ_ASSERT(data == GetDisplayItemData(aFrame, aDisplayItemKey));
2539
0
2540
0
  return data;
2541
0
}
2542
2543
Layer*
2544
FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem,
2545
                                  nsDisplayItemGeometry** aOldGeometry,
2546
                                  DisplayItemClip** aOldClip)
2547
0
{
2548
0
  uint32_t key = aItem->GetPerFrameKey();
2549
0
  nsIFrame* frame = aItem->Frame();
2550
0
2551
0
  DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
2552
0
  if (oldData) {
2553
0
    if (aOldGeometry) {
2554
0
      *aOldGeometry = oldData->mGeometry.get();
2555
0
    }
2556
0
    if (aOldClip) {
2557
0
      *aOldClip = &oldData->mClip;
2558
0
    }
2559
0
    return oldData->mLayer;
2560
0
  }
2561
0
2562
0
  return nullptr;
2563
0
}
2564
2565
/* static */ DisplayItemData*
2566
FrameLayerBuilder::GetOldDataFor(nsDisplayItem* aItem)
2567
0
{
2568
0
  const SmallPointerArray<DisplayItemData>& array =
2569
0
    aItem->Frame()->DisplayItemData();
2570
0
2571
0
  for (uint32_t i = 0; i < array.Length(); i++) {
2572
0
    DisplayItemData* data =
2573
0
      DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
2574
0
2575
0
    if (data->mDisplayItemKey == aItem->GetPerFrameKey()) {
2576
0
      return data;
2577
0
    }
2578
0
  }
2579
0
  return nullptr;
2580
0
}
2581
2582
// Reset state that should not persist when a layer is recycled.
2583
static void
2584
ResetLayerStateForRecycling(Layer* aLayer)
2585
0
{
2586
0
  // Currently, this clears the mask layer and ancestor mask layers.
2587
0
  // Other cleanup may be added here.
2588
0
  aLayer->SetMaskLayer(nullptr);
2589
0
  aLayer->SetAncestorMaskLayers({});
2590
0
}
2591
2592
already_AddRefed<ColorLayer>
2593
ContainerState::CreateOrRecycleColorLayer(PaintedLayer* aPainted)
2594
0
{
2595
0
  PaintedDisplayItemLayerUserData* data =
2596
0
    static_cast<PaintedDisplayItemLayerUserData*>(
2597
0
      aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
2598
0
  RefPtr<ColorLayer> layer = data->mColorLayer;
2599
0
  if (layer) {
2600
0
    ResetLayerStateForRecycling(layer);
2601
0
    layer->ClearExtraDumpInfo();
2602
0
  } else {
2603
0
    // Create a new layer
2604
0
    layer = mManager->CreateColorLayer();
2605
0
    if (!layer)
2606
0
      return nullptr;
2607
0
    // Mark this layer as being used for painting display items
2608
0
    data->mColorLayer = layer;
2609
0
    layer->SetUserData(&gColorLayerUserData, nullptr);
2610
0
2611
0
    // Remove other layer types we might have stored for this PaintedLayer
2612
0
    data->mImageLayer = nullptr;
2613
0
  }
2614
0
  return layer.forget();
2615
0
}
2616
2617
already_AddRefed<ImageLayer>
2618
ContainerState::CreateOrRecycleImageLayer(PaintedLayer* aPainted)
2619
0
{
2620
0
  PaintedDisplayItemLayerUserData* data =
2621
0
    static_cast<PaintedDisplayItemLayerUserData*>(
2622
0
      aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
2623
0
  RefPtr<ImageLayer> layer = data->mImageLayer;
2624
0
  if (layer) {
2625
0
    ResetLayerStateForRecycling(layer);
2626
0
    layer->ClearExtraDumpInfo();
2627
0
  } else {
2628
0
    // Create a new layer
2629
0
    layer = mManager->CreateImageLayer();
2630
0
    if (!layer)
2631
0
      return nullptr;
2632
0
    // Mark this layer as being used for painting display items
2633
0
    data->mImageLayer = layer;
2634
0
    layer->SetUserData(&gImageLayerUserData, nullptr);
2635
0
2636
0
    // Remove other layer types we might have stored for this PaintedLayer
2637
0
    data->mColorLayer = nullptr;
2638
0
  }
2639
0
  return layer.forget();
2640
0
}
2641
2642
template<typename UserData>
2643
already_AddRefed<ImageLayer>
2644
ContainerState::CreateOrRecycleMaskImageLayerFor(
2645
  const MaskLayerKey& aKey,
2646
  UserData* (*aGetUserData)(Layer* aLayer),
2647
  void (*aSetDefaultUserData)(Layer* aLayer))
2648
0
{
2649
0
  RefPtr<ImageLayer> result = mRecycledMaskImageLayers.Get(aKey);
2650
0
2651
0
  if (result && aGetUserData(result.get())) {
2652
0
    mRecycledMaskImageLayers.Remove(aKey);
2653
0
    aKey.mLayer->ClearExtraDumpInfo();
2654
0
    // XXX if we use clip on mask layers, null it out here
2655
0
  } else {
2656
0
    // Create a new layer
2657
0
    result = mManager->CreateImageLayer();
2658
0
    if (!result) {
2659
0
      return nullptr;
2660
0
    }
2661
0
    aSetDefaultUserData(result);
2662
0
  }
2663
0
2664
0
  return result.forget();
2665
0
}
Unexecuted instantiation: already_AddRefed<mozilla::layers::ImageLayer> mozilla::ContainerState::CreateOrRecycleMaskImageLayerFor<mozilla::CSSMaskLayerUserData>(mozilla::ContainerState::MaskLayerKey const&, mozilla::CSSMaskLayerUserData* (*)(mozilla::layers::Layer*), void (*)(mozilla::layers::Layer*))
Unexecuted instantiation: already_AddRefed<mozilla::layers::ImageLayer> mozilla::ContainerState::CreateOrRecycleMaskImageLayerFor<mozilla::MaskLayerUserData>(mozilla::ContainerState::MaskLayerKey const&, mozilla::MaskLayerUserData* (*)(mozilla::layers::Layer*), void (*)(mozilla::layers::Layer*))
2666
2667
static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
2668
2669
/**
2670
 * This normally computes NSToIntRoundUp(aValue). However, if that would
2671
 * give a residual near 0.5 while aOldResidual is near -0.5, or
2672
 * it would give a residual near -0.5 while aOldResidual is near 0.5, then
2673
 * instead we return the integer in the other direction so that the residual
2674
 * is close to aOldResidual.
2675
 */
2676
static int32_t
2677
RoundToMatchResidual(double aValue, double aOldResidual)
2678
0
{
2679
0
  int32_t v = NSToIntRoundUp(aValue);
2680
0
  double residual = aValue - v;
2681
0
  if (aOldResidual < 0) {
2682
0
    if (residual > 0 &&
2683
0
        fabs(residual - 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
2684
0
      // Round up instead
2685
0
      return int32_t(ceil(aValue));
2686
0
    }
2687
0
  } else if (aOldResidual > 0) {
2688
0
    if (residual < 0 &&
2689
0
        fabs(residual + 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
2690
0
      // Round down instead
2691
0
      return int32_t(floor(aValue));
2692
0
    }
2693
0
  }
2694
0
  return v;
2695
0
}
2696
2697
static void
2698
ResetScrollPositionForLayerPixelAlignment(
2699
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
2700
0
{
2701
0
  nsIScrollableFrame* sf =
2702
0
    nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
2703
0
  if (sf) {
2704
0
    sf->ResetScrollPositionForLayerPixelAlignment();
2705
0
  }
2706
0
}
2707
2708
static void
2709
InvalidateEntirePaintedLayer(PaintedLayer* aLayer,
2710
                             AnimatedGeometryRoot* aAnimatedGeometryRoot,
2711
                             const char* aReason)
2712
0
{
2713
#ifdef MOZ_DUMP_PAINTING
2714
  if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2715
    printf_stderr("Invalidating entire layer %p: %s\n", aLayer, aReason);
2716
  }
2717
#endif
2718
  aLayer->InvalidateWholeLayer();
2719
0
  aLayer->SetInvalidRectToVisibleRegion();
2720
0
  ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot);
2721
0
}
2722
2723
LayerManager::PaintedLayerCreationHint
2724
ContainerState::GetLayerCreationHint(
2725
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
2726
0
{
2727
0
  // Check whether the layer will be scrollable. This is used as a hint to
2728
0
  // influence whether tiled layers are used or not.
2729
0
2730
0
  // Check creation hint inherited from our parent.
2731
0
  if (mParameters.mLayerCreationHint == LayerManager::SCROLLABLE) {
2732
0
    return LayerManager::SCROLLABLE;
2733
0
  }
2734
0
2735
0
  // Check whether there's any active scroll frame on the animated geometry
2736
0
  // root chain.
2737
0
  for (AnimatedGeometryRoot* agr = aAnimatedGeometryRoot;
2738
0
       agr && agr != mContainerAnimatedGeometryRoot;
2739
0
       agr = agr->mParentAGR) {
2740
0
    nsIFrame* fParent = nsLayoutUtils::GetCrossDocParentFrame(*agr);
2741
0
    if (!fParent) {
2742
0
      break;
2743
0
    }
2744
0
    nsIScrollableFrame* scrollable = do_QueryFrame(fParent);
2745
0
    if (scrollable) {
2746
0
      return LayerManager::SCROLLABLE;
2747
0
    }
2748
0
  }
2749
0
  return LayerManager::NONE;
2750
0
}
2751
2752
already_AddRefed<PaintedLayer>
2753
ContainerState::AttemptToRecyclePaintedLayer(
2754
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
2755
  nsDisplayItem* aItem,
2756
  const nsPoint& aTopLeft,
2757
  const nsIFrame* aReferenceFrame)
2758
0
{
2759
0
  Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem);
2760
0
  if (!oldLayer || !oldLayer->AsPaintedLayer()) {
2761
0
    return nullptr;
2762
0
  }
2763
0
2764
0
  if (!mPaintedLayersAvailableForRecycling.EnsureRemoved(
2765
0
        oldLayer->AsPaintedLayer())) {
2766
0
    // Not found.
2767
0
    return nullptr;
2768
0
  }
2769
0
2770
0
  // Try to recycle the layer.
2771
0
  RefPtr<PaintedLayer> layer = oldLayer->AsPaintedLayer();
2772
0
2773
0
  // Check if the layer hint has changed and whether or not the layer should
2774
0
  // be recreated because of it.
2775
0
  if (!layer->IsOptimizedFor(GetLayerCreationHint(aAnimatedGeometryRoot))) {
2776
0
    return nullptr;
2777
0
  }
2778
0
2779
0
  bool didResetScrollPositionForLayerPixelAlignment = false;
2780
0
  PaintedDisplayItemLayerUserData* data = RecyclePaintedLayer(
2781
0
    layer, aAnimatedGeometryRoot, didResetScrollPositionForLayerPixelAlignment);
2782
0
  PreparePaintedLayerForUse(layer,
2783
0
                            data,
2784
0
                            aAnimatedGeometryRoot,
2785
0
                            aReferenceFrame,
2786
0
                            aTopLeft,
2787
0
                            didResetScrollPositionForLayerPixelAlignment);
2788
0
2789
0
  return layer.forget();
2790
0
}
2791
2792
void
2793
ReleaseLayerUserData(void* aData)
2794
0
{
2795
0
  PaintedDisplayItemLayerUserData* userData =
2796
0
    static_cast<PaintedDisplayItemLayerUserData*>(aData);
2797
0
  userData->Release();
2798
0
}
2799
2800
already_AddRefed<PaintedLayer>
2801
ContainerState::CreatePaintedLayer(PaintedLayerData* aData)
2802
0
{
2803
0
  LayerManager::PaintedLayerCreationHint creationHint =
2804
0
    GetLayerCreationHint(aData->mAnimatedGeometryRoot);
2805
0
2806
0
  // Create a new painted layer
2807
0
  RefPtr<PaintedLayer> layer =
2808
0
    mManager->CreatePaintedLayerWithHint(creationHint);
2809
0
  if (!layer) {
2810
0
    return nullptr;
2811
0
  }
2812
0
2813
0
  // Mark this layer as being used for painting display items
2814
0
  RefPtr<PaintedDisplayItemLayerUserData> userData =
2815
0
    new PaintedDisplayItemLayerUserData();
2816
0
  userData->mDisabledAlpha =
2817
0
    mParameters.mDisableSubpixelAntialiasingInDescendants;
2818
0
  userData.get()->AddRef();
2819
0
  layer->SetUserData(
2820
0
    &gPaintedDisplayItemLayerUserData, userData, ReleaseLayerUserData);
2821
0
  ResetScrollPositionForLayerPixelAlignment(aData->mAnimatedGeometryRoot);
2822
0
2823
0
  PreparePaintedLayerForUse(layer,
2824
0
                            userData,
2825
0
                            aData->mAnimatedGeometryRoot,
2826
0
                            aData->mReferenceFrame,
2827
0
                            aData->mAnimatedGeometryRootOffset,
2828
0
                            true);
2829
0
2830
0
  return layer.forget();
2831
0
}
2832
2833
PaintedDisplayItemLayerUserData*
2834
ContainerState::RecyclePaintedLayer(
2835
  PaintedLayer* aLayer,
2836
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
2837
  bool& didResetScrollPositionForLayerPixelAlignment)
2838
0
{
2839
0
  // Clear clip rect and mask layer so we don't accidentally stay clipped.
2840
0
  // We will reapply any necessary clipping.
2841
0
  ResetLayerStateForRecycling(aLayer);
2842
0
  aLayer->ClearExtraDumpInfo();
2843
0
2844
0
  PaintedDisplayItemLayerUserData* data =
2845
0
    static_cast<PaintedDisplayItemLayerUserData*>(
2846
0
      aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2847
0
  NS_ASSERTION(data, "Recycled PaintedLayers must have user data");
2848
0
2849
0
  // This gets called on recycled PaintedLayers that are going to be in the
2850
0
  // final layer tree, so it's a convenient time to invalidate the
2851
0
  // content that changed where we don't know what PaintedLayer it belonged
2852
0
  // to, or if we need to invalidate the entire layer, we can do that.
2853
0
  // This needs to be done before we update the PaintedLayer to its new
2854
0
  // transform. See nsGfxScrollFrame::InvalidateInternal, where
2855
0
  // we ensure that mInvalidPaintedContent is updated according to the
2856
0
  // scroll position as of the most recent paint.
2857
0
  if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) ||
2858
0
      !FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) ||
2859
0
      data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) {
2860
#ifdef MOZ_DUMP_PAINTING
2861
    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2862
      printf_stderr("Recycled layer %p changed scale\n", aLayer);
2863
    }
2864
#endif
2865
    InvalidateEntirePaintedLayer(
2866
0
      aLayer, aAnimatedGeometryRoot, "recycled layer changed state");
2867
0
    didResetScrollPositionForLayerPixelAlignment = true;
2868
0
  }
2869
0
  if (!data->mRegionToInvalidate.IsEmpty()) {
2870
#ifdef MOZ_DUMP_PAINTING
2871
    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2872
      printf_stderr("Invalidating deleted frame content from layer %p\n",
2873
                    aLayer);
2874
    }
2875
#endif
2876
    aLayer->InvalidateRegion(data->mRegionToInvalidate);
2877
#ifdef MOZ_DUMP_PAINTING
2878
    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2879
      nsAutoCString str;
2880
      AppendToString(str, data->mRegionToInvalidate);
2881
      printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
2882
    }
2883
#endif
2884
    data->mRegionToInvalidate.SetEmpty();
2885
0
  }
2886
0
  return data;
2887
0
}
2888
2889
void
2890
ContainerState::PreparePaintedLayerForUse(
2891
  PaintedLayer* aLayer,
2892
  PaintedDisplayItemLayerUserData* aData,
2893
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
2894
  const nsIFrame* aReferenceFrame,
2895
  const nsPoint& aTopLeft,
2896
  bool didResetScrollPositionForLayerPixelAlignment)
2897
0
{
2898
0
  aData->mXScale = mParameters.mXScale;
2899
0
  aData->mYScale = mParameters.mYScale;
2900
0
  aData->mLastAnimatedGeometryRootOrigin = aData->mAnimatedGeometryRootOrigin;
2901
0
  aData->mAnimatedGeometryRootOrigin = aTopLeft;
2902
0
  aData->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
2903
0
  aLayer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation());
2904
0
2905
0
  aData->mLastPaintOffset = GetTranslationForPaintedLayer(aLayer);
2906
0
  aData->mHasExplicitLastPaintOffset = true;
2907
0
2908
0
  // Set up transform so that 0,0 in the PaintedLayer corresponds to the
2909
0
  // (pixel-snapped) top-left of the aAnimatedGeometryRoot.
2910
0
  nsPoint offset =
2911
0
    (*aAnimatedGeometryRoot)->GetOffsetToCrossDoc(aReferenceFrame);
2912
0
  nscoord appUnitsPerDevPixel =
2913
0
    (*aAnimatedGeometryRoot)->PresContext()->AppUnitsPerDevPixel();
2914
0
  gfxPoint scaledOffset(
2915
0
    NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel) *
2916
0
      mParameters.mXScale,
2917
0
    NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel) *
2918
0
      mParameters.mYScale);
2919
0
  // We call RoundToMatchResidual here so that the residual after rounding
2920
0
  // is close to aData->mAnimatedGeometryRootPosition if possible.
2921
0
  nsIntPoint pixOffset(
2922
0
    RoundToMatchResidual(scaledOffset.x,
2923
0
                         aData->mAnimatedGeometryRootPosition.x),
2924
0
    RoundToMatchResidual(scaledOffset.y,
2925
0
                         aData->mAnimatedGeometryRootPosition.y));
2926
0
  aData->mTranslation = pixOffset;
2927
0
  pixOffset += mParameters.mOffset;
2928
0
  Matrix matrix = Matrix::Translation(pixOffset.x, pixOffset.y);
2929
0
  aLayer->SetBaseTransform(Matrix4x4::From2D(matrix));
2930
0
2931
0
  aData->mVisibilityComputedRegion.SetEmpty();
2932
0
2933
0
  // Calculate exact position of the top-left of the active scrolled root.
2934
0
  // This might not be 0,0 due to the snapping in ScaleToNearestPixels.
2935
0
  gfxPoint animatedGeometryRootTopLeft =
2936
0
    scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset;
2937
0
  const bool disableAlpha =
2938
0
    mParameters.mDisableSubpixelAntialiasingInDescendants;
2939
0
  if (aData->mDisabledAlpha != disableAlpha) {
2940
0
    aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
2941
0
    InvalidateEntirePaintedLayer(
2942
0
      aLayer, aAnimatedGeometryRoot, "change of subpixel-AA");
2943
0
    aData->mDisabledAlpha = disableAlpha;
2944
0
    return;
2945
0
  }
2946
0
2947
0
    // FIXME: Temporary workaround for bug 681192 and bug 724786.
2948
0
#ifndef MOZ_WIDGET_ANDROID
2949
0
  // If it has changed, then we need to invalidate the entire layer since the
2950
0
  // pixels in the layer buffer have the content at a (subpixel) offset
2951
0
  // from what we need.
2952
0
  if (!animatedGeometryRootTopLeft.WithinEpsilonOf(
2953
0
        aData->mAnimatedGeometryRootPosition, SUBPIXEL_OFFSET_EPSILON)) {
2954
0
    aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
2955
0
    InvalidateEntirePaintedLayer(
2956
0
      aLayer, aAnimatedGeometryRoot, "subpixel offset");
2957
0
  } else if (didResetScrollPositionForLayerPixelAlignment) {
2958
0
    aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
2959
0
  }
2960
#else
2961
  Unused << didResetScrollPositionForLayerPixelAlignment;
2962
#endif
2963
}
2964
2965
#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
2966
/**
2967
 * Returns the appunits per dev pixel for the item's frame
2968
 */
2969
static int32_t
2970
AppUnitsPerDevPixel(nsDisplayItem* aItem)
2971
{
2972
  // The underlying frame for zoom items is the root frame of the subdocument.
2973
  // But zoom display items report their bounds etc using the parent document's
2974
  // APD because zoom items act as a conversion layer between the two different
2975
  // APDs.
2976
  if (aItem->GetType() == DisplayItemType::TYPE_ZOOM) {
2977
    return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
2978
  }
2979
  return aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
2980
}
2981
#endif
2982
2983
/**
2984
 * Set the visible region for aLayer.
2985
 * aOuterVisibleRegion is the visible region relative to the parent layer.
2986
 * aLayerContentsVisibleRect, if non-null, is a rectangle in the layer's
2987
 * own coordinate system to which the layer's visible region is restricted.
2988
 * Consumes *aOuterVisibleRegion.
2989
 */
2990
static void
2991
SetOuterVisibleRegion(Layer* aLayer,
2992
                      nsIntRegion* aOuterVisibleRegion,
2993
                      const nsIntRect* aLayerContentsVisibleRect = nullptr,
2994
                      bool aOuterUntransformed = false)
2995
0
{
2996
0
  Matrix4x4 transform = aLayer->GetTransform();
2997
0
  Matrix transform2D;
2998
0
  if (aOuterUntransformed) {
2999
0
    if (aLayerContentsVisibleRect) {
3000
0
      aOuterVisibleRegion->And(*aOuterVisibleRegion,
3001
0
                               *aLayerContentsVisibleRect);
3002
0
    }
3003
0
  } else if (transform.Is2D(&transform2D) &&
3004
0
             !transform2D.HasNonIntegerTranslation()) {
3005
0
    aOuterVisibleRegion->MoveBy(-int(transform2D._31), -int(transform2D._32));
3006
0
    if (aLayerContentsVisibleRect) {
3007
0
      aOuterVisibleRegion->And(*aOuterVisibleRegion,
3008
0
                               *aLayerContentsVisibleRect);
3009
0
    }
3010
0
  } else {
3011
0
    nsIntRect outerRect = aOuterVisibleRegion->GetBounds();
3012
0
    // if 'transform' is not invertible, then nothing will be displayed
3013
0
    // for the layer, so it doesn't really matter what we do here
3014
0
    Rect outerVisible(
3015
0
      outerRect.x, outerRect.y, outerRect.width, outerRect.height);
3016
0
    transform.Invert();
3017
0
3018
0
    Rect layerContentsVisible = Rect::MaxIntRect();
3019
0
3020
0
    if (aLayerContentsVisibleRect) {
3021
0
      NS_ASSERTION(aLayerContentsVisibleRect->width >= 0 &&
3022
0
                     aLayerContentsVisibleRect->height >= 0,
3023
0
                   "Bad layer contents rectangle");
3024
0
      // restrict to aLayerContentsVisibleRect before call GfxRectToIntRect,
3025
0
      // in case layerVisible is extremely large (as it can be when
3026
0
      // projecting through the inverse of a 3D transform)
3027
0
      layerContentsVisible = Rect(aLayerContentsVisibleRect->x,
3028
0
                                  aLayerContentsVisibleRect->y,
3029
0
                                  aLayerContentsVisibleRect->width,
3030
0
                                  aLayerContentsVisibleRect->height);
3031
0
    }
3032
0
3033
0
    Rect layerVisible =
3034
0
      transform.ProjectRectBounds(outerVisible, layerContentsVisible);
3035
0
3036
0
    layerVisible.RoundOut();
3037
0
3038
0
    IntRect intRect;
3039
0
    if (!layerVisible.ToIntRect(&intRect)) {
3040
0
      intRect = IntRect::MaxIntRect();
3041
0
    }
3042
0
3043
0
    *aOuterVisibleRegion = intRect;
3044
0
  }
3045
0
3046
0
  aLayer->SetVisibleRegion(
3047
0
    LayerIntRegion::FromUnknownRegion(*aOuterVisibleRegion));
3048
0
}
3049
3050
void
3051
ContainerState::SetOuterVisibleRegionForLayer(
3052
  Layer* aLayer,
3053
  const nsIntRegion& aOuterVisibleRegion,
3054
  const nsIntRect* aLayerContentsVisibleRect,
3055
  bool aOuterUntransformed) const
3056
0
{
3057
0
  nsIntRegion visRegion = aOuterVisibleRegion;
3058
0
  if (!aOuterUntransformed) {
3059
0
    visRegion.MoveBy(mParameters.mOffset);
3060
0
  }
3061
0
  SetOuterVisibleRegion(
3062
0
    aLayer, &visRegion, aLayerContentsVisibleRect, aOuterUntransformed);
3063
0
}
3064
3065
nscolor
3066
ContainerState::FindOpaqueBackgroundColorInLayer(
3067
  const PaintedLayerData* aData,
3068
  const nsIntRect& aRect,
3069
  bool* aOutIntersectsLayer) const
3070
0
{
3071
0
  *aOutIntersectsLayer = true;
3072
0
3073
0
  // Scan the candidate's display items.
3074
0
  nsIntRect deviceRect = aRect;
3075
0
  nsRect appUnitRect = ToAppUnits(deviceRect, mAppUnitsPerDevPixel);
3076
0
  appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
3077
0
3078
0
  for (auto& assignedItem : Reversed(aData->mAssignedDisplayItems)) {
3079
0
    if (assignedItem.mHasOpacity || assignedItem.mHasTransform) {
3080
0
      // We cannot easily calculate the opaque background color for items inside
3081
0
      // a flattened effect.
3082
0
      continue;
3083
0
    }
3084
0
3085
0
    if (IsEffectEndMarker(assignedItem.mType)) {
3086
0
      // An optimization: the underlying display item for effect markers is the
3087
0
      // same for both start and end markers. Skip the effect end markers.
3088
0
      continue;
3089
0
    }
3090
0
3091
0
    nsDisplayItem* item = assignedItem.mItem;
3092
0
    bool snap;
3093
0
    nsRect bounds = item->GetBounds(mBuilder, &snap);
3094
0
    if (snap && mSnappingEnabled) {
3095
0
      nsIntRect snappedBounds = ScaleToNearestPixels(bounds);
3096
0
      if (!snappedBounds.Intersects(deviceRect))
3097
0
        continue;
3098
0
3099
0
      if (!snappedBounds.Contains(deviceRect))
3100
0
        return NS_RGBA(0, 0, 0, 0);
3101
0
3102
0
    } else {
3103
0
      // The layer's visible rect is already (close enough to) pixel
3104
0
      // aligned, so no need to round out and in here.
3105
0
      if (!bounds.Intersects(appUnitRect))
3106
0
        continue;
3107
0
3108
0
      if (!bounds.Contains(appUnitRect))
3109
0
        return NS_RGBA(0, 0, 0, 0);
3110
0
    }
3111
0
3112
0
    if (item->IsInvisibleInRect(appUnitRect)) {
3113
0
      continue;
3114
0
    }
3115
0
3116
0
    if (item->GetClip().IsRectAffectedByClip(deviceRect,
3117
0
                                             mParameters.mXScale,
3118
0
                                             mParameters.mYScale,
3119
0
                                             mAppUnitsPerDevPixel)) {
3120
0
      return NS_RGBA(0, 0, 0, 0);
3121
0
    }
3122
0
3123
0
    MOZ_ASSERT(!assignedItem.mHasOpacity && !assignedItem.mHasTransform);
3124
0
    Maybe<nscolor> color = item->IsUniform(mBuilder);
3125
0
3126
0
    if (color && NS_GET_A(*color) == 255) {
3127
0
      return *color;
3128
0
    }
3129
0
3130
0
    return NS_RGBA(0, 0, 0, 0);
3131
0
  }
3132
0
3133
0
  *aOutIntersectsLayer = false;
3134
0
  return NS_RGBA(0, 0, 0, 0);
3135
0
}
3136
3137
nscolor
3138
PaintedLayerDataNode::FindOpaqueBackgroundColor(
3139
  const nsIntRegion& aTargetVisibleRegion,
3140
  int32_t aUnderIndex) const
3141
0
{
3142
0
  if (aUnderIndex == ABOVE_TOP) {
3143
0
    aUnderIndex = mPaintedLayerDataStack.Length();
3144
0
  }
3145
0
  for (int32_t i = aUnderIndex - 1; i >= 0; --i) {
3146
0
    const PaintedLayerData* candidate = &mPaintedLayerDataStack[i];
3147
0
    if (candidate->VisibleAboveRegionIntersects(aTargetVisibleRegion)) {
3148
0
      // Some non-PaintedLayer content between target and candidate; this is
3149
0
      // hopeless
3150
0
      return NS_RGBA(0, 0, 0, 0);
3151
0
    }
3152
0
3153
0
    if (!candidate->VisibleRegionIntersects(aTargetVisibleRegion)) {
3154
0
      // The layer doesn't intersect our target, ignore it and move on
3155
0
      continue;
3156
0
    }
3157
0
3158
0
    bool intersectsLayer = true;
3159
0
    nsIntRect rect = aTargetVisibleRegion.GetBounds();
3160
0
    nscolor color = mTree.ContState().FindOpaqueBackgroundColorInLayer(
3161
0
      candidate, rect, &intersectsLayer);
3162
0
    if (!intersectsLayer) {
3163
0
      continue;
3164
0
    }
3165
0
    return color;
3166
0
  }
3167
0
  if (mAllDrawingAboveBackground ||
3168
0
      !mVisibleAboveBackgroundRegion.Intersect(aTargetVisibleRegion)
3169
0
         .IsEmpty()) {
3170
0
    // Some non-PaintedLayer content is between this node's background and
3171
0
    // target.
3172
0
    return NS_RGBA(0, 0, 0, 0);
3173
0
  }
3174
0
  return FindOpaqueBackgroundColorInParentNode();
3175
0
}
3176
3177
nscolor
3178
PaintedLayerDataNode::FindOpaqueBackgroundColorCoveringEverything() const
3179
0
{
3180
0
  if (!mPaintedLayerDataStack.IsEmpty() || mAllDrawingAboveBackground ||
3181
0
      !mVisibleAboveBackgroundRegion.IsEmpty()) {
3182
0
    return NS_RGBA(0, 0, 0, 0);
3183
0
  }
3184
0
  return FindOpaqueBackgroundColorInParentNode();
3185
0
}
3186
3187
nscolor
3188
PaintedLayerDataNode::FindOpaqueBackgroundColorInParentNode() const
3189
0
{
3190
0
  if (mParent) {
3191
0
    if (mHasClip) {
3192
0
      // Check whether our parent node has uniform content behind our whole
3193
0
      // clip.
3194
0
      // There's one tricky case here: If our parent node is also a scrollable,
3195
0
      // and is currently scrolled in such a way that this inner one is
3196
0
      // clipped by it, then it's not really clear how we should determine
3197
0
      // whether we have a uniform background in the parent: There might be
3198
0
      // non-uniform content in the parts that our scroll port covers in the
3199
0
      // parent and that are currently outside the parent's clip.
3200
0
      // For now, we'll fail to pull a background color in that case.
3201
0
      return mParent->FindOpaqueBackgroundColor(mClipRect);
3202
0
    }
3203
0
    return mParent->FindOpaqueBackgroundColorCoveringEverything();
3204
0
  }
3205
0
  // We are the root.
3206
0
  return mTree.UniformBackgroundColor();
3207
0
}
3208
3209
bool
3210
PaintedLayerData::CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
3211
0
{
3212
0
  if (!mImage) {
3213
0
    return false;
3214
0
  }
3215
0
3216
0
  return mImage->CanOptimizeToImageLayer(mLayer->Manager(), aBuilder);
3217
0
}
3218
3219
already_AddRefed<ImageContainer>
3220
PaintedLayerData::GetContainerForImageLayer(nsDisplayListBuilder* aBuilder)
3221
0
{
3222
0
  if (!mImage) {
3223
0
    return nullptr;
3224
0
  }
3225
0
3226
0
  return mImage->GetContainer(mLayer->Manager(), aBuilder);
3227
0
}
3228
3229
PaintedLayerDataNode::PaintedLayerDataNode(
3230
  PaintedLayerDataTree& aTree,
3231
  PaintedLayerDataNode* aParent,
3232
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
3233
  : mTree(aTree)
3234
  , mParent(aParent)
3235
  , mAnimatedGeometryRoot(aAnimatedGeometryRoot)
3236
  , mAllDrawingAboveBackground(false)
3237
0
{
3238
0
  MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(
3239
0
    mTree.Builder()->RootReferenceFrame(), *mAnimatedGeometryRoot));
3240
0
  mHasClip = mTree.IsClippedWithRespectToParentAnimatedGeometryRoot(
3241
0
    mAnimatedGeometryRoot, &mClipRect);
3242
0
}
3243
3244
PaintedLayerDataNode::~PaintedLayerDataNode()
3245
0
{
3246
0
  MOZ_ASSERT(mPaintedLayerDataStack.IsEmpty());
3247
0
  MOZ_ASSERT(mChildren.IsEmpty());
3248
0
}
3249
3250
PaintedLayerDataNode*
3251
PaintedLayerDataNode::AddChildNodeFor(
3252
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
3253
0
{
3254
0
  MOZ_ASSERT(aAnimatedGeometryRoot->mParentAGR == mAnimatedGeometryRoot);
3255
0
  UniquePtr<PaintedLayerDataNode> child =
3256
0
    MakeUnique<PaintedLayerDataNode>(mTree, this, aAnimatedGeometryRoot);
3257
0
  mChildren.AppendElement(std::move(child));
3258
0
  return mChildren.LastElement().get();
3259
0
}
3260
3261
template<typename NewPaintedLayerCallbackType>
3262
PaintedLayerData*
3263
PaintedLayerDataNode::FindPaintedLayerFor(
3264
  const nsIntRect& aVisibleRect,
3265
  const bool aBackfaceHidden,
3266
  const ActiveScrolledRoot* aASR,
3267
  const DisplayItemClipChain* aClipChain,
3268
  NewPaintedLayerCallbackType aNewPaintedLayerCallback)
3269
0
{
3270
0
  if (!mPaintedLayerDataStack.IsEmpty()) {
3271
0
    PaintedLayerData* lowestUsableLayer = nullptr;
3272
0
    for (auto& data : Reversed(mPaintedLayerDataStack)) {
3273
0
      if (data.mVisibleAboveRegion.Intersects(aVisibleRect)) {
3274
0
        break;
3275
0
      }
3276
0
      if (data.mBackfaceHidden == aBackfaceHidden && data.mASR == aASR &&
3277
0
          data.mClipChain == aClipChain) {
3278
0
        lowestUsableLayer = &data;
3279
0
      }
3280
0
      // Also check whether the event-regions intersect the visible rect,
3281
0
      // unless we're in an inactive layer, in which case the event-regions
3282
0
      // will be hoisted out into their own layer.
3283
0
      // For performance reasons, we check the intersection with the bounds
3284
0
      // of the event-regions.
3285
0
      if (!mTree.ContState().IsInInactiveLayer() &&
3286
0
          (data.mScaledHitRegionBounds.Intersects(aVisibleRect) ||
3287
0
           data.mScaledMaybeHitRegionBounds.Intersects(aVisibleRect))) {
3288
0
        break;
3289
0
      }
3290
0
      // If the visible region intersects with the current layer then we
3291
0
      // can't possibly use any of the layers below it, so stop the search
3292
0
      // now.
3293
0
      //
3294
0
      // If we're trying to minimize painted layer size and we don't
3295
0
      // intersect the current visible region, then make sure we don't
3296
0
      // use this painted layer.
3297
0
      if (data.mVisibleRegion.Intersects(aVisibleRect)) {
3298
0
        break;
3299
0
      }
3300
0
3301
0
      if (gfxPrefs::LayoutSmallerPaintedLayers()) {
3302
0
        lowestUsableLayer = nullptr;
3303
0
      }
3304
0
    }
3305
0
    if (lowestUsableLayer) {
3306
0
      return lowestUsableLayer;
3307
0
    }
3308
0
  }
3309
0
  PaintedLayerData* data = mPaintedLayerDataStack.AppendElement();
3310
0
  aNewPaintedLayerCallback(data);
3311
0
3312
0
  return data;
3313
0
}
3314
3315
void
3316
PaintedLayerDataNode::FinishChildrenIntersecting(const nsIntRect& aRect)
3317
0
{
3318
0
  for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
3319
0
    if (mChildren[i]->Intersects(aRect)) {
3320
0
      mChildren[i]->Finish(true);
3321
0
      mChildren.RemoveElementAt(i);
3322
0
    }
3323
0
  }
3324
0
}
3325
3326
void
3327
PaintedLayerDataNode::FinishAllChildren(
3328
  bool aThisNodeNeedsAccurateVisibleAboveRegion)
3329
0
{
3330
0
  for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
3331
0
    mChildren[i]->Finish(aThisNodeNeedsAccurateVisibleAboveRegion);
3332
0
  }
3333
0
  mChildren.Clear();
3334
0
}
3335
3336
void
3337
PaintedLayerDataNode::Finish(bool aParentNeedsAccurateVisibleAboveRegion)
3338
0
{
3339
0
  // Skip "visible above region" maintenance, because this node is going away.
3340
0
  FinishAllChildren(false);
3341
0
3342
0
  PopAllPaintedLayerData();
3343
0
3344
0
  if (mParent && aParentNeedsAccurateVisibleAboveRegion) {
3345
0
    if (mHasClip) {
3346
0
      mParent->AddToVisibleAboveRegion(mClipRect);
3347
0
    } else {
3348
0
      mParent->SetAllDrawingAbove();
3349
0
    }
3350
0
  }
3351
0
  mTree.NodeWasFinished(mAnimatedGeometryRoot);
3352
0
}
3353
3354
void
3355
PaintedLayerDataNode::AddToVisibleAboveRegion(const nsIntRect& aRect)
3356
0
{
3357
0
  nsIntRegion& visibleAboveRegion =
3358
0
    mPaintedLayerDataStack.IsEmpty()
3359
0
      ? mVisibleAboveBackgroundRegion
3360
0
      : mPaintedLayerDataStack.LastElement().mVisibleAboveRegion;
3361
0
  visibleAboveRegion.Or(visibleAboveRegion, aRect);
3362
0
  visibleAboveRegion.SimplifyOutward(8);
3363
0
}
3364
3365
void
3366
PaintedLayerDataNode::SetAllDrawingAbove()
3367
0
{
3368
0
  PopAllPaintedLayerData();
3369
0
  mAllDrawingAboveBackground = true;
3370
0
  mVisibleAboveBackgroundRegion.SetEmpty();
3371
0
}
3372
3373
void
3374
PaintedLayerDataNode::PopAllPaintedLayerData()
3375
0
{
3376
0
  for (int32_t index = mPaintedLayerDataStack.Length() - 1; index >= 0;
3377
0
       index--) {
3378
0
    PaintedLayerData& data = mPaintedLayerDataStack[index];
3379
0
    mTree.ContState().FinishPaintedLayerData(data, [this, &data, index]() {
3380
0
      return this->FindOpaqueBackgroundColor(data.mVisibleRegion, index);
3381
0
    });
3382
0
  }
3383
0
  mPaintedLayerDataStack.Clear();
3384
0
}
3385
3386
void
3387
PaintedLayerDataTree::InitializeForInactiveLayer(
3388
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
3389
0
{
3390
0
  mForInactiveLayer = true;
3391
0
  mRoot.emplace(*this, nullptr, aAnimatedGeometryRoot);
3392
0
}
3393
3394
nsDisplayListBuilder*
3395
PaintedLayerDataTree::Builder() const
3396
0
{
3397
0
  return mContainerState.Builder();
3398
0
}
3399
3400
void
3401
PaintedLayerDataTree::Finish()
3402
0
{
3403
0
  if (mRoot) {
3404
0
    mRoot->Finish(false);
3405
0
  }
3406
0
  MOZ_ASSERT(mNodes.Count() == 0);
3407
0
  mRoot.reset();
3408
0
}
3409
3410
void
3411
PaintedLayerDataTree::NodeWasFinished(
3412
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
3413
0
{
3414
0
  mNodes.Remove(aAnimatedGeometryRoot);
3415
0
}
3416
3417
void
3418
PaintedLayerDataTree::AddingOwnLayer(
3419
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
3420
  const nsIntRect* aRect,
3421
  nscolor* aOutUniformBackgroundColor)
3422
0
{
3423
0
  PaintedLayerDataNode* node = nullptr;
3424
0
  if (mForInactiveLayer) {
3425
0
    node = mRoot.ptr();
3426
0
  } else {
3427
0
    FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, aRect);
3428
0
    node = EnsureNodeFor(aAnimatedGeometryRoot);
3429
0
  }
3430
0
  if (aRect) {
3431
0
    if (aOutUniformBackgroundColor) {
3432
0
      *aOutUniformBackgroundColor = node->FindOpaqueBackgroundColor(*aRect);
3433
0
    }
3434
0
    node->AddToVisibleAboveRegion(*aRect);
3435
0
  } else {
3436
0
    if (aOutUniformBackgroundColor) {
3437
0
      *aOutUniformBackgroundColor =
3438
0
        node->FindOpaqueBackgroundColorCoveringEverything();
3439
0
    }
3440
0
    node->SetAllDrawingAbove();
3441
0
  }
3442
0
}
3443
3444
template<typename NewPaintedLayerCallbackType>
3445
PaintedLayerData*
3446
PaintedLayerDataTree::FindPaintedLayerFor(
3447
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
3448
  const ActiveScrolledRoot* aASR,
3449
  const DisplayItemClipChain* aClipChain,
3450
  const nsIntRect& aVisibleRect,
3451
  const bool aBackfaceHidden,
3452
  NewPaintedLayerCallbackType aNewPaintedLayerCallback)
3453
0
{
3454
0
  const nsIntRect* bounds = &aVisibleRect;
3455
0
  PaintedLayerDataNode* node = nullptr;
3456
0
  if (mForInactiveLayer) {
3457
0
    node = mRoot.ptr();
3458
0
  } else {
3459
0
    FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, bounds);
3460
0
    node = EnsureNodeFor(aAnimatedGeometryRoot);
3461
0
  }
3462
0
3463
0
  PaintedLayerData* data = node->FindPaintedLayerFor(
3464
0
    aVisibleRect, aBackfaceHidden, aASR, aClipChain, aNewPaintedLayerCallback);
3465
0
  return data;
3466
0
}
3467
3468
void
3469
PaintedLayerDataTree::FinishPotentiallyIntersectingNodes(
3470
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
3471
  const nsIntRect* aRect)
3472
0
{
3473
0
  AnimatedGeometryRoot* ancestorThatIsChildOfCommonAncestor = nullptr;
3474
0
  PaintedLayerDataNode* ancestorNode = FindNodeForAncestorAnimatedGeometryRoot(
3475
0
    aAnimatedGeometryRoot, &ancestorThatIsChildOfCommonAncestor);
3476
0
  if (!ancestorNode) {
3477
0
    // None of our ancestors are in the tree. This should only happen if this
3478
0
    // is the very first item we're looking at.
3479
0
    MOZ_ASSERT(!mRoot);
3480
0
    return;
3481
0
  }
3482
0
3483
0
  if (ancestorNode->GetAnimatedGeometryRoot() == aAnimatedGeometryRoot) {
3484
0
    // aAnimatedGeometryRoot already has a node in the tree.
3485
0
    // This is the common case.
3486
0
    MOZ_ASSERT(!ancestorThatIsChildOfCommonAncestor);
3487
0
    if (aRect) {
3488
0
      ancestorNode->FinishChildrenIntersecting(*aRect);
3489
0
    } else {
3490
0
      ancestorNode->FinishAllChildren();
3491
0
    }
3492
0
    return;
3493
0
  }
3494
0
3495
0
  // We have found an existing ancestor, but it's a proper ancestor of our
3496
0
  // animated geometry root.
3497
0
  // ancestorThatIsChildOfCommonAncestor is the last animated geometry root
3498
0
  // encountered on the way up from aAnimatedGeometryRoot to ancestorNode.
3499
0
  MOZ_ASSERT(ancestorThatIsChildOfCommonAncestor);
3500
0
  MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(
3501
0
    *ancestorThatIsChildOfCommonAncestor, *aAnimatedGeometryRoot));
3502
0
  MOZ_ASSERT(ancestorThatIsChildOfCommonAncestor->mParentAGR ==
3503
0
             ancestorNode->GetAnimatedGeometryRoot());
3504
0
3505
0
  // ancestorThatIsChildOfCommonAncestor is not in the tree yet!
3506
0
  MOZ_ASSERT(!mNodes.Get(ancestorThatIsChildOfCommonAncestor));
3507
0
3508
0
  // We're about to add a node for ancestorThatIsChildOfCommonAncestor, so we
3509
0
  // finish all intersecting siblings.
3510
0
  nsIntRect clip;
3511
0
  if (IsClippedWithRespectToParentAnimatedGeometryRoot(
3512
0
        ancestorThatIsChildOfCommonAncestor, &clip)) {
3513
0
    ancestorNode->FinishChildrenIntersecting(clip);
3514
0
  } else {
3515
0
    ancestorNode->FinishAllChildren();
3516
0
  }
3517
0
}
3518
3519
PaintedLayerDataNode*
3520
PaintedLayerDataTree::EnsureNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot)
3521
0
{
3522
0
  MOZ_ASSERT(aAnimatedGeometryRoot);
3523
0
  PaintedLayerDataNode* node = mNodes.Get(aAnimatedGeometryRoot);
3524
0
  if (node) {
3525
0
    return node;
3526
0
  }
3527
0
3528
0
  AnimatedGeometryRoot* parentAnimatedGeometryRoot =
3529
0
    aAnimatedGeometryRoot->mParentAGR;
3530
0
  if (!parentAnimatedGeometryRoot) {
3531
0
    MOZ_ASSERT(!mRoot);
3532
0
    MOZ_ASSERT(*aAnimatedGeometryRoot == Builder()->RootReferenceFrame());
3533
0
    mRoot.emplace(*this, nullptr, aAnimatedGeometryRoot);
3534
0
    node = mRoot.ptr();
3535
0
  } else {
3536
0
    PaintedLayerDataNode* parentNode =
3537
0
      EnsureNodeFor(parentAnimatedGeometryRoot);
3538
0
    MOZ_ASSERT(parentNode);
3539
0
    node = parentNode->AddChildNodeFor(aAnimatedGeometryRoot);
3540
0
  }
3541
0
  MOZ_ASSERT(node);
3542
0
  mNodes.Put(aAnimatedGeometryRoot, node);
3543
0
  return node;
3544
0
}
3545
3546
bool
3547
PaintedLayerDataTree::IsClippedWithRespectToParentAnimatedGeometryRoot(
3548
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
3549
  nsIntRect* aOutClip)
3550
0
{
3551
0
  if (mForInactiveLayer) {
3552
0
    return false;
3553
0
  }
3554
0
  nsIScrollableFrame* scrollableFrame =
3555
0
    nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
3556
0
  if (!scrollableFrame) {
3557
0
    return false;
3558
0
  }
3559
0
  nsIFrame* scrollFrame = do_QueryFrame(scrollableFrame);
3560
0
  nsRect scrollPort = scrollableFrame->GetScrollPortRect() +
3561
0
                      Builder()->ToReferenceFrame(scrollFrame);
3562
0
  *aOutClip = mContainerState.ScaleToNearestPixels(scrollPort);
3563
0
  return true;
3564
0
}
3565
3566
PaintedLayerDataNode*
3567
PaintedLayerDataTree::FindNodeForAncestorAnimatedGeometryRoot(
3568
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
3569
  AnimatedGeometryRoot** aOutAncestorChild)
3570
0
{
3571
0
  if (!aAnimatedGeometryRoot) {
3572
0
    return nullptr;
3573
0
  }
3574
0
  PaintedLayerDataNode* node = mNodes.Get(aAnimatedGeometryRoot);
3575
0
  if (node) {
3576
0
    return node;
3577
0
  }
3578
0
  *aOutAncestorChild = aAnimatedGeometryRoot;
3579
0
  return FindNodeForAncestorAnimatedGeometryRoot(
3580
0
    aAnimatedGeometryRoot->mParentAGR, aOutAncestorChild);
3581
0
}
3582
3583
static bool
3584
CanOptimizeAwayPaintedLayer(PaintedLayerData* aData,
3585
                            FrameLayerBuilder* aLayerBuilder)
3586
0
{
3587
0
  if (!aLayerBuilder->IsBuildingRetainedLayers()) {
3588
0
    return false;
3589
0
  }
3590
0
3591
0
  // If there's no painted layer with valid content in it that we can reuse,
3592
0
  // always create a color or image layer (and potentially throw away an
3593
0
  // existing completely invalid painted layer).
3594
0
  if (aData->mLayer->GetValidRegion().IsEmpty()) {
3595
0
    return true;
3596
0
  }
3597
0
3598
0
  // There is an existing painted layer we can reuse. Throwing it away can make
3599
0
  // compositing cheaper (see bug 946952), but it might cause us to re-allocate
3600
0
  // the painted layer frequently due to an animation. So we only discard it if
3601
0
  // we're in tree compression mode, which is triggered at a low frequency.
3602
0
  return aLayerBuilder->CheckInLayerTreeCompressionMode();
3603
0
}
3604
3605
#ifdef DEBUG
3606
static int32_t
3607
FindIndexOfLayerIn(nsTArray<NewLayerEntry>& aArray, Layer* aLayer)
3608
{
3609
  for (uint32_t i = 0; i < aArray.Length(); ++i) {
3610
    if (aArray[i].mLayer == aLayer) {
3611
      return i;
3612
    }
3613
  }
3614
  return -1;
3615
}
3616
#endif
3617
3618
already_AddRefed<Layer>
3619
ContainerState::PrepareImageLayer(PaintedLayerData* aData)
3620
0
{
3621
0
  RefPtr<ImageContainer> imageContainer =
3622
0
    aData->GetContainerForImageLayer(mBuilder);
3623
0
  if (!imageContainer) {
3624
0
    return nullptr;
3625
0
  }
3626
0
3627
0
  RefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(aData->mLayer);
3628
0
  imageLayer->SetContainer(imageContainer);
3629
0
  aData->mImage->ConfigureLayer(imageLayer, mParameters);
3630
0
  imageLayer->SetPostScale(mParameters.mXScale, mParameters.mYScale);
3631
0
3632
0
  if (aData->mItemClip->HasClip()) {
3633
0
    ParentLayerIntRect clip = ViewAs<ParentLayerPixel>(
3634
0
      ScaleToNearestPixels(aData->mItemClip->GetClipRect()));
3635
0
    clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
3636
0
    imageLayer->SetClipRect(Some(clip));
3637
0
  } else {
3638
0
    imageLayer->SetClipRect(Nothing());
3639
0
  }
3640
0
3641
0
  FLB_LOG_PAINTED_LAYER_DECISION(
3642
0
    aData, "  Selected image layer=%p\n", imageLayer.get());
3643
0
3644
0
  return imageLayer.forget();
3645
0
}
3646
3647
already_AddRefed<Layer>
3648
ContainerState::PrepareColorLayer(PaintedLayerData* aData)
3649
0
{
3650
0
  RefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(aData->mLayer);
3651
0
  colorLayer->SetColor(Color::FromABGR(aData->mSolidColor));
3652
0
3653
0
  // Copy transform
3654
0
  colorLayer->SetBaseTransform(aData->mLayer->GetBaseTransform());
3655
0
  colorLayer->SetPostScale(aData->mLayer->GetPostXScale(),
3656
0
                           aData->mLayer->GetPostYScale());
3657
0
3658
0
  nsIntRect visibleRect = aData->mVisibleRegion.GetBounds();
3659
0
  visibleRect.MoveBy(-GetTranslationForPaintedLayer(aData->mLayer));
3660
0
  colorLayer->SetBounds(visibleRect);
3661
0
  colorLayer->SetClipRect(Nothing());
3662
0
3663
0
  FLB_LOG_PAINTED_LAYER_DECISION(
3664
0
    aData, "  Selected color layer=%p\n", colorLayer.get());
3665
0
3666
0
  return colorLayer.forget();
3667
0
}
3668
3669
static void
3670
SetBackfaceHiddenForLayer(bool aBackfaceHidden, Layer* aLayer)
3671
0
{
3672
0
  if (aBackfaceHidden) {
3673
0
    aLayer->SetContentFlags(aLayer->GetContentFlags() |
3674
0
                            Layer::CONTENT_BACKFACE_HIDDEN);
3675
0
  } else {
3676
0
    aLayer->SetContentFlags(aLayer->GetContentFlags() &
3677
0
                            ~Layer::CONTENT_BACKFACE_HIDDEN);
3678
0
  }
3679
0
}
3680
3681
template<typename FindOpaqueBackgroundColorCallbackType>
3682
void
3683
ContainerState::FinishPaintedLayerData(
3684
  PaintedLayerData& aData,
3685
  FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor)
3686
0
{
3687
0
  PaintedLayerData* data = &aData;
3688
0
3689
0
  if (!data->mLayer) {
3690
0
    // No layer was recycled, so we create a new one.
3691
0
    RefPtr<PaintedLayer> paintedLayer = CreatePaintedLayer(data);
3692
0
    data->mLayer = paintedLayer;
3693
0
3694
0
    NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, paintedLayer) < 0,
3695
0
                 "Layer already in list???");
3696
0
    mNewChildLayers[data->mNewChildLayersIndex].mLayer = paintedLayer.forget();
3697
0
  }
3698
0
3699
0
  PaintedDisplayItemLayerUserData* userData =
3700
0
    GetPaintedDisplayItemLayerUserData(data->mLayer);
3701
0
  NS_ASSERTION(userData, "where did our user data go?");
3702
0
  userData->mLastItemCount = data->mAssignedDisplayItems.size();
3703
0
3704
0
  NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex];
3705
0
3706
0
  RefPtr<Layer> layer;
3707
0
  bool canOptimizeToImageLayer = data->CanOptimizeToImageLayer(mBuilder);
3708
0
3709
0
  FLB_LOG_PAINTED_LAYER_DECISION(data, "Selecting layer for pld=%p\n", data);
3710
0
  FLB_LOG_PAINTED_LAYER_DECISION(
3711
0
    data,
3712
0
    "  Solid=%i, hasImage=%c, canOptimizeAwayPaintedLayer=%i\n",
3713
0
    data->mIsSolidColorInVisibleRegion,
3714
0
    canOptimizeToImageLayer ? 'y' : 'n',
3715
0
    CanOptimizeAwayPaintedLayer(data, mLayerBuilder));
3716
0
3717
0
  if ((data->mIsSolidColorInVisibleRegion || canOptimizeToImageLayer) &&
3718
0
      CanOptimizeAwayPaintedLayer(data, mLayerBuilder)) {
3719
0
    NS_ASSERTION(
3720
0
      !(data->mIsSolidColorInVisibleRegion && canOptimizeToImageLayer),
3721
0
      "Can't be a solid color as well as an image!");
3722
0
3723
0
    layer = canOptimizeToImageLayer ? PrepareImageLayer(data)
3724
0
                                    : PrepareColorLayer(data);
3725
0
3726
0
    if (layer) {
3727
0
      NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
3728
0
                   "Layer already in list???");
3729
0
      NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
3730
0
                   "Painted layer at wrong index");
3731
0
      // Store optimized layer in reserved slot
3732
0
      NewLayerEntry* paintedLayerEntry = newLayerEntry;
3733
0
      newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
3734
0
      NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
3735
0
      newLayerEntry->mLayer = layer;
3736
0
      newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
3737
0
      newLayerEntry->mASR = paintedLayerEntry->mASR;
3738
0
      newLayerEntry->mClipChain = paintedLayerEntry->mClipChain;
3739
0
      newLayerEntry->mScrollMetadataASR = paintedLayerEntry->mScrollMetadataASR;
3740
0
3741
0
      // Hide the PaintedLayer. We leave it in the layer tree so that we
3742
0
      // can find and recycle it later.
3743
0
      ParentLayerIntRect emptyRect;
3744
0
      data->mLayer->SetClipRect(Some(emptyRect));
3745
0
      data->mLayer->SetVisibleRegion(LayerIntRegion());
3746
0
      data->mLayer->InvalidateWholeLayer();
3747
0
      data->mLayer->SetEventRegions(EventRegions());
3748
0
    }
3749
0
  }
3750
0
3751
0
  if (!layer) {
3752
0
    // We couldn't optimize to an image layer or a color layer above.
3753
0
    layer = data->mLayer;
3754
0
    layer->SetClipRect(Nothing());
3755
0
    FLB_LOG_PAINTED_LAYER_DECISION(
3756
0
      data, "  Selected painted layer=%p\n", layer.get());
3757
0
  }
3758
0
3759
0
  for (auto& item : data->mAssignedDisplayItems) {
3760
0
    MOZ_ASSERT(item.mItem->GetType() !=
3761
0
               DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO);
3762
0
3763
0
    if (IsEffectEndMarker(item.mType)) {
3764
0
      // Do not invalidate for end markers.
3765
0
      continue;
3766
0
    }
3767
0
3768
0
    InvalidateForLayerChange(item.mItem, data->mLayer, item.mDisplayItemData);
3769
0
    mLayerBuilder->AddPaintedDisplayItem(data, item, *this, layer);
3770
0
    item.mDisplayItemData = nullptr;
3771
0
  }
3772
0
3773
0
  if (mLayerBuilder->IsBuildingRetainedLayers()) {
3774
0
    newLayerEntry->mVisibleRegion = data->mVisibleRegion;
3775
0
    newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
3776
0
    newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
3777
0
    newLayerEntry->mOpaqueForAnimatedGeometryRootParent =
3778
0
      data->mOpaqueForAnimatedGeometryRootParent;
3779
0
  } else {
3780
0
    SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
3781
0
  }
3782
0
3783
#ifdef MOZ_DUMP_PAINTING
3784
  if (!data->mLog.IsEmpty()) {
3785
    if (PaintedLayerData* containingPld =
3786
          mLayerBuilder->GetContainingPaintedLayerData()) {
3787
      containingPld->mLayer->AddExtraDumpInfo(nsCString(data->mLog));
3788
    } else {
3789
      layer->AddExtraDumpInfo(nsCString(data->mLog));
3790
    }
3791
  }
3792
#endif
3793
3794
0
  mLayerBuilder->AddPaintedLayerItemsEntry(userData);
3795
0
3796
0
  nsIntRegion transparentRegion;
3797
0
  transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
3798
0
  bool isOpaque = transparentRegion.IsEmpty();
3799
0
  // For translucent PaintedLayers, try to find an opaque background
3800
0
  // color that covers the entire area beneath it so we can pull that
3801
0
  // color into this layer to make it opaque.
3802
0
  if (layer == data->mLayer) {
3803
0
    nscolor backgroundColor = NS_RGBA(0, 0, 0, 0);
3804
0
    if (!isOpaque) {
3805
0
      backgroundColor = aFindOpaqueBackgroundColor();
3806
0
      if (NS_GET_A(backgroundColor) == 255) {
3807
0
        isOpaque = true;
3808
0
      }
3809
0
    }
3810
0
3811
0
    // Store the background color
3812
0
    if (userData->mForcedBackgroundColor != backgroundColor) {
3813
0
    // Invalidate the entire target PaintedLayer since we're changing
3814
0
    // the background color
3815
#ifdef MOZ_DUMP_PAINTING
3816
      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
3817
        printf_stderr("Forced background color has changed from #%08X to #%08X "
3818
                      "on layer %p\n",
3819
                      userData->mForcedBackgroundColor,
3820
                      backgroundColor,
3821
                      data->mLayer);
3822
        nsAutoCString str;
3823
        AppendToString(str, data->mLayer->GetValidRegion());
3824
        printf_stderr("Invalidating layer %p: %s\n", data->mLayer, str.get());
3825
      }
3826
#endif
3827
      data->mLayer->InvalidateWholeLayer();
3828
0
    }
3829
0
    userData->mForcedBackgroundColor = backgroundColor;
3830
0
  } else {
3831
0
    // mask layer for image and color layers
3832
0
    SetupMaskLayer(layer, *data->mItemClip);
3833
0
  }
3834
0
3835
0
  uint32_t flags = 0;
3836
0
  nsIWidget* widget = mContainerReferenceFrame->PresContext()->GetRootWidget();
3837
0
  // See bug 941095. Not quite ready to disable this.
3838
0
  bool hidpi = false && widget && widget->GetDefaultScale().scale >= 2;
3839
0
  if (hidpi) {
3840
0
    flags |= Layer::CONTENT_DISABLE_SUBPIXEL_AA;
3841
0
  }
3842
0
  if (isOpaque && !data->mForceTransparentSurface) {
3843
0
    flags |= Layer::CONTENT_OPAQUE;
3844
0
  } else if (data->mNeedComponentAlpha && !hidpi) {
3845
0
    flags |= Layer::CONTENT_COMPONENT_ALPHA;
3846
0
  }
3847
0
  if (data->mDisableFlattening) {
3848
0
    flags |= Layer::CONTENT_DISABLE_FLATTENING;
3849
0
  }
3850
0
  layer->SetContentFlags(flags);
3851
0
3852
0
  userData->mItems = std::move(data->mAssignedDisplayItems);
3853
0
  userData->mContainerLayerFrame = GetContainerFrame();
3854
0
3855
0
  PaintedLayerData* containingPaintedLayerData =
3856
0
    mLayerBuilder->GetContainingPaintedLayerData();
3857
0
  // If we're building layers for an inactive layer, the event regions are
3858
0
  // clipped to the inactive layer's clip prior to being combined into the
3859
0
  // event regions of the containing PLD.
3860
0
  // For the dispatch-to-content and maybe-hit regions, rounded corners on
3861
0
  // the clip are ignored, since these are approximate regions. For the
3862
0
  // remaining regions, rounded corners in the clip cause the region to
3863
0
  // be combined into the corresponding "imprecise" region of the
3864
0
  // containing's PLD (e.g. the maybe-hit region instead of the hit region).
3865
0
  const DisplayItemClip* inactiveLayerClip =
3866
0
    mLayerBuilder->GetInactiveLayerClip();
3867
0
  if (containingPaintedLayerData) {
3868
0
    if (!data->mDispatchToContentHitRegion.GetBounds().IsEmpty()) {
3869
0
      nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
3870
0
        mContainerReferenceFrame,
3871
0
        data->mDispatchToContentHitRegion.GetBounds(),
3872
0
        containingPaintedLayerData->mReferenceFrame);
3873
0
      if (inactiveLayerClip) {
3874
0
        rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
3875
0
      }
3876
0
      containingPaintedLayerData->mDispatchToContentHitRegion.Or(
3877
0
        containingPaintedLayerData->mDispatchToContentHitRegion, rect);
3878
0
      containingPaintedLayerData->mDispatchToContentHitRegion.SimplifyOutward(
3879
0
        8);
3880
0
      if (data->mDTCRequiresTargetConfirmation) {
3881
0
        containingPaintedLayerData->mDTCRequiresTargetConfirmation = true;
3882
0
      }
3883
0
    }
3884
0
    if (!data->mMaybeHitRegion.GetBounds().IsEmpty()) {
3885
0
      nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
3886
0
        mContainerReferenceFrame,
3887
0
        data->mMaybeHitRegion.GetBounds(),
3888
0
        containingPaintedLayerData->mReferenceFrame);
3889
0
      if (inactiveLayerClip) {
3890
0
        rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
3891
0
      }
3892
0
      containingPaintedLayerData->mMaybeHitRegion.Or(
3893
0
        containingPaintedLayerData->mMaybeHitRegion, rect);
3894
0
      containingPaintedLayerData->mMaybeHitRegion.SimplifyOutward(8);
3895
0
    }
3896
0
    Maybe<Matrix4x4Flagged> matrixCache;
3897
0
    nsLayoutUtils::TransformToAncestorAndCombineRegions(
3898
0
      data->mHitRegion,
3899
0
      mContainerReferenceFrame,
3900
0
      containingPaintedLayerData->mReferenceFrame,
3901
0
      &containingPaintedLayerData->mHitRegion,
3902
0
      &containingPaintedLayerData->mMaybeHitRegion,
3903
0
      &matrixCache,
3904
0
      inactiveLayerClip);
3905
0
    // See the comment in nsDisplayList::AddFrame, where the touch action
3906
0
    // regions are handled. The same thing applies here.
3907
0
    bool alreadyHadRegions =
3908
0
      !containingPaintedLayerData->mNoActionRegion.IsEmpty() ||
3909
0
      !containingPaintedLayerData->mHorizontalPanRegion.IsEmpty() ||
3910
0
      !containingPaintedLayerData->mVerticalPanRegion.IsEmpty();
3911
0
    nsLayoutUtils::TransformToAncestorAndCombineRegions(
3912
0
      data->mNoActionRegion,
3913
0
      mContainerReferenceFrame,
3914
0
      containingPaintedLayerData->mReferenceFrame,
3915
0
      &containingPaintedLayerData->mNoActionRegion,
3916
0
      &containingPaintedLayerData->mDispatchToContentHitRegion,
3917
0
      &matrixCache,
3918
0
      inactiveLayerClip);
3919
0
    nsLayoutUtils::TransformToAncestorAndCombineRegions(
3920
0
      data->mHorizontalPanRegion,
3921
0
      mContainerReferenceFrame,
3922
0
      containingPaintedLayerData->mReferenceFrame,
3923
0
      &containingPaintedLayerData->mHorizontalPanRegion,
3924
0
      &containingPaintedLayerData->mDispatchToContentHitRegion,
3925
0
      &matrixCache,
3926
0
      inactiveLayerClip);
3927
0
    nsLayoutUtils::TransformToAncestorAndCombineRegions(
3928
0
      data->mVerticalPanRegion,
3929
0
      mContainerReferenceFrame,
3930
0
      containingPaintedLayerData->mReferenceFrame,
3931
0
      &containingPaintedLayerData->mVerticalPanRegion,
3932
0
      &containingPaintedLayerData->mDispatchToContentHitRegion,
3933
0
      &matrixCache,
3934
0
      inactiveLayerClip);
3935
0
    if (alreadyHadRegions) {
3936
0
      containingPaintedLayerData->mDispatchToContentHitRegion.OrWith(
3937
0
        containingPaintedLayerData->CombinedTouchActionRegion());
3938
0
    }
3939
0
  } else {
3940
0
    EventRegions regions(
3941
0
      ScaleRegionToOutsidePixels(data->mHitRegion),
3942
0
      ScaleRegionToOutsidePixels(data->mMaybeHitRegion),
3943
0
      ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion),
3944
0
      ScaleRegionToOutsidePixels(data->mNoActionRegion),
3945
0
      ScaleRegionToOutsidePixels(data->mHorizontalPanRegion),
3946
0
      ScaleRegionToOutsidePixels(data->mVerticalPanRegion),
3947
0
      data->mDTCRequiresTargetConfirmation);
3948
0
3949
0
    Matrix mat = layer->GetTransform().As2D();
3950
0
    mat.Invert();
3951
0
    regions.ApplyTranslationAndScale(mat._31, mat._32, mat._11, mat._22);
3952
0
3953
0
    layer->SetEventRegions(regions);
3954
0
  }
3955
0
3956
0
  SetBackfaceHiddenForLayer(data->mBackfaceHidden, data->mLayer);
3957
0
  if (layer != data->mLayer) {
3958
0
    SetBackfaceHiddenForLayer(data->mBackfaceHidden, layer);
3959
0
  }
3960
0
}
3961
3962
static bool
3963
IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder,
3964
                               nsDisplayItem* aItem,
3965
                               const nsRect& aComponentAlphaBounds)
3966
0
{
3967
0
  if (!aItem->Frame()->PresContext()->IsChrome()) {
3968
0
    // Assume that Web content is always in the window opaque region.
3969
0
    return true;
3970
0
  }
3971
0
  if (aItem->ReferenceFrame() != aBuilder->RootReferenceFrame()) {
3972
0
    // aItem is probably in some transformed subtree.
3973
0
    // We're not going to bother figuring out where this landed, we're just
3974
0
    // going to assume it might have landed over a transparent part of
3975
0
    // the window.
3976
0
    return false;
3977
0
  }
3978
0
  return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds);
3979
0
}
3980
3981
void
3982
PaintedLayerData::UpdateEffectStatus(DisplayItemEntryType aType,
3983
                                     nsTArray<size_t>& aOpacityIndices)
3984
0
{
3985
0
  switch (aType) {
3986
0
    case DisplayItemEntryType::PUSH_OPACITY:
3987
0
      // The index of the new assigned display item in |mAssignedDisplayItems|
3988
0
      // array will be the current length of the array.
3989
0
      aOpacityIndices.AppendElement(mAssignedDisplayItems.size());
3990
0
      break;
3991
0
    case DisplayItemEntryType::POP_OPACITY:
3992
0
      MOZ_ASSERT(!aOpacityIndices.IsEmpty());
3993
0
      aOpacityIndices.RemoveLastElement();
3994
0
      break;
3995
#ifdef DEBUG
3996
    case DisplayItemEntryType::POP_TRANSFORM:
3997
      MOZ_ASSERT(mTransformLevel >= 0);
3998
      mTransformLevel--;
3999
      break;
4000
    case DisplayItemEntryType::PUSH_TRANSFORM:
4001
      mTransformLevel++;
4002
      break;
4003
#endif
4004
0
    default:
4005
0
      break;
4006
0
  }
4007
0
}
4008
4009
void
4010
PaintedLayerData::Accumulate(ContainerState* aState,
4011
                             nsDisplayItem* aItem,
4012
                             const nsIntRect& aVisibleRect,
4013
                             const nsRect& aContentRect,
4014
                             const DisplayItemClip& aClip,
4015
                             LayerState aLayerState,
4016
                             nsDisplayList* aList,
4017
                             DisplayItemEntryType aType,
4018
                             nsTArray<size_t>& aOpacityIndices,
4019
                             const RefPtr<TransformClipNode>& aTransform)
4020
0
{
4021
0
  FLB_LOG_PAINTED_LAYER_DECISION(
4022
0
    this,
4023
0
    "Accumulating dp=%s(%p), f=%p against pld=%p\n",
4024
0
    aItem->Name(),
4025
0
    aItem,
4026
0
    aItem->Frame(),
4027
0
    this);
4028
0
4029
0
  const bool hasOpacity = aOpacityIndices.Length() > 0;
4030
0
4031
0
  const DisplayItemClip* oldClip = mItemClip;
4032
0
  mItemClip = &aClip;
4033
0
4034
0
  UpdateEffectStatus(aType, aOpacityIndices);
4035
0
4036
0
  if (IsEffectEndMarker(aType)) {
4037
0
    mAssignedDisplayItems.emplace_back(
4038
0
      aItem, aLayerState, nullptr, aContentRect, aType, hasOpacity, aTransform);
4039
0
    return;
4040
0
  }
4041
0
4042
0
  bool clipMatches =
4043
0
    (oldClip == mItemClip) || (oldClip && *oldClip == *mItemClip);
4044
0
4045
0
  DisplayItemData* currentData =
4046
0
    aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData();
4047
0
4048
0
  DisplayItemData* oldData = aState->mLayerBuilder->GetOldLayerForFrame(
4049
0
    aItem->Frame(),
4050
0
    aItem->GetPerFrameKey(),
4051
0
    currentData,
4052
0
    aItem->GetDisplayItemDataLayerManager());
4053
0
4054
0
  mAssignedDisplayItems.emplace_back(
4055
0
    aItem, aLayerState, oldData, aContentRect, aType, hasOpacity, aTransform);
4056
0
4057
0
  if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
4058
0
    mForceTransparentSurface = true;
4059
0
  }
4060
0
4061
0
  nsRect componentAlphaBounds;
4062
0
  if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
4063
0
    // Disable component alpha.
4064
0
    // Note that the transform (if any) on the PaintedLayer is always an integer
4065
0
    // translation so we don't have to factor that in here.
4066
0
    aItem->DisableComponentAlpha();
4067
0
  } else {
4068
0
    componentAlphaBounds = aItem->GetComponentAlphaBounds(aState->mBuilder);
4069
0
4070
0
    if (!componentAlphaBounds.IsEmpty()) {
4071
0
      // This display item needs background copy when pushing opacity group.
4072
0
      for (size_t i : aOpacityIndices) {
4073
0
        AssignedDisplayItem& item = mAssignedDisplayItems[i];
4074
0
        MOZ_ASSERT(item.mType == DisplayItemEntryType::PUSH_OPACITY ||
4075
0
                   item.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG);
4076
0
        item.mType = DisplayItemEntryType::PUSH_OPACITY_WITH_BG;
4077
0
      }
4078
0
    }
4079
0
  }
4080
0
4081
0
  if (aItem->MustPaintOnContentSide()) {
4082
0
    mShouldPaintOnContentSide = true;
4083
0
  }
4084
0
4085
0
  if (aTransform && aType == DisplayItemEntryType::ITEM) {
4086
0
    // Bounds transformed with axis-aligned transforms could be included in the
4087
0
    // opaque region calculations. For simplicity, this is currently not done.
4088
0
    return;
4089
0
  }
4090
0
4091
0
  if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aVisibleRect) &&
4092
0
      mVisibleRegion.Contains(aVisibleRect) && !mImage) {
4093
0
    // A very common case! Most pages have a PaintedLayer with the page
4094
0
    // background (opaque) visible and most or all of the page content over the
4095
0
    // top of that background.
4096
0
    // The rest of this method won't do anything. mVisibleRegion and
4097
0
    // mOpaqueRegion don't need updating. mVisibleRegion contains aVisibleRect
4098
0
    // already, mOpaqueRegion contains aVisibleRect and therefore whatever the
4099
0
    // opaque region of the item is. mVisibleRegion must contain mOpaqueRegion
4100
0
    // and therefore aVisibleRect.
4101
0
    return;
4102
0
  }
4103
0
4104
0
  nsIntRegion opaquePixels;
4105
0
4106
0
  // Active opacity means no opaque pixels.
4107
0
  if (!hasOpacity) {
4108
0
    opaquePixels =
4109
0
      aState->ComputeOpaqueRect(aItem,
4110
0
                                mAnimatedGeometryRoot,
4111
0
                                mASR,
4112
0
                                aClip,
4113
0
                                aList,
4114
0
                                &mHideAllLayersBelow,
4115
0
                                &mOpaqueForAnimatedGeometryRootParent);
4116
0
    opaquePixels.AndWith(aVisibleRect);
4117
0
  }
4118
0
4119
0
  /* Mark as available for conversion to image layer if this is a nsDisplayImage
4120
0
   * and it's the only thing visible in this layer.
4121
0
   */
4122
0
  if (nsIntRegion(aVisibleRect).Contains(mVisibleRegion) &&
4123
0
      opaquePixels.Contains(mVisibleRegion) &&
4124
0
      aItem->SupportsOptimizingToImage()) {
4125
0
    mImage = static_cast<nsDisplayImageContainer*>(aItem);
4126
0
    FLB_LOG_PAINTED_LAYER_DECISION(
4127
0
      this, "  Tracking image: nsDisplayImageContainer covers the layer\n");
4128
0
  } else if (mImage) {
4129
0
    FLB_LOG_PAINTED_LAYER_DECISION(this, "  No longer tracking image\n");
4130
0
    mImage = nullptr;
4131
0
  }
4132
0
4133
0
  bool isFirstVisibleItem = mVisibleRegion.IsEmpty();
4134
0
4135
0
  Maybe<nscolor> uniformColor;
4136
0
  if (!hasOpacity) {
4137
0
    uniformColor = aItem->IsUniform(aState->mBuilder);
4138
0
  }
4139
0
4140
0
  // Some display items have to exist (so they can set forceTransparentSurface
4141
0
  // below) but don't draw anything. They'll return true for isUniform but
4142
0
  // a color with opacity 0.
4143
0
  if (!uniformColor || NS_GET_A(*uniformColor) > 0) {
4144
0
    // Make sure that the visible area is covered by uniform pixels. In
4145
0
    // particular this excludes cases where the edges of the item are not
4146
0
    // pixel-aligned (thus the item will not be truly uniform).
4147
0
    if (uniformColor) {
4148
0
      bool snap;
4149
0
      nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap);
4150
0
      if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) {
4151
0
        uniformColor = Nothing();
4152
0
        FLB_LOG_PAINTED_LAYER_DECISION(
4153
0
          this, "  Display item does not cover the visible rect\n");
4154
0
      }
4155
0
    }
4156
0
    if (uniformColor) {
4157
0
      if (isFirstVisibleItem) {
4158
0
        // This color is all we have
4159
0
        mSolidColor = *uniformColor;
4160
0
        mIsSolidColorInVisibleRegion = true;
4161
0
      } else if (mIsSolidColorInVisibleRegion &&
4162
0
                 mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect)) &&
4163
0
                 clipMatches) {
4164
0
        // we can just blend the colors together
4165
0
        mSolidColor = NS_ComposeColors(mSolidColor, *uniformColor);
4166
0
      } else {
4167
0
        FLB_LOG_PAINTED_LAYER_DECISION(
4168
0
          this, "  Layer not a solid color: Can't blend colors togethers\n");
4169
0
        mIsSolidColorInVisibleRegion = false;
4170
0
      }
4171
0
    } else {
4172
0
      FLB_LOG_PAINTED_LAYER_DECISION(this,
4173
0
                                     "  Layer is not a solid color: Display "
4174
0
                                     "item is not uniform over the visible "
4175
0
                                     "bound\n");
4176
0
      mIsSolidColorInVisibleRegion = false;
4177
0
    }
4178
0
4179
0
    mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
4180
0
    mVisibleRegion.SimplifyOutward(4);
4181
0
  }
4182
0
4183
0
  if (!opaquePixels.IsEmpty()) {
4184
0
    for (auto iter = opaquePixels.RectIter(); !iter.Done(); iter.Next()) {
4185
0
      // We don't use SimplifyInward here since it's not defined exactly
4186
0
      // what it will discard. For our purposes the most important case
4187
0
      // is a large opaque background at the bottom of z-order (e.g.,
4188
0
      // a canvas background), so we need to make sure that the first rect
4189
0
      // we see doesn't get discarded.
4190
0
      nsIntRegion tmp;
4191
0
      tmp.Or(mOpaqueRegion, iter.Get());
4192
0
      // Opaque display items in chrome documents whose window is partially
4193
0
      // transparent are always added to the opaque region. This helps ensure
4194
0
      // that we get as much subpixel-AA as possible in the chrome.
4195
0
      if (tmp.GetNumRects() <= 4 || aItem->Frame()->PresContext()->IsChrome()) {
4196
0
        mOpaqueRegion = std::move(tmp);
4197
0
      }
4198
0
    }
4199
0
  }
4200
0
4201
0
  if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants &&
4202
0
      !componentAlphaBounds.IsEmpty()) {
4203
0
    nsIntRect componentAlphaRect =
4204
0
      aState->ScaleToOutsidePixels(componentAlphaBounds, false)
4205
0
        .Intersect(aVisibleRect);
4206
0
4207
0
    if (!mOpaqueRegion.Contains(componentAlphaRect)) {
4208
0
      if (IsItemAreaInWindowOpaqueRegion(
4209
0
            aState->mBuilder,
4210
0
            aItem,
4211
0
            componentAlphaBounds.Intersect(aItem->GetBuildingRect()))) {
4212
0
        mNeedComponentAlpha = true;
4213
0
      } else {
4214
0
        aItem->DisableComponentAlpha();
4215
0
      }
4216
0
    }
4217
0
  }
4218
0
4219
0
  // Ensure animated text does not get flattened, even if it forces other
4220
0
  // content in the container to be layerized. The content backend might
4221
0
  // not support subpixel positioning of text that animated transforms can
4222
0
  // generate. bug 633097
4223
0
  if (aState->mParameters.mInActiveTransformedSubtree &&
4224
0
      (mNeedComponentAlpha || !componentAlphaBounds.IsEmpty())) {
4225
0
    mDisableFlattening = true;
4226
0
  }
4227
0
}
4228
4229
nsRegion
4230
PaintedLayerData::CombinedTouchActionRegion()
4231
0
{
4232
0
  nsRegion result;
4233
0
  result.Or(mHorizontalPanRegion, mVerticalPanRegion);
4234
0
  result.OrWith(mNoActionRegion);
4235
0
  return result;
4236
0
}
4237
4238
void
4239
PaintedLayerData::AccumulateHitTestInfo(ContainerState* aState,
4240
                                        nsDisplayCompositorHitTestInfo* aItem,
4241
                                        TransformClipNode* aTransform)
4242
0
{
4243
0
  FLB_LOG_PAINTED_LAYER_DECISION(
4244
0
    this, "Accumulating hit test info %p against pld=%p\n", aItem, this);
4245
0
4246
0
  const mozilla::DisplayItemClip& clip = aItem->GetClip();
4247
0
  nsRect area = clip.ApplyNonRoundedIntersection(aItem->Area());
4248
0
  if (aTransform) {
4249
0
    area = aTransform->TransformRect(area, aState->mAppUnitsPerDevPixel);
4250
0
  }
4251
0
  const mozilla::gfx::CompositorHitTestInfo hitTestInfo = aItem->HitTestInfo();
4252
0
4253
0
  bool hasRoundedCorners = clip.GetRoundedRectCount() > 0;
4254
0
4255
0
  // use the NS_FRAME_SIMPLE_EVENT_REGIONS to avoid calling the slightly
4256
0
  // expensive HasNonZeroCorner function if we know from a previous run that
4257
0
  // the frame has zero corners.
4258
0
  nsIFrame* frame = aItem->Frame();
4259
0
4260
0
  bool simpleRegions = frame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
4261
0
  if (!simpleRegions) {
4262
0
    if (nsLayoutUtils::HasNonZeroCorner(frame->StyleBorder()->mBorderRadius)) {
4263
0
      hasRoundedCorners = true;
4264
0
    } else {
4265
0
      frame->AddStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
4266
0
    }
4267
0
  }
4268
0
4269
0
  if (hasRoundedCorners || (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
4270
0
    mMaybeHitRegion.OrWith(area);
4271
0
  } else {
4272
0
    mHitRegion.OrWith(area);
4273
0
  }
4274
0
4275
0
  if (aItem->HitTestInfo() & CompositorHitTestInfo::eDispatchToContent) {
4276
0
    mDispatchToContentHitRegion.OrWith(area);
4277
0
4278
0
    if (aItem->HitTestInfo() &
4279
0
        CompositorHitTestInfo::eRequiresTargetConfirmation) {
4280
0
      mDTCRequiresTargetConfirmation = true;
4281
0
    }
4282
0
  }
4283
0
4284
0
  auto touchFlags = hitTestInfo & CompositorHitTestInfo::eTouchActionMask;
4285
0
  if (touchFlags) {
4286
0
    // If there are multiple touch-action areas, there are multiple elements
4287
0
    // with touch-action properties. We don't know what the relationship is
4288
0
    // between those elements in terms of DOM ancestry, and so we don't know how
4289
0
    // to combine the regions properly. Instead, we just add all the areas to
4290
0
    // the dispatch-to-content region, so that the APZ knows to check with the
4291
0
    // main thread. See bug 1286957.
4292
0
    if (mCollapsedTouchActions) {
4293
0
      mDispatchToContentHitRegion.OrWith(area);
4294
0
    } else if (touchFlags == CompositorHitTestInfo::eTouchActionMask) {
4295
0
      // everything was disabled, so touch-action:none
4296
0
      mNoActionRegion.OrWith(area);
4297
0
    } else {
4298
0
      // The event regions code does not store enough information to actually
4299
0
      // represent all the different states. Prior to the introduction of
4300
0
      // CompositorHitTestInfo here in bug 1389149, the following two cases
4301
0
      // were effectively getting collapsed:
4302
0
      //   (1) touch-action: auto
4303
0
      //   (2) touch-action: manipulation
4304
0
      // In both of these cases, none of {mNoActionRegion, mHorizontalPanRegion,
4305
0
      // mVerticalPanRegion} were modified, and so the fact that case (2) should
4306
0
      // have prevented double-tap-zooming was getting lost.
4307
0
      // With CompositorHitTestInfo we can now represent that case correctly,
4308
0
      // but only if we use CompositorHitTestInfo all the way to the compositor
4309
0
      // (i.e. in the WebRender-enabled case). In the non-WebRender case where
4310
0
      // we still use the event regions, we must collapse these two cases back
4311
0
      // together. Or add another region to the event regions to fix this
4312
0
      // properly.
4313
0
      if (touchFlags !=
4314
0
          CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled) {
4315
0
        if (!(hitTestInfo & CompositorHitTestInfo::eTouchActionPanXDisabled)) {
4316
0
          // pan-x is allowed
4317
0
          mHorizontalPanRegion.OrWith(area);
4318
0
        }
4319
0
        if (!(hitTestInfo & CompositorHitTestInfo::eTouchActionPanYDisabled)) {
4320
0
          // pan-y is allowed
4321
0
          mVerticalPanRegion.OrWith(area);
4322
0
        }
4323
0
      } else {
4324
0
        // the touch-action: manipulation case described above. To preserve the
4325
0
        // existing behaviour, don't touch either mHorizontalPanRegion or
4326
0
        // mVerticalPanRegion
4327
0
      }
4328
0
    }
4329
0
  }
4330
0
4331
0
  if (!mCollapsedTouchActions) {
4332
0
    // If there are multiple touch-action areas, there are multiple elements
4333
0
    // with touch-action properties. We don't know what the relationship is
4334
0
    // between those elements in terms of DOM ancestry, and so we don't know how
4335
0
    // to combine the regions properly. Instead, we just add all the areas to
4336
0
    // the dispatch-to-content region, so that the APZ knows to check with the
4337
0
    // main thread. See bug 1286957.
4338
0
    const int alreadyHadRegions = mNoActionRegion.GetNumRects() +
4339
0
                                  mHorizontalPanRegion.GetNumRects() +
4340
0
                                  mVerticalPanRegion.GetNumRects();
4341
0
4342
0
    if (alreadyHadRegions > 1) {
4343
0
      mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion());
4344
0
      mNoActionRegion.SetEmpty();
4345
0
      mHorizontalPanRegion.SetEmpty();
4346
0
      mVerticalPanRegion.SetEmpty();
4347
0
      mCollapsedTouchActions = true;
4348
0
    }
4349
0
  }
4350
0
4351
0
  // Avoid quadratic performance as a result of the region growing to include
4352
0
  // and arbitrarily large number of rects, which can happen on some pages.
4353
0
  mMaybeHitRegion.SimplifyOutward(8);
4354
0
  mDispatchToContentHitRegion.SimplifyOutward(8);
4355
0
4356
0
  // Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion
4357
0
  // for quick access in FindPaintedLayerFor().
4358
0
  mScaledHitRegionBounds = aState->ScaleToOutsidePixels(mHitRegion.GetBounds());
4359
0
  mScaledMaybeHitRegionBounds =
4360
0
    aState->ScaleToOutsidePixels(mMaybeHitRegion.GetBounds());
4361
0
}
4362
4363
void
4364
ContainerState::NewPaintedLayerData(
4365
  PaintedLayerData* aData,
4366
  AnimatedGeometryRoot* aAnimatedGeometryRoot,
4367
  const ActiveScrolledRoot* aASR,
4368
  const DisplayItemClipChain* aClipChain,
4369
  const ActiveScrolledRoot* aScrollMetadataASR,
4370
  const nsPoint& aTopLeft,
4371
  const nsIFrame* aReferenceFrame,
4372
  const bool aBackfaceHidden)
4373
0
{
4374
0
  aData->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
4375
0
  aData->mASR = aASR;
4376
0
  aData->mClipChain = aClipChain;
4377
0
  aData->mAnimatedGeometryRootOffset = aTopLeft;
4378
0
  aData->mReferenceFrame = aReferenceFrame;
4379
0
  aData->mBackfaceHidden = aBackfaceHidden;
4380
0
4381
0
  aData->mNewChildLayersIndex = mNewChildLayers.Length();
4382
0
  NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
4383
0
  newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
4384
0
  newLayerEntry->mASR = aASR;
4385
0
  newLayerEntry->mScrollMetadataASR = aScrollMetadataASR;
4386
0
  newLayerEntry->mClipChain = aClipChain;
4387
0
  // newLayerEntry->mOpaqueRegion is filled in later from
4388
0
  // paintedLayerData->mOpaqueRegion, if necessary.
4389
0
4390
0
  // Allocate another entry for this layer's optimization to
4391
0
  // ColorLayer/ImageLayer
4392
0
  mNewChildLayers.AppendElement();
4393
0
}
4394
4395
#ifdef MOZ_DUMP_PAINTING
4396
static void
4397
DumpPaintedImage(nsDisplayItem* aItem, SourceSurface* aSurface)
4398
{
4399
  nsCString string(aItem->Name());
4400
  string.Append('-');
4401
  string.AppendInt((uint64_t)aItem);
4402
  fprintf_stderr(gfxUtils::sDumpPaintFile,
4403
                 "<script>array[\"%s\"]=\"",
4404
                 string.BeginReading());
4405
  gfxUtils::DumpAsDataURI(aSurface, gfxUtils::sDumpPaintFile);
4406
  fprintf_stderr(gfxUtils::sDumpPaintFile, "\";</script>\n");
4407
}
4408
#endif
4409
4410
static void
4411
PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
4412
                   LayerManager* aManager,
4413
                   nsDisplayItem* aItem,
4414
                   gfxContext* aContext,
4415
                   gfxContext* aCtx)
4416
0
{
4417
0
  // This item has an inactive layer. Render it to a PaintedLayer
4418
0
  // using a temporary BasicLayerManager.
4419
0
  BasicLayerManager* basic = static_cast<BasicLayerManager*>(aManager);
4420
0
  RefPtr<gfxContext> context = aContext;
4421
#ifdef MOZ_DUMP_PAINTING
4422
  int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
4423
  nsIntRect itemVisibleRect =
4424
    aItem->GetPaintRect().ToOutsidePixels(appUnitsPerDevPixel);
4425
4426
  RefPtr<DrawTarget> tempDT;
4427
  if (gfxEnv::DumpPaint()) {
4428
    tempDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
4429
      itemVisibleRect.Size(), SurfaceFormat::B8G8R8A8);
4430
    if (tempDT) {
4431
      context = gfxContext::CreateOrNull(tempDT);
4432
      if (!context) {
4433
        // Leave this as crash, it's in the debugging code, we want to know
4434
        gfxDevCrash(LogReason::InvalidContext)
4435
          << "PaintInactive context problem " << gfx::hexa(tempDT);
4436
        return;
4437
      }
4438
      context->SetMatrix(
4439
        Matrix::Translation(-itemVisibleRect.x, -itemVisibleRect.y));
4440
    }
4441
  }
4442
#endif
4443
  basic->BeginTransaction();
4444
0
  basic->SetTarget(context);
4445
0
4446
0
  if (aItem->GetType() == DisplayItemType::TYPE_MASK) {
4447
0
    static_cast<nsDisplayMask*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
4448
0
    if (basic->InTransaction()) {
4449
0
      basic->AbortTransaction();
4450
0
    }
4451
0
  } else if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
4452
0
    static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
4453
0
    if (basic->InTransaction()) {
4454
0
      basic->AbortTransaction();
4455
0
    }
4456
0
  } else {
4457
0
    basic->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder);
4458
0
  }
4459
0
  FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(
4460
0
    basic->GetUserData(&gLayerManagerLayerBuilder));
4461
0
  if (builder) {
4462
0
    builder->DidEndTransaction();
4463
0
  }
4464
0
4465
0
  basic->SetTarget(nullptr);
4466
0
4467
#ifdef MOZ_DUMP_PAINTING
4468
  if (gfxEnv::DumpPaint() && tempDT) {
4469
    RefPtr<SourceSurface> surface = tempDT->Snapshot();
4470
    DumpPaintedImage(aItem, surface);
4471
4472
    DrawTarget* drawTarget = aContext->GetDrawTarget();
4473
    Rect rect(itemVisibleRect.x,
4474
              itemVisibleRect.y,
4475
              itemVisibleRect.width,
4476
              itemVisibleRect.height);
4477
    drawTarget->DrawSurface(surface, rect, Rect(Point(0, 0), rect.Size()));
4478
4479
    aItem->SetPainted();
4480
  }
4481
#endif
4482
}
4483
4484
nsRect
4485
ContainerState::GetDisplayPortForAnimatedGeometryRoot(
4486
  AnimatedGeometryRoot* aAnimatedGeometryRoot)
4487
0
{
4488
0
  if (mLastDisplayPortAGR == aAnimatedGeometryRoot) {
4489
0
    return mLastDisplayPortRect;
4490
0
  }
4491
0
4492
0
  mLastDisplayPortAGR = aAnimatedGeometryRoot;
4493
0
4494
0
  nsIScrollableFrame* sf =
4495
0
    nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
4496
0
  if (sf == nullptr ||
4497
0
      nsLayoutUtils::UsesAsyncScrolling(*aAnimatedGeometryRoot)) {
4498
0
    mLastDisplayPortRect = nsRect();
4499
0
    return mLastDisplayPortRect;
4500
0
  }
4501
0
4502
0
  bool usingDisplayport =
4503
0
    nsLayoutUtils::GetDisplayPort((*aAnimatedGeometryRoot)->GetContent(),
4504
0
                                  &mLastDisplayPortRect,
4505
0
                                  RelativeTo::ScrollFrame);
4506
0
  if (!usingDisplayport) {
4507
0
    // No async scrolling, so all that matters is that the layer contents
4508
0
    // cover the scrollport.
4509
0
    mLastDisplayPortRect = sf->GetScrollPortRect();
4510
0
  }
4511
0
  nsIFrame* scrollFrame = do_QueryFrame(sf);
4512
0
  mLastDisplayPortRect +=
4513
0
    scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
4514
0
  return mLastDisplayPortRect;
4515
0
}
4516
4517
nsIntRegion
4518
ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
4519
                                  AnimatedGeometryRoot* aAnimatedGeometryRoot,
4520
                                  const ActiveScrolledRoot* aASR,
4521
                                  const DisplayItemClip& aClip,
4522
                                  nsDisplayList* aList,
4523
                                  bool* aHideAllLayersBelow,
4524
                                  bool* aOpaqueForAnimatedGeometryRootParent)
4525
0
{
4526
0
  bool snapOpaque;
4527
0
  nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
4528
0
  if (opaque.IsEmpty()) {
4529
0
    return nsIntRegion();
4530
0
  }
4531
0
4532
0
  nsIntRegion opaquePixels;
4533
0
  nsRegion opaqueClipped;
4534
0
  for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
4535
0
    opaqueClipped.Or(opaqueClipped,
4536
0
                     aClip.ApproximateIntersectInward(iter.Get()));
4537
0
  }
4538
0
  if (aAnimatedGeometryRoot == mContainerAnimatedGeometryRoot &&
4539
0
      aASR == mContainerASR && opaqueClipped.Contains(mContainerBounds)) {
4540
0
    *aHideAllLayersBelow = true;
4541
0
    aList->SetIsOpaque();
4542
0
  }
4543
0
  // Add opaque areas to the "exclude glass" region. Only do this when our
4544
0
  // container layer is going to be the rootmost layer, otherwise transforms
4545
0
  // etc will mess us up (and opaque contributions from other containers are
4546
0
  // not needed).
4547
0
  if (!nsLayoutUtils::GetCrossDocParentFrame(mContainerFrame)) {
4548
0
    mBuilder->AddWindowOpaqueRegion(opaqueClipped);
4549
0
  }
4550
0
  opaquePixels = ScaleRegionToInsidePixels(opaqueClipped, snapOpaque);
4551
0
4552
0
  if (IsInInactiveLayer()) {
4553
0
    return opaquePixels;
4554
0
  }
4555
0
4556
0
  const nsRect& displayport =
4557
0
    GetDisplayPortForAnimatedGeometryRoot(aAnimatedGeometryRoot);
4558
0
  if (!displayport.IsEmpty() &&
4559
0
      opaquePixels.Contains(ScaleRegionToNearestPixels(displayport))) {
4560
0
    *aOpaqueForAnimatedGeometryRootParent = true;
4561
0
  }
4562
0
  return opaquePixels;
4563
0
}
4564
4565
Maybe<size_t>
4566
ContainerState::SetupMaskLayerForScrolledClip(Layer* aLayer,
4567
                                              const DisplayItemClip& aClip)
4568
0
{
4569
0
  if (aClip.GetRoundedRectCount() > 0) {
4570
0
    Maybe<size_t> maskLayerIndex = Some(aLayer->GetAncestorMaskLayerCount());
4571
0
    if (RefPtr<Layer> maskLayer =
4572
0
          CreateMaskLayer(aLayer, aClip, maskLayerIndex)) {
4573
0
      aLayer->AddAncestorMaskLayer(maskLayer);
4574
0
      return maskLayerIndex;
4575
0
    }
4576
0
    // Fall through to |return Nothing()|.
4577
0
  }
4578
0
  return Nothing();
4579
0
}
4580
4581
static const ActiveScrolledRoot*
4582
GetASRForPerspective(const ActiveScrolledRoot* aASR,
4583
                     nsIFrame* aPerspectiveFrame)
4584
0
{
4585
0
  for (const ActiveScrolledRoot* asr = aASR; asr; asr = asr->mParent) {
4586
0
    nsIFrame* scrolledFrame = asr->mScrollableFrame->GetScrolledFrame();
4587
0
    if (nsLayoutUtils::IsAncestorFrameCrossDoc(scrolledFrame,
4588
0
                                               aPerspectiveFrame)) {
4589
0
      return asr;
4590
0
    }
4591
0
  }
4592
0
  return nullptr;
4593
0
}
4594
4595
static CSSMaskLayerUserData*
4596
GetCSSMaskLayerUserData(Layer* aMaskLayer)
4597
0
{
4598
0
  if (!aMaskLayer) {
4599
0
    return nullptr;
4600
0
  }
4601
0
4602
0
  return static_cast<CSSMaskLayerUserData*>(
4603
0
    aMaskLayer->GetUserData(&gCSSMaskLayerUserData));
4604
0
}
4605
4606
static void
4607
SetCSSMaskLayerUserData(Layer* aMaskLayer)
4608
0
{
4609
0
  MOZ_ASSERT(aMaskLayer);
4610
0
4611
0
  aMaskLayer->SetUserData(&gCSSMaskLayerUserData, new CSSMaskLayerUserData());
4612
0
}
4613
4614
void
4615
ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
4616
                                         nsDisplayMask* aMaskItem)
4617
0
{
4618
0
  RefPtr<ImageLayer> maskLayer =
4619
0
    CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, Nothing()),
4620
0
                                     GetCSSMaskLayerUserData,
4621
0
                                     SetCSSMaskLayerUserData);
4622
0
  CSSMaskLayerUserData* oldUserData = GetCSSMaskLayerUserData(maskLayer.get());
4623
0
  MOZ_ASSERT(oldUserData);
4624
0
4625
0
  bool snap;
4626
0
  nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
4627
0
  nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
4628
0
4629
0
  // Setup mask layer offset.
4630
0
  // We do not repaint mask for mask position change, so update base transform
4631
0
  // each time is required.
4632
0
  Matrix4x4 matrix;
4633
0
  matrix.PreTranslate(itemRect.x, itemRect.y, 0);
4634
0
  matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
4635
0
  maskLayer->SetBaseTransform(matrix);
4636
0
4637
0
  nsPoint maskLayerOffset = aMaskItem->ToReferenceFrame() - bounds.TopLeft();
4638
0
4639
0
  CSSMaskLayerUserData newUserData(
4640
0
    aMaskItem->Frame(), itemRect, maskLayerOffset);
4641
0
  nsRect dirtyRect;
4642
0
  if (!aMaskItem->IsInvalid(dirtyRect) && *oldUserData == newUserData) {
4643
0
    aLayer->SetMaskLayer(maskLayer);
4644
0
    return;
4645
0
  }
4646
0
4647
0
  int32_t maxSize = mManager->GetMaxTextureSize();
4648
0
  IntSize surfaceSize(std::min(itemRect.width, maxSize),
4649
0
                      std::min(itemRect.height, maxSize));
4650
0
4651
0
  if (surfaceSize.IsEmpty()) {
4652
0
    // Return early if we know that the size of this mask surface is empty.
4653
0
    return;
4654
0
  }
4655
0
4656
0
  MaskImageData imageData(surfaceSize, mManager);
4657
0
  RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
4658
0
  if (!dt || !dt->IsValid()) {
4659
0
    NS_WARNING("Could not create DrawTarget for mask layer.");
4660
0
    return;
4661
0
  }
4662
0
4663
0
  RefPtr<gfxContext> maskCtx = gfxContext::CreateOrNull(dt);
4664
0
  maskCtx->SetMatrix(Matrix::Translation(-itemRect.TopLeft()));
4665
0
  maskCtx->Multiply(
4666
0
    gfxMatrix::Scaling(mParameters.mXScale, mParameters.mYScale));
4667
0
4668
0
  bool isPaintFinished = aMaskItem->PaintMask(mBuilder, maskCtx);
4669
0
4670
0
  RefPtr<ImageContainer> imgContainer =
4671
0
    imageData.CreateImageAndImageContainer();
4672
0
  if (!imgContainer) {
4673
0
    return;
4674
0
  }
4675
0
  maskLayer->SetContainer(imgContainer);
4676
0
4677
0
  if (isPaintFinished) {
4678
0
    *oldUserData = std::move(newUserData);
4679
0
  }
4680
0
  aLayer->SetMaskLayer(maskLayer);
4681
0
}
4682
4683
static bool
4684
IsScrollThumbLayer(nsDisplayItem* aItem)
4685
0
{
4686
0
  return aItem->GetType() == DisplayItemType::TYPE_OWN_LAYER &&
4687
0
         static_cast<nsDisplayOwnLayer*>(aItem)->IsScrollThumbLayer();
4688
0
}
4689
4690
template<typename ClearFn, typename SelectFn>
4691
static void
4692
ProcessDisplayItemMarker(DisplayItemEntryType aMarker,
4693
                         ClearFn ClearLayerSelectionIfNeeded,
4694
                         SelectFn SelectLayerIfNeeded)
4695
{
4696
  switch (aMarker) {
4697
    case DisplayItemEntryType::PUSH_TRANSFORM:
4698
    case DisplayItemEntryType::PUSH_OPACITY:
4699
      SelectLayerIfNeeded();
4700
      break;
4701
    case DisplayItemEntryType::POP_TRANSFORM:
4702
    case DisplayItemEntryType::POP_OPACITY:
4703
      ClearLayerSelectionIfNeeded();
4704
      break;
4705
    default:
4706
      break;
4707
  }
4708
}
4709
/*
4710
 * Iterate through the non-clip items in aList and its descendants.
4711
 * For each item we compute the effective clip rect. Each item is assigned
4712
 * to a layer. We invalidate the areas in PaintedLayers where an item
4713
 * has moved from one PaintedLayer to another. Also,
4714
 * aState->mInvalidPaintedContent is invalidated in every PaintedLayer.
4715
 * We set the clip rect for items that generated their own layer, and
4716
 * create a mask layer to do any rounded rect clipping.
4717
 * (PaintedLayers don't need a clip rect on the layer, we clip the items
4718
 * individually when we draw them.)
4719
 * We set the visible rect for all layers, although the actual setting
4720
 * of visible rects for some PaintedLayers is deferred until the calling
4721
 * of ContainerState::Finish.
4722
 */
4723
void
4724
ContainerState::ProcessDisplayItems(nsDisplayList* aList)
4725
0
{
4726
0
  AUTO_PROFILER_LABEL("ContainerState::ProcessDisplayItems", GRAPHICS);
4727
0
4728
0
  nsPoint topLeft(0, 0);
4729
0
4730
0
  int32_t maxLayers = gfxPrefs::MaxActiveLayers();
4731
0
  int layerCount = 0;
4732
0
4733
0
  if (!mManager->IsWidgetLayerManager()) {
4734
0
    mPaintedLayerDataTree.InitializeForInactiveLayer(
4735
0
      mContainerAnimatedGeometryRoot);
4736
0
  }
4737
0
4738
0
  AnimatedGeometryRoot* lastAnimatedGeometryRoot = nullptr;
4739
0
  nsPoint lastTopLeft;
4740
0
4741
0
  // Tracks the PaintedLayerData that the item will be accumulated in, if it is
4742
0
  // non-null.
4743
0
  PaintedLayerData* selectedLayer = nullptr;
4744
0
  AutoTArray<size_t, 2> opacityIndices;
4745
0
4746
0
  AnimatedGeometryRoot* containerAGR = nullptr;
4747
0
  const ActiveScrolledRoot* containerASR = nullptr;
4748
0
  RefPtr<TransformClipNode> transformNode = nullptr;
4749
0
4750
0
  const auto InTransform = [&]() { return transformNode; };
4751
0
4752
0
  const auto InOpacity = [&]() {
4753
0
    return selectedLayer && opacityIndices.Length() > 0;
4754
0
  };
4755
0
4756
0
  FLBDisplayItemIterator iter(mBuilder, aList, this);
4757
0
  while (iter.HasNext()) {
4758
0
    DisplayItemEntry e = iter.GetNextEntry();
4759
0
    DisplayItemEntryType marker = e.mType;
4760
0
    nsDisplayItem* item = e.mItem;
4761
0
    MOZ_ASSERT(item);
4762
0
    DisplayItemType itemType = item->GetType();
4763
0
4764
0
    const bool inEffect = InTransform() || InOpacity();
4765
0
4766
0
    if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
4767
0
      nsDisplayCompositorHitTestInfo* hitTestInfo =
4768
0
        static_cast<nsDisplayCompositorHitTestInfo*>(item);
4769
0
4770
0
      if (hitTestInfo->Area().IsEmpty()) {
4771
0
        continue;
4772
0
      }
4773
0
4774
0
      if (inEffect) {
4775
0
        // If this item is inside a flattened effect, everything below is
4776
0
        // unnecessary processing.
4777
0
        MOZ_ASSERT(selectedLayer);
4778
0
        selectedLayer->AccumulateHitTestInfo(this, hitTestInfo, transformNode);
4779
0
        continue;
4780
0
      }
4781
0
    }
4782
0
4783
0
    MOZ_ASSERT(item->GetType() != DisplayItemType::TYPE_WRAP_LIST);
4784
0
4785
0
    NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
4786
0
                 "items in a container layer should all have the same app "
4787
0
                 "units per dev pixel");
4788
0
4789
0
    if (mBuilder->NeedToForceTransparentSurfaceForItem(item)) {
4790
0
      aList->SetNeedsTransparentSurface();
4791
0
    }
4792
0
4793
0
    if (mParameters.mForEventsAndPluginsOnly && !item->GetChildren() &&
4794
0
        (itemType != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
4795
0
         itemType != DisplayItemType::TYPE_PLUGIN)) {
4796
0
      continue;
4797
0
    }
4798
0
4799
0
    LayerState layerState = LAYER_NONE;
4800
0
4801
0
    if (marker == DisplayItemEntryType::ITEM) {
4802
0
      layerState = item->GetLayerState(mBuilder, mManager, mParameters);
4803
0
4804
0
      if (layerState == LAYER_INACTIVE && nsDisplayItem::ForceActiveLayers()) {
4805
0
        layerState = LAYER_ACTIVE;
4806
0
      }
4807
0
    }
4808
0
4809
0
    bool forceInactive = false;
4810
0
    AnimatedGeometryRoot* animatedGeometryRoot;
4811
0
    const ActiveScrolledRoot* itemASR = nullptr;
4812
0
    const DisplayItemClipChain* layerClipChain = nullptr;
4813
0
4814
0
    if (mManager->IsWidgetLayerManager() && !inEffect) {
4815
0
      animatedGeometryRoot = item->GetAnimatedGeometryRoot();
4816
0
      itemASR = item->GetActiveScrolledRoot();
4817
0
      const DisplayItemClipChain* itemClipChain = item->GetClipChain();
4818
0
      if (itemClipChain && itemClipChain->mASR == itemASR &&
4819
0
          itemType != DisplayItemType::TYPE_STICKY_POSITION) {
4820
0
        layerClipChain = itemClipChain->mParent;
4821
0
      } else {
4822
0
        layerClipChain = itemClipChain;
4823
0
      }
4824
0
    } else if (inEffect) {
4825
0
      animatedGeometryRoot = containerAGR;
4826
0
      itemASR = containerASR;
4827
0
4828
0
      if (marker != DisplayItemEntryType::POP_TRANSFORM) {
4829
0
        item->FuseClipChainUpTo(mBuilder, containerASR);
4830
0
      }
4831
0
    } else {
4832
0
      animatedGeometryRoot = mContainerAnimatedGeometryRoot;
4833
0
      itemASR = mContainerASR;
4834
0
      item->FuseClipChainUpTo(mBuilder, mContainerASR);
4835
0
    }
4836
0
4837
0
    const DisplayItemClip& itemClip = item->GetClip();
4838
0
4839
0
    if (inEffect && marker == DisplayItemEntryType::ITEM) {
4840
0
      MOZ_ASSERT(selectedLayer);
4841
0
      selectedLayer->Accumulate(this,
4842
0
                                item,
4843
0
                                nsIntRect(),
4844
0
                                nsRect(),
4845
0
                                itemClip,
4846
0
                                layerState,
4847
0
                                aList,
4848
0
                                marker,
4849
0
                                opacityIndices,
4850
0
                                transformNode);
4851
0
      continue;
4852
0
    }
4853
0
4854
0
    if (animatedGeometryRoot == lastAnimatedGeometryRoot) {
4855
0
      topLeft = lastTopLeft;
4856
0
    } else {
4857
0
      lastTopLeft = topLeft =
4858
0
        (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
4859
0
      lastAnimatedGeometryRoot = animatedGeometryRoot;
4860
0
    }
4861
0
4862
0
    const ActiveScrolledRoot* scrollMetadataASR =
4863
0
      layerClipChain
4864
0
        ? ActiveScrolledRoot::PickDescendant(itemASR, layerClipChain->mASR)
4865
0
        : itemASR;
4866
0
4867
0
    const bool prerenderedTransform =
4868
0
      itemType == DisplayItemType::TYPE_TRANSFORM &&
4869
0
      static_cast<nsDisplayTransform*>(item)->MayBeAnimated(mBuilder);
4870
0
4871
0
    bool snap;
4872
0
    nsRect itemContent = item->GetBounds(mBuilder, &snap);
4873
0
4874
0
    if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
4875
0
      nsDisplayCompositorHitTestInfo* hitInfo =
4876
0
        static_cast<nsDisplayCompositorHitTestInfo*>(item);
4877
0
      itemContent = hitInfo->Area();
4878
0
    }
4879
0
4880
0
    nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
4881
0
    ParentLayerIntRect clipRect;
4882
0
    if (itemClip.HasClip()) {
4883
0
      const nsRect& itemClipRect = itemClip.GetClipRect();
4884
0
      itemContent.IntersectRect(itemContent, itemClipRect);
4885
0
      clipRect = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(itemClipRect));
4886
0
4887
0
      if (!prerenderedTransform && !IsScrollThumbLayer(item)) {
4888
0
        itemDrawRect.IntersectRect(itemDrawRect, clipRect.ToUnknownRect());
4889
0
      }
4890
0
4891
0
      clipRect.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
4892
0
    }
4893
0
4894
0
    if (marker == DisplayItemEntryType::POP_TRANSFORM) {
4895
0
      MOZ_ASSERT(transformNode);
4896
0
      transformNode = transformNode->Parent();
4897
0
    }
4898
0
4899
0
    if (transformNode) {
4900
0
      // If we are within transform, transform itemContent and itemDrawRect.
4901
0
      MOZ_ASSERT(transformNode);
4902
0
4903
0
      itemContent =
4904
0
        transformNode->TransformRect(itemContent, mAppUnitsPerDevPixel);
4905
0
4906
0
      itemDrawRect =
4907
0
        transformNode->TransformRect(itemDrawRect);
4908
0
    }
4909
0
4910
#ifdef DEBUG
4911
    nsRect bounds = itemContent;
4912
4913
    if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO || inEffect) {
4914
      bounds.SetEmpty();
4915
    }
4916
4917
    if (!bounds.IsEmpty() && itemASR != mContainerASR) {
4918
      if (Maybe<nsRect> clip =
4919
            item->GetClipWithRespectToASR(mBuilder, mContainerASR)) {
4920
        bounds = clip.ref();
4921
      }
4922
    }
4923
4924
    ((nsRect&)mAccumulatedChildBounds)
4925
      .UnionRect(mAccumulatedChildBounds, bounds);
4926
#endif
4927
4928
0
    nsIntRect itemVisibleRect = itemDrawRect;
4929
0
4930
0
    // We intersect the building rect with the clipped item bounds to get a
4931
0
    // tighter visible rect.
4932
0
    if (!prerenderedTransform) {
4933
0
      nsRect itemBuildingRect = item->GetBuildingRect();
4934
0
4935
0
      if (transformNode) {
4936
0
        itemBuildingRect =
4937
0
          transformNode->TransformRect(itemBuildingRect, mAppUnitsPerDevPixel);
4938
0
      }
4939
0
4940
0
      itemVisibleRect = itemVisibleRect.Intersect(
4941
0
        ScaleToOutsidePixels(itemBuildingRect, false));
4942
0
    }
4943
0
4944
0
    if (maxLayers != -1 && layerCount >= maxLayers) {
4945
0
      forceInactive = true;
4946
0
    }
4947
0
4948
0
    // Assign the item to a layer
4949
0
    bool treatInactiveItemAsActive =
4950
0
      (layerState == LAYER_INACTIVE &&
4951
0
       mLayerBuilder->GetContainingPaintedLayerData());
4952
0
    if (layerState == LAYER_ACTIVE_FORCE || treatInactiveItemAsActive ||
4953
0
        (!forceInactive &&
4954
0
         (layerState == LAYER_ACTIVE_EMPTY || layerState == LAYER_ACTIVE))) {
4955
0
4956
0
      layerCount++;
4957
0
4958
0
      // Currently we do not support flattening effects within nested inactive
4959
0
      // layer trees.
4960
0
      MOZ_ASSERT(selectedLayer == nullptr);
4961
0
      MOZ_ASSERT(marker == DisplayItemEntryType::ITEM);
4962
0
4963
0
      // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
4964
0
      // We should never see an empty layer with any visible content!
4965
0
      NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
4966
0
                     itemVisibleRect.IsEmpty(),
4967
0
                   "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
4968
0
4969
0
      // As long as the new layer isn't going to be a PaintedLayer,
4970
0
      // InvalidateForLayerChange doesn't need the new layer pointer.
4971
0
      // We also need to check the old data now, because BuildLayer
4972
0
      // can overwrite it.
4973
0
      DisplayItemData* oldData = mLayerBuilder->GetOldLayerForFrame(
4974
0
        item->Frame(), item->GetPerFrameKey());
4975
0
      InvalidateForLayerChange(item, nullptr, oldData);
4976
0
4977
0
      // If the item would have its own layer but is invisible, just hide it.
4978
0
      // Note that items without their own layers can't be skipped this
4979
0
      // way, since their PaintedLayer may decide it wants to draw them
4980
0
      // into its buffer even if they're currently covered.
4981
0
      if (itemVisibleRect.IsEmpty() &&
4982
0
          !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
4983
0
        continue;
4984
0
      }
4985
0
4986
0
      // 3D-transformed layers don't necessarily draw in the order in which
4987
0
      // they're added to their parent container layer.
4988
0
      bool mayDrawOutOfOrder =
4989
0
        itemType == DisplayItemType::TYPE_TRANSFORM &&
4990
0
        (item->Frame()->Combines3DTransformWithAncestors() ||
4991
0
         item->Frame()->Extend3DContext());
4992
0
4993
0
      // Let mPaintedLayerDataTree know about this item, so that
4994
0
      // FindPaintedLayerFor and FindOpaqueBackgroundColor are aware of this
4995
0
      // item, even though it's not in any PaintedLayerDataStack.
4996
0
      // Ideally we'd only need the "else" case here and have
4997
0
      // mPaintedLayerDataTree figure out the right clip from the animated
4998
0
      // geometry root that we give it, but it can't easily figure about
4999
0
      // overflow:hidden clips on ancestors just by looking at the frame.
5000
0
      // So we'll do a little hand holding and pass the clip instead of the
5001
0
      // visible rect for the two important cases.
5002
0
      nscolor uniformColor = NS_RGBA(0, 0, 0, 0);
5003
0
      nscolor* uniformColorPtr =
5004
0
        (mayDrawOutOfOrder || IsInInactiveLayer()) ? nullptr : &uniformColor;
5005
0
      nsIntRect clipRectUntyped;
5006
0
      nsIntRect* clipPtr = nullptr;
5007
0
      if (itemClip.HasClip()) {
5008
0
        clipRectUntyped = clipRect.ToUnknownRect();
5009
0
        clipPtr = &clipRectUntyped;
5010
0
      }
5011
0
5012
0
      bool hasScrolledClip =
5013
0
        layerClipChain && layerClipChain->mClip.HasClip() &&
5014
0
        (!ActiveScrolledRoot::IsAncestor(layerClipChain->mASR, itemASR) ||
5015
0
         itemType == DisplayItemType::TYPE_STICKY_POSITION);
5016
0
5017
0
      if (hasScrolledClip) {
5018
0
        // If the clip is scrolled, reserve just the area of the clip for
5019
0
        // layerization, so that elements outside the clip can still merge
5020
0
        // into the same layer.
5021
0
        const ActiveScrolledRoot* clipASR = layerClipChain->mASR;
5022
0
        AnimatedGeometryRoot* clipAGR =
5023
0
          mBuilder->AnimatedGeometryRootForASR(clipASR);
5024
0
        nsIntRect scrolledClipRect =
5025
0
          ScaleToNearestPixels(layerClipChain->mClip.GetClipRect()) +
5026
0
          mParameters.mOffset;
5027
0
        mPaintedLayerDataTree.AddingOwnLayer(
5028
0
          clipAGR, &scrolledClipRect, uniformColorPtr);
5029
0
      } else if (item->ShouldFixToViewport(mBuilder) && itemClip.HasClip() &&
5030
0
                 item->AnimatedGeometryRootForScrollMetadata() !=
5031
0
                   animatedGeometryRoot &&
5032
0
                 !nsLayoutUtils::UsesAsyncScrolling(item->Frame())) {
5033
0
        // This is basically the same as the case above, but for the non-APZ
5034
0
        // case. At the moment, when APZ is off, there is only the root ASR
5035
0
        // (because scroll frames without display ports don't create ASRs) and
5036
0
        // the whole clip chain is always just one fused clip.
5037
0
        // Bug 1336516 aims to change that and to remove this workaround.
5038
0
        AnimatedGeometryRoot* clipAGR =
5039
0
          item->AnimatedGeometryRootForScrollMetadata();
5040
0
        nsIntRect scrolledClipRect =
5041
0
          ScaleToNearestPixels(itemClip.GetClipRect()) + mParameters.mOffset;
5042
0
        mPaintedLayerDataTree.AddingOwnLayer(
5043
0
          clipAGR, &scrolledClipRect, uniformColorPtr);
5044
0
      } else if (IsScrollThumbLayer(item) && mManager->IsWidgetLayerManager()) {
5045
0
        // For scrollbar thumbs, the clip we care about is the clip added by the
5046
0
        // slider frame.
5047
0
        mPaintedLayerDataTree.AddingOwnLayer(
5048
0
          animatedGeometryRoot->mParentAGR, clipPtr, uniformColorPtr);
5049
0
      } else if (prerenderedTransform && mManager->IsWidgetLayerManager()) {
5050
0
        if (animatedGeometryRoot->mParentAGR) {
5051
0
          mPaintedLayerDataTree.AddingOwnLayer(
5052
0
            animatedGeometryRoot->mParentAGR, clipPtr, uniformColorPtr);
5053
0
        } else {
5054
0
          mPaintedLayerDataTree.AddingOwnLayer(
5055
0
            animatedGeometryRoot, nullptr, uniformColorPtr);
5056
0
        }
5057
0
      } else {
5058
0
        // Using itemVisibleRect here isn't perfect. itemVisibleRect can be
5059
0
        // larger or smaller than the potential bounds of item's contents in
5060
0
        // animatedGeometryRoot: It's too large if there's a clipped display
5061
0
        // port somewhere among item's contents (see bug 1147673), and it can
5062
0
        // be too small if the contents can move, because it only looks at the
5063
0
        // contents' current bounds and doesn't anticipate any animations.
5064
0
        // Time will tell whether this is good enough, or whether we need to do
5065
0
        // something more sophisticated here.
5066
0
        mPaintedLayerDataTree.AddingOwnLayer(
5067
0
          animatedGeometryRoot, &itemVisibleRect, uniformColorPtr);
5068
0
      }
5069
0
5070
0
      ContainerLayerParameters params = mParameters;
5071
0
      params.mBackgroundColor = uniformColor;
5072
0
      params.mLayerCreationHint = GetLayerCreationHint(animatedGeometryRoot);
5073
0
      params.mScrollMetadataASR = ActiveScrolledRoot::PickDescendant(
5074
0
        mContainerScrollMetadataASR, scrollMetadataASR);
5075
0
      params.mCompositorASR =
5076
0
        params.mScrollMetadataASR != mContainerScrollMetadataASR
5077
0
          ? params.mScrollMetadataASR
5078
0
          : mContainerCompositorASR;
5079
0
      if (itemType == DisplayItemType::TYPE_FIXED_POSITION) {
5080
0
        params.mCompositorASR = itemASR;
5081
0
      }
5082
0
5083
0
      if (itemType == DisplayItemType::TYPE_PERSPECTIVE) {
5084
0
        // Perspective items have a single child item, an nsDisplayTransform.
5085
0
        // If the perspective item is scrolled, but the perspective-inducing
5086
0
        // frame is outside the scroll frame (indicated by item->Frame()
5087
0
        // being outside that scroll frame), we have to take special care to
5088
0
        // make APZ scrolling work properly. APZ needs us to put the scroll
5089
0
        // frame's FrameMetrics on our child transform ContainerLayer instead.
5090
0
        // It's worth investigating whether this ASR adjustment can be done at
5091
0
        // display item creation time.
5092
0
        scrollMetadataASR = GetASRForPerspective(
5093
0
          scrollMetadataASR,
5094
0
          item->Frame()->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME));
5095
0
        params.mScrollMetadataASR = scrollMetadataASR;
5096
0
        itemASR = scrollMetadataASR;
5097
0
      }
5098
0
5099
0
      // Just use its layer.
5100
0
      // Set layerContentsVisibleRect.width/height to -1 to indicate we
5101
0
      // currently don't know. If BuildContainerLayerFor gets called by
5102
0
      // item->BuildLayer, this will be set to a proper rect.
5103
0
      nsIntRect layerContentsVisibleRect(0, 0, -1, -1);
5104
0
      params.mLayerContentsVisibleRect = &layerContentsVisibleRect;
5105
0
5106
0
      // If this display item wants to build inactive layers but we are treating
5107
0
      // it as active because we are already inside an inactive layer tree,
5108
0
      // we need to make sure that the display item's clip is reflected in
5109
0
      // FrameLayerBuilder::mInactiveLayerClip (which is normally set in
5110
0
      // AddPaintedDisplayItem() when entering an inactive layer tree).
5111
0
      // We intersect the display item's clip into any existing inactive layer
5112
0
      // clip.
5113
0
      const DisplayItemClip* originalInactiveClip = nullptr;
5114
0
      DisplayItemClip combinedInactiveClip;
5115
0
      if (treatInactiveItemAsActive) {
5116
0
        originalInactiveClip = mLayerBuilder->GetInactiveLayerClip();
5117
0
        if (originalInactiveClip) {
5118
0
          combinedInactiveClip = *originalInactiveClip;
5119
0
        }
5120
0
        DisplayItemClip nestedClip = item->GetClip();
5121
0
        if (nestedClip.HasClip()) {
5122
0
          nsRect nestedClipRect = nestedClip.NonRoundedIntersection();
5123
0
5124
0
          // Transform the nested clip to be relative to the same reference
5125
0
          // frame as the existing mInactiveLayerClip, so that we can intersect
5126
0
          // them below.
5127
0
          nestedClipRect = nsLayoutUtils::TransformFrameRectToAncestor(
5128
0
            item->ReferenceFrame(),
5129
0
            nestedClipRect,
5130
0
            mLayerBuilder->GetContainingPaintedLayerData()->mReferenceFrame);
5131
0
5132
0
          nestedClip.SetTo(nestedClipRect);
5133
0
          combinedInactiveClip.IntersectWith(nestedClip);
5134
0
          mLayerBuilder->SetInactiveLayerClip(&combinedInactiveClip);
5135
0
        }
5136
0
      }
5137
0
5138
0
      RefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, params);
5139
0
5140
0
      // If above we combined a nested clip into mInactiveLayerClip, restore
5141
0
      // the original inactive layer clip here.
5142
0
      if (treatInactiveItemAsActive) {
5143
0
        mLayerBuilder->SetInactiveLayerClip(originalInactiveClip);
5144
0
      }
5145
0
5146
0
      if (!ownLayer) {
5147
0
        continue;
5148
0
      }
5149
0
5150
0
      NS_ASSERTION(!ownLayer->AsPaintedLayer(),
5151
0
                   "Should never have created a dedicated Painted layer!");
5152
0
5153
0
      if (item->BackfaceIsHidden()) {
5154
0
        ownLayer->SetContentFlags(ownLayer->GetContentFlags() |
5155
0
                                  Layer::CONTENT_BACKFACE_HIDDEN);
5156
0
      } else {
5157
0
        ownLayer->SetContentFlags(ownLayer->GetContentFlags() &
5158
0
                                  ~Layer::CONTENT_BACKFACE_HIDDEN);
5159
0
      }
5160
0
5161
0
      nsRect invalid;
5162
0
      if (item->IsInvalid(invalid)) {
5163
0
        ownLayer->SetInvalidRectToVisibleRegion();
5164
0
      }
5165
0
5166
0
      // If it's not a ContainerLayer, we need to apply the scale transform
5167
0
      // ourselves.
5168
0
      if (!ownLayer->AsContainerLayer()) {
5169
0
        ownLayer->SetPostScale(mParameters.mXScale, mParameters.mYScale);
5170
0
      }
5171
0
5172
0
      // Update that layer's clip and visible rects.
5173
0
      NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
5174
0
      NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
5175
0
                   "We shouldn't have a FrameLayerBuilder-managed layer here!");
5176
0
      NS_ASSERTION(itemClip.HasClip() || itemClip.GetRoundedRectCount() == 0,
5177
0
                   "If we have rounded rects, we must have a clip rect");
5178
0
5179
0
      // It has its own layer. Update that layer's clip and visible rects.
5180
0
      ownLayer->SetClipRect(Nothing());
5181
0
      ownLayer->SetScrolledClip(Nothing());
5182
0
      ownLayer->SetAncestorMaskLayers({});
5183
0
      if (itemClip.HasClip()) {
5184
0
        ownLayer->SetClipRect(Some(clipRect));
5185
0
5186
0
        // rounded rectangle clipping using mask layers
5187
0
        // (must be done after visible rect is set on layer)
5188
0
        if (itemClip.GetRoundedRectCount() > 0) {
5189
0
          SetupMaskLayer(ownLayer, itemClip);
5190
0
        }
5191
0
      }
5192
0
5193
0
      if (hasScrolledClip) {
5194
0
        const DisplayItemClip& scrolledClip = layerClipChain->mClip;
5195
0
        LayerClip scrolledLayerClip;
5196
0
        scrolledLayerClip.SetClipRect(ViewAs<ParentLayerPixel>(
5197
0
          ScaleToNearestPixels(scrolledClip.GetClipRect()) +
5198
0
          mParameters.mOffset));
5199
0
        if (scrolledClip.GetRoundedRectCount() > 0) {
5200
0
          scrolledLayerClip.SetMaskLayerIndex(
5201
0
            SetupMaskLayerForScrolledClip(ownLayer.get(), scrolledClip));
5202
0
        }
5203
0
        ownLayer->SetScrolledClip(Some(scrolledLayerClip));
5204
0
      }
5205
0
5206
0
      if (item->GetType() == DisplayItemType::TYPE_MASK) {
5207
0
        MOZ_ASSERT(itemClip.GetRoundedRectCount() == 0);
5208
0
5209
0
        nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
5210
0
        SetupMaskLayerForCSSMask(ownLayer, maskItem);
5211
0
5212
0
        if (iter.PeekNext() && iter.PeekNext()->GetType() ==
5213
0
                                 DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
5214
0
          // Since we do build a layer for mask, there is no need for this
5215
0
          // scroll info layer anymore.
5216
0
          iter.GetNext();
5217
0
        }
5218
0
      }
5219
0
5220
0
      // Convert the visible rect to a region and give the item
5221
0
      // a chance to try restrict it further.
5222
0
      nsIntRegion itemVisibleRegion = itemVisibleRect;
5223
0
      nsRegion tightBounds = item->GetTightBounds(mBuilder, &snap);
5224
0
      if (!tightBounds.IsEmpty()) {
5225
0
        itemVisibleRegion.AndWith(ScaleToOutsidePixels(tightBounds, snap));
5226
0
      }
5227
0
5228
0
      ContainerLayer* oldContainer = ownLayer->GetParent();
5229
0
      if (oldContainer && oldContainer != mContainerLayer) {
5230
0
        oldContainer->RemoveChild(ownLayer);
5231
0
      }
5232
0
      NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
5233
0
                   "Layer already in list???");
5234
0
5235
0
      NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
5236
0
      newLayerEntry->mLayer = ownLayer;
5237
0
      newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot;
5238
0
      newLayerEntry->mASR = itemASR;
5239
0
      newLayerEntry->mScrollMetadataASR = scrollMetadataASR;
5240
0
      newLayerEntry->mClipChain = layerClipChain;
5241
0
      newLayerEntry->mLayerState = layerState;
5242
0
      if (itemType == DisplayItemType::TYPE_FIXED_POSITION) {
5243
0
        newLayerEntry->mIsFixedToRootScrollFrame =
5244
0
          item->Frame()->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
5245
0
          nsLayoutUtils::IsReallyFixedPos(item->Frame());
5246
0
      }
5247
0
5248
0
      // Don't attempt to flatten compnent alpha layers that are within
5249
0
      // a forced active layer, or an active transform;
5250
0
      if (itemType == DisplayItemType::TYPE_TRANSFORM ||
5251
0
          layerState == LAYER_ACTIVE_FORCE) {
5252
0
        newLayerEntry->mPropagateComponentAlphaFlattening = false;
5253
0
      }
5254
0
5255
0
      float contentXScale = 1.0f;
5256
0
      float contentYScale = 1.0f;
5257
0
      if (ContainerLayer* ownContainer = ownLayer->AsContainerLayer()) {
5258
0
        contentXScale = 1 / ownContainer->GetPreXScale();
5259
0
        contentYScale = 1 / ownContainer->GetPreYScale();
5260
0
      }
5261
0
      // nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
5262
0
      // We rely on this to ensure 3D transforms compute a reasonable
5263
0
      // layer visible region.
5264
0
      NS_ASSERTION(itemType != DisplayItemType::TYPE_TRANSFORM ||
5265
0
                     layerContentsVisibleRect.width >= 0,
5266
0
                   "Transform items must set layerContentsVisibleRect!");
5267
0
      if (mLayerBuilder->IsBuildingRetainedLayers()) {
5268
0
        newLayerEntry->mLayerContentsVisibleRect = layerContentsVisibleRect;
5269
0
        if (itemType == DisplayItemType::TYPE_PERSPECTIVE ||
5270
0
            (itemType == DisplayItemType::TYPE_TRANSFORM &&
5271
0
             (item->Frame()->Extend3DContext() ||
5272
0
              item->Frame()->Combines3DTransformWithAncestors() ||
5273
0
              item->Frame()->HasPerspective()))) {
5274
0
          // Give untransformed visible region as outer visible region
5275
0
          // to avoid failure caused by singular transforms.
5276
0
          newLayerEntry->mUntransformedVisibleRegion = true;
5277
0
          newLayerEntry->mVisibleRegion =
5278
0
            item->GetBuildingRectForChildren().ScaleToOutsidePixels(
5279
0
              contentXScale, contentYScale, mAppUnitsPerDevPixel);
5280
0
        } else {
5281
0
          newLayerEntry->mVisibleRegion = itemVisibleRegion;
5282
0
        }
5283
0
        newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(
5284
0
          item,
5285
0
          animatedGeometryRoot,
5286
0
          itemASR,
5287
0
          itemClip,
5288
0
          aList,
5289
0
          &newLayerEntry->mHideAllLayersBelow,
5290
0
          &newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
5291
0
      } else {
5292
0
        bool useChildrenVisible = itemType == DisplayItemType::TYPE_TRANSFORM &&
5293
0
                                  (item->Frame()->IsPreserve3DLeaf() ||
5294
0
                                   item->Frame()->HasPerspective());
5295
0
        const nsIntRegion& visible =
5296
0
          useChildrenVisible
5297
0
            ? item->GetBuildingRectForChildren().ScaleToOutsidePixels(
5298
0
                contentXScale, contentYScale, mAppUnitsPerDevPixel)
5299
0
            : itemVisibleRegion;
5300
0
5301
0
        SetOuterVisibleRegionForLayer(ownLayer,
5302
0
                                      visible,
5303
0
                                      layerContentsVisibleRect.width >= 0
5304
0
                                        ? &layerContentsVisibleRect
5305
0
                                        : nullptr,
5306
0
                                      useChildrenVisible);
5307
0
      }
5308
0
      if (itemType == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
5309
0
        nsDisplayScrollInfoLayer* scrollItem =
5310
0
          static_cast<nsDisplayScrollInfoLayer*>(item);
5311
0
        newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false;
5312
0
        newLayerEntry->mBaseScrollMetadata =
5313
0
          scrollItem->ComputeScrollMetadata(ownLayer->Manager(), mParameters);
5314
0
      } else if ((itemType == DisplayItemType::TYPE_SUBDOCUMENT ||
5315
0
                  itemType == DisplayItemType::TYPE_ZOOM ||
5316
0
                  itemType == DisplayItemType::TYPE_RESOLUTION) &&
5317
0
                 gfxPrefs::LayoutUseContainersForRootFrames()) {
5318
0
        newLayerEntry->mBaseScrollMetadata =
5319
0
          static_cast<nsDisplaySubDocument*>(item)->ComputeScrollMetadata(
5320
0
            ownLayer->Manager(), mParameters);
5321
0
      }
5322
0
5323
0
      /**
5324
0
       * No need to allocate geometry for items that aren't
5325
0
       * part of a PaintedLayer.
5326
0
       */
5327
0
      if (ownLayer->Manager() == mLayerBuilder->GetRetainingLayerManager()) {
5328
0
        oldData = mLayerBuilder->GetOldLayerForFrame(item->Frame(),
5329
0
                                                     item->GetPerFrameKey());
5330
0
        mLayerBuilder->StoreDataForFrame(item, ownLayer, layerState, oldData);
5331
0
      }
5332
0
    } else {
5333
0
      const bool backfaceHidden = item->In3DContextAndBackfaceIsHidden();
5334
0
      const nsIFrame* referenceFrame = item->ReferenceFrame();
5335
0
5336
0
      PaintedLayerData* paintedLayerData = selectedLayer;
5337
0
5338
0
      if (!paintedLayerData) {
5339
0
        paintedLayerData = mPaintedLayerDataTree.FindPaintedLayerFor(
5340
0
          animatedGeometryRoot,
5341
0
          itemASR,
5342
0
          layerClipChain,
5343
0
          itemVisibleRect,
5344
0
          backfaceHidden,
5345
0
          [&](PaintedLayerData* aData) {
5346
0
            NewPaintedLayerData(aData,
5347
0
                                animatedGeometryRoot,
5348
0
                                itemASR,
5349
0
                                layerClipChain,
5350
0
                                scrollMetadataASR,
5351
0
                                topLeft,
5352
0
                                referenceFrame,
5353
0
                                backfaceHidden);
5354
0
          });
5355
0
      }
5356
0
      MOZ_ASSERT(paintedLayerData);
5357
0
5358
0
      if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
5359
0
        nsDisplayCompositorHitTestInfo* hitTestInfo =
5360
0
          static_cast<nsDisplayCompositorHitTestInfo*>(item);
5361
0
        MOZ_ASSERT(!transformNode);
5362
0
        paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo, nullptr);
5363
0
      } else {
5364
0
        paintedLayerData->Accumulate(this,
5365
0
                                     item,
5366
0
                                     itemVisibleRect,
5367
0
                                     itemContent,
5368
0
                                     itemClip,
5369
0
                                     layerState,
5370
0
                                     aList,
5371
0
                                     marker,
5372
0
                                     opacityIndices,
5373
0
                                     transformNode);
5374
0
5375
0
        if (!paintedLayerData->mLayer) {
5376
0
          // Try to recycle the old layer of this display item.
5377
0
          RefPtr<PaintedLayer> layer = AttemptToRecyclePaintedLayer(
5378
0
            animatedGeometryRoot, item, topLeft, referenceFrame);
5379
0
          if (layer) {
5380
0
            paintedLayerData->mLayer = layer;
5381
0
5382
0
            PaintedDisplayItemLayerUserData* userData =
5383
0
              GetPaintedDisplayItemLayerUserData(layer);
5384
0
            paintedLayerData->mAssignedDisplayItems.reserve(
5385
0
              userData->mLastItemCount);
5386
0
5387
0
            NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
5388
0
                         "Layer already in list???");
5389
0
            mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer =
5390
0
              layer.forget();
5391
0
          }
5392
0
        }
5393
0
      }
5394
0
5395
0
      const auto ClearLayerSelectionIfNeeded = [&]() {
5396
0
        if (!InOpacity() && !InTransform()) {
5397
0
          selectedLayer = nullptr;
5398
0
          containerAGR = nullptr;
5399
0
          containerASR = nullptr;
5400
0
        }
5401
0
      };
5402
0
5403
0
      const auto SelectLayerIfNeeded = [&]() {
5404
0
        if (!selectedLayer) {
5405
0
          selectedLayer = paintedLayerData;
5406
0
          containerAGR = item->GetAnimatedGeometryRoot();
5407
0
          containerASR = item->GetActiveScrolledRoot();
5408
0
        }
5409
0
      };
5410
0
5411
0
      if (marker == DisplayItemEntryType::PUSH_TRANSFORM) {
5412
0
        nsDisplayTransform* transform = static_cast<nsDisplayTransform*>(item);
5413
0
5414
0
        const Matrix4x4Flagged& matrix = transform->GetTransformForRendering();
5415
0
5416
0
        Maybe<gfx::IntRect> clip;
5417
0
        if (itemClip.HasClip()) {
5418
0
          const nsRect nonRoundedClip = itemClip.NonRoundedIntersection();
5419
0
          clip.emplace(nonRoundedClip.ToNearestPixels(mAppUnitsPerDevPixel));
5420
0
        }
5421
0
5422
0
        transformNode = new TransformClipNode(transformNode, matrix, clip);
5423
0
      }
5424
0
5425
0
      ProcessDisplayItemMarker(
5426
0
        marker, ClearLayerSelectionIfNeeded, SelectLayerIfNeeded);
5427
0
    }
5428
0
5429
0
    nsDisplayList* childItems = item->GetSameCoordinateSystemChildren();
5430
0
    if (childItems && childItems->NeedsTransparentSurface()) {
5431
0
      aList->SetNeedsTransparentSurface();
5432
0
    }
5433
0
  }
5434
0
5435
0
  MOZ_ASSERT(selectedLayer == nullptr);
5436
0
}
5437
5438
void
5439
ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
5440
                                         PaintedLayer* aNewLayer,
5441
                                         DisplayItemData* aData)
5442
0
{
5443
0
  NS_ASSERTION(aItem->GetPerFrameKey(),
5444
0
               "Display items that render using Thebes must have a key");
5445
0
  Layer* oldLayer = aData ? aData->mLayer.get() : nullptr;
5446
0
  if (aNewLayer != oldLayer && oldLayer) {
5447
0
    // The item has changed layers.
5448
0
    // Invalidate the old bounds in the old layer and new bounds in the new
5449
0
    // layer.
5450
0
    PaintedLayer* t = oldLayer->AsPaintedLayer();
5451
0
    if (t && aData->mGeometry) {
5452
0
    // Note that whenever the layer's scale changes, we invalidate the whole
5453
0
    // thing, so it doesn't matter whether we are using the old scale at last
5454
0
    // paint or a new scale here
5455
#ifdef MOZ_DUMP_PAINTING
5456
      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
5457
        printf_stderr("Display item type %s(%p) changed layers %p to %p!\n",
5458
                      aItem->Name(),
5459
                      aItem->Frame(),
5460
                      t,
5461
                      aNewLayer);
5462
      }
5463
#endif
5464
      InvalidatePreTransformRect(t,
5465
0
                                 aData->mGeometry->ComputeInvalidationRegion(),
5466
0
                                 aData->mClip,
5467
0
                                 mLayerBuilder->GetLastPaintOffset(t),
5468
0
                                 aData->mTransform);
5469
0
    }
5470
0
    // Clear the old geometry so that invalidation thinks the item has been
5471
0
    // added this paint.
5472
0
    aData->mGeometry = nullptr;
5473
0
  }
5474
0
}
5475
5476
static nsRect
5477
GetInvalidationRect(nsDisplayItemGeometry* aGeometry,
5478
                    const DisplayItemClip& aClip,
5479
                    TransformClipNode* aTransform,
5480
                    const int32_t aA2D)
5481
0
{
5482
0
  const nsRect& rect = aGeometry->ComputeInvalidationRegion();
5483
0
  const nsRect clipped = aClip.ApplyNonRoundedIntersection(rect);
5484
0
5485
0
  if (aTransform) {
5486
0
    return aTransform->TransformRect(clipped, aA2D);
5487
0
  }
5488
0
5489
0
  return clipped;
5490
0
}
5491
5492
void
5493
FrameLayerBuilder::ComputeGeometryChangeForItem(DisplayItemData* aData)
5494
0
{
5495
0
  nsDisplayItem* item = aData->mItem;
5496
0
  PaintedLayer* paintedLayer = aData->mLayer->AsPaintedLayer();
5497
0
  // If aData->mOptLayer is presence, means this item has been optimized to the
5498
0
  // separate layer. Thus, skip geometry change calculation.
5499
0
  if (aData->mOptLayer || !item || !paintedLayer) {
5500
0
    aData->EndUpdate();
5501
0
    return;
5502
0
  }
5503
0
5504
0
  // If we're a reused display item, then we can't be invalid, so no need to
5505
0
  // do an in-depth comparison. If we haven't previously stored geometry
5506
0
  // for this item (if it was an active layer), then we can't skip this
5507
0
  // yet.
5508
0
  nsAutoPtr<nsDisplayItemGeometry> geometry;
5509
0
  if (aData->mReusedItem && aData->mGeometry) {
5510
0
    aData->EndUpdate();
5511
0
    return;
5512
0
  }
5513
0
5514
0
  PaintedDisplayItemLayerUserData* layerData =
5515
0
    static_cast<PaintedDisplayItemLayerUserData*>(
5516
0
      aData->mLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
5517
0
  nsPoint shift = layerData->mAnimatedGeometryRootOrigin -
5518
0
                  layerData->mLastAnimatedGeometryRootOrigin;
5519
0
5520
0
  if (aData->mTransform) {
5521
0
    // If this display item is inside a flattened transform, the shift is
5522
0
    // already included in the root transform.
5523
0
    shift = nsPoint();
5524
0
  }
5525
0
5526
0
  const DisplayItemClip& clip = item->GetClip();
5527
0
  const int32_t appUnitsPerDevPixel = layerData->mAppUnitsPerDevPixel;
5528
0
5529
0
  // If the frame is marked as invalidated, and didn't specify a rect to
5530
0
  // invalidate then we want to invalidate both the old and new bounds,
5531
0
  // otherwise we only want to invalidate the changed areas. If we do get an
5532
0
  // invalid rect, then we want to add this on top of the change areas.
5533
0
  nsRect invalid;
5534
0
  nsIntRegion invalidPixels;
5535
0
5536
0
  if (!aData->mGeometry) {
5537
0
    // This item is being added for the first time, invalidate its entire area.
5538
0
    geometry = item->AllocateGeometry(mDisplayListBuilder);
5539
0
5540
0
    const nsRect bounds = GetInvalidationRect(
5541
0
      geometry, clip, aData->mTransform, appUnitsPerDevPixel);
5542
0
5543
0
    invalidPixels = bounds.ScaleToOutsidePixels(
5544
0
      layerData->mXScale, layerData->mYScale, appUnitsPerDevPixel);
5545
#ifdef MOZ_DUMP_PAINTING
5546
    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
5547
      printf_stderr("Display item type %s(%p) added to layer %p!\n",
5548
                    item->Name(),
5549
                    item->Frame(),
5550
                    aData->mLayer.get());
5551
    }
5552
#endif
5553
0
  } else if (aData->mIsInvalid ||
5554
0
             (item->IsInvalid(invalid) && invalid.IsEmpty())) {
5555
0
    // Layout marked item/frame as needing repainting (without an explicit
5556
0
    // rect), invalidate the entire old and new areas.
5557
0
    geometry = item->AllocateGeometry(mDisplayListBuilder);
5558
0
5559
0
    nsRect oldArea = GetInvalidationRect(aData->mGeometry,
5560
0
                                         aData->mClip,
5561
0
                                         aData->mOldTransform,
5562
0
                                         appUnitsPerDevPixel);
5563
0
    oldArea.MoveBy(shift);
5564
0
5565
0
    nsRect newArea = GetInvalidationRect(
5566
0
      geometry, clip, aData->mTransform, appUnitsPerDevPixel);
5567
0
5568
0
    nsRegion combined;
5569
0
    combined.Or(oldArea, newArea);
5570
0
    invalidPixels = combined.ScaleToOutsidePixels(
5571
0
      layerData->mXScale, layerData->mYScale, appUnitsPerDevPixel);
5572
#ifdef MOZ_DUMP_PAINTING
5573
    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
5574
      printf_stderr("Display item type %s(%p) (in layer %p) belongs to an "
5575
                    "invalidated frame!\n",
5576
                    item->Name(),
5577
                    item->Frame(),
5578
                    aData->mLayer.get());
5579
    }
5580
#endif
5581
0
  } else {
5582
0
    // Let the display item check for geometry changes and decide what needs to
5583
0
    // be repainted.
5584
0
    const nsRegion& changedFrameInvalidations =
5585
0
      aData->GetChangedFrameInvalidations();
5586
0
5587
0
    aData->mGeometry->MoveBy(shift);
5588
0
5589
0
    nsRegion combined;
5590
0
    item->ComputeInvalidationRegion(
5591
0
      mDisplayListBuilder, aData->mGeometry, &combined);
5592
0
5593
0
    // Only allocate a new geometry object if something actually changed,
5594
0
    // otherwise the existing one should be fine. We always reallocate for
5595
0
    // inactive layers, since these types don't implement
5596
0
    // ComputeInvalidateRegion (and rely on the ComputeDifferences call in
5597
0
    // AddPaintedDisplayItem instead).
5598
0
    if (!combined.IsEmpty() || aData->mLayerState == LAYER_INACTIVE ||
5599
0
        item->NeedsGeometryUpdates()) {
5600
0
      geometry = item->AllocateGeometry(mDisplayListBuilder);
5601
0
    }
5602
0
5603
0
    aData->mClip.AddOffsetAndComputeDifference(
5604
0
      shift,
5605
0
      aData->mGeometry->ComputeInvalidationRegion(),
5606
0
      clip,
5607
0
      geometry ? geometry->ComputeInvalidationRegion()
5608
0
               : aData->mGeometry->ComputeInvalidationRegion(),
5609
0
      &combined);
5610
0
5611
0
    // Add in any rect that the frame specified
5612
0
    combined.Or(combined, invalid);
5613
0
    combined.Or(combined, changedFrameInvalidations);
5614
0
5615
0
    // Restrict invalidation to the clipped region
5616
0
    nsRegion clipRegion;
5617
0
    if (clip.ComputeRegionInClips(&aData->mClip, shift, &clipRegion)) {
5618
0
      combined.And(combined, clipRegion);
5619
0
    }
5620
0
5621
0
    invalidPixels = combined.ToOutsidePixels(appUnitsPerDevPixel);
5622
0
5623
0
    if (aData->mTransform) {
5624
0
      invalidPixels = aData->mTransform->TransformRegion(invalidPixels);
5625
0
    }
5626
0
5627
0
    invalidPixels.ScaleRoundOut(layerData->mXScale, layerData->mYScale);
5628
0
5629
#ifdef MOZ_DUMP_PAINTING
5630
    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
5631
      if (!combined.IsEmpty()) {
5632
        printf_stderr(
5633
          "Display item type %s(%p) (in layer %p) changed geometry!\n",
5634
          item->Name(),
5635
          item->Frame(),
5636
          aData->mLayer.get());
5637
      }
5638
    }
5639
#endif
5640
  }
5641
0
5642
0
  if (!invalidPixels.IsEmpty()) {
5643
0
    InvalidatePostTransformRegion(
5644
0
      paintedLayer, invalidPixels, layerData->mTranslation);
5645
0
  }
5646
0
5647
0
  aData->EndUpdate(geometry);
5648
0
}
5649
5650
void
5651
FrameLayerBuilder::AddPaintedDisplayItem(PaintedLayerData* aLayerData,
5652
                                         AssignedDisplayItem& aItem,
5653
                                         ContainerState& aContainerState,
5654
                                         Layer* aLayer)
5655
0
{
5656
0
  PaintedLayer* layer = aLayerData->mLayer;
5657
0
  PaintedDisplayItemLayerUserData* paintedData =
5658
0
    static_cast<PaintedDisplayItemLayerUserData*>(
5659
0
      layer->GetUserData(&gPaintedDisplayItemLayerUserData));
5660
0
  RefPtr<BasicLayerManager> tempManager;
5661
0
  nsIntRect intClip;
5662
0
  bool hasClip = false;
5663
0
  if (aItem.mLayerState != LAYER_NONE) {
5664
0
    if (aItem.mDisplayItemData) {
5665
0
      tempManager = aItem.mDisplayItemData->mInactiveManager;
5666
0
5667
0
      // We need to grab these before updating the DisplayItemData because it
5668
0
      // will overwrite them.
5669
0
      nsRegion clip;
5670
0
      if (aItem.mItem->GetClip().ComputeRegionInClips(
5671
0
            &aItem.mDisplayItemData->GetClip(),
5672
0
            aLayerData->mAnimatedGeometryRootOffset -
5673
0
              paintedData->mLastAnimatedGeometryRootOrigin,
5674
0
            &clip)) {
5675
0
        intClip = clip.GetBounds().ScaleToOutsidePixels(
5676
0
          paintedData->mXScale,
5677
0
          paintedData->mYScale,
5678
0
          paintedData->mAppUnitsPerDevPixel);
5679
0
      }
5680
0
    }
5681
0
    if (!tempManager) {
5682
0
      tempManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
5683
0
    }
5684
0
  }
5685
0
5686
0
  if (layer->Manager() == mRetainingManager) {
5687
0
    DisplayItemData* data = aItem.mDisplayItemData;
5688
0
    if (data && !data->mUsed) {
5689
0
      data->BeginUpdate(
5690
0
        layer, aItem.mLayerState, aItem.mItem, aItem.mReused, aItem.mMerged);
5691
0
    } else {
5692
0
      if (data && data->mUsed) {
5693
0
        // If the DID has already been used (by a previously merged frame,
5694
0
        // which is not merged this paint) we must create a new DID for the
5695
0
        // item.
5696
0
        aItem.mItem->SetDisplayItemData(nullptr, nullptr);
5697
0
      }
5698
0
      data = StoreDataForFrame(aItem.mItem, layer, aItem.mLayerState, nullptr);
5699
0
    }
5700
0
    data->mInactiveManager = tempManager;
5701
0
    // We optimized this PaintedLayer into a ColorLayer/ImageLayer. Store the
5702
0
    // optimized layer here.
5703
0
    if (aLayer != layer) {
5704
0
      data->mOptLayer = aLayer;
5705
0
    }
5706
0
5707
0
    data->mOldTransform = data->mTransform;
5708
0
    data->mTransform = aItem.mTransform;
5709
0
  }
5710
0
5711
0
  if (tempManager) {
5712
0
    FLB_LOG_PAINTED_LAYER_DECISION(
5713
0
      aLayerData, "Creating nested FLB for item %p\n", aItem.mItem);
5714
0
    FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
5715
0
    layerBuilder->Init(mDisplayListBuilder,
5716
0
                       tempManager,
5717
0
                       aLayerData,
5718
0
                       true,
5719
0
                       &aItem.mItem->GetClip());
5720
0
5721
0
    tempManager->BeginTransaction();
5722
0
    if (mRetainingManager) {
5723
0
      layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
5724
0
    }
5725
0
5726
0
    UniquePtr<LayerProperties> props(
5727
0
      LayerProperties::CloneFrom(tempManager->GetRoot()));
5728
0
    RefPtr<Layer> tmpLayer = aItem.mItem->BuildLayer(
5729
0
      mDisplayListBuilder, tempManager, ContainerLayerParameters());
5730
0
    // We have no easy way of detecting if this transaction will ever actually
5731
0
    // get finished. For now, I've just silenced the warning with nested
5732
0
    // transactions in BasicLayers.cpp
5733
0
    if (!tmpLayer) {
5734
0
      tempManager->EndTransaction(nullptr, nullptr);
5735
0
      tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
5736
0
      aItem.mItem = nullptr;
5737
0
      return;
5738
0
    }
5739
0
5740
0
    bool snap;
5741
0
    nsRect visibleRect = aItem.mItem->GetBuildingRect().Intersect(
5742
0
      aItem.mItem->GetBounds(mDisplayListBuilder, &snap));
5743
0
    nsIntRegion rgn =
5744
0
      visibleRect.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
5745
0
5746
0
    // Convert the visible rect to a region and give the item
5747
0
    // a chance to try restrict it further.
5748
0
    nsRegion tightBounds =
5749
0
      aItem.mItem->GetTightBounds(mDisplayListBuilder, &snap);
5750
0
    if (!tightBounds.IsEmpty()) {
5751
0
      rgn.AndWith(
5752
0
        tightBounds.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel));
5753
0
    }
5754
0
    SetOuterVisibleRegion(tmpLayer, &rgn);
5755
0
5756
0
    DisplayItemData* data = nullptr;
5757
0
    // If BuildLayer didn't call BuildContainerLayerFor, then our new layer
5758
0
    // won't have been stored in layerBuilder. Manually add it now.
5759
0
    if (mRetainingManager) {
5760
#ifdef DEBUG_DISPLAY_ITEM_DATA
5761
      LayerManagerData* parentLmd = static_cast<LayerManagerData*>(
5762
        layer->Manager()->GetUserData(&gLayerManagerUserData));
5763
      LayerManagerData* lmd = static_cast<LayerManagerData*>(
5764
        tempManager->GetUserData(&gLayerManagerUserData));
5765
      lmd->mParent = parentLmd;
5766
#endif
5767
      data =
5768
0
        layerBuilder->GetDisplayItemDataForManager(aItem.mItem, tempManager);
5769
0
      data = layerBuilder->StoreDataForFrame(
5770
0
        aItem.mItem, tmpLayer, LAYER_ACTIVE, data);
5771
0
      data->mOldTransform = data->mTransform;
5772
0
      data->mTransform = aItem.mTransform;
5773
0
    }
5774
0
5775
0
    tempManager->SetRoot(tmpLayer);
5776
0
    layerBuilder->WillEndTransaction();
5777
0
    tempManager->AbortTransaction();
5778
0
5779
0
    if (gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint()) {
5780
0
      fprintf_stderr(
5781
0
        gfxUtils::sDumpPaintFile,
5782
0
        "Basic layer tree for painting contents of display item %s(%p):\n",
5783
0
        aItem.mItem->Name(),
5784
0
        aItem.mItem->Frame());
5785
0
      std::stringstream stream;
5786
0
      tempManager->Dump(stream, "", gfxEnv::DumpPaintToFile());
5787
0
      fprint_stderr(
5788
0
        gfxUtils::sDumpPaintFile,
5789
0
        stream); // not a typo, fprint_stderr declared in LayersLogging.h
5790
0
    }
5791
0
5792
0
    nsIntPoint offset =
5793
0
      GetLastPaintOffset(layer) - GetTranslationForPaintedLayer(layer);
5794
0
    props->MoveBy(-offset);
5795
0
    // Effective transforms are needed by ComputeDifferences().
5796
0
    tmpLayer->ComputeEffectiveTransforms(Matrix4x4());
5797
0
    nsIntRegion invalid;
5798
0
    if (!props->ComputeDifferences(tmpLayer, invalid, nullptr)) {
5799
0
      nsRect visible = aItem.mItem->Frame()->GetVisualOverflowRect();
5800
0
      invalid = visible.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
5801
0
    }
5802
0
    if (aItem.mLayerState == LAYER_SVG_EFFECTS) {
5803
0
      invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(
5804
0
        aItem.mItem->Frame(), aItem.mItem->ToReferenceFrame(), invalid);
5805
0
    }
5806
0
    if (!invalid.IsEmpty()) {
5807
#ifdef MOZ_DUMP_PAINTING
5808
      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
5809
        printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has "
5810
                      "an invalid region - invalidating layer %p\n",
5811
                      tempManager.get(),
5812
                      aItem.mItem->Name(),
5813
                      aItem.mItem->Frame(),
5814
                      layer);
5815
      }
5816
#endif
5817
5818
0
      if (data && data->mTransform) {
5819
0
        invalid = data->mTransform->TransformRegion(invalid);
5820
0
      }
5821
0
5822
0
      invalid.ScaleRoundOut(paintedData->mXScale, paintedData->mYScale);
5823
0
5824
0
      if (hasClip) {
5825
0
        invalid.And(invalid, intClip);
5826
0
      }
5827
0
5828
0
      InvalidatePostTransformRegion(
5829
0
        layer, invalid, GetTranslationForPaintedLayer(layer));
5830
0
    }
5831
0
  }
5832
0
  aItem.mInactiveLayerManager = tempManager;
5833
0
}
5834
5835
DisplayItemData*
5836
FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem,
5837
                                     Layer* aLayer,
5838
                                     LayerState aState,
5839
                                     DisplayItemData* aData)
5840
0
{
5841
0
  if (aData) {
5842
0
    if (!aData->mUsed) {
5843
0
      aData->BeginUpdate(aLayer, aState, false, aItem);
5844
0
    }
5845
0
    return aData;
5846
0
  }
5847
0
5848
0
  LayerManagerData* lmd = static_cast<LayerManagerData*>(
5849
0
    mRetainingManager->GetUserData(&gLayerManagerUserData));
5850
0
5851
0
  RefPtr<DisplayItemData> data = new (aItem->Frame()->PresContext())
5852
0
    DisplayItemData(lmd, aItem->GetPerFrameKey(), aLayer);
5853
0
5854
0
  data->BeginUpdate(aLayer, aState, true, aItem);
5855
0
5856
0
  lmd->mDisplayItems.push_back(data);
5857
0
  return data;
5858
0
}
5859
5860
void
5861
FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
5862
                                     uint32_t aDisplayItemKey,
5863
                                     Layer* aLayer,
5864
                                     LayerState aState)
5865
0
{
5866
0
  DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey);
5867
0
  if (oldData && oldData->mFrameList.Length() == 1) {
5868
0
    oldData->BeginUpdate(aLayer, aState, false);
5869
0
    return;
5870
0
  }
5871
0
5872
0
  LayerManagerData* lmd = static_cast<LayerManagerData*>(
5873
0
    mRetainingManager->GetUserData(&gLayerManagerUserData));
5874
0
5875
0
  RefPtr<DisplayItemData> data = new (aFrame->PresContext())
5876
0
    DisplayItemData(lmd, aDisplayItemKey, aLayer, aFrame);
5877
0
5878
0
  data->BeginUpdate(aLayer, aState, true);
5879
0
5880
0
  lmd->mDisplayItems.push_back(data);
5881
0
}
5882
5883
AssignedDisplayItem::AssignedDisplayItem(
5884
  nsDisplayItem* aItem,
5885
  LayerState aLayerState,
5886
  DisplayItemData* aData,
5887
  const nsRect& aContentRect,
5888
  DisplayItemEntryType aType,
5889
  const bool aHasOpacity,
5890
  const RefPtr<TransformClipNode>& aTransform)
5891
  : mItem(aItem)
5892
  , mLayerState(aLayerState)
5893
  , mDisplayItemData(aData)
5894
  , mContentRect(aContentRect)
5895
  , mTransform(aTransform)
5896
  , mType(aType)
5897
  , mReused(aItem->IsReused())
5898
  , mMerged(aItem->HasMergedFrames())
5899
  , mHasOpacity(aHasOpacity)
5900
  , mHasTransform(aTransform)
5901
  , mHasPaintRect(aItem->HasPaintRect())
5902
0
{
5903
0
}
5904
5905
AssignedDisplayItem::~AssignedDisplayItem()
5906
0
{
5907
0
  if (mInactiveLayerManager) {
5908
0
    mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
5909
0
  }
5910
0
}
5911
5912
nsIntPoint
5913
FrameLayerBuilder::GetLastPaintOffset(PaintedLayer* aLayer)
5914
0
{
5915
0
  PaintedDisplayItemLayerUserData* layerData =
5916
0
    GetPaintedDisplayItemLayerUserData(aLayer);
5917
0
  MOZ_ASSERT(layerData);
5918
0
  if (layerData->mHasExplicitLastPaintOffset) {
5919
0
    return layerData->mLastPaintOffset;
5920
0
  }
5921
0
  return GetTranslationForPaintedLayer(aLayer);
5922
0
}
5923
5924
bool
5925
FrameLayerBuilder::CheckInLayerTreeCompressionMode()
5926
0
{
5927
0
  if (mInLayerTreeCompressionMode) {
5928
0
    return true;
5929
0
  }
5930
0
5931
0
  // If we wanted to be in layer tree compression mode, but weren't, then
5932
0
  // scheduled a delayed repaint where we will be.
5933
0
  mRootPresContext->PresShell()->GetRootFrame()->SchedulePaint(
5934
0
    nsIFrame::PAINT_DELAYED_COMPRESS, false);
5935
0
5936
0
  return false;
5937
0
}
5938
5939
void
5940
ContainerState::CollectOldLayers()
5941
0
{
5942
0
  for (Layer* layer = mContainerLayer->GetFirstChild(); layer;
5943
0
       layer = layer->GetNextSibling()) {
5944
0
    NS_ASSERTION(!layer->HasUserData(&gMaskLayerUserData),
5945
0
                 "Mask layers should not be part of the layer tree.");
5946
0
    if (layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
5947
0
      NS_ASSERTION(layer->AsPaintedLayer(), "Wrong layer type");
5948
0
      mPaintedLayersAvailableForRecycling.PutEntry(
5949
0
        static_cast<PaintedLayer*>(layer));
5950
0
    }
5951
0
5952
0
    if (Layer* maskLayer = layer->GetMaskLayer()) {
5953
0
      NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
5954
0
                   "Could not recycle mask layer, unsupported layer type.");
5955
0
      mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Nothing()),
5956
0
                                   static_cast<ImageLayer*>(maskLayer));
5957
0
    }
5958
0
    for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
5959
0
      Layer* maskLayer = layer->GetAncestorMaskLayerAt(i);
5960
0
5961
0
      NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
5962
0
                   "Could not recycle mask layer, unsupported layer type.");
5963
0
      mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Some(i)),
5964
0
                                   static_cast<ImageLayer*>(maskLayer));
5965
0
    }
5966
0
  }
5967
0
}
5968
5969
struct OpaqueRegionEntry
5970
{
5971
  AnimatedGeometryRoot* mAnimatedGeometryRoot;
5972
  const ActiveScrolledRoot* mASR;
5973
  nsIntRegion mOpaqueRegion;
5974
};
5975
5976
static OpaqueRegionEntry*
5977
FindOpaqueRegionEntry(nsTArray<OpaqueRegionEntry>& aEntries,
5978
                      AnimatedGeometryRoot* aAnimatedGeometryRoot,
5979
                      const ActiveScrolledRoot* aASR)
5980
0
{
5981
0
  for (uint32_t i = 0; i < aEntries.Length(); ++i) {
5982
0
    OpaqueRegionEntry* d = &aEntries[i];
5983
0
    if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot && d->mASR == aASR) {
5984
0
      return d;
5985
0
    }
5986
0
  }
5987
0
  return nullptr;
5988
0
}
5989
5990
static const ActiveScrolledRoot*
5991
FindDirectChildASR(const ActiveScrolledRoot* aParent,
5992
                   const ActiveScrolledRoot* aDescendant)
5993
0
{
5994
0
  MOZ_ASSERT(aDescendant, "can't start at the root when looking for a child");
5995
0
  MOZ_ASSERT(ActiveScrolledRoot::IsAncestor(aParent, aDescendant));
5996
0
  const ActiveScrolledRoot* directChild = aDescendant;
5997
0
  while (directChild->mParent != aParent) {
5998
0
    directChild = directChild->mParent;
5999
0
    MOZ_RELEASE_ASSERT(directChild, "this must not be null");
6000
0
  }
6001
0
  return directChild;
6002
0
}
6003
6004
static void
6005
FixUpFixedPositionLayer(Layer* aLayer,
6006
                        const ActiveScrolledRoot* aTargetASR,
6007
                        const ActiveScrolledRoot* aLeafScrollMetadataASR,
6008
                        const ActiveScrolledRoot* aContainerScrollMetadataASR,
6009
                        const ActiveScrolledRoot* aContainerCompositorASR,
6010
                        bool aIsFixedToRootScrollFrame)
6011
0
{
6012
0
  if (!aLayer->GetIsFixedPosition()) {
6013
0
    return;
6014
0
  }
6015
0
6016
0
  // Analyze ASRs to figure out if we need to fix up fixedness annotations on
6017
0
  // the layer. Fixed annotations are required in multiple cases:
6018
0
  //  - Sometimes we set scroll metadata on a layer for a scroll frame that we
6019
0
  //    don't want the layer to be moved by. (We have to do this if there is a
6020
0
  //    scrolled clip that is moved by that scroll frame.) So we set the fixed
6021
0
  //    annotation so that the compositor knows that it should ignore that
6022
0
  //    scroll metadata when determining the layer's position.
6023
0
  //  - Sometimes there is a scroll meta data on aLayer's parent layer for a
6024
0
  //    scroll frame that we don't want aLayer to be moved by. The most common
6025
0
  //    way for this to happen is with containerful root scrolling, where the
6026
0
  //    scroll metadata for the root scroll frame is on a container layer that
6027
0
  //    wraps the whole document's contents.
6028
0
  //  - Sometimes it's just needed for hit testing, i.e. figuring out what
6029
0
  //    scroll frame should be scrolled by events over the layer.
6030
0
  // A fixed layer needs to be annotated with the scroll ID of the scroll frame
6031
0
  // that it is *fixed with respect to*, i.e. the outermost scroll frame which
6032
0
  // does not move the layer. nsDisplayFixedPosition only ever annotates layers
6033
0
  // with the scroll ID of the presshell's root scroll frame, which is
6034
0
  // sometimes the wrong thing to do, so we correct it here. Specifically,
6035
0
  // it's the wrong thing to do if the fixed frame's containing block is a
6036
0
  // transformed frame - in that case, the fixed frame needs to scroll along
6037
0
  // with the transformed frame instead of being fixed with respect to the rsf.
6038
0
  // (It would be nice to compute the annotation only in one place and get it
6039
0
  // right, instead of fixing it up after the fact like this, but this will
6040
0
  // need to do for now.)
6041
0
  // compositorASR is the ASR that the layer would move with on the compositor
6042
0
  // if there were no fixed annotation on it.
6043
0
  const ActiveScrolledRoot* compositorASR =
6044
0
    aLeafScrollMetadataASR == aContainerScrollMetadataASR
6045
0
      ? aContainerCompositorASR
6046
0
      : aLeafScrollMetadataASR;
6047
0
6048
0
  // The goal of the annotation is to have the layer move with aTargetASR.
6049
0
  if (compositorASR && aTargetASR != compositorASR) {
6050
0
    // Mark this layer as fixed with respect to the child scroll frame of
6051
0
    // aTargetASR.
6052
0
    aLayer->SetFixedPositionData(
6053
0
      FindDirectChildASR(aTargetASR, compositorASR)->GetViewId(),
6054
0
      aLayer->GetFixedPositionAnchor(),
6055
0
      aLayer->GetFixedPositionSides());
6056
0
  } else {
6057
0
    // Remove the fixed annotation from the layer, unless this layers is fixed
6058
0
    // to the document's root scroll frame - in that case, the annotation is
6059
0
    // needed for hit testing, because fixed layers in iframes should scroll
6060
0
    // the iframe, even though their position is not affected by scrolling in
6061
0
    // the iframe. (The APZ hit testing code has a special case for this.)
6062
0
    // nsDisplayFixedPosition has annotated this layer with the document's
6063
0
    // root scroll frame's scroll id.
6064
0
    aLayer->SetIsFixedPosition(aIsFixedToRootScrollFrame);
6065
0
  }
6066
0
}
6067
6068
void
6069
ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
6070
0
{
6071
0
  if (!mBuilder->IsPaintingToWindow()) {
6072
0
    // async scrolling not possible, and async scrolling info not computed
6073
0
    // for this paint.
6074
0
    return;
6075
0
  }
6076
0
6077
0
  const ActiveScrolledRoot* startASR = aEntry->mScrollMetadataASR;
6078
0
  const ActiveScrolledRoot* stopASR = mContainerScrollMetadataASR;
6079
0
  if (!ActiveScrolledRoot::IsAncestor(stopASR, startASR)) {
6080
0
    if (ActiveScrolledRoot::IsAncestor(startASR, stopASR)) {
6081
0
      // startASR and stopASR are in the same branch of the ASR tree, but
6082
0
      // startASR is closer to the root. Just start at stopASR so that the loop
6083
0
      // below doesn't actually do anything.
6084
0
      startASR = stopASR;
6085
0
    } else {
6086
0
      // startASR and stopASR are in different branches of the
6087
0
      // ASR tree. Find a common ancestor and make that the stopASR.
6088
0
      // This can happen when there's a scrollable frame inside a fixed layer
6089
0
      // which has a scrolled clip. As far as scroll metadata is concerned,
6090
0
      // the scroll frame's scroll metadata will be a child of the scroll ID
6091
0
      // that scrolls the clip on the fixed layer. But as far as ASRs are
6092
0
      // concerned, those two ASRs are siblings, parented to the ASR of the
6093
0
      // fixed layer.
6094
0
      do {
6095
0
        stopASR = stopASR->mParent;
6096
0
      } while (!ActiveScrolledRoot::IsAncestor(stopASR, startASR));
6097
0
    }
6098
0
  }
6099
0
6100
0
  FixUpFixedPositionLayer(aEntry->mLayer,
6101
0
                          aEntry->mASR,
6102
0
                          startASR,
6103
0
                          mContainerScrollMetadataASR,
6104
0
                          mContainerCompositorASR,
6105
0
                          aEntry->mIsFixedToRootScrollFrame);
6106
0
6107
0
  AutoTArray<ScrollMetadata, 2> metricsArray;
6108
0
  if (aEntry->mBaseScrollMetadata) {
6109
0
    metricsArray.AppendElement(*aEntry->mBaseScrollMetadata);
6110
0
6111
0
    // The base FrameMetrics was not computed by the nsIScrollableframe, so it
6112
0
    // should not have a mask layer.
6113
0
    MOZ_ASSERT(!aEntry->mBaseScrollMetadata->HasMaskLayer());
6114
0
  }
6115
0
6116
0
  // Any extra mask layers we need to attach to ScrollMetadatas.
6117
0
  // The list may already contain an entry added for the layer's scrolled clip
6118
0
  // so add to it rather than overwriting it (we clear the list when recycling
6119
0
  // a layer).
6120
0
  nsTArray<RefPtr<Layer>> maskLayers(
6121
0
    aEntry->mLayer->GetAllAncestorMaskLayers());
6122
0
6123
0
  // Iterate over the ASR chain and create the corresponding scroll metadatas.
6124
0
  // This loop is slightly tricky because the scrollframe-to-clip relationship
6125
0
  // is reversed between DisplayItemClipChain and ScrollMetadata:
6126
0
  //  - DisplayItemClipChain associates the clip with the scroll frame that
6127
0
  //    this clip is *moved by*, i.e. the clip is moving inside the scroll
6128
0
  //    frame.
6129
0
  //  - ScrollMetaData associates the scroll frame with the clip that's
6130
0
  //    *just outside* the scroll frame, i.e. not moved by the scroll frame
6131
0
  //    itself.
6132
0
  // This discrepancy means that the leaf clip item of the clip chain is never
6133
0
  // applied to any scroll meta data. Instead, it was applied earlier as the
6134
0
  // layer's clip (or fused with the painted layer contents), or it was applied
6135
0
  // as a ScrolledClip on the layer.
6136
0
  const DisplayItemClipChain* clipChain = aEntry->mClipChain;
6137
0
6138
0
  for (const ActiveScrolledRoot* asr = startASR; asr != stopASR;
6139
0
       asr = asr->mParent) {
6140
0
    if (!asr) {
6141
0
      MOZ_ASSERT_UNREACHABLE("Should have encountered stopASR on the way up.");
6142
0
      break;
6143
0
    }
6144
0
    if (clipChain && clipChain->mASR == asr) {
6145
0
      clipChain = clipChain->mParent;
6146
0
    }
6147
0
6148
0
    nsIScrollableFrame* scrollFrame = asr->mScrollableFrame;
6149
0
    const DisplayItemClip* clip = (clipChain && clipChain->mASR == asr->mParent)
6150
0
                                    ? &clipChain->mClip
6151
0
                                    : nullptr;
6152
0
6153
0
    scrollFrame->ClipLayerToDisplayPort(aEntry->mLayer, clip, mParameters);
6154
0
6155
0
    Maybe<ScrollMetadata> metadata;
6156
0
    if (mCachedScrollMetadata.mASR == asr &&
6157
0
        mCachedScrollMetadata.mClip == clip) {
6158
0
      metadata = mCachedScrollMetadata.mMetadata;
6159
0
    } else {
6160
0
      metadata = scrollFrame->ComputeScrollMetadata(
6161
0
        aEntry->mLayer->Manager(), mContainerReferenceFrame, mParameters, clip);
6162
0
      mCachedScrollMetadata.mASR = asr;
6163
0
      mCachedScrollMetadata.mClip = clip;
6164
0
      mCachedScrollMetadata.mMetadata = metadata;
6165
0
    }
6166
0
6167
0
    if (!metadata) {
6168
0
      continue;
6169
0
    }
6170
0
6171
0
    if (clip && clip->HasClip() && clip->GetRoundedRectCount() > 0) {
6172
0
      // The clip in between this scrollframe and its ancestor scrollframe
6173
0
      // requires a mask layer. Since this mask layer should not move with
6174
0
      // the APZC associated with this FrameMetrics, we attach the mask
6175
0
      // layer as an additional, separate clip.
6176
0
      Maybe<size_t> nextIndex = Some(maskLayers.Length());
6177
0
      RefPtr<Layer> maskLayer =
6178
0
        CreateMaskLayer(aEntry->mLayer, *clip, nextIndex);
6179
0
      if (maskLayer) {
6180
0
        MOZ_ASSERT(metadata->HasScrollClip());
6181
0
        metadata->ScrollClip().SetMaskLayerIndex(nextIndex);
6182
0
        maskLayers.AppendElement(maskLayer);
6183
0
      }
6184
0
    }
6185
0
6186
0
    metricsArray.AppendElement(*metadata);
6187
0
  }
6188
0
6189
0
  // Watch out for FrameMetrics copies in profiles
6190
0
  aEntry->mLayer->SetScrollMetadata(metricsArray);
6191
0
  aEntry->mLayer->SetAncestorMaskLayers(maskLayers);
6192
0
}
6193
6194
static inline Maybe<ParentLayerIntRect>
6195
GetStationaryClipInContainer(Layer* aLayer)
6196
0
{
6197
0
  if (size_t metricsCount = aLayer->GetScrollMetadataCount()) {
6198
0
    return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect();
6199
0
  }
6200
0
  return aLayer->GetClipRect();
6201
0
}
6202
6203
void
6204
ContainerState::PostprocessRetainedLayers(
6205
  nsIntRegion* aOpaqueRegionForContainer)
6206
0
{
6207
0
  AutoTArray<OpaqueRegionEntry, 4> opaqueRegions;
6208
0
  bool hideAll = false;
6209
0
  int32_t opaqueRegionForContainer = -1;
6210
0
6211
0
  for (int32_t i = mNewChildLayers.Length() - 1; i >= 0; --i) {
6212
0
    NewLayerEntry* e = &mNewChildLayers.ElementAt(i);
6213
0
    if (!e->mLayer) {
6214
0
      continue;
6215
0
    }
6216
0
6217
0
    OpaqueRegionEntry* data =
6218
0
      FindOpaqueRegionEntry(opaqueRegions, e->mAnimatedGeometryRoot, e->mASR);
6219
0
6220
0
    SetupScrollingMetadata(e);
6221
0
6222
0
    if (hideAll) {
6223
0
      e->mVisibleRegion.SetEmpty();
6224
0
    } else if (!e->mLayer->IsScrollbarContainer()) {
6225
0
      Maybe<ParentLayerIntRect> clipRect =
6226
0
        GetStationaryClipInContainer(e->mLayer);
6227
0
      if (clipRect && opaqueRegionForContainer >= 0 &&
6228
0
          opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(
6229
0
            clipRect->ToUnknownRect())) {
6230
0
        e->mVisibleRegion.SetEmpty();
6231
0
      } else if (data) {
6232
0
        e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
6233
0
      }
6234
0
    }
6235
0
6236
0
    SetOuterVisibleRegionForLayer(e->mLayer,
6237
0
                                  e->mVisibleRegion,
6238
0
                                  e->mLayerContentsVisibleRect.width >= 0
6239
0
                                    ? &e->mLayerContentsVisibleRect
6240
0
                                    : nullptr,
6241
0
                                  e->mUntransformedVisibleRegion);
6242
0
6243
0
    if (!e->mOpaqueRegion.IsEmpty()) {
6244
0
      AnimatedGeometryRoot* animatedGeometryRootToCover =
6245
0
        e->mAnimatedGeometryRoot;
6246
0
      const ActiveScrolledRoot* asrToCover = e->mASR;
6247
0
      if (e->mOpaqueForAnimatedGeometryRootParent &&
6248
0
          e->mAnimatedGeometryRoot->mParentAGR ==
6249
0
            mContainerAnimatedGeometryRoot) {
6250
0
        animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
6251
0
        asrToCover = mContainerASR;
6252
0
        data = FindOpaqueRegionEntry(
6253
0
          opaqueRegions, animatedGeometryRootToCover, asrToCover);
6254
0
      }
6255
0
6256
0
      if (!data) {
6257
0
        if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot &&
6258
0
            asrToCover == mContainerASR) {
6259
0
          NS_ASSERTION(opaqueRegionForContainer == -1, "Already found it?");
6260
0
          opaqueRegionForContainer = opaqueRegions.Length();
6261
0
        }
6262
0
        data = opaqueRegions.AppendElement();
6263
0
        data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
6264
0
        data->mASR = asrToCover;
6265
0
      }
6266
0
6267
0
      nsIntRegion clippedOpaque = e->mOpaqueRegion;
6268
0
      Maybe<ParentLayerIntRect> clipRect = e->mLayer->GetCombinedClipRect();
6269
0
      if (clipRect) {
6270
0
        clippedOpaque.AndWith(clipRect->ToUnknownRect());
6271
0
      }
6272
0
      if (e->mLayer->GetScrolledClip()) {
6273
0
        // The clip can move asynchronously, so we can't rely on opaque parts
6274
0
        // staying visible.
6275
0
        clippedOpaque.SetEmpty();
6276
0
      } else if (e->mHideAllLayersBelow) {
6277
0
        hideAll = true;
6278
0
      }
6279
0
      data->mOpaqueRegion.Or(data->mOpaqueRegion, clippedOpaque);
6280
0
    }
6281
0
6282
0
    if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
6283
0
      // ReadbackLayers need to accurately read what's behind them. So,
6284
0
      // we don't want to do any occlusion culling of layers behind them.
6285
0
      // Theoretically we could just punch out the ReadbackLayer's rectangle
6286
0
      // from all mOpaqueRegions, but that's probably not worth doing.
6287
0
      opaqueRegions.Clear();
6288
0
      opaqueRegionForContainer = -1;
6289
0
    }
6290
0
  }
6291
0
6292
0
  if (opaqueRegionForContainer >= 0) {
6293
0
    aOpaqueRegionForContainer->Or(
6294
0
      *aOpaqueRegionForContainer,
6295
0
      opaqueRegions[opaqueRegionForContainer].mOpaqueRegion);
6296
0
  }
6297
0
}
6298
6299
void
6300
ContainerState::Finish(uint32_t* aTextContentFlags,
6301
                       const nsIntRect& aContainerPixelBounds,
6302
                       nsDisplayList* aChildItems)
6303
0
{
6304
0
  mPaintedLayerDataTree.Finish();
6305
0
6306
0
  if (!mParameters.mForEventsAndPluginsOnly &&
6307
0
      !gfxPrefs::LayoutUseContainersForRootFrames()) {
6308
0
    // Bug 1336544 tracks re-enabling this assertion in the
6309
0
    // gfxPrefs::LayoutUseContainersForRootFrames() case.
6310
0
    NS_ASSERTION(mContainerBounds.IsEqualInterior(mAccumulatedChildBounds),
6311
0
                 "Bounds computation mismatch");
6312
0
  }
6313
0
6314
0
  if (mLayerBuilder->IsBuildingRetainedLayers()) {
6315
0
    nsIntRegion containerOpaqueRegion;
6316
0
    PostprocessRetainedLayers(&containerOpaqueRegion);
6317
0
    if (containerOpaqueRegion.Contains(aContainerPixelBounds)) {
6318
0
      aChildItems->SetIsOpaque();
6319
0
    }
6320
0
  }
6321
0
6322
0
  uint32_t textContentFlags = 0;
6323
0
6324
0
  // Make sure that current/existing layers are added to the parent and are
6325
0
  // in the correct order.
6326
0
  Layer* layer = nullptr;
6327
0
  Layer* prevChild = nullptr;
6328
0
  for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i, prevChild = layer) {
6329
0
    if (!mNewChildLayers[i].mLayer) {
6330
0
      continue;
6331
0
    }
6332
0
6333
0
    layer = mNewChildLayers[i].mLayer;
6334
0
6335
0
    if (!layer->GetVisibleRegion().IsEmpty()) {
6336
0
      textContentFlags |=
6337
0
        layer->GetContentFlags() & (Layer::CONTENT_COMPONENT_ALPHA |
6338
0
                                    Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT |
6339
0
                                    Layer::CONTENT_DISABLE_FLATTENING);
6340
0
    }
6341
0
6342
0
    if (!layer->GetParent()) {
6343
0
      // This is not currently a child of the container, so just add it
6344
0
      // now.
6345
0
      mContainerLayer->InsertAfter(layer, prevChild);
6346
0
    } else {
6347
0
      NS_ASSERTION(layer->GetParent() == mContainerLayer,
6348
0
                   "Layer shouldn't be the child of some other container");
6349
0
      if (layer->GetPrevSibling() != prevChild) {
6350
0
        mContainerLayer->RepositionChild(layer, prevChild);
6351
0
      }
6352
0
    }
6353
0
  }
6354
0
6355
0
  // Remove old layers that have become unused.
6356
0
  if (!layer) {
6357
0
    layer = mContainerLayer->GetFirstChild();
6358
0
  } else {
6359
0
    layer = layer->GetNextSibling();
6360
0
  }
6361
0
  while (layer) {
6362
0
    Layer* layerToRemove = layer;
6363
0
    layer = layer->GetNextSibling();
6364
0
    mContainerLayer->RemoveChild(layerToRemove);
6365
0
  }
6366
0
6367
0
  *aTextContentFlags = textContentFlags;
6368
0
}
6369
6370
static void
6371
RestrictScaleToMaxLayerSize(Size& aScale,
6372
                            const nsRect& aVisibleRect,
6373
                            nsIFrame* aContainerFrame,
6374
                            Layer* aContainerLayer)
6375
0
{
6376
0
  if (!aContainerLayer->Manager()->IsWidgetLayerManager()) {
6377
0
    return;
6378
0
  }
6379
0
6380
0
  nsIntRect pixelSize = aVisibleRect.ScaleToOutsidePixels(
6381
0
    aScale.width,
6382
0
    aScale.height,
6383
0
    aContainerFrame->PresContext()->AppUnitsPerDevPixel());
6384
0
6385
0
  int32_t maxLayerSize = aContainerLayer->GetMaxLayerSize();
6386
0
6387
0
  if (pixelSize.width > maxLayerSize) {
6388
0
    float scale = (float)pixelSize.width / maxLayerSize;
6389
0
    scale = gfxUtils::ClampToScaleFactor(scale);
6390
0
    aScale.width /= scale;
6391
0
  }
6392
0
  if (pixelSize.height > maxLayerSize) {
6393
0
    float scale = (float)pixelSize.height / maxLayerSize;
6394
0
    scale = gfxUtils::ClampToScaleFactor(scale);
6395
0
    aScale.height /= scale;
6396
0
  }
6397
0
}
6398
6399
static nsSize
6400
ComputeDesiredDisplaySizeForAnimation(nsIFrame* aContainerFrame)
6401
0
{
6402
0
  // Use the size of the nearest widget as the maximum size.  This
6403
0
  // is important since it might be a popup that is bigger than the
6404
0
  // pres context's size.
6405
0
  nsPresContext* presContext = aContainerFrame->PresContext();
6406
0
  nsIWidget* widget = aContainerFrame->GetNearestWidget();
6407
0
  if (widget) {
6408
0
    return LayoutDevicePixel::ToAppUnits(widget->GetClientSize(),
6409
0
                                         presContext->AppUnitsPerDevPixel());
6410
0
  }
6411
0
6412
0
  return presContext->GetVisibleArea().Size();
6413
0
}
6414
6415
static bool
6416
ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
6417
                           nsDisplayListBuilder* aDisplayListBuilder,
6418
                           nsIFrame* aContainerFrame,
6419
                           nsDisplayItem* aContainerItem,
6420
                           const nsRect& aVisibleRect,
6421
                           const Matrix4x4* aTransform,
6422
                           const ContainerLayerParameters& aIncomingScale,
6423
                           ContainerLayer* aLayer,
6424
                           ContainerLayerParameters& aOutgoingScale)
6425
0
{
6426
0
  nsIntPoint offset;
6427
0
6428
0
  Matrix4x4 transform =
6429
0
    Matrix4x4::Scaling(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
6430
0
  if (aTransform) {
6431
0
    // aTransform is applied first, then the scale is applied to the result
6432
0
    transform = (*aTransform) * transform;
6433
0
    // Set any matrix entries close to integers to be those exact integers.
6434
0
    // This protects against floating-point inaccuracies causing problems
6435
0
    // in the checks below.
6436
0
    // We use the fixed epsilon version here because we don't want the nudging
6437
0
    // to depend on the scroll position.
6438
0
    transform.NudgeToIntegersFixedEpsilon();
6439
0
  }
6440
0
  Matrix transform2d;
6441
0
  if (aContainerFrame && aLayerBuilder->GetContainingPaintedLayerData() &&
6442
0
      (!aTransform ||
6443
0
       (aTransform->Is2D(&transform2d) && !transform2d.HasNonTranslation()))) {
6444
0
    // When we have an inactive ContainerLayer, translate the container by the
6445
0
    // offset to the reference frame (and offset all child layers by the
6446
0
    // reverse) so that the coordinate space of the child layers isn't affected
6447
0
    // by scrolling. This gets confusing for complicated transform (since we'd
6448
0
    // have to compute the scale factors for the matrix), so we don't bother.
6449
0
    // Any frames that are building an nsDisplayTransform for a css transform
6450
0
    // would have 0,0 as their offset to the reference frame, so this doesn't
6451
0
    // matter.
6452
0
    nsPoint appUnitOffset =
6453
0
      aDisplayListBuilder->ToReferenceFrame(aContainerFrame);
6454
0
    nscoord appUnitsPerDevPixel =
6455
0
      aContainerFrame->PresContext()->AppUnitsPerDevPixel();
6456
0
    offset = nsIntPoint(
6457
0
      NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel) *
6458
0
                aIncomingScale.mXScale),
6459
0
      NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel) *
6460
0
                aIncomingScale.mYScale));
6461
0
  }
6462
0
  transform.PostTranslate(offset.x + aIncomingScale.mOffset.x,
6463
0
                          offset.y + aIncomingScale.mOffset.y,
6464
0
                          0);
6465
0
6466
0
  if (transform.IsSingular()) {
6467
0
    return false;
6468
0
  }
6469
0
6470
0
  bool canDraw2D = transform.CanDraw2D(&transform2d);
6471
0
  Size scale;
6472
0
  // XXX Should we do something for 3D transforms?
6473
0
  if (canDraw2D && !aContainerFrame->Combines3DTransformWithAncestors() &&
6474
0
      !aContainerFrame->HasPerspective()) {
6475
0
    // If the container's transform is animated off main thread, fix a suitable
6476
0
    // scale size for animation
6477
0
    if (aContainerItem &&
6478
0
        aContainerItem->GetType() == DisplayItemType::TYPE_TRANSFORM &&
6479
0
        EffectCompositor::HasAnimationsForCompositor(aContainerFrame,
6480
0
                                                     eCSSProperty_transform)) {
6481
0
      nsSize displaySize =
6482
0
        ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
6483
0
      // compute scale using the animation on the container, taking ancestors in
6484
0
      // to account
6485
0
      nsSize scaledVisibleSize =
6486
0
        nsSize(aVisibleRect.Width() * aIncomingScale.mXScale,
6487
0
               aVisibleRect.Height() * aIncomingScale.mYScale);
6488
0
      scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
6489
0
        aContainerFrame, scaledVisibleSize, displaySize);
6490
0
      // multiply by the scale inherited from ancestors--we use a uniform
6491
0
      // scale factor to prevent blurring when the layer is rotated.
6492
0
      float incomingScale =
6493
0
        std::max(aIncomingScale.mXScale, aIncomingScale.mYScale);
6494
0
      scale.width *= incomingScale;
6495
0
      scale.height *= incomingScale;
6496
0
    } else {
6497
0
      // Scale factors are normalized to a power of 2 to reduce the number of
6498
0
      // resolution changes
6499
0
      scale = transform2d.ScaleFactors(true);
6500
0
      // For frames with a changing scale transform round scale factors up to
6501
0
      // nearest power-of-2 boundary so that we don't keep having to redraw
6502
0
      // the content as it scales up and down. Rounding up to nearest
6503
0
      // power-of-2 boundary ensures we never scale up, only down --- avoiding
6504
0
      // jaggies. It also ensures we never scale down by more than a factor of
6505
0
      // 2, avoiding bad downscaling quality.
6506
0
      Matrix frameTransform;
6507
0
      if (ActiveLayerTracker::IsScaleSubjectToAnimation(aContainerFrame)) {
6508
0
        scale.width = gfxUtils::ClampToScaleFactor(scale.width);
6509
0
        scale.height = gfxUtils::ClampToScaleFactor(scale.height);
6510
0
6511
0
        // Limit animated scale factors to not grow excessively beyond the
6512
0
        // display size.
6513
0
        nsSize maxScale(4, 4);
6514
0
        if (!aVisibleRect.IsEmpty()) {
6515
0
          nsSize displaySize =
6516
0
            ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
6517
0
          maxScale = Max(maxScale, displaySize / aVisibleRect.Size());
6518
0
        }
6519
0
        if (scale.width > maxScale.width) {
6520
0
          scale.width = gfxUtils::ClampToScaleFactor(maxScale.width, true);
6521
0
        }
6522
0
        if (scale.height > maxScale.height) {
6523
0
          scale.height = gfxUtils::ClampToScaleFactor(maxScale.height, true);
6524
0
        }
6525
0
      } else {
6526
0
        // XXX Do we need to move nearly-integer values to integers here?
6527
0
      }
6528
0
    }
6529
0
    // If the scale factors are too small, just use 1.0. The content is being
6530
0
    // scaled out of sight anyway.
6531
0
    if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
6532
0
      scale = Size(1.0, 1.0);
6533
0
    }
6534
0
    // If this is a transform container layer, then pre-rendering might
6535
0
    // mean we try render a layer bigger than the max texture size. If we have
6536
0
    // tiling, that's not a problem, since we'll automatically choose a tiled
6537
0
    // layer for layers of that size. If not, we need to apply clamping to
6538
0
    // prevent this.
6539
0
    if (aTransform && !gfxPrefs::LayersTilesEnabled()) {
6540
0
      RestrictScaleToMaxLayerSize(scale, aVisibleRect, aContainerFrame, aLayer);
6541
0
    }
6542
0
  } else {
6543
0
    scale = Size(1.0, 1.0);
6544
0
  }
6545
0
6546
0
  // Store the inverse of our resolution-scale on the layer
6547
0
  aLayer->SetBaseTransform(transform);
6548
0
  aLayer->SetPreScale(1.0f / scale.width, 1.0f / scale.height);
6549
0
  aLayer->SetInheritedScale(aIncomingScale.mXScale, aIncomingScale.mYScale);
6550
0
6551
0
  aOutgoingScale = ContainerLayerParameters(
6552
0
    scale.width, scale.height, -offset, aIncomingScale);
6553
0
  if (aTransform) {
6554
0
    aOutgoingScale.mInTransformedSubtree = true;
6555
0
    if (ActiveLayerTracker::IsStyleAnimated(
6556
0
          aDisplayListBuilder, aContainerFrame, eCSSProperty_transform)) {
6557
0
      aOutgoingScale.mInActiveTransformedSubtree = true;
6558
0
    }
6559
0
  }
6560
0
  if ((aLayerBuilder->IsBuildingRetainedLayers() &&
6561
0
       (!canDraw2D || transform2d.HasNonIntegerTranslation())) ||
6562
0
      aContainerFrame->Extend3DContext() ||
6563
0
      aContainerFrame->Combines3DTransformWithAncestors() ||
6564
0
      // For async transform animation, the value would be changed at
6565
0
      // any time, integer translation is not always true.
6566
0
      aContainerFrame->HasAnimationOfTransform()) {
6567
0
    aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true;
6568
0
  }
6569
0
  return true;
6570
0
}
6571
6572
already_AddRefed<ContainerLayer>
6573
FrameLayerBuilder::BuildContainerLayerFor(
6574
  nsDisplayListBuilder* aBuilder,
6575
  LayerManager* aManager,
6576
  nsIFrame* aContainerFrame,
6577
  nsDisplayItem* aContainerItem,
6578
  nsDisplayList* aChildren,
6579
  const ContainerLayerParameters& aParameters,
6580
  const Matrix4x4* aTransform,
6581
  uint32_t aFlags)
6582
0
{
6583
0
  uint32_t containerDisplayItemKey =
6584
0
    aContainerItem ? aContainerItem->GetPerFrameKey() : 0;
6585
0
  NS_ASSERTION(aContainerFrame,
6586
0
               "Container display items here should have a frame");
6587
0
  NS_ASSERTION(!aContainerItem || aContainerItem->Frame() == aContainerFrame,
6588
0
               "Container display item must match given frame");
6589
0
6590
0
  if (!aParameters.mXScale || !aParameters.mYScale) {
6591
0
    return nullptr;
6592
0
  }
6593
0
6594
0
  RefPtr<ContainerLayer> containerLayer;
6595
0
  if (aManager == mRetainingManager) {
6596
0
    // Using GetOldLayerFor will search merged frames, as well as the underlying
6597
0
    // frame. The underlying frame can change when a page scrolls, so this
6598
0
    // avoids layer recreation in the situation that a new underlying frame is
6599
0
    // picked for a layer.
6600
0
    Layer* oldLayer = nullptr;
6601
0
    if (aContainerItem) {
6602
0
      oldLayer = GetOldLayerFor(aContainerItem);
6603
0
    } else {
6604
0
      DisplayItemData* data =
6605
0
        GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
6606
0
      if (data) {
6607
0
        oldLayer = data->mLayer;
6608
0
      }
6609
0
    }
6610
0
6611
0
    if (oldLayer) {
6612
0
      NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
6613
0
      if (oldLayer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
6614
0
        // The old layer for this item is actually our PaintedLayer
6615
0
        // because we rendered its layer into that PaintedLayer. So we
6616
0
        // don't actually have a retained container layer.
6617
0
      } else {
6618
0
        NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
6619
0
                     "Wrong layer type");
6620
0
        containerLayer = static_cast<ContainerLayer*>(oldLayer);
6621
0
        ResetLayerStateForRecycling(containerLayer);
6622
0
      }
6623
0
    }
6624
0
  }
6625
0
  if (!containerLayer) {
6626
0
    // No suitable existing layer was found.
6627
0
    containerLayer = aManager->CreateContainerLayer();
6628
0
    if (!containerLayer)
6629
0
      return nullptr;
6630
0
  }
6631
0
6632
0
  if (aContainerItem &&
6633
0
      aContainerItem->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
6634
0
    // Empty layers only have metadata and should never have display items. We
6635
0
    // early exit because later, invalidation will walk up the frame tree to
6636
0
    // determine which painted layer gets invalidated. Since an empty layer
6637
0
    // should never have anything to paint, it should never be invalidated.
6638
0
    NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
6639
0
    return containerLayer.forget();
6640
0
  }
6641
0
6642
0
  const ActiveScrolledRoot* containerASR =
6643
0
    aContainerItem ? aContainerItem->GetActiveScrolledRoot() : nullptr;
6644
0
  const ActiveScrolledRoot* containerScrollMetadataASR =
6645
0
    aParameters.mScrollMetadataASR;
6646
0
  const ActiveScrolledRoot* containerCompositorASR = aParameters.mCompositorASR;
6647
0
6648
0
  if (!aContainerItem && gfxPrefs::LayoutUseContainersForRootFrames()) {
6649
0
    containerASR = aBuilder->ActiveScrolledRootForRootScrollframe();
6650
0
    containerScrollMetadataASR = containerASR;
6651
0
    containerCompositorASR = containerASR;
6652
0
  }
6653
0
6654
0
  ContainerLayerParameters scaleParameters;
6655
0
  nsRect bounds =
6656
0
    aChildren->GetClippedBoundsWithRespectToASR(aBuilder, containerASR);
6657
0
  nsRect childrenVisible =
6658
0
    aContainerItem ? aContainerItem->GetBuildingRectForChildren()
6659
0
                   : aContainerFrame->GetVisualOverflowRectRelativeToSelf();
6660
0
  if (!ChooseScaleAndSetTransform(this,
6661
0
                                  aBuilder,
6662
0
                                  aContainerFrame,
6663
0
                                  aContainerItem,
6664
0
                                  bounds.Intersect(childrenVisible),
6665
0
                                  aTransform,
6666
0
                                  aParameters,
6667
0
                                  containerLayer,
6668
0
                                  scaleParameters)) {
6669
0
    return nullptr;
6670
0
  }
6671
0
6672
0
  if (mRetainingManager) {
6673
0
    if (aContainerItem) {
6674
0
      DisplayItemData* data =
6675
0
        GetDisplayItemDataForManager(aContainerItem, mRetainingManager);
6676
0
      StoreDataForFrame(aContainerItem, containerLayer, LAYER_ACTIVE, data);
6677
0
    } else {
6678
0
      StoreDataForFrame(
6679
0
        aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE);
6680
0
    }
6681
0
  }
6682
0
6683
0
  nsIntRect pixBounds;
6684
0
  nscoord appUnitsPerDevPixel;
6685
0
6686
0
  nscolor backgroundColor = NS_RGBA(0, 0, 0, 0);
6687
0
  if (aFlags & CONTAINER_ALLOW_PULL_BACKGROUND_COLOR) {
6688
0
    backgroundColor = aParameters.mBackgroundColor;
6689
0
  }
6690
0
6691
0
  uint32_t flags;
6692
0
  ContainerState state(aBuilder,
6693
0
                       aManager,
6694
0
                       aManager->GetLayerBuilder(),
6695
0
                       aContainerFrame,
6696
0
                       aContainerItem,
6697
0
                       bounds,
6698
0
                       containerLayer,
6699
0
                       scaleParameters,
6700
0
                       backgroundColor,
6701
0
                       containerASR,
6702
0
                       containerScrollMetadataASR,
6703
0
                       containerCompositorASR);
6704
0
6705
0
  state.ProcessDisplayItems(aChildren);
6706
0
6707
0
  // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
6708
0
  // This is suboptimal ... a child could have text that's over transparent
6709
0
  // pixels in its own layer, but over opaque parts of previous siblings.
6710
0
  pixBounds = state.ScaleToOutsidePixels(bounds, false);
6711
0
  appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
6712
0
  state.Finish(&flags, pixBounds, aChildren);
6713
0
6714
0
  // CONTENT_COMPONENT_ALPHA is propogated up to the nearest CONTENT_OPAQUE
6715
0
  // ancestor so that BasicLayerManager knows when to copy the background into
6716
0
  // pushed groups. Accelerated layers managers can't necessarily do this (only
6717
0
  // when the visible region is a simple rect), so we propogate
6718
0
  // CONTENT_COMPONENT_ALPHA_DESCENDANT all the way to the root.
6719
0
  if (flags & Layer::CONTENT_COMPONENT_ALPHA) {
6720
0
    flags |= Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT;
6721
0
  }
6722
0
6723
0
  // Make sure that rounding the visible region out didn't add any area
6724
0
  // we won't paint
6725
0
  if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) {
6726
0
    bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
6727
0
    if (bounds.Contains(ToAppUnits(pixBounds, appUnitsPerDevPixel))) {
6728
0
      // Clear CONTENT_COMPONENT_ALPHA and add CONTENT_OPAQUE instead.
6729
0
      flags &= ~Layer::CONTENT_COMPONENT_ALPHA;
6730
0
      flags |= Layer::CONTENT_OPAQUE;
6731
0
    }
6732
0
  }
6733
0
  containerLayer->SetContentFlags(flags);
6734
0
  // If aContainerItem is non-null some BuildContainerLayer further up the
6735
0
  // call stack is responsible for setting containerLayer's visible region.
6736
0
  if (!aContainerItem) {
6737
0
    containerLayer->SetVisibleRegion(
6738
0
      LayerIntRegion::FromUnknownRegion(pixBounds));
6739
0
  }
6740
0
  if (aParameters.mLayerContentsVisibleRect) {
6741
0
    *aParameters.mLayerContentsVisibleRect =
6742
0
      pixBounds + scaleParameters.mOffset;
6743
0
  }
6744
0
6745
0
  nsPresContext::ClearNotifySubDocInvalidationData(containerLayer);
6746
0
6747
0
  return containerLayer.forget();
6748
0
}
6749
6750
Layer*
6751
FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
6752
                                   nsDisplayItem* aItem)
6753
0
{
6754
0
  Layer* layer = GetOldLayerFor(aItem);
6755
0
  if (!layer)
6756
0
    return nullptr;
6757
0
  if (layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
6758
0
    // This layer was created to render Thebes-rendered content for this
6759
0
    // display item. The display item should not use it for its own
6760
0
    // layer rendering.
6761
0
    return nullptr;
6762
0
  }
6763
0
  ResetLayerStateForRecycling(layer);
6764
0
  return layer;
6765
0
}
6766
6767
/* static */ void
6768
FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
6769
0
{
6770
0
  LayerManagerData* data = static_cast<LayerManagerData*>(
6771
0
    aManager->GetUserData(&gLayerManagerUserData));
6772
0
  if (data) {
6773
0
    data->mInvalidateAllLayers = true;
6774
0
  }
6775
0
}
6776
6777
/* static */ void
6778
FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame* aFrame)
6779
0
{
6780
0
  const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
6781
0
6782
0
  for (uint32_t i = 0; i < array.Length(); i++) {
6783
0
    DisplayItemData::AssertDisplayItemData(array.ElementAt(i))
6784
0
      ->mParent->mInvalidateAllLayers = true;
6785
0
  }
6786
0
}
6787
6788
/* static */
6789
Layer*
6790
FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame,
6791
                                     DisplayItemType aDisplayItemKey)
6792
0
{
6793
0
  // TODO: This isn't completely correct, since a frame could exist as a layer
6794
0
  // in the normal widget manager, and as a different layer (or no layer)
6795
0
  // in the secondary manager
6796
0
6797
0
  const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
6798
0
  ;
6799
0
6800
0
  for (uint32_t i = 0; i < array.Length(); i++) {
6801
0
    DisplayItemData* element =
6802
0
      DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
6803
0
    if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
6804
0
      continue;
6805
0
    }
6806
0
    if (GetDisplayItemTypeFromKey(element->mDisplayItemKey) ==
6807
0
        aDisplayItemKey) {
6808
0
      if (element->mOptLayer) {
6809
0
        return element->mOptLayer;
6810
0
      }
6811
0
6812
0
      Layer* layer = element->mLayer;
6813
0
      if (!layer->HasUserData(&gColorLayerUserData) &&
6814
0
          !layer->HasUserData(&gImageLayerUserData) &&
6815
0
          !layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
6816
0
        return layer;
6817
0
      }
6818
0
    }
6819
0
  }
6820
0
  return nullptr;
6821
0
}
6822
6823
gfxSize
6824
FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame)
6825
0
{
6826
0
  MOZ_ASSERT(aFrame, "need a frame");
6827
0
6828
0
  nsPresContext* presCtx = aFrame->PresContext()->GetRootPresContext();
6829
0
6830
0
  if (!presCtx) {
6831
0
    presCtx = aFrame->PresContext();
6832
0
    MOZ_ASSERT(presCtx);
6833
0
  }
6834
0
6835
0
  nsIFrame* root = presCtx->PresShell()->GetRootFrame();
6836
0
6837
0
  MOZ_ASSERT(root);
6838
0
6839
0
  float resolution = presCtx->PresShell()->GetResolution();
6840
0
6841
0
  Matrix4x4Flagged transform = Matrix4x4::Scaling(resolution, resolution, 1.0);
6842
0
  if (aFrame != root) {
6843
0
    // aTransform is applied first, then the scale is applied to the result
6844
0
    transform = nsLayoutUtils::GetTransformToAncestor(aFrame, root) * transform;
6845
0
  }
6846
0
6847
0
  Matrix transform2d;
6848
0
  if (transform.CanDraw2D(&transform2d)) {
6849
0
    return ThebesMatrix(transform2d).ScaleFactors(true);
6850
0
  }
6851
0
6852
0
  return gfxSize(1.0, 1.0);
6853
0
}
6854
6855
#ifdef MOZ_DUMP_PAINTING
6856
static void
6857
DebugPaintItem(DrawTarget& aDrawTarget,
6858
               nsPresContext* aPresContext,
6859
               nsDisplayItem* aItem,
6860
               nsDisplayListBuilder* aBuilder)
6861
{
6862
  bool snap;
6863
  Rect bounds = NSRectToRect(aItem->GetBounds(aBuilder, &snap),
6864
                             aPresContext->AppUnitsPerDevPixel());
6865
6866
  RefPtr<DrawTarget> tempDT = aDrawTarget.CreateSimilarDrawTarget(
6867
    IntSize::Truncate(bounds.width, bounds.height), SurfaceFormat::B8G8R8A8);
6868
  RefPtr<gfxContext> context = gfxContext::CreateOrNull(tempDT);
6869
  if (!context) {
6870
    // Leave this as crash, it's in the debugging code, we want to know
6871
    gfxDevCrash(LogReason::InvalidContext)
6872
      << "DebugPaintItem context problem " << gfx::hexa(tempDT);
6873
    return;
6874
  }
6875
  context->SetMatrix(Matrix::Translation(-bounds.x, -bounds.y));
6876
6877
  aItem->Paint(aBuilder, context);
6878
  RefPtr<SourceSurface> surface = tempDT->Snapshot();
6879
  DumpPaintedImage(aItem, surface);
6880
6881
  aDrawTarget.DrawSurface(surface, bounds, Rect(Point(0, 0), bounds.Size()));
6882
6883
  aItem->SetPainted();
6884
}
6885
#endif
6886
6887
/* static */ void
6888
FrameLayerBuilder::RecomputeVisibilityForItems(
6889
  std::vector<AssignedDisplayItem>& aItems,
6890
  nsDisplayListBuilder* aBuilder,
6891
  const nsIntRegion& aRegionToDraw,
6892
  nsRect& aPreviousRectToDraw,
6893
  const nsIntPoint& aOffset,
6894
  int32_t aAppUnitsPerDevPixel,
6895
  float aXScale,
6896
  float aYScale)
6897
0
{
6898
0
  uint32_t i;
6899
0
  // Update visible regions. We perform visibility analysis to take account
6900
0
  // of occlusion culling.
6901
0
  nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel);
6902
0
  visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel),
6903
0
                 NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
6904
0
  visible.ScaleInverseRoundOut(aXScale, aYScale);
6905
0
6906
0
  // We're going to read from previousRectToDraw for every iteration, let's do
6907
0
  // that on the stack, and just update the heap allocated one now. By the end
6908
0
  // of this function {visible} will have been modified by occlusion culling.
6909
0
  nsRect previousRectToDraw = aPreviousRectToDraw;
6910
0
  aPreviousRectToDraw = visible.GetBounds();
6911
0
6912
0
  for (i = aItems.size(); i > 0; --i) {
6913
0
    AssignedDisplayItem* cdi = &aItems[i - 1];
6914
0
    if (!cdi->mItem) {
6915
0
      continue;
6916
0
    }
6917
0
6918
0
    if (cdi->mHasPaintRect &&
6919
0
        !cdi->mContentRect.Intersects(visible.GetBounds()) &&
6920
0
        !cdi->mContentRect.Intersects(previousRectToDraw)) {
6921
0
      continue;
6922
0
    }
6923
0
6924
0
    if (IsEffectEndMarker(cdi->mType) || cdi->mHasOpacity ||
6925
0
        cdi->mHasTransform) {
6926
0
      // The visibility calculations are skipped when the item is an effect end
6927
0
      // marker, or when the display item is within a flattened effect group.
6928
0
      // This is because RecomputeVisibility has already been called for the
6929
0
      // group item, and all the children.
6930
0
      continue;
6931
0
    }
6932
0
6933
0
    const DisplayItemClip& clip = cdi->mItem->GetClip();
6934
0
6935
0
    NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel,
6936
0
                 "a painted layer should contain items only at the same zoom");
6937
0
6938
0
    MOZ_ASSERT(clip.HasClip() || clip.GetRoundedRectCount() == 0,
6939
0
               "If we have rounded rects, we must have a clip rect");
6940
0
6941
0
    if (!clip.IsRectAffectedByClip(visible.GetBounds())) {
6942
0
      cdi->mItem->RecomputeVisibility(aBuilder, &visible);
6943
0
      continue;
6944
0
    }
6945
0
6946
0
    // Do a little dance to account for the fact that we're clipping
6947
0
    // to cdi->mClipRect
6948
0
    nsRegion clipped;
6949
0
    clipped.And(visible, clip.NonRoundedIntersection());
6950
0
    nsRegion finalClipped = clipped;
6951
0
    cdi->mItem->RecomputeVisibility(aBuilder, &finalClipped);
6952
0
    // If we have rounded clip rects, don't subtract from the visible
6953
0
    // region since we aren't displaying everything inside the rect.
6954
0
    if (clip.GetRoundedRectCount() == 0) {
6955
0
      nsRegion removed;
6956
0
      removed.Sub(clipped, finalClipped);
6957
0
      nsRegion newVisible;
6958
0
      newVisible.Sub(visible, removed);
6959
0
      // Don't let the visible region get too complex.
6960
0
      if (newVisible.GetNumRects() <= 15) {
6961
0
        visible = std::move(newVisible);
6962
0
      }
6963
0
    }
6964
0
  }
6965
0
}
6966
6967
/**
6968
 * Tracks and caches the item clip.
6969
 */
6970
struct ItemClipTracker
6971
{
6972
  explicit ItemClipTracker(gfxContext* aContext,
6973
                           const int32_t aAppUnitsPerDevPixel)
6974
    : mContext(aContext)
6975
    , mHasClip(false)
6976
    , mAppUnitsPerDevPixel(aAppUnitsPerDevPixel)
6977
0
  {
6978
0
  }
6979
6980
  /**
6981
   * Returns true if a clip is set.
6982
   */
6983
0
  bool HasClip() const { return mHasClip; }
6984
6985
  /**
6986
   * Returns true if the given |aClip| is set.
6987
   */
6988
  bool HasClip(const DisplayItemClip* aClip) const
6989
0
  {
6990
0
    MOZ_ASSERT(aClip && aClip->HasClip());
6991
0
    return mHasClip && mCurrentClip == *aClip;
6992
0
  }
6993
6994
  /**
6995
   * Removes the clip, if there is one.
6996
   */
6997
  void Restore()
6998
0
  {
6999
0
    if (mCurrentClip.HasClip()) {
7000
0
      mCurrentClip = DisplayItemClip::NoClip();
7001
0
    }
7002
0
7003
0
    if (!HasClip()) {
7004
0
      return;
7005
0
    }
7006
0
7007
0
    mContext->Restore();
7008
0
    mHasClip = false;
7009
0
  };
7010
7011
  /**
7012
   * Sets the clip to |aClip|, if it is not set already.
7013
   */
7014
  void ChangeClipIfNeeded(const DisplayItemClip* aClip)
7015
0
  {
7016
0
    MOZ_ASSERT(aClip && aClip->HasClip());
7017
0
7018
0
    if (HasClip(aClip)) {
7019
0
      // Reuse the old clip.
7020
0
      return;
7021
0
    }
7022
0
7023
0
    // Remove the previous clip and save the current state.
7024
0
    Restore();
7025
0
    mContext->Save();
7026
0
7027
0
    // Apply the new clip.
7028
0
    mHasClip = true;
7029
0
    mCurrentClip = *aClip;
7030
0
    mCurrentClip.ApplyTo(mContext, mAppUnitsPerDevPixel);
7031
0
    mContext->NewPath();
7032
0
  }
7033
7034
private:
7035
  gfxContext* mContext;
7036
  bool mHasClip;
7037
  const int32_t mAppUnitsPerDevPixel;
7038
7039
  DisplayItemClip mCurrentClip;
7040
};
7041
7042
/**
7043
 * Tracks clips managed by |PushClip()| and |PopClip()|.
7044
 * If allowed by the caller, the top clip may be reused when a new clip that
7045
 * matches the previous one is pushed to the stack.
7046
 */
7047
struct ClipStack
7048
{
7049
  explicit ClipStack(gfxContext* aContext, const int32_t aAppUnitsPerDevPixel)
7050
    : mContext(aContext)
7051
    , mAppUnitsPerDevPixel(aAppUnitsPerDevPixel)
7052
    , mDeferredPopClip(false)
7053
0
  {
7054
0
  }
7055
7056
  ~ClipStack()
7057
0
  {
7058
0
    MOZ_ASSERT(!mDeferredPopClip);
7059
0
    MOZ_ASSERT(!HasClips());
7060
0
  }
7061
7062
  /**
7063
   * Returns true if there are clips set.
7064
   */
7065
0
  bool HasClips() const { return mClips.Length() > 0; }
7066
7067
  /**
7068
   * Returns the clip at the top of the stack.
7069
   */
7070
  const DisplayItemClip& TopClip() const
7071
0
  {
7072
0
    MOZ_ASSERT(HasClips());
7073
0
    return mClips.LastElement();
7074
0
  }
7075
7076
  /**
7077
   * Returns true if the top clip matches the given |aClip|.
7078
   */
7079
  bool TopClipMatches(const DisplayItemClip& aClip)
7080
0
  {
7081
0
    return HasClips() && TopClip() == aClip;
7082
0
  }
7083
7084
  /**
7085
   * Pops the current top clip. If |aDeferPopClip| is true, the top clip will
7086
   * not be popped before the next call to |PopClip(false)|.
7087
   * This allows the previously set clip to be reused during the next
7088
   * |PushClip()| call, if the new clip is identical with the top clip.
7089
   */
7090
  void PopClip(bool aDeferPopClip)
7091
0
  {
7092
0
    MOZ_ASSERT(HasClips());
7093
0
7094
0
    if (aDeferPopClip) {
7095
0
      // Do not allow reusing clip with nested effects.
7096
0
      MOZ_ASSERT(!mDeferredPopClip);
7097
0
      mDeferredPopClip = true;
7098
0
      return;
7099
0
    }
7100
0
7101
0
    if (TopClip().HasClip()) {
7102
0
      mContext->Restore();
7103
0
    }
7104
0
7105
0
    mClips.RemoveLastElement();
7106
0
    mDeferredPopClip = false;
7107
0
  }
7108
7109
  /**
7110
   * Pops the clip, if a call to |PopClip()| has been deferred.
7111
   */
7112
  void PopDeferredClip()
7113
0
  {
7114
0
    if (mDeferredPopClip) {
7115
0
      PopClip(false);
7116
0
    }
7117
0
  }
7118
7119
  /**
7120
   * Pushes the given |aClip| to the stack.
7121
   */
7122
  void PushClip(const DisplayItemClip& aClip)
7123
0
  {
7124
0
    if (mDeferredPopClip && TopClipMatches(aClip)) {
7125
0
      // Reuse this clip. Defer the decision to reuse it again until the next
7126
0
      // call to PopClip().
7127
0
      mDeferredPopClip = false;
7128
0
      return;
7129
0
    }
7130
0
7131
0
    PopDeferredClip();
7132
0
7133
0
    mClips.AppendElement(aClip);
7134
0
7135
0
    // Save the current state and apply new clip, if needed.
7136
0
    if (aClip.HasClip()) {
7137
0
      mContext->Save();
7138
0
      aClip.ApplyTo(mContext, mAppUnitsPerDevPixel);
7139
0
      mContext->NewPath();
7140
0
    }
7141
0
  }
7142
7143
private:
7144
  gfxContext* mContext;
7145
  const int32_t mAppUnitsPerDevPixel;
7146
  AutoTArray<DisplayItemClip, 2> mClips;
7147
  bool mDeferredPopClip;
7148
};
7149
7150
/**
7151
 * Returns a clip for the given |aItem|. If the clip can be simplified to not
7152
 * include rounded rects, |aOutClip| is used to store the simplified clip.
7153
 */
7154
static const DisplayItemClip*
7155
GetItemClip(const nsDisplayItem* aItem, DisplayItemClip& aOutClip)
7156
0
{
7157
0
  const DisplayItemClip& clip = aItem->GetClip();
7158
0
7159
0
  if (!clip.HasClip()) {
7160
0
    return nullptr;
7161
0
  }
7162
0
7163
0
  if (clip.GetRoundedRectCount() > 0 &&
7164
0
      !clip.IsRectClippedByRoundedCorner(aItem->GetPaintRect())) {
7165
0
    aOutClip.SetTo(clip.GetClipRect());
7166
0
    return &aOutClip;
7167
0
  }
7168
0
7169
0
  return &clip;
7170
0
}
7171
7172
/**
7173
 * Pushes a new opacity group for |aContext| based on |aItem|.
7174
 */
7175
static void
7176
PushOpacity(gfxContext* aContext, AssignedDisplayItem& aItem)
7177
0
{
7178
0
  MOZ_ASSERT(aItem.mType == DisplayItemEntryType::PUSH_OPACITY ||
7179
0
             aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG);
7180
0
  MOZ_ASSERT(aItem.mItem->GetType() == DisplayItemType::TYPE_OPACITY);
7181
0
  nsDisplayOpacity* item = static_cast<nsDisplayOpacity*>(aItem.mItem);
7182
0
7183
0
  const float opacity = item->GetOpacity();
7184
0
  if (aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
7185
0
    aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA, opacity);
7186
0
  } else {
7187
0
    aContext->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity);
7188
0
  }
7189
0
}
7190
7191
/**
7192
 * Pushes the transformation matrix of |aItem| into |aMatrixStack| and sets the
7193
 * accumulated transform as the current transformation matrix for |aContext|.
7194
 */
7195
static void
7196
PushTransform(gfxContext* aContext,
7197
              AssignedDisplayItem& aItem,
7198
              nsDisplayListBuilder* aBuilder,
7199
              MatrixStack4x4& aMatrixStack,
7200
              const Matrix4x4Flagged& aBaseMatrix)
7201
0
{
7202
0
  MOZ_ASSERT(aItem.mType == DisplayItemEntryType::PUSH_TRANSFORM);
7203
0
  MOZ_ASSERT(aItem.mItem->GetType() == DisplayItemType::TYPE_TRANSFORM);
7204
0
7205
0
  nsDisplayTransform* item = static_cast<nsDisplayTransform*>(aItem.mItem);
7206
0
  if (item->ShouldSkipTransform(aBuilder)) {
7207
0
    aMatrixStack.Push(Matrix4x4Flagged());
7208
0
  } else {
7209
0
    aMatrixStack.Push(item->GetTransformForRendering());
7210
0
  }
7211
0
7212
0
  gfx::Matrix4x4Flagged matrix = aMatrixStack.CurrentMatrix() * aBaseMatrix;
7213
0
  gfx::Matrix matrix2d;
7214
0
  DebugOnly<bool> ok = matrix.CanDraw2D(&matrix2d);
7215
0
  MOZ_ASSERT(ok);
7216
0
7217
0
  aContext->SetMatrix(matrix2d);
7218
0
}
7219
7220
static void
7221
UpdateEffectTracking(int& aOpacityLevel,
7222
                     int& aTransformLevel,
7223
                     const DisplayItemEntryType aType)
7224
0
{
7225
0
  switch (aType) {
7226
0
    case DisplayItemEntryType::PUSH_OPACITY:
7227
0
    case DisplayItemEntryType::PUSH_OPACITY_WITH_BG:
7228
0
      aOpacityLevel++;
7229
0
      break;
7230
0
    case DisplayItemEntryType::POP_OPACITY:
7231
0
      aOpacityLevel--;
7232
0
      break;
7233
0
    case DisplayItemEntryType::PUSH_TRANSFORM:
7234
0
      aTransformLevel++;
7235
0
      break;
7236
0
    case DisplayItemEntryType::POP_TRANSFORM:
7237
0
      aTransformLevel--;
7238
0
      break;
7239
0
    default:
7240
0
      break;
7241
0
  }
7242
0
7243
0
  MOZ_ASSERT(aOpacityLevel >= 0 && aTransformLevel >= 0);
7244
0
}
7245
7246
void
7247
FrameLayerBuilder::PaintItems(std::vector<AssignedDisplayItem>& aItems,
7248
                              const nsIntRect& aRect,
7249
                              gfxContext* aContext,
7250
                              nsDisplayListBuilder* aBuilder,
7251
                              nsPresContext* aPresContext,
7252
                              const nsIntPoint& aOffset,
7253
                              float aXScale,
7254
                              float aYScale)
7255
0
{
7256
0
  DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
7257
0
7258
0
  int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
7259
0
  nsRect boundRect = ToAppUnits(aRect, appUnitsPerDevPixel);
7260
0
  boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
7261
0
                   NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
7262
0
  boundRect.ScaleInverseRoundOut(aXScale, aYScale);
7263
0
7264
#ifdef DEBUG
7265
  // Tracks effect nesting level. These are used to track that every effect
7266
  // start marker has a corresponding end marker.
7267
  int opacityLevel = 0;
7268
  int transformLevel = 0;
7269
#endif
7270
7271
0
  // Tracks effect nesting level for skipping items between effect markers,
7272
0
  // when the effect display item does not intersect with the invalidated area.
7273
0
  int emptyEffectLevel = 0;
7274
0
7275
0
  // Stores a simplified version of the item clip, if needed.
7276
0
  DisplayItemClip temporaryClip;
7277
0
7278
0
  // Two types of clips are used during PaintItems(): clips for items and clips
7279
0
  // for effects. Item clips are always the most recent clip set, and they are
7280
0
  // never nested. The previous item clip is reused, if the next item has the
7281
0
  // same clip. Item clips are removed when an effect starts or ends.
7282
0
  ItemClipTracker itemClipTracker(aContext, appUnitsPerDevPixel);
7283
0
7284
0
  // Since effects can be nested, the effect clips need to be nested as well.
7285
0
  // They are pushed for effect start marker, and popped for effect end marker.
7286
0
  // Effect clips are tracked by |effectClipStack|. If there are consecutive
7287
0
  // effects with the same clip, |effectClipStack| defers popping the clip for
7288
0
  // the first end marker, and tries to reuse the previously set clip, when
7289
0
  // processing the start marker for the next effect.
7290
0
  ClipStack effectClipStack(aContext, appUnitsPerDevPixel);
7291
0
7292
0
  MatrixStack4x4 matrixStack;
7293
0
  const Matrix4x4Flagged base = Matrix4x4::From2D(aContext->CurrentMatrix());
7294
0
7295
0
  for (uint32_t i = 0; i < aItems.size(); ++i) {
7296
0
    AssignedDisplayItem& cdi = aItems[i];
7297
0
    nsDisplayItem* item = cdi.mItem;
7298
0
7299
0
    const auto NextItemStartsEffect = [&]() {
7300
0
      const uint32_t next = i + 1;
7301
0
      return next < aItems.size() && IsEffectStartMarker(aItems[next].mType);
7302
0
    };
7303
0
7304
0
    if (!item) {
7305
0
      MOZ_ASSERT(cdi.mType == DisplayItemEntryType::ITEM);
7306
0
      continue;
7307
0
    }
7308
0
7309
0
    nsRect visibleRect = item->GetPaintRect();
7310
0
7311
0
    if (matrixStack.HasTransform()) {
7312
0
      MOZ_ASSERT(transformLevel > 0);
7313
0
7314
0
      if (IsEffectEndMarker(cdi.mType)) {
7315
0
        // Always process the effect end markers.
7316
0
        visibleRect = boundRect;
7317
0
      } else {
7318
0
        const Matrix4x4Flagged& matrix = matrixStack.CurrentMatrix();
7319
0
        visibleRect = nsLayoutUtils::MatrixTransformRect(
7320
0
          visibleRect, matrix, appUnitsPerDevPixel);
7321
0
      }
7322
0
    }
7323
0
7324
0
    const nsRect paintRect = visibleRect.Intersect(boundRect);
7325
0
7326
0
    if (paintRect.IsEmpty() || emptyEffectLevel > 0) {
7327
0
      // In order for this branch to be hit, either this item has an empty paint
7328
0
      // rect and nothing would be drawn, or an effect marker before this
7329
0
      // item had an empty paint rect. In the latter case, the items are skipped
7330
0
      // until effect POP markers bring |emptyEffectLevel| back to 0.
7331
0
      UpdateEffectTracking(emptyEffectLevel, emptyEffectLevel, cdi.mType);
7332
0
7333
0
      // Sometimes the item that was going to reuse the previous clip is culled.
7334
0
      // Since |PushClip()| is never called for culled items, pop the clip now.
7335
0
      effectClipStack.PopDeferredClip();
7336
0
      continue;
7337
0
    }
7338
0
7339
#ifdef MOZ_DUMP_PAINTING
7340
    AUTO_PROFILER_LABEL_DYNAMIC_CSTR(
7341
      "FrameLayerBuilder::PaintItems", GRAPHICS, item->Name());
7342
#else
7343
0
    AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems", GRAPHICS);
7344
0
#endif
7345
0
7346
0
    MOZ_ASSERT((opacityLevel == 0 && !cdi.mHasOpacity) ||
7347
0
               (opacityLevel > 0 && cdi.mHasOpacity) ||
7348
0
               (transformLevel == 0 && !cdi.mHasTransform) ||
7349
0
               (transformLevel > 0 && cdi.mHasTransform));
7350
0
7351
0
    if (cdi.mType != DisplayItemEntryType::ITEM) {
7352
0
      // If we are processing an effect marker, remove the current item clip, if
7353
0
      // there is one.
7354
0
      itemClipTracker.Restore();
7355
0
    }
7356
0
7357
0
    if (cdi.mType == DisplayItemEntryType::PUSH_OPACITY ||
7358
0
        cdi.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
7359
0
      // To avoid pushing large temporary surfaces, it is important to clip
7360
0
      // opacity group with both the paint rect and the actual opacity clip.
7361
0
      DisplayItemClip effectClip;
7362
0
      effectClip.SetTo(item->GetPaintRect());
7363
0
      effectClip.IntersectWith(item->GetClip());
7364
0
      effectClipStack.PushClip(effectClip);
7365
0
      PushOpacity(aContext, cdi);
7366
0
    }
7367
0
7368
0
    if (cdi.mType == DisplayItemEntryType::POP_OPACITY) {
7369
0
      MOZ_ASSERT(opacityLevel > 0);
7370
0
      aContext->PopGroupAndBlend();
7371
0
    }
7372
0
7373
0
    if (cdi.mType == DisplayItemEntryType::PUSH_TRANSFORM) {
7374
0
      effectClipStack.PushClip(item->GetClip());
7375
0
      aContext->Save();
7376
0
      PushTransform(aContext, cdi, aBuilder, matrixStack, base);
7377
0
    }
7378
0
7379
0
    if (cdi.mType == DisplayItemEntryType::POP_TRANSFORM) {
7380
0
      MOZ_ASSERT(transformLevel > 0);
7381
0
      matrixStack.Pop();
7382
0
      aContext->Restore();
7383
0
    }
7384
0
7385
0
    if (IsEffectEndMarker(cdi.mType)) {
7386
0
      // Pop the clip for the effect.
7387
0
      MOZ_ASSERT(effectClipStack.HasClips());
7388
0
7389
0
      // If the next item starts an effect, defer popping the current clip, and
7390
0
      // try to reuse it during the next call to |PushClip()|. Trying to reuse
7391
0
      // clips between nested effects would be difficult, for example due to
7392
0
      // possibly different coordinate system, so this optimization is limited
7393
0
      // to consecutive effects.
7394
0
      effectClipStack.PopClip(NextItemStartsEffect());
7395
0
    }
7396
0
7397
0
    if (cdi.mType != DisplayItemEntryType::ITEM) {
7398
#ifdef DEBUG
7399
      UpdateEffectTracking(opacityLevel, transformLevel, cdi.mType);
7400
#endif
7401
      // Nothing more to do with effect markers.
7402
0
      continue;
7403
0
    }
7404
0
7405
0
    const DisplayItemClip* itemClip = GetItemClip(item, temporaryClip);
7406
0
    bool itemPaintsOwnClip = false;
7407
0
7408
0
    if (itemClip && !itemClipTracker.HasClip(itemClip)) {
7409
0
      // The clip has changed. Remove the previous clip.
7410
0
      itemClipTracker.Restore();
7411
0
7412
0
      // Check if the item supports painting with clip.
7413
0
      itemPaintsOwnClip = item->CanPaintWithClip(*itemClip);
7414
0
7415
0
      if (!itemPaintsOwnClip) {
7416
0
        // Item does not support painting with clip, set the clip.
7417
0
        itemClipTracker.ChangeClipIfNeeded(itemClip);
7418
0
      }
7419
0
    }
7420
0
7421
0
    if (!itemClip) {
7422
0
      // Item does not need clipping, remove the clip if there is one.
7423
0
      itemClipTracker.Restore();
7424
0
    }
7425
0
7426
0
    if (cdi.mInactiveLayerManager) {
7427
0
      bool saved = aDrawTarget.GetPermitSubpixelAA();
7428
0
      PaintInactiveLayer(
7429
0
        aBuilder, cdi.mInactiveLayerManager, item, aContext, aContext);
7430
0
      aDrawTarget.SetPermitSubpixelAA(saved);
7431
0
    } else {
7432
0
      nsIFrame* frame = item->Frame();
7433
0
      if (aBuilder->IsPaintingToWindow()) {
7434
0
        frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
7435
0
      }
7436
#ifdef MOZ_DUMP_PAINTING
7437
      if (gfxEnv::DumpPaintItems()) {
7438
        DebugPaintItem(aDrawTarget, aPresContext, item, aBuilder);
7439
      } else
7440
#endif
7441
0
        if (itemPaintsOwnClip) {
7442
0
        MOZ_ASSERT(itemClip);
7443
0
        item->PaintWithClip(aBuilder, aContext, *itemClip);
7444
0
      } else {
7445
0
        item->Paint(aBuilder, aContext);
7446
0
      }
7447
0
    }
7448
0
  }
7449
0
7450
0
  itemClipTracker.Restore();
7451
0
7452
0
  MOZ_ASSERT(opacityLevel == 0);
7453
0
  MOZ_ASSERT(transformLevel == 0);
7454
0
  MOZ_ASSERT(emptyEffectLevel == 0);
7455
0
}
7456
7457
/**
7458
 * Returns true if it is preferred to draw the list of display
7459
 * items separately for each rect in the visible region rather
7460
 * than clipping to a complex region.
7461
 */
7462
static bool
7463
ShouldDrawRectsSeparately(DrawTarget* aDrawTarget, DrawRegionClip aClip)
7464
0
{
7465
0
  if (!gfxPrefs::LayoutPaintRectsSeparately() ||
7466
0
      aClip == DrawRegionClip::NONE) {
7467
0
    return false;
7468
0
  }
7469
0
7470
0
  return !aDrawTarget->SupportsRegionClipping();
7471
0
}
7472
7473
static void
7474
DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
7475
                          const IntRect& aBounds,
7476
                          nscolor aBackgroundColor)
7477
0
{
7478
0
  if (NS_GET_A(aBackgroundColor) > 0) {
7479
0
    ColorPattern color(ToDeviceColor(aBackgroundColor));
7480
0
    aDrawTarget.FillRect(Rect(aBounds), color);
7481
0
  }
7482
0
}
7483
7484
/*
7485
 * A note on residual transforms:
7486
 *
7487
 * In a transformed subtree we sometimes apply the PaintedLayer's
7488
 * "residual transform" when drawing content into the PaintedLayer.
7489
 * This is a translation by components in the range [-0.5,0.5) provided
7490
 * by the layer system; applying the residual transform followed by the
7491
 * transforms used by layer compositing ensures that the subpixel alignment
7492
 * of the content of the PaintedLayer exactly matches what it would be if
7493
 * we used cairo/Thebes to draw directly to the screen without going through
7494
 * retained layer buffers.
7495
 *
7496
 * The visible and valid regions of the PaintedLayer are computed without
7497
 * knowing the residual transform (because we don't know what the residual
7498
 * transform is going to be until we've built the layer tree!). So we have to
7499
 * consider whether content painted in the range [x, xmost) might be painted
7500
 * outside the visible region we computed for that content. The visible region
7501
 * would be [floor(x), ceil(xmost)). The content would be rendered at
7502
 * [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could
7503
 * indeed fall outside the computed visible region, which is not a big deal;
7504
 * similar issues already arise when we snap cliprects to nearest pixels.
7505
 * Note that if the rendering of the content is snapped to nearest pixels ---
7506
 * which it often is --- then the content is actually rendered at
7507
 * [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r)
7508
 * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
7509
 * always falls within the visible region we computed.
7510
 */
7511
7512
/* static */ void
7513
FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
7514
                                    gfxContext* aContext,
7515
                                    const nsIntRegion& aRegionToDraw,
7516
                                    const nsIntRegion& aDirtyRegion,
7517
                                    DrawRegionClip aClip,
7518
                                    const nsIntRegion& aRegionToInvalidate,
7519
                                    void* aCallbackData)
7520
0
{
7521
0
  DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
7522
0
7523
0
  AUTO_PROFILER_LABEL("FrameLayerBuilder::DrawPaintedLayer", GRAPHICS);
7524
0
7525
0
  nsDisplayListBuilder* builder =
7526
0
    static_cast<nsDisplayListBuilder*>(aCallbackData);
7527
0
7528
0
  FrameLayerBuilder* layerBuilder = aLayer->Manager()->GetLayerBuilder();
7529
0
  NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!");
7530
0
7531
0
  PaintedDisplayItemLayerUserData* userData =
7532
0
    static_cast<PaintedDisplayItemLayerUserData*>(
7533
0
      aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
7534
0
  NS_ASSERTION(userData, "where did our user data go?");
7535
0
  if (!userData->mContainerLayerFrame) {
7536
0
    return;
7537
0
  }
7538
0
7539
0
  bool shouldDrawRectsSeparately =
7540
0
    ShouldDrawRectsSeparately(&aDrawTarget, aClip);
7541
0
7542
0
  if (!shouldDrawRectsSeparately) {
7543
0
    if (aClip == DrawRegionClip::DRAW) {
7544
0
      gfxUtils::ClipToRegion(aContext, aRegionToDraw);
7545
0
    }
7546
0
7547
0
    DrawForcedBackgroundColor(
7548
0
      aDrawTarget, aRegionToDraw.GetBounds(), userData->mForcedBackgroundColor);
7549
0
  }
7550
0
7551
0
  // make the origin of the context coincide with the origin of the
7552
0
  // PaintedLayer
7553
0
  gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
7554
0
  nsIntPoint offset = GetTranslationForPaintedLayer(aLayer);
7555
0
  nsPresContext* presContext = userData->mContainerLayerFrame->PresContext();
7556
0
7557
0
  if (!userData->mVisibilityComputedRegion.Contains(aDirtyRegion) &&
7558
0
      !layerBuilder->GetContainingPaintedLayerData()) {
7559
0
    // Recompute visibility of items in our PaintedLayer, if required. Note
7560
0
    // that this recomputes visibility for all descendants of our display
7561
0
    // items too, so there's no need to do this for the items in inactive
7562
0
    // PaintedLayers. If aDirtyRegion has not changed since the previous call
7563
0
    // then we can skip this.
7564
0
    int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
7565
0
    RecomputeVisibilityForItems(userData->mItems,
7566
0
                                builder,
7567
0
                                aDirtyRegion,
7568
0
                                userData->mPreviousRecomputeVisibilityRect,
7569
0
                                offset,
7570
0
                                appUnitsPerDevPixel,
7571
0
                                userData->mXScale,
7572
0
                                userData->mYScale);
7573
0
    userData->mVisibilityComputedRegion = aDirtyRegion;
7574
0
  }
7575
0
7576
0
  if (shouldDrawRectsSeparately) {
7577
0
    for (auto iter = aRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
7578
0
      const nsIntRect& iterRect = iter.Get();
7579
0
      gfxContextAutoSaveRestore save(aContext);
7580
0
      aContext->NewPath();
7581
0
      aContext->Rectangle(ThebesRect(iterRect));
7582
0
      aContext->Clip();
7583
0
7584
0
      DrawForcedBackgroundColor(
7585
0
        aDrawTarget, iterRect, userData->mForcedBackgroundColor);
7586
0
7587
0
      // Apply the residual transform if it has been enabled, to ensure that
7588
0
      // snapping when we draw into aContext exactly matches the ideal
7589
0
      // transform. See above for why this is OK.
7590
0
      aContext->SetMatrixDouble(
7591
0
        aContext->CurrentMatrixDouble()
7592
0
          .PreTranslate(aLayer->GetResidualTranslation() -
7593
0
                        gfxPoint(offset.x, offset.y))
7594
0
          .PreScale(userData->mXScale, userData->mYScale));
7595
0
7596
0
      layerBuilder->PaintItems(userData->mItems,
7597
0
                               iterRect,
7598
0
                               aContext,
7599
0
                               builder,
7600
0
                               presContext,
7601
0
                               offset,
7602
0
                               userData->mXScale,
7603
0
                               userData->mYScale);
7604
0
      if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
7605
0
        aLayer->Manager()->AddPaintedPixelCount(iterRect.Area());
7606
0
      }
7607
0
    }
7608
0
  } else {
7609
0
    // Apply the residual transform if it has been enabled, to ensure that
7610
0
    // snapping when we draw into aContext exactly matches the ideal transform.
7611
0
    // See above for why this is OK.
7612
0
    aContext->SetMatrixDouble(
7613
0
      aContext->CurrentMatrixDouble()
7614
0
        .PreTranslate(aLayer->GetResidualTranslation() -
7615
0
                      gfxPoint(offset.x, offset.y))
7616
0
        .PreScale(userData->mXScale, userData->mYScale));
7617
0
7618
0
    layerBuilder->PaintItems(userData->mItems,
7619
0
                             aRegionToDraw.GetBounds(),
7620
0
                             aContext,
7621
0
                             builder,
7622
0
                             presContext,
7623
0
                             offset,
7624
0
                             userData->mXScale,
7625
0
                             userData->mYScale);
7626
0
    if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
7627
0
      aLayer->Manager()->AddPaintedPixelCount(aRegionToDraw.GetBounds().Area());
7628
0
    }
7629
0
  }
7630
0
7631
0
  bool isActiveLayerManager = !aLayer->Manager()->IsInactiveLayerManager();
7632
0
7633
0
  if (presContext->GetPaintFlashing() && isActiveLayerManager) {
7634
0
    gfxContextAutoSaveRestore save(aContext);
7635
0
    if (shouldDrawRectsSeparately) {
7636
0
      if (aClip == DrawRegionClip::DRAW) {
7637
0
        gfxUtils::ClipToRegion(aContext, aRegionToDraw);
7638
0
      }
7639
0
    }
7640
0
    FlashPaint(aContext);
7641
0
  }
7642
0
7643
0
  if (presContext->GetDocShell() && isActiveLayerManager) {
7644
0
    nsDocShell* docShell = static_cast<nsDocShell*>(presContext->GetDocShell());
7645
0
    RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
7646
0
7647
0
    if (timelines && timelines->HasConsumer(docShell)) {
7648
0
      timelines->AddMarkerForDocShell(
7649
0
        docShell, MakeUnique<LayerTimelineMarker>(aRegionToDraw));
7650
0
    }
7651
0
  }
7652
0
7653
0
  if (!aRegionToInvalidate.IsEmpty()) {
7654
0
    aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
7655
0
  }
7656
0
}
7657
7658
/* static */ void
7659
FrameLayerBuilder::DumpRetainedLayerTree(LayerManager* aManager,
7660
                                         std::stringstream& aStream,
7661
                                         bool aDumpHtml)
7662
0
{
7663
0
  aManager->Dump(aStream, "", aDumpHtml);
7664
0
}
7665
7666
nsDisplayItemGeometry*
7667
FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem)
7668
0
{
7669
0
  typedef SmallPointerArray<DisplayItemData> DataArray;
7670
0
7671
0
  // Retrieve the array of DisplayItemData associated with our frame.
7672
0
  const DataArray& dataArray = aItem->Frame()->DisplayItemData();
7673
0
7674
0
  // Find our display item data, if it exists, and return its geometry.
7675
0
  uint32_t itemPerFrameKey = aItem->GetPerFrameKey();
7676
0
  for (uint32_t i = 0; i < dataArray.Length(); i++) {
7677
0
    DisplayItemData* data =
7678
0
      DisplayItemData::AssertDisplayItemData(dataArray.ElementAt(i));
7679
0
    if (data->GetDisplayItemKey() == itemPerFrameKey) {
7680
0
      return data->GetGeometry();
7681
0
    }
7682
0
  }
7683
0
  if (RefPtr<WebRenderFallbackData> data =
7684
0
        GetWebRenderUserData<WebRenderFallbackData>(aItem->Frame(),
7685
0
                                                    itemPerFrameKey)) {
7686
0
    return data->GetGeometry();
7687
0
  }
7688
0
7689
0
  return nullptr;
7690
0
}
7691
7692
static gfx::Rect
7693
CalculateBounds(const nsTArray<DisplayItemClip::RoundedRect>& aRects,
7694
                int32_t aAppUnitsPerDevPixel)
7695
0
{
7696
0
  nsRect bounds = aRects[0].mRect;
7697
0
  for (uint32_t i = 1; i < aRects.Length(); ++i) {
7698
0
    bounds.UnionRect(bounds, aRects[i].mRect);
7699
0
  }
7700
0
7701
0
  return gfx::Rect(bounds.ToNearestPixels(aAppUnitsPerDevPixel));
7702
0
}
7703
7704
void
7705
ContainerState::SetupMaskLayer(Layer* aLayer, const DisplayItemClip& aClip)
7706
0
{
7707
0
  // don't build an unnecessary mask
7708
0
  if (aClip.GetRoundedRectCount() == 0) {
7709
0
    return;
7710
0
  }
7711
0
7712
0
  RefPtr<Layer> maskLayer = CreateMaskLayer(aLayer, aClip, Nothing());
7713
0
7714
0
  if (!maskLayer) {
7715
0
    return;
7716
0
  }
7717
0
7718
0
  aLayer->SetMaskLayer(maskLayer);
7719
0
}
7720
7721
static MaskLayerUserData*
7722
GetMaskLayerUserData(Layer* aMaskLayer)
7723
0
{
7724
0
  if (!aMaskLayer) {
7725
0
    return nullptr;
7726
0
  }
7727
0
7728
0
  return static_cast<MaskLayerUserData*>(
7729
0
    aMaskLayer->GetUserData(&gMaskLayerUserData));
7730
0
}
7731
7732
static void
7733
SetMaskLayerUserData(Layer* aMaskLayer)
7734
0
{
7735
0
  MOZ_ASSERT(aMaskLayer);
7736
0
7737
0
  aMaskLayer->SetUserData(&gMaskLayerUserData, new MaskLayerUserData());
7738
0
}
7739
7740
already_AddRefed<Layer>
7741
ContainerState::CreateMaskLayer(Layer* aLayer,
7742
                                const DisplayItemClip& aClip,
7743
                                const Maybe<size_t>& aForAncestorMaskLayer)
7744
0
{
7745
0
  // aLayer will never be the container layer created by an nsDisplayMask
7746
0
  // because nsDisplayMask propagates the DisplayItemClip to its contents
7747
0
  // and is not clipped itself.
7748
0
  // This assertion will fail if that ever stops being the case.
7749
0
  MOZ_ASSERT(!aLayer->GetUserData(&gCSSMaskLayerUserData),
7750
0
             "A layer contains round clips should not have css-mask on it.");
7751
0
7752
0
  // check if we can re-use the mask layer
7753
0
  RefPtr<ImageLayer> maskLayer = CreateOrRecycleMaskImageLayerFor(
7754
0
    MaskLayerKey(aLayer, aForAncestorMaskLayer),
7755
0
    GetMaskLayerUserData,
7756
0
    SetMaskLayerUserData);
7757
0
  MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer.get());
7758
0
7759
0
  int32_t A2D = mContainerFrame->PresContext()->AppUnitsPerDevPixel();
7760
0
  MaskLayerUserData newData(aClip, A2D, mParameters);
7761
0
  if (*userData == newData) {
7762
0
    return maskLayer.forget();
7763
0
  }
7764
0
7765
0
  gfx::Rect boundingRect =
7766
0
    CalculateBounds(newData.mRoundedClipRects, newData.mAppUnitsPerDevPixel);
7767
0
  boundingRect.Scale(mParameters.mXScale, mParameters.mYScale);
7768
0
  if (boundingRect.IsEmpty()) {
7769
0
    // Return early if we know that there is effectively no visible data.
7770
0
    return nullptr;
7771
0
  }
7772
0
7773
0
  uint32_t maxSize = mManager->GetMaxTextureSize();
7774
0
  NS_ASSERTION(maxSize > 0, "Invalid max texture size");
7775
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
7776
  // Make mask image width aligned to 4. See Bug 1245552.
7777
  gfx::Size surfaceSize(
7778
    std::min<gfx::Float>(
7779
      GetAlignedStride<4>(NSToIntCeil(boundingRect.Width()), 1), maxSize),
7780
    std::min<gfx::Float>(boundingRect.Height(), maxSize));
7781
#else
7782
  gfx::Size surfaceSize(std::min<gfx::Float>(boundingRect.Width(), maxSize),
7783
0
                        std::min<gfx::Float>(boundingRect.Height(), maxSize));
7784
0
#endif
7785
0
7786
0
  // maskTransform is applied to the clip when it is painted into the mask (as a
7787
0
  // component of imageTransform), and its inverse used when the mask is used
7788
0
  // for masking. It is the transform from the masked layer's space to mask
7789
0
  // space
7790
0
  gfx::Matrix maskTransform =
7791
0
    Matrix::Scaling(surfaceSize.width / boundingRect.Width(),
7792
0
                    surfaceSize.height / boundingRect.Height());
7793
0
  if (surfaceSize.IsEmpty()) {
7794
0
    // Return early if we know that the size of this mask surface is empty.
7795
0
    return nullptr;
7796
0
  }
7797
0
7798
0
  gfx::Point p = boundingRect.TopLeft();
7799
0
  maskTransform.PreTranslate(-p.x, -p.y);
7800
0
  // imageTransform is only used when the clip is painted to the mask
7801
0
  gfx::Matrix imageTransform = maskTransform;
7802
0
  imageTransform.PreScale(mParameters.mXScale, mParameters.mYScale);
7803
0
7804
0
  nsAutoPtr<MaskLayerImageCache::MaskLayerImageKey> newKey(
7805
0
    new MaskLayerImageCache::MaskLayerImageKey());
7806
0
7807
0
  // copy and transform the rounded rects
7808
0
  for (uint32_t i = 0; i < newData.mRoundedClipRects.Length(); ++i) {
7809
0
    newKey->mRoundedClipRects.AppendElement(
7810
0
      MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i],
7811
0
                                            mContainerFrame->PresContext()));
7812
0
    newKey->mRoundedClipRects[i].ScaleAndTranslate(imageTransform);
7813
0
  }
7814
0
  newKey->mKnowsCompositor = mManager->AsKnowsCompositor();
7815
0
7816
0
  const MaskLayerImageCache::MaskLayerImageKey* lookupKey = newKey;
7817
0
7818
0
  // check to see if we can reuse a mask image
7819
0
  RefPtr<ImageContainer> container =
7820
0
    GetMaskLayerImageCache()->FindImageFor(&lookupKey);
7821
0
7822
0
  if (!container) {
7823
0
    IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width),
7824
0
                           NSToIntCeil(surfaceSize.height));
7825
0
    // no existing mask image, so build a new one
7826
0
    MaskImageData imageData(surfaceSizeInt, mManager);
7827
0
    RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
7828
0
7829
0
    // fail if we can't get the right surface
7830
0
    if (!dt || !dt->IsValid()) {
7831
0
      NS_WARNING("Could not create DrawTarget for mask layer.");
7832
0
      return nullptr;
7833
0
    }
7834
0
7835
0
    RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
7836
0
    MOZ_ASSERT(context); // already checked the draw target above
7837
0
    context->Multiply(ThebesMatrix(imageTransform));
7838
0
7839
0
    // paint the clipping rects with alpha to create the mask
7840
0
    aClip.FillIntersectionOfRoundedRectClips(
7841
0
      context, Color(1.f, 1.f, 1.f, 1.f), newData.mAppUnitsPerDevPixel);
7842
0
7843
0
    // build the image and container
7844
0
    MOZ_ASSERT(aLayer->Manager() == mManager);
7845
0
    container = imageData.CreateImageAndImageContainer();
7846
0
    NS_ASSERTION(container, "Could not create image container for mask layer.");
7847
0
7848
0
    if (!container) {
7849
0
      return nullptr;
7850
0
    }
7851
0
7852
0
    GetMaskLayerImageCache()->PutImage(newKey.forget(), container);
7853
0
  }
7854
0
7855
0
  maskLayer->SetContainer(container);
7856
0
7857
0
  maskTransform.Invert();
7858
0
  Matrix4x4 matrix = Matrix4x4::From2D(maskTransform);
7859
0
  matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
7860
0
  maskLayer->SetBaseTransform(matrix);
7861
0
7862
0
  // save the details of the clip in user data
7863
0
  *userData = std::move(newData);
7864
0
  userData->mImageKey.Reset(lookupKey);
7865
0
7866
0
  return maskLayer.forget();
7867
0
}
7868
7869
} // namespace mozilla