Source code

Revision control

Other Tools

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 "WebRenderCommandBuilder.h"
8
9
#include "BasicLayers.h"
10
#include "mozilla/AutoRestore.h"
11
#include "mozilla/DebugOnly.h"
12
#include "mozilla/StaticPrefs_gfx.h"
13
#include "mozilla/gfx/2D.h"
14
#include "mozilla/gfx/Logging.h"
15
#include "mozilla/gfx/Types.h"
16
#include "mozilla/layers/AnimationHelper.h"
17
#include "mozilla/layers/ClipManager.h"
18
#include "mozilla/layers/ImageClient.h"
19
#include "mozilla/layers/RenderRootStateManager.h"
20
#include "mozilla/layers/WebRenderBridgeChild.h"
21
#include "mozilla/layers/WebRenderLayerManager.h"
22
#include "mozilla/layers/IpcResourceUpdateQueue.h"
23
#include "mozilla/layers/SharedSurfacesChild.h"
24
#include "mozilla/layers/SourceSurfaceSharedData.h"
25
#include "mozilla/layers/StackingContextHelper.h"
26
#include "mozilla/layers/UpdateImageHelper.h"
27
#include "mozilla/layers/WebRenderDrawEventRecorder.h"
28
#include "UnitTransforms.h"
29
#include "gfxEnv.h"
30
#include "nsDisplayListInvalidation.h"
31
#include "WebRenderCanvasRenderer.h"
32
#include "LayersLogging.h"
33
#include "LayerTreeInvalidation.h"
34
35
namespace mozilla {
36
namespace layers {
37
38
using namespace gfx;
39
static bool PaintByLayer(nsDisplayItem* aItem,
40
nsDisplayListBuilder* aDisplayListBuilder,
41
const RefPtr<BasicLayerManager>& aManager,
42
gfxContext* aContext, const gfx::Size& aScale,
43
const std::function<void()>& aPaintFunc);
44
static int sIndent;
45
#include <stdarg.h>
46
#include <stdio.h>
47
48
static void GP(const char* fmt, ...) {
49
va_list args;
50
va_start(args, fmt);
51
#if 0
52
for (int i = 0; i < sIndent; i++) { printf(" "); }
53
vprintf(fmt, args);
54
#endif
55
va_end(args);
56
}
57
58
// XXX: problems:
59
// - How do we deal with scrolling while having only a single invalidation rect?
60
// We can have a valid rect and an invalid rect. As we scroll the valid rect
61
// will move and the invalid rect will be the new area
62
63
struct BlobItemData;
64
static void DestroyBlobGroupDataProperty(nsTArray<BlobItemData*>* aArray);
65
NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(BlobGroupDataProperty,
66
nsTArray<BlobItemData*>,
67
DestroyBlobGroupDataProperty);
68
69
// These are currently manually allocated and ownership is help by the
70
// mDisplayItems hash table in DIGroup
71
struct BlobItemData {
72
// a weak pointer to the frame for this item.
73
// DisplayItemData has a mFrameList to deal with merged frames. Hopefully we
74
// don't need to worry about that.
75
nsIFrame* mFrame;
76
77
uint32_t mDisplayItemKey;
78
nsTArray<BlobItemData*>*
79
mArray; // a weak pointer to the array that's owned by the frame property
80
81
IntRect mRect;
82
// It would be nice to not need this. We need to be able to call
83
// ComputeInvalidationRegion. ComputeInvalidationRegion will sometimes reach
84
// into parent style structs to get information that can change the
85
// invalidation region
86
UniquePtr<nsDisplayItemGeometry> mGeometry;
87
DisplayItemClip mClip;
88
bool mUsed; // initialized near construction
89
// XXX: only used for debugging
90
bool mInvalid;
91
92
// a weak pointer to the group that owns this item
93
// we use this to track whether group for a particular item has changed
94
struct DIGroup* mGroup;
95
96
// properties that are used to emulate layer tree invalidation
97
Matrix mMatrix; // updated to track the current transform to device space
98
RefPtr<BasicLayerManager> mLayerManager;
99
100
// We need to keep a list of all the external surfaces used by the blob image.
101
// We do this on a per-display item basis so that the lists remains correct
102
// during invalidations.
103
std::vector<RefPtr<SourceSurface>> mExternalSurfaces;
104
105
IntRect mImageRect;
106
107
BlobItemData(DIGroup* aGroup, nsDisplayItem* aItem)
108
: mUsed(false), mGroup(aGroup) {
109
mInvalid = false;
110
mDisplayItemKey = aItem->GetPerFrameKey();
111
AddFrame(aItem->Frame());
112
}
113
114
private:
115
void AddFrame(nsIFrame* aFrame) {
116
mFrame = aFrame;
117
118
nsTArray<BlobItemData*>* array =
119
aFrame->GetProperty(BlobGroupDataProperty());
120
if (!array) {
121
array = new nsTArray<BlobItemData*>();
122
aFrame->SetProperty(BlobGroupDataProperty(), array);
123
}
124
array->AppendElement(this);
125
mArray = array;
126
}
127
128
public:
129
void ClearFrame() {
130
// Delete the weak pointer to this BlobItemData on the frame
131
MOZ_RELEASE_ASSERT(mFrame);
132
// the property may already be removed if WebRenderUserData got deleted
133
// first so we use our own mArray pointer.
134
mArray->RemoveElement(this);
135
136
// drop the entire property if nothing's left in the array
137
if (mArray->IsEmpty()) {
138
// If the frame is in the process of being destroyed this will fail
139
// but that's ok, because the the property will be removed then anyways
140
mFrame->DeleteProperty(BlobGroupDataProperty());
141
}
142
mFrame = nullptr;
143
}
144
145
~BlobItemData() {
146
if (mFrame) {
147
ClearFrame();
148
}
149
}
150
};
151
152
static BlobItemData* GetBlobItemData(nsDisplayItem* aItem) {
153
nsIFrame* frame = aItem->Frame();
154
uint32_t key = aItem->GetPerFrameKey();
155
const nsTArray<BlobItemData*>* array =
156
frame->GetProperty(BlobGroupDataProperty());
157
if (array) {
158
for (BlobItemData* item : *array) {
159
if (item->mDisplayItemKey == key) {
160
return item;
161
}
162
}
163
}
164
return nullptr;
165
}
166
167
// We keep around the BlobItemData so that when we invalidate it get properly
168
// included in the rect
169
static void DestroyBlobGroupDataProperty(nsTArray<BlobItemData*>* aArray) {
170
for (BlobItemData* item : *aArray) {
171
GP("DestroyBlobGroupDataProperty: %p-%d\n", item->mFrame,
172
item->mDisplayItemKey);
173
item->mFrame = nullptr;
174
}
175
delete aArray;
176
}
177
178
static void TakeExternalSurfaces(
179
WebRenderDrawEventRecorder* aRecorder,
180
std::vector<RefPtr<SourceSurface>>& aExternalSurfaces,
181
RenderRootStateManager* aManager, wr::IpcResourceUpdateQueue& aResources) {
182
aRecorder->TakeExternalSurfaces(aExternalSurfaces);
183
184
for (auto& surface : aExternalSurfaces) {
185
// While we don't use the image key with the surface, because the blob image
186
// renderer doesn't have easy access to the resource set, we still want to
187
// ensure one is generated. That will ensure the surface remains alive until
188
// at least the last epoch which the blob image could be used in.
189
wr::ImageKey key;
190
DebugOnly<nsresult> rv =
191
SharedSurfacesChild::Share(surface, aManager, aResources, key);
192
MOZ_ASSERT(rv.value != NS_ERROR_NOT_IMPLEMENTED);
193
}
194
}
195
196
struct DIGroup;
197
struct Grouper {
198
explicit Grouper(ClipManager& aClipManager)
199
: mAppUnitsPerDevPixel(0),
200
mDisplayListBuilder(nullptr),
201
mClipManager(aClipManager) {}
202
203
int32_t mAppUnitsPerDevPixel;
204
nsDisplayListBuilder* mDisplayListBuilder;
205
ClipManager& mClipManager;
206
Matrix mTransform;
207
208
// Paint the list of aChildren display items.
209
void PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem,
210
BlobItemData* aData, const IntRect& aItemBounds,
211
nsDisplayList* aChildren, gfxContext* aContext,
212
WebRenderDrawEventRecorder* aRecorder,
213
RenderRootStateManager* aRootManager,
214
wr::IpcResourceUpdateQueue& aResources);
215
216
// Builds groups of display items split based on 'layer activity'
217
void ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder,
218
WebRenderCommandBuilder* aCommandBuilder,
219
wr::DisplayListBuilder& aBuilder,
220
wr::IpcResourceUpdateQueue& aResources, DIGroup* aGroup,
221
nsDisplayList* aList, const StackingContextHelper& aSc);
222
// Builds a group of display items without promoting anything to active.
223
void ConstructGroupInsideInactive(WebRenderCommandBuilder* aCommandBuilder,
224
wr::DisplayListBuilder& aBuilder,
225
wr::IpcResourceUpdateQueue& aResources,
226
DIGroup* aGroup, nsDisplayList* aList,
227
const StackingContextHelper& aSc);
228
// Helper method for processing a single inactive item
229
void ConstructItemInsideInactive(WebRenderCommandBuilder* aCommandBuilder,
230
wr::DisplayListBuilder& aBuilder,
231
wr::IpcResourceUpdateQueue& aResources,
232
DIGroup* aGroup, nsDisplayItem* aItem,
233
const StackingContextHelper& aSc);
234
~Grouper() {}
235
};
236
237
// Returns whether this is an item for which complete invalidation was
238
// reliant on LayerTreeInvalidation in the pre-webrender world.
239
static bool IsContainerLayerItem(nsDisplayItem* aItem) {
240
switch (aItem->GetType()) {
241
case DisplayItemType::TYPE_WRAP_LIST:
242
case DisplayItemType::TYPE_CONTAINER:
243
case DisplayItemType::TYPE_TRANSFORM:
244
case DisplayItemType::TYPE_OPACITY:
245
case DisplayItemType::TYPE_FILTER:
246
case DisplayItemType::TYPE_BLEND_CONTAINER:
247
case DisplayItemType::TYPE_BLEND_MODE:
248
case DisplayItemType::TYPE_MASK:
249
case DisplayItemType::TYPE_PERSPECTIVE: {
250
return true;
251
}
252
default: {
253
return false;
254
}
255
}
256
}
257
258
#include <sstream>
259
260
static bool DetectContainerLayerPropertiesBoundsChange(
261
nsDisplayItem* aItem, BlobItemData* aData,
262
nsDisplayItemGeometry& aGeometry) {
263
if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
264
// Filters go through BasicLayerManager composition which clips to
265
// the BuildingRect
266
aGeometry.mBounds = aGeometry.mBounds.Intersect(aItem->GetBuildingRect());
267
}
268
269
return !aGeometry.mBounds.IsEqualEdges(aData->mGeometry->mBounds);
270
}
271
272
struct DIGroup {
273
// XXX: Storing owning pointers to the BlobItemData in a hash table is not
274
// a good choice. There are two better options:
275
//
276
// 1. We should just be using a linked list for this stuff.
277
// That we can iterate over only the used items.
278
// We remove from the unused list and add to the used list
279
// when we see an item.
280
//
281
// we allocate using a free list.
282
//
283
// 2. We can use a Vec and use SwapRemove().
284
// We'll just need to be careful when iterating.
285
// The advantage of a Vec is that everything stays compact
286
// and we don't need to heap allocate the BlobItemData's
287
nsTHashtable<nsPtrHashKey<BlobItemData>> mDisplayItems;
288
289
IntRect mInvalidRect;
290
nsRect mGroupBounds;
291
LayerIntRect mVisibleRect;
292
// This is the last visible rect sent to WebRender. It's used
293
// to compute the invalid rect and ensure that we send
294
// the appropriate data to WebRender for merging.
295
LayerIntRect mLastVisibleRect;
296
297
// This is the intersection of mVisibleRect and mLastVisibleRect
298
// we ensure that mInvalidRect is contained in mPreservedRect
299
IntRect mPreservedRect;
300
IntRect mActualBounds;
301
int32_t mAppUnitsPerDevPixel;
302
gfx::Size mScale;
303
ScrollableLayerGuid::ViewID mScrollId;
304
LayerPoint mResidualOffset;
305
LayerIntRect mLayerBounds; // mGroupBounds converted to Layer space
306
// mLayerBounds clipped to the container/parent of the
307
// current item being processed.
308
IntRect mClippedImageBounds; // mLayerBounds with the clipping of any
309
// containers applied
310
Maybe<mozilla::Pair<wr::RenderRoot, wr::BlobImageKey>> mKey;
311
std::vector<RefPtr<ScaledFont>> mFonts;
312
313
DIGroup()
314
: mAppUnitsPerDevPixel(0),
315
mScrollId(ScrollableLayerGuid::NULL_SCROLL_ID) {}
316
317
void InvalidateRect(const IntRect& aRect) {
318
auto r = aRect.Intersect(mPreservedRect);
319
// Empty rects get dropped
320
if (!r.IsEmpty()) {
321
mInvalidRect = mInvalidRect.Union(r);
322
}
323
}
324
325
IntRect ItemBounds(nsDisplayItem* aItem) {
326
BlobItemData* data = GetBlobItemData(aItem);
327
return data->mRect;
328
}
329
330
void ClearItems() {
331
GP("items: %d\n", mDisplayItems.Count());
332
for (auto iter = mDisplayItems.Iter(); !iter.Done(); iter.Next()) {
333
BlobItemData* data = iter.Get()->GetKey();
334
GP("Deleting %p-%d\n", data->mFrame, data->mDisplayItemKey);
335
iter.Remove();
336
delete data;
337
}
338
}
339
340
void ClearImageKey(RenderRootStateManager* aManager, bool aForce = false) {
341
if (mKey) {
342
MOZ_RELEASE_ASSERT(aForce || mInvalidRect.IsEmpty());
343
aManager->AddBlobImageKeyForDiscard(mKey.value().second());
344
mKey = Nothing();
345
}
346
mFonts.clear();
347
}
348
349
static IntRect ToDeviceSpace(nsRect aBounds, Matrix& aMatrix,
350
int32_t aAppUnitsPerDevPixel) {
351
// RoundedOut can convert empty rectangles to non-empty ones
352
// so special case them here
353
if (aBounds.IsEmpty()) {
354
return IntRect();
355
}
356
return RoundedOut(aMatrix.TransformBounds(
357
ToRect(nsLayoutUtils::RectToGfxRect(aBounds, aAppUnitsPerDevPixel))));
358
}
359
360
void ComputeGeometryChange(nsDisplayItem* aItem, BlobItemData* aData,
361
Matrix& aMatrix, nsDisplayListBuilder* aBuilder) {
362
// If the frame is marked as invalidated, and didn't specify a rect to
363
// invalidate then we want to invalidate both the old and new bounds,
364
// otherwise we only want to invalidate the changed areas. If we do get an
365
// invalid rect, then we want to add this on top of the change areas.
366
nsRect invalid;
367
const DisplayItemClip& clip = aItem->GetClip();
368
369
int32_t appUnitsPerDevPixel =
370
aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
371
MOZ_RELEASE_ASSERT(mAppUnitsPerDevPixel == appUnitsPerDevPixel);
372
GP("\n");
373
GP("clippedImageRect %d %d %d %d\n", mClippedImageBounds.x,
374
mClippedImageBounds.y, mClippedImageBounds.width,
375
mClippedImageBounds.height);
376
LayerIntSize size = mVisibleRect.Size();
377
GP("imageSize: %d %d\n", size.width, size.height);
378
/*if (aItem->IsReused() && aData->mGeometry) {
379
return;
380
}*/
381
382
GP("pre mInvalidRect: %s %p-%d - inv: %d %d %d %d\n", aItem->Name(),
383
aItem->Frame(), aItem->GetPerFrameKey(), mInvalidRect.x, mInvalidRect.y,
384
mInvalidRect.width, mInvalidRect.height);
385
if (!aData->mGeometry) {
386
// This item is being added for the first time, invalidate its entire
387
// area.
388
UniquePtr<nsDisplayItemGeometry> geometry(
389
aItem->AllocateGeometry(aBuilder));
390
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
391
geometry->ComputeInvalidationRegion());
392
aData->mGeometry = std::move(geometry);
393
394
IntRect transformedRect =
395
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
396
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
397
GP("CGC %s %d %d %d %d\n", aItem->Name(), clippedBounds.x,
398
clippedBounds.y, clippedBounds.width, clippedBounds.height);
399
GP("%d %d, %f %f\n", mVisibleRect.TopLeft().x, mVisibleRect.TopLeft().y,
400
aMatrix._11, aMatrix._22);
401
GP("mRect %d %d %d %d\n", aData->mRect.x, aData->mRect.y,
402
aData->mRect.width, aData->mRect.height);
403
InvalidateRect(aData->mRect);
404
aData->mInvalid = true;
405
} else if (aData->mInvalid ||
406
/* XXX: handle image load invalidation */ (
407
aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
408
UniquePtr<nsDisplayItemGeometry> geometry(
409
aItem->AllocateGeometry(aBuilder));
410
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
411
geometry->ComputeInvalidationRegion());
412
aData->mGeometry = std::move(geometry);
413
414
GP("matrix: %f %f\n", aMatrix._31, aMatrix._32);
415
GP("frame invalid invalidate: %s\n", aItem->Name());
416
GP("old rect: %d %d %d %d\n", aData->mRect.x, aData->mRect.y,
417
aData->mRect.width, aData->mRect.height);
418
InvalidateRect(aData->mRect);
419
// We want to snap to outside pixels. When should we multiply by the
420
// matrix?
421
// XXX: TransformBounds is expensive. We should avoid doing it if we have
422
// no transform
423
IntRect transformedRect =
424
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
425
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
426
InvalidateRect(aData->mRect);
427
GP("new rect: %d %d %d %d\n", aData->mRect.x, aData->mRect.y,
428
aData->mRect.width, aData->mRect.height);
429
aData->mInvalid = true;
430
} else {
431
GP("else invalidate: %s\n", aItem->Name());
432
nsRegion combined;
433
// this includes situations like reflow changing the position
434
aItem->ComputeInvalidationRegion(aBuilder, aData->mGeometry.get(),
435
&combined);
436
if (!combined.IsEmpty()) {
437
// There might be no point in doing this elaborate tracking here to get
438
// smaller areas
439
InvalidateRect(aData->mRect); // invalidate the old area -- in theory
440
// combined should take care of this
441
UniquePtr<nsDisplayItemGeometry> geometry(
442
aItem->AllocateGeometry(aBuilder));
443
// invalidate the invalidated area.
444
445
aData->mGeometry = std::move(geometry);
446
447
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
448
aData->mGeometry->ComputeInvalidationRegion());
449
IntRect transformedRect =
450
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
451
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
452
InvalidateRect(aData->mRect);
453
454
aData->mInvalid = true;
455
} else {
456
if (aData->mClip != clip) {
457
UniquePtr<nsDisplayItemGeometry> geometry(
458
aItem->AllocateGeometry(aBuilder));
459
if (!IsContainerLayerItem(aItem)) {
460
// the bounds of layer items can change on us without
461
// ComputeInvalidationRegion returning any change. Other items
462
// shouldn't have any hidden geometry change.
463
MOZ_RELEASE_ASSERT(
464
geometry->mBounds.IsEqualEdges(aData->mGeometry->mBounds));
465
} else {
466
aData->mGeometry = std::move(geometry);
467
}
468
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
469
aData->mGeometry->ComputeInvalidationRegion());
470
IntRect transformedRect =
471
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
472
InvalidateRect(aData->mRect);
473
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
474
InvalidateRect(aData->mRect);
475
476
GP("ClipChange: %s %d %d %d %d\n", aItem->Name(), aData->mRect.x,
477
aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
478
479
} else if (!aMatrix.ExactlyEquals(aData->mMatrix)) {
480
// We haven't detected any changes so far. Unfortunately we don't
481
// currently have a good way of checking if the transform has changed
482
// so we just store it and see if it see if it has changed.
483
// If we want this to go faster, we can probably put a flag on the
484
// frame using the style sytem UpdateTransformLayer hint and check for
485
// that.
486
487
UniquePtr<nsDisplayItemGeometry> geometry(
488
aItem->AllocateGeometry(aBuilder));
489
if (!IsContainerLayerItem(aItem)) {
490
// the bounds of layer items can change on us
491
// other items shouldn't
492
MOZ_RELEASE_ASSERT(
493
geometry->mBounds.IsEqualEdges(aData->mGeometry->mBounds));
494
} else {
495
aData->mGeometry = std::move(geometry);
496
}
497
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
498
aData->mGeometry->ComputeInvalidationRegion());
499
IntRect transformedRect =
500
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
501
InvalidateRect(aData->mRect);
502
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
503
InvalidateRect(aData->mRect);
504
505
GP("TransformChange: %s %d %d %d %d\n", aItem->Name(), aData->mRect.x,
506
aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
507
} else if (IsContainerLayerItem(aItem)) {
508
UniquePtr<nsDisplayItemGeometry> geometry(
509
aItem->AllocateGeometry(aBuilder));
510
// we need to catch bounds changes of containers so that we continue
511
// to have the correct bounds rects in the recording
512
if (DetectContainerLayerPropertiesBoundsChange(aItem, aData,
513
*geometry)) {
514
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
515
geometry->ComputeInvalidationRegion());
516
aData->mGeometry = std::move(geometry);
517
IntRect transformedRect =
518
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
519
InvalidateRect(aData->mRect);
520
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
521
InvalidateRect(aData->mRect);
522
GP("DetectContainerLayerPropertiesBoundsChange change\n");
523
} else {
524
// Handle changes in mClippedImageBounds
525
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
526
geometry->ComputeInvalidationRegion());
527
IntRect transformedRect =
528
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
529
auto rect = transformedRect.Intersect(mClippedImageBounds);
530
if (!rect.IsEqualEdges(aData->mRect)) {
531
GP("ContainerLayer image rect bounds change\n");
532
InvalidateRect(aData->mRect);
533
aData->mRect = rect;
534
InvalidateRect(aData->mRect);
535
} else {
536
GP("Layer NoChange: %s %d %d %d %d\n", aItem->Name(),
537
aData->mRect.x, aData->mRect.y, aData->mRect.XMost(),
538
aData->mRect.YMost());
539
}
540
}
541
} else {
542
UniquePtr<nsDisplayItemGeometry> geometry(
543
aItem->AllocateGeometry(aBuilder));
544
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
545
geometry->ComputeInvalidationRegion());
546
IntRect transformedRect =
547
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
548
auto rect = transformedRect.Intersect(mClippedImageBounds);
549
// Make sure we update mRect for mClippedImageBounds changes
550
if (!rect.IsEqualEdges(aData->mRect)) {
551
GP("ContainerLayer image rect bounds change\n");
552
InvalidateRect(aData->mRect);
553
aData->mRect = rect;
554
InvalidateRect(aData->mRect);
555
} else {
556
GP("NoChange: %s %d %d %d %d\n", aItem->Name(), aData->mRect.x,
557
aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
558
}
559
}
560
}
561
}
562
mActualBounds.OrWith(aData->mRect);
563
aData->mClip = clip;
564
aData->mMatrix = aMatrix;
565
aData->mImageRect = mClippedImageBounds;
566
GP("post mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y,
567
mInvalidRect.width, mInvalidRect.height);
568
}
569
570
void EndGroup(WebRenderLayerManager* aWrManager,
571
nsDisplayListBuilder* aDisplayListBuilder,
572
wr::DisplayListBuilder& aBuilder,
573
wr::IpcResourceUpdateQueue& aResources, Grouper* aGrouper,
574
nsDisplayItem* aStartItem, nsDisplayItem* aEndItem) {
575
GP("\n\n");
576
GP("Begin EndGroup\n");
577
578
mVisibleRect = mVisibleRect.Intersect(ViewAs<LayerPixel>(
579
mActualBounds, PixelCastJustification::LayerIsImage));
580
581
if (mVisibleRect.IsEmpty()) {
582
return;
583
}
584
585
// Invalidate any unused items
586
GP("mDisplayItems\n");
587
for (auto iter = mDisplayItems.Iter(); !iter.Done(); iter.Next()) {
588
BlobItemData* data = iter.Get()->GetKey();
589
GP(" : %p-%d\n", data->mFrame, data->mDisplayItemKey);
590
if (!data->mUsed) {
591
GP("Invalidate unused: %p-%d\n", data->mFrame, data->mDisplayItemKey);
592
InvalidateRect(data->mRect);
593
iter.Remove();
594
delete data;
595
} else {
596
data->mUsed = false;
597
}
598
}
599
600
IntSize dtSize = mVisibleRect.Size().ToUnknownSize();
601
// The actual display item's size shouldn't have the scale factored in
602
// Round the bounds out to leave space for unsnapped content
603
LayoutDeviceToLayerScale2D scale(mScale.width, mScale.height);
604
LayoutDeviceRect itemBounds =
605
(LayerRect(mVisibleRect) - mResidualOffset) / scale;
606
607
if (mInvalidRect.IsEmpty() && mVisibleRect.IsEqualEdges(mLastVisibleRect)) {
608
GP("Not repainting group because it's empty\n");
609
GP("End EndGroup\n");
610
if (mKey) {
611
// Although the contents haven't changed, the visible area *may* have,
612
// so request it be updated unconditionally (wr should be able to easily
613
// detect if this is a no-op on its side, if that matters)
614
aResources.SetBlobImageVisibleArea(
615
mKey.value().second(),
616
ViewAs<ImagePixel>(mVisibleRect,
617
PixelCastJustification::LayerIsImage));
618
mLastVisibleRect = mVisibleRect;
619
PushImage(aBuilder, itemBounds);
620
}
621
return;
622
}
623
624
gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
625
std::vector<RefPtr<ScaledFont>> fonts;
626
bool validFonts = true;
627
RefPtr<WebRenderDrawEventRecorder> recorder =
628
MakeAndAddRef<WebRenderDrawEventRecorder>(
629
[&](MemStream& aStream,
630
std::vector<RefPtr<ScaledFont>>& aScaledFonts) {
631
size_t count = aScaledFonts.size();
632
aStream.write((const char*)&count, sizeof(count));
633
for (auto& scaled : aScaledFonts) {
634
Maybe<wr::FontInstanceKey> key =
635
aWrManager->WrBridge()->GetFontKeyForScaledFont(
636
scaled, aBuilder.GetRenderRoot(), &aResources);
637
if (key.isNothing()) {
638
validFonts = false;
639
break;
640
}
641
BlobFont font = {key.value(), scaled};
642
aStream.write((const char*)&font, sizeof(font));
643
}
644
fonts = std::move(aScaledFonts);
645
});
646
647
RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(
648
gfx::BackendType::SKIA, gfx::IntSize(1, 1), format);
649
650
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(
651
recorder, dummyDt, mLayerBounds.ToUnknownRect());
652
// Setup the gfxContext
653
RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
654
context->SetMatrix(
655
Matrix::Scaling(mScale.width, mScale.height)
656
.PostTranslate(mResidualOffset.x, mResidualOffset.y));
657
658
GP("mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y,
659
mInvalidRect.width, mInvalidRect.height);
660
661
RenderRootStateManager* rootManager =
662
aWrManager->GetRenderRootStateManager(aBuilder.GetRenderRoot());
663
bool empty = aStartItem == aEndItem;
664
if (empty) {
665
ClearImageKey(rootManager, true);
666
return;
667
}
668
669
PaintItemRange(aGrouper, aStartItem, aEndItem, context, recorder,
670
rootManager, aResources);
671
672
// XXX: set this correctly perhaps using
673
// aItem->GetOpaqueRegion(aDisplayListBuilder, &snapped).
674
// Contains(paintBounds);?
675
wr::OpacityType opacity = wr::OpacityType::HasAlphaChannel;
676
677
bool hasItems = recorder->Finish();
678
GP("%d Finish\n", hasItems);
679
if (!validFonts) {
680
gfxCriticalNote << "Failed serializing fonts for blob image";
681
return;
682
}
683
Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData,
684
recorder->mOutputStream.mLength);
685
if (!mKey) {
686
// we don't want to send a new image that doesn't have any
687
// items in it
688
if (!hasItems || mVisibleRect.IsEmpty()) {
689
return;
690
}
691
692
wr::BlobImageKey key =
693
wr::BlobImageKey{aWrManager->WrBridge()->GetNextImageKey()};
694
GP("No previous key making new one %d\n", key._0.mHandle);
695
wr::ImageDescriptor descriptor(dtSize, 0, dt->GetFormat(), opacity);
696
MOZ_RELEASE_ASSERT(bytes.length() > sizeof(size_t));
697
if (!aResources.AddBlobImage(
698
key, descriptor, bytes,
699
ViewAs<ImagePixel>(mVisibleRect,
700
PixelCastJustification::LayerIsImage))) {
701
return;
702
}
703
mKey = Some(MakePair(aBuilder.GetRenderRoot(), key));
704
} else {
705
wr::ImageDescriptor descriptor(dtSize, 0, dt->GetFormat(), opacity);
706
707
// Convert mInvalidRect to image space by subtracting the corner of the
708
// image bounds
709
auto dirtyRect = ViewAs<ImagePixel>(mInvalidRect);
710
711
auto bottomRight = dirtyRect.BottomRight();
712
GP("check invalid %d %d - %d %d\n", bottomRight.x, bottomRight.y,
713
dtSize.width, dtSize.height);
714
GP("Update Blob %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y,
715
mInvalidRect.width, mInvalidRect.height);
716
if (!aResources.UpdateBlobImage(
717
mKey.value().second(), descriptor, bytes,
718
ViewAs<ImagePixel>(mVisibleRect,
719
PixelCastJustification::LayerIsImage),
720
dirtyRect)) {
721
return;
722
}
723
}
724
mFonts = std::move(fonts);
725
aResources.SetBlobImageVisibleArea(
726
mKey.value().second(),
727
ViewAs<ImagePixel>(mVisibleRect, PixelCastJustification::LayerIsImage));
728
mLastVisibleRect = mVisibleRect;
729
PushImage(aBuilder, itemBounds);
730
GP("End EndGroup\n\n");
731
}
732
733
void PushImage(wr::DisplayListBuilder& aBuilder,
734
const LayoutDeviceRect& bounds) {
735
wr::LayoutRect dest = wr::ToLayoutRect(bounds);
736
GP("PushImage: %f %f %f %f\n", dest.origin.x, dest.origin.y,
737
dest.size.width, dest.size.height);
738
gfx::SamplingFilter sampleFilter = gfx::SamplingFilter::
739
LINEAR; // nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
740
bool backfaceHidden = false;
741
742
// We don't really know the exact shape of this blob because it may contain
743
// SVG shapes so generate an irregular-area hit-test region for it.
744
CompositorHitTestInfo hitInfo(CompositorHitTestFlags::eVisibleToHitTest,
745
CompositorHitTestFlags::eIrregularArea);
746
747
// XXX - clipping the item against the paint rect breaks some content.
748
// cf. Bug 1455422.
749
// wr::LayoutRect clip = wr::ToLayoutRect(bounds.Intersect(mVisibleRect));
750
751
aBuilder.SetHitTestInfo(mScrollId, hitInfo);
752
aBuilder.PushImage(dest, dest, !backfaceHidden,
753
wr::ToImageRendering(sampleFilter),
754
wr::AsImageKey(mKey.value().second()));
755
aBuilder.ClearHitTestInfo();
756
}
757
758
void PaintItemRange(Grouper* aGrouper, nsDisplayItem* aStartItem,
759
nsDisplayItem* aEndItem, gfxContext* aContext,
760
WebRenderDrawEventRecorder* aRecorder,
761
RenderRootStateManager* aRootManager,
762
wr::IpcResourceUpdateQueue& aResources) {
763
LayerIntSize size = mVisibleRect.Size();
764
for (nsDisplayItem* item = aStartItem; item != aEndItem;
765
item = item->GetAbove()) {
766
BlobItemData* data = GetBlobItemData(item);
767
IntRect bounds = data->mRect;
768
auto bottomRight = bounds.BottomRight();
769
770
GP("Trying %s %p-%d %d %d %d %d\n", item->Name(), item->Frame(),
771
item->GetPerFrameKey(), bounds.x, bounds.y, bounds.XMost(),
772
bounds.YMost());
773
GP("paint check invalid %d %d - %d %d\n", bottomRight.x, bottomRight.y,
774
size.width, size.height);
775
// skip empty items
776
if (bounds.IsEmpty()) {
777
continue;
778
}
779
780
bool dirty = true;
781
auto preservedBounds = bounds.Intersect(mPreservedRect);
782
if (!mInvalidRect.Contains(preservedBounds)) {
783
GP("Passing\n");
784
dirty = false;
785
BlobItemData* data = GetBlobItemData(item);
786
if (data->mInvalid) {
787
gfxCriticalError()
788
<< "DisplayItem" << item->Name() << "-should be invalid";
789
}
790
// if the item is invalid it needs to be fully contained
791
MOZ_RELEASE_ASSERT(!data->mInvalid);
792
}
793
794
nsDisplayList* children = item->GetChildren();
795
if (children) {
796
GP("doing children in EndGroup\n");
797
aGrouper->PaintContainerItem(this, item, data, bounds, children,
798
aContext, aRecorder, aRootManager,
799
aResources);
800
} else {
801
nsPaintedDisplayItem* paintedItem = item->AsPaintedDisplayItem();
802
if (paintedItem &&
803
// Hit test items don't have anything to paint so skip them.
804
// Ideally we would drop these items earlier...
805
item->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
806
if (dirty) {
807
// What should the clip settting strategy be? We can set the full
808
// clip everytime. this is probably easiest for now. An alternative
809
// would be to put the push and the pop into separate items and let
810
// invalidation handle it that way.
811
DisplayItemClip currentClip = paintedItem->GetClip();
812
813
if (currentClip.HasClip()) {
814
aContext->Save();
815
currentClip.ApplyTo(aContext, aGrouper->mAppUnitsPerDevPixel);
816
}
817
aContext->NewPath();
818
GP("painting %s %p-%d\n", paintedItem->Name(), paintedItem->Frame(),
819
paintedItem->GetPerFrameKey());
820
if (aGrouper->mDisplayListBuilder->IsPaintingToWindow()) {
821
paintedItem->Frame()->AddStateBits(NS_FRAME_PAINTED_THEBES);
822
}
823
824
paintedItem->Paint(aGrouper->mDisplayListBuilder, aContext);
825
TakeExternalSurfaces(aRecorder, data->mExternalSurfaces,
826
aRootManager, aResources);
827
828
if (currentClip.HasClip()) {
829
aContext->Restore();
830
}
831
}
832
aContext->GetDrawTarget()->FlushItem(bounds);
833
}
834
}
835
}
836
}
837
838
~DIGroup() {
839
GP("Group destruct\n");
840
for (auto iter = mDisplayItems.Iter(); !iter.Done(); iter.Next()) {
841
BlobItemData* data = iter.Get()->GetKey();
842
GP("Deleting %p-%d\n", data->mFrame, data->mDisplayItemKey);
843
iter.Remove();
844
delete data;
845
}
846
}
847
};
848
849
// If we have an item we need to make sure it matches the current group
850
// otherwise it means the item switched groups and we need to invalidate
851
// it and recreate the data.
852
static BlobItemData* GetBlobItemDataForGroup(nsDisplayItem* aItem,
853
DIGroup* aGroup) {
854
BlobItemData* data = GetBlobItemData(aItem);
855
if (data) {
856
MOZ_RELEASE_ASSERT(data->mGroup->mDisplayItems.Contains(data));
857
if (data->mGroup != aGroup) {
858
GP("group don't match %p %p\n", data->mGroup, aGroup);
859
data->ClearFrame();
860
// the item is for another group
861
// it should be cleared out as being unused at the end of this paint
862
data = nullptr;
863
}
864
}
865
if (!data) {
866
GP("Allocating blob data\n");
867
data = new BlobItemData(aGroup, aItem);
868
aGroup->mDisplayItems.PutEntry(data);
869
}
870
data->mUsed = true;
871
return data;
872
}
873
874
void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem,
875
BlobItemData* aData,
876
const IntRect& aItemBounds,
877
nsDisplayList* aChildren, gfxContext* aContext,
878
WebRenderDrawEventRecorder* aRecorder,
879
RenderRootStateManager* aRootManager,
880
wr::IpcResourceUpdateQueue& aResources) {
881
switch (aItem->GetType()) {
882
case DisplayItemType::TYPE_TRANSFORM: {
883
DisplayItemClip currentClip = aItem->GetClip();
884
885
gfxContextMatrixAutoSaveRestore saveMatrix;
886
if (currentClip.HasClip()) {
887
aContext->Save();
888
currentClip.ApplyTo(aContext, this->mAppUnitsPerDevPixel);
889
aContext->GetDrawTarget()->FlushItem(aItemBounds);
890
} else {
891
saveMatrix.SetContext(aContext);
892
}
893
894
auto transformItem = static_cast<nsDisplayTransform*>(aItem);
895
Matrix4x4Flagged trans = transformItem->GetTransform();
896
Matrix trans2d;
897
if (!trans.Is2D(&trans2d)) {
898
// We don't currently support doing invalidation inside 3d transforms.
899
// For now just paint it as a single item.
900
BlobItemData* data = GetBlobItemDataForGroup(aItem, aGroup);
901
if (data->mLayerManager->GetRoot()) {
902
data->mLayerManager->BeginTransaction();
903
data->mLayerManager->EndTransaction(
904
FrameLayerBuilder::DrawPaintedLayer, mDisplayListBuilder);
905
TakeExternalSurfaces(aRecorder, data->mExternalSurfaces, aRootManager,
906
aResources);
907
aContext->GetDrawTarget()->FlushItem(aItemBounds);
908
}
909
} else {
910
aContext->Multiply(ThebesMatrix(trans2d));
911
aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
912
aRecorder, aRootManager, aResources);
913
}
914
915
if (currentClip.HasClip()) {
916
aContext->Restore();
917
aContext->GetDrawTarget()->FlushItem(aItemBounds);
918
}
919
break;
920
}
921
case DisplayItemType::TYPE_OPACITY: {
922
auto opacityItem = static_cast<nsDisplayOpacity*>(aItem);
923
float opacity = opacityItem->GetOpacity();
924
if (opacity == 0.0f) {
925
return;
926
}
927
928
aContext->GetDrawTarget()->PushLayer(false, opacityItem->GetOpacity(),
929
nullptr, mozilla::gfx::Matrix(),
930
aItemBounds);
931
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
932
aItem->GetPerFrameKey());
933
aContext->GetDrawTarget()->FlushItem(aItemBounds);
934
aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
935
aRecorder, aRootManager, aResources);
936
aContext->GetDrawTarget()->PopLayer();
937
GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
938
aItem->GetPerFrameKey());
939
aContext->GetDrawTarget()->FlushItem(aItemBounds);
940
break;
941
}
942
case DisplayItemType::TYPE_BLEND_MODE: {
943
auto blendItem = static_cast<nsDisplayBlendMode*>(aItem);
944
auto blendMode = blendItem->BlendMode();
945
aContext->GetDrawTarget()->PushLayerWithBlend(
946
false, 1.0, nullptr, mozilla::gfx::Matrix(), aItemBounds, false,
947
blendMode);
948
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
949
aItem->GetPerFrameKey());
950
aContext->GetDrawTarget()->FlushItem(aItemBounds);
951
aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
952
aRecorder, aRootManager, aResources);
953
aContext->GetDrawTarget()->PopLayer();
954
GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
955
aItem->GetPerFrameKey());
956
aContext->GetDrawTarget()->FlushItem(aItemBounds);
957
break;
958
}
959
case DisplayItemType::TYPE_BLEND_CONTAINER: {
960
aContext->GetDrawTarget()->PushLayer(false, 1.0, nullptr,
961
mozilla::gfx::Matrix(), aItemBounds);
962
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
963
aItem->GetPerFrameKey());
964
aContext->GetDrawTarget()->FlushItem(aItemBounds);
965
aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
966
aRecorder, aRootManager, aResources);
967
aContext->GetDrawTarget()->PopLayer();
968
GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
969
aItem->GetPerFrameKey());
970
aContext->GetDrawTarget()->FlushItem(aItemBounds);
971
break;
972
}
973
case DisplayItemType::TYPE_MASK: {
974
GP("Paint Mask\n");
975
auto maskItem = static_cast<nsDisplayMasksAndClipPaths*>(aItem);
976
maskItem->SetPaintRect(maskItem->GetClippedBounds(mDisplayListBuilder));
977
if (maskItem->IsValidMask()) {
978
maskItem->PaintWithContentsPaintCallback(
979
mDisplayListBuilder, aContext, [&] {
980
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
981
aItem->GetPerFrameKey());
982
aContext->GetDrawTarget()->FlushItem(aItemBounds);
983
aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr,
984
aContext, aRecorder, aRootManager,
985
aResources);
986
GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
987
aItem->GetPerFrameKey());
988
});
989
TakeExternalSurfaces(aRecorder, aData->mExternalSurfaces, aRootManager,
990
aResources);
991
aContext->GetDrawTarget()->FlushItem(aItemBounds);
992
}
993
break;
994
}
995
case DisplayItemType::TYPE_FILTER: {
996
GP("Paint Filter\n");
997
// We don't currently support doing invalidation inside nsDisplayFilters
998
// for now just paint it as a single item
999
BlobItemData* data = GetBlobItemDataForGroup(aItem, aGroup);
1000
if (data->mLayerManager->GetRoot()) {
1001
data->mLayerManager->BeginTransaction();
1002
static_cast<nsDisplayFilters*>(aItem)->PaintAsLayer(
1003
mDisplayListBuilder, aContext, data->mLayerManager);
1004
if (data->mLayerManager->InTransaction()) {
1005
data->mLayerManager->AbortTransaction();
1006
}
1007
TakeExternalSurfaces(aRecorder, data->mExternalSurfaces, aRootManager,
1008
aResources);
1009
aContext->GetDrawTarget()->FlushItem(aItemBounds);
1010
}
1011
break;
1012
}
1013
1014
default:
1015
aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
1016
aRecorder, aRootManager, aResources);
1017
break;
1018
}
1019
}
1020
1021
size_t WebRenderScrollDataCollection::GetLayerCount(
1022
wr::RenderRoot aRoot) const {
1023
return mInternalScrollDatas[aRoot].size();
1024
}
1025
1026
void WebRenderScrollDataCollection::AppendRoot(
1027
Maybe<ScrollMetadata>& aRootMetadata,
1028
wr::RenderRootArray<WebRenderScrollData>& aScrollDatas) {
1029
mSeenRenderRoot[wr::RenderRoot::Default] = true;
1030
1031
for (auto renderRoot : wr::kRenderRoots) {
1032
if (mSeenRenderRoot[renderRoot]) {
1033
auto& layerScrollData = mInternalScrollDatas[renderRoot];
1034
layerScrollData.emplace_back();
1035
layerScrollData.back().InitializeRoot(layerScrollData.size() - 1);
1036
1037
if (aRootMetadata) {
1038
// Put the fallback root metadata on the rootmost layer that is
1039
// a matching async zoom container, or the root layer that we just
1040
// created above.
1041
size_t rootMetadataTarget = layerScrollData.size() - 1;
1042
for (size_t i = rootMetadataTarget; i > 0; i--) {
1043
if (auto zoomContainerId =
1044
layerScrollData[i - 1].GetAsyncZoomContainerId()) {
1045
if (*zoomContainerId == aRootMetadata->GetMetrics().GetScrollId()) {
1046
rootMetadataTarget = i - 1;
1047
break;
1048
}
1049
}
1050
}
1051
layerScrollData[rootMetadataTarget].AppendScrollMetadata(
1052
aScrollDatas[renderRoot], aRootMetadata.ref());
1053
}
1054
}
1055
}
1056
}
1057
1058
void WebRenderScrollDataCollection::AppendWrapper(
1059
const RenderRootBoundary& aBoundary, size_t aLayerCountBeforeRecursing) {
1060
wr::RenderRoot root = aBoundary.GetChildType();
1061
size_t layerCountAfterRecursing = GetLayerCount(root);
1062
MOZ_ASSERT(layerCountAfterRecursing >= aLayerCountBeforeRecursing);
1063
if (layerCountAfterRecursing == aLayerCountBeforeRecursing) {
1064
// nothing to wrap
1065
return;
1066
}
1067
mInternalScrollDatas[root].emplace_back();
1068
mInternalScrollDatas[root].back().InitializeRoot(layerCountAfterRecursing -
1069
aLayerCountBeforeRecursing);
1070
mInternalScrollDatas[root].back().SetBoundaryRoot(aBoundary);
1071
}
1072
1073
void WebRenderScrollDataCollection::AppendScrollData(
1074
const wr::DisplayListBuilder& aBuilder, WebRenderLayerManager* aManager,
1075
nsDisplayItem* aItem, size_t aLayerCountBeforeRecursing,
1076
const ActiveScrolledRoot* aStopAtAsr,
1077
const Maybe<gfx::Matrix4x4>& aAncestorTransform) {
1078
wr::RenderRoot renderRoot = aBuilder.GetRenderRoot();
1079
mSeenRenderRoot[renderRoot] = true;
1080
1081
int descendants =
1082
mInternalScrollDatas[renderRoot].size() - aLayerCountBeforeRecursing;
1083
1084
mInternalScrollDatas[renderRoot].emplace_back();
1085
mInternalScrollDatas[renderRoot].back().Initialize(
1086
aManager->GetScrollData(renderRoot), aItem, descendants, aStopAtAsr,
1087
aAncestorTransform, renderRoot);
1088
}
1089
1090
class WebRenderGroupData : public WebRenderUserData {
1091
public:
1092
WebRenderGroupData(RenderRootStateManager* aWRManager, nsDisplayItem* aItem);
1093
virtual ~WebRenderGroupData();
1094
1095
WebRenderGroupData* AsGroupData() override { return this; }
1096
UserDataType GetType() override { return UserDataType::eGroup; }
1097
static UserDataType Type() { return UserDataType::eGroup; }
1098
1099
DIGroup mSubGroup;
1100
DIGroup mFollowingGroup;
1101
};
1102
1103
static bool IsItemProbablyActive(nsDisplayItem* aItem,
1104
nsDisplayListBuilder* aDisplayListBuilder,
1105
bool aParentActive = true);
1106
1107
static bool HasActiveChildren(const nsDisplayList& aList,
1108
nsDisplayListBuilder* aDisplayListBuilder) {
1109
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
1110
if (IsItemProbablyActive(i, aDisplayListBuilder, false)) {
1111
return true;
1112
}
1113
}
1114
return false;
1115
}
1116
1117
// This function decides whether we want to treat this item as "active", which
1118
// means that it's a container item which we will turn into a WebRender
1119
// StackingContext, or whether we treat it as "inactive" and include it inside
1120
// the parent blob image.
1121
//
1122
// We can't easily use GetLayerState because it wants a bunch of layers related
1123
// information.
1124
static bool IsItemProbablyActive(nsDisplayItem* aItem,
1125
nsDisplayListBuilder* aDisplayListBuilder,
1126
bool aParentActive) {
1127
switch (aItem->GetType()) {
1128
case DisplayItemType::TYPE_TRANSFORM: {
1129
nsDisplayTransform* transformItem =
1130
static_cast<nsDisplayTransform*>(aItem);
1131
const Matrix4x4Flagged& t = transformItem->GetTransform();
1132
Matrix t2d;
1133
bool is2D = t.Is2D(&t2d);
1134
GP("active: %d\n", transformItem->MayBeAnimated(aDisplayListBuilder));
1135
return transformItem->MayBeAnimated(aDisplayListBuilder, false) ||
1136
!is2D ||
1137
HasActiveChildren(*transformItem->GetChildren(),
1138
aDisplayListBuilder);
1139
}
1140
case DisplayItemType::TYPE_OPACITY: {
1141
nsDisplayOpacity* opacityItem = static_cast<nsDisplayOpacity*>(aItem);
1142
bool active = opacityItem->NeedsActiveLayer(aDisplayListBuilder,
1143
opacityItem->Frame(), false);
1144
GP("active: %d\n", active);
1145
return active || HasActiveChildren(*opacityItem->GetChildren(),
1146
aDisplayListBuilder);
1147
}
1148
case DisplayItemType::TYPE_FOREIGN_OBJECT: {
1149
return true;
1150
}
1151
case DisplayItemType::TYPE_BLEND_MODE: {
1152
/* BLEND_MODE needs to be active if it might have a previous sibling
1153
* that is active. We use the activeness of the parent as a rough
1154
* proxy for this situation. */
1155
return aParentActive ||
1156
HasActiveChildren(*aItem->GetChildren(), aDisplayListBuilder);
1157
}
1158
case DisplayItemType::TYPE_WRAP_LIST:
1159
case DisplayItemType::TYPE_CONTAINER:
1160
case DisplayItemType::TYPE_MASK:
1161
case DisplayItemType::TYPE_PERSPECTIVE: {
1162
if (aItem->GetChildren()) {
1163
return HasActiveChildren(*aItem->GetChildren(), aDisplayListBuilder);
1164
}
1165
return false;
1166
}
1167
case DisplayItemType::TYPE_FILTER: {
1168
nsDisplayFilters* filters = static_cast<nsDisplayFilters*>(aItem);
1169
return filters->CanCreateWebRenderCommands();
1170
}
1171
default:
1172
// TODO: handle other items?
1173
return false;
1174
}
1175
}
1176
1177
// This does a pass over the display lists and will join the display items
1178
// into groups as well as paint them
1179
void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder,
1180
WebRenderCommandBuilder* aCommandBuilder,
1181
wr::DisplayListBuilder& aBuilder,
1182
wr::IpcResourceUpdateQueue& aResources,
1183
DIGroup* aGroup, nsDisplayList* aList,
1184
const StackingContextHelper& aSc) {
1185
DIGroup* currentGroup = aGroup;
1186
1187
nsDisplayItem* item = aList->GetBottom();
1188
nsDisplayItem* startOfCurrentGroup = item;
1189
while (item) {
1190
if (IsItemProbablyActive(item, mDisplayListBuilder)) {
1191
// We're going to be starting a new group.
1192
RefPtr<WebRenderGroupData> groupData =
1193
aCommandBuilder->CreateOrRecycleWebRenderUserData<WebRenderGroupData>(
1194
item, aBuilder.GetRenderRoot());
1195
1196
groupData->mFollowingGroup.mInvalidRect.SetEmpty();
1197
1198
// Initialize groupData->mFollowingGroup with data from currentGroup.
1199
// We want to copy out this information before calling EndGroup because
1200
// EndGroup will set mLastVisibleRect depending on whether
1201
// we send something to WebRender.
1202
1203
// TODO: compute the group bounds post-grouping, so that they can be
1204
// tighter for just the sublist that made it into this group.
1205
// We want to ensure the tight bounds are still clipped by area
1206
// that we're building the display list for.
1207
if (groupData->mFollowingGroup.mScale != currentGroup->mScale ||
1208
groupData->mFollowingGroup.mAppUnitsPerDevPixel !=
1209
currentGroup->mAppUnitsPerDevPixel ||
1210
groupData->mFollowingGroup.mResidualOffset !=
1211
currentGroup->mResidualOffset) {
1212
if (groupData->mFollowingGroup.mAppUnitsPerDevPixel !=
1213
currentGroup->mAppUnitsPerDevPixel) {
1214
GP("app unit change following: %d %d\n",
1215
groupData->mFollowingGroup.mAppUnitsPerDevPixel,
1216
currentGroup->mAppUnitsPerDevPixel);
1217
}
1218
// The group changed size
1219
GP("Inner group size change\n");
1220
groupData->mFollowingGroup.ClearItems();
1221
groupData->mFollowingGroup.ClearImageKey(
1222
aCommandBuilder->mManager->GetRenderRootStateManager(
1223
aBuilder.GetRenderRoot()));
1224
}
1225
groupData->mFollowingGroup.mGroupBounds = currentGroup->mGroupBounds;
1226
groupData->mFollowingGroup.mAppUnitsPerDevPixel =
1227
currentGroup->mAppUnitsPerDevPixel;
1228
groupData->mFollowingGroup.mLayerBounds = currentGroup->mLayerBounds;
1229
groupData->mFollowingGroup.mClippedImageBounds =
1230
currentGroup->mClippedImageBounds;
1231
groupData->mFollowingGroup.mScale = currentGroup->mScale;
1232
groupData->mFollowingGroup.mResidualOffset =
1233
currentGroup->mResidualOffset;
1234
groupData->mFollowingGroup.mVisibleRect = currentGroup->mVisibleRect;
1235
groupData->mFollowingGroup.mPreservedRect =
1236
groupData->mFollowingGroup.mVisibleRect
1237
.Intersect(groupData->mFollowingGroup.mLastVisibleRect)
1238
.ToUnknownRect();
1239
groupData->mFollowingGroup.mActualBounds = IntRect();
1240
1241
currentGroup->EndGroup(aCommandBuilder->mManager, aDisplayListBuilder,
1242
aBuilder, aResources, this, startOfCurrentGroup,
1243
item);
1244
1245
{
1246
MOZ_ASSERT(item->GetType() != DisplayItemType::TYPE_RENDER_ROOT);
1247
auto spaceAndClipChain = mClipManager.SwitchItem(item);
1248
wr::SpaceAndClipChainHelper saccHelper(aBuilder, spaceAndClipChain);
1249
1250
sIndent++;
1251
// Note: this call to CreateWebRenderCommands can recurse back into
1252
// this function.
1253
RenderRootStateManager* manager =
1254
aCommandBuilder->mManager->GetRenderRootStateManager(
1255
aBuilder.GetRenderRoot());
1256
bool createdWRCommands = item->CreateWebRenderCommands(
1257
aBuilder, aResources, aSc, manager, mDisplayListBuilder);
1258
sIndent--;
1259
MOZ_RELEASE_ASSERT(
1260
createdWRCommands,
1261
"active transforms should always succeed at creating "
1262
"WebRender commands");
1263
}
1264
1265
currentGroup = &groupData->mFollowingGroup;
1266
1267
startOfCurrentGroup = item->GetAbove();
1268
} else { // inactive item
1269
ConstructItemInsideInactive(aCommandBuilder, aBuilder, aResources,
1270
currentGroup, item, aSc);
1271
}
1272
1273
item = item->GetAbove();
1274
}
1275
1276
currentGroup->EndGroup(aCommandBuilder->mManager, aDisplayListBuilder,
1277
aBuilder, aResources, this, startOfCurrentGroup,
1278
nullptr);
1279
}
1280
1281
// This does a pass over the display lists and will join the display items
1282
// into a single group.
1283
void Grouper::ConstructGroupInsideInactive(
1284
WebRenderCommandBuilder* aCommandBuilder, wr::DisplayListBuilder& aBuilder,
1285
wr::IpcResourceUpdateQueue& aResources, DIGroup* aGroup,
1286
nsDisplayList* aList, const StackingContextHelper& aSc) {
1287
nsDisplayItem* item = aList->GetBottom();
1288
while (item) {
1289
ConstructItemInsideInactive(aCommandBuilder, aBuilder, aResources, aGroup,
1290
item, aSc);
1291
item = item->GetAbove();
1292
}
1293
}
1294
1295
bool BuildLayer(nsDisplayItem* aItem, BlobItemData* aData,
1296
nsDisplayListBuilder* aDisplayListBuilder,
1297
const gfx::Size& aScale);
1298
1299
void Grouper::ConstructItemInsideInactive(
1300
WebRenderCommandBuilder* aCommandBuilder, wr::DisplayListBuilder& aBuilder,
1301
wr::IpcResourceUpdateQueue& aResources, DIGroup* aGroup,
1302
nsDisplayItem* aItem, const StackingContextHelper& aSc) {
1303
nsDisplayList* children = aItem->GetChildren();
1304
BlobItemData* data = GetBlobItemDataForGroup(aItem, aGroup);
1305
1306
/* mInvalid unfortunately persists across paints. Clear it so that if we don't
1307
* set it to 'true' we ensure that we're not using the value from the last
1308
* time that we painted */
1309
data->mInvalid = false;
1310
1311
// we compute the geometry change here because we have the transform around
1312
// still
1313
aGroup->ComputeGeometryChange(aItem, data, mTransform, mDisplayListBuilder);
1314
1315
// Temporarily restrict the image bounds to the bounds of the container so
1316
// that clipped children within the container know about the clip. This
1317
// ensures that the bounds passed to FlushItem are contained in the bounds of
1318
// the clip so that we don't include items in the recording without including
1319
// their corresponding clipping items.
1320
IntRect oldClippedImageBounds = aGroup->mClippedImageBounds;
1321
aGroup->mClippedImageBounds =
1322
aGroup->mClippedImageBounds.Intersect(data->mRect);
1323
1324
if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
1325
gfx::Size scale(1, 1);
1326
// If ComputeDifferences finds any change, we invalidate the entire
1327
// container item. This is needed because blob merging requires the entire
1328
// item to be within the invalid region.
1329
if (BuildLayer(aItem, data, mDisplayListBuilder, scale)) {
1330
data->mInvalid = true;
1331
aGroup->InvalidateRect(data->mRect);
1332
}
1333
} else if (aItem->GetType() == DisplayItemType::TYPE_TRANSFORM) {
1334
nsDisplayTransform* transformItem = static_cast<nsDisplayTransform*>(aItem);
1335
const Matrix4x4Flagged& t = transformItem->GetTransform();
1336
Matrix t2d;
1337
bool is2D = t.Is2D(&t2d);
1338
if (!is2D) {
1339
// We'll use BasicLayerManager to handle 3d transforms.
1340
gfx::Size scale(1, 1);
1341
// If ComputeDifferences finds any change, we invalidate the entire
1342
// container item. This is needed because blob merging requires the entire
1343
// item to be within the invalid region.
1344
if (BuildLayer(aItem, data, mDisplayListBuilder, scale)) {
1345
data->mInvalid = true;
1346
aGroup->InvalidateRect(data->mRect);
1347
}
1348
} else {
1349
Matrix m = mTransform;
1350
1351
GP("t2d: %f %f\n", t2d._31, t2d._32);
1352
mTransform.PreMultiply(t2d);
1353
GP("mTransform: %f %f\n", mTransform._31, mTransform._32);
1354
ConstructGroupInsideInactive(aCommandBuilder, aBuilder, aResources,
1355
aGroup, children, aSc);
1356
1357
mTransform = m;
1358
}
1359
} else if (children) {
1360
sIndent++;
1361
ConstructGroupInsideInactive(aCommandBuilder, aBuilder, aResources, aGroup,
1362
children, aSc);
1363
sIndent--;
1364
}
1365
1366
GP("Including %s of %d\n", aItem->Name(), aGroup->mDisplayItems.Count());
1367
aGroup->mClippedImageBounds = oldClippedImageBounds;
1368
}
1369
1370
/* This is just a copy of nsRect::ScaleToOutsidePixels with an offset added in.
1371
* The offset is applied just before the rounding. It's in the scaled space. */
1372
static mozilla::gfx::IntRect ScaleToOutsidePixelsOffset(
1373
nsRect aRect, float aXScale, float aYScale, nscoord aAppUnitsPerPixel,
1374
LayerPoint aOffset) {
1375
mozilla::gfx::IntRect rect;
1376
rect.SetNonEmptyBox(
1377
NSToIntFloor(NSAppUnitsToFloatPixels(aRect.x, float(aAppUnitsPerPixel)) *
1378
aXScale +
1379
aOffset.x),
1380
NSToIntFloor(NSAppUnitsToFloatPixels(aRect.y, float(aAppUnitsPerPixel)) *
1381
aYScale +
1382
aOffset.y),
1383
NSToIntCeil(
1384
NSAppUnitsToFloatPixels(aRect.XMost(), float(aAppUnitsPerPixel)) *
1385
aXScale +
1386
aOffset.x),
1387
NSToIntCeil(
1388
NSAppUnitsToFloatPixels(aRect.YMost(), float(aAppUnitsPerPixel)) *
1389
aYScale +
1390
aOffset.y));
1391
return rect;
1392
}
1393
1394
RenderRootStateManager* WebRenderCommandBuilder::GetRenderRootStateManager(
1395
wr::RenderRoot aRenderRoot) {
1396
return mManager->GetRenderRootStateManager(aRenderRoot);
1397
}
1398
1399
void WebRenderCommandBuilder::DoGroupingForDisplayList(
1400
nsDisplayList* aList, nsDisplayItem* aWrappingItem,
1401
nsDisplayListBuilder* aDisplayListBuilder, const StackingContextHelper& aSc,
1402
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources) {
1403
if (!aList->GetBottom()) {
1404
return;
1405
}
1406
1407
GP("DoGroupingForDisplayList\n");
1408
1409
mCurrentClipManager->BeginList(aSc);
1410
Grouper g(*mCurrentClipManager);
1411
1412
int32_t appUnitsPerDevPixel =
1413
aWrappingItem->Frame()->PresContext()->AppUnitsPerDevPixel();
1414
1415
g.mDisplayListBuilder = aDisplayListBuilder;
1416
RefPtr<WebRenderGroupData> groupData =
1417
CreateOrRecycleWebRenderUserData<WebRenderGroupData>(
1418
aWrappingItem, aBuilder.GetRenderRoot());
1419
1420
bool snapped;
1421
nsRect groupBounds =
1422
aWrappingItem->GetUntransformedBounds(aDisplayListBuilder, &snapped);
1423
DIGroup& group = groupData->mSubGroup;
1424
1425
gfx::Size scale = aSc.GetInheritedScale();
1426
GP("Inherrited scale %f %f\n", scale.width, scale.height);
1427
1428
auto trans =
1429
ViewAs<LayerPixel>(aSc.GetSnappingSurfaceTransform().GetTranslation());
1430
auto snappedTrans = LayerIntPoint::Floor(trans);
1431
LayerPoint residualOffset = trans - snappedTrans;
1432
1433
auto p = group.mGroupBounds;
1434
auto q = groupBounds;
1435
// XXX: we currently compute the paintRect for the entire svg, but if the svg
1436
// gets split into multiple groups (blobs), then they will all inherit this
1437
// overall size even though they may each be much smaller. This can lead to
1438
// allocating much larger textures than necessary in webrender.
1439
//
1440
// Don't bother fixing this unless we run into this in the real world, though.
1441
auto layerBounds = LayerIntRect::FromUnknownRect(
1442
ScaleToOutsidePixelsOffset(groupBounds, scale.width, scale.height,
1443
appUnitsPerDevPixel, residualOffset));
1444
1445
const nsRect& untransformedPaintRect =
1446
aWrappingItem->GetUntransformedPaintRect();
1447
1448
auto visibleRect = LayerIntRect::FromUnknownRect(
1449
ScaleToOutsidePixelsOffset(
1450
untransformedPaintRect, scale.width, scale.height,
1451
appUnitsPerDevPixel, residualOffset))
1452
.Intersect(layerBounds);
1453
1454
GP("LayerBounds: %d %d %d %d\n", layerBounds.x, layerBounds.y,
1455
layerBounds.width, layerBounds.height);
1456
GP("VisibleRect: %d %d %d %d\n", visibleRect.x, visibleRect.y,
1457
visibleRect.width, visibleRect.height);
1458
1459
GP("Inherrited scale %f %f\n", scale.width, scale.height);
1460
GP("Bounds: %d %d %d %d vs %d %d %d %d\n", p.x, p.y, p.width, p.height, q.x,
1461
q.y, q.width, q.height);
1462
1463
group.mInvalidRect.SetEmpty();
1464
if (group.mAppUnitsPerDevPixel != appUnitsPerDevPixel ||
1465
group.mScale != scale || group.mResidualOffset != residualOffset) {
1466
GP("Property change. Deleting blob\n");
1467
1468
if (group.mAppUnitsPerDevPixel != appUnitsPerDevPixel) {
1469
GP(" App unit change %d -> %d\n", group.mAppUnitsPerDevPixel,
1470
appUnitsPerDevPixel);
1471
}
1472
// The bounds have changed so we need to discard the old image and add all
1473
// the commands again.
1474
auto p = group.mGroupBounds;
1475
auto q = groupBounds;
1476
if (!group.mGroupBounds.IsEqualEdges(groupBounds)) {
1477
GP(" Bounds change: %d %d %d %d -> %d %d %d %d\n", p.x, p.y, p.width,
1478
p.height, q.x, q.y, q.width, q.height);
1479
}
1480
1481
if (group.mScale != scale) {
1482
GP(" Scale %f %f -> %f %f\n", group.mScale.width, group.mScale.height,
1483
scale.width, scale.height);
1484
}
1485
1486
if (group.mResidualOffset != residualOffset) {
1487
GP(" Residual Offset %f %f -> %f %f\n", group.mResidualOffset.x,
1488
group.mResidualOffset.y, residualOffset.x, residualOffset.y);
1489
}
1490
1491
group.ClearItems();
1492
group.ClearImageKey(
1493
mManager->GetRenderRootStateManager(aBuilder.GetRenderRoot()));
1494
}
1495
1496
ScrollableLayerGuid::ViewID scrollId = ScrollableLayerGuid::NULL_SCROLL_ID;
1497
if (const ActiveScrolledRoot* asr = aWrappingItem->GetActiveScrolledRoot()) {
1498
scrollId = asr->GetViewId();
1499
}
1500
1501
g.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
1502
group.mResidualOffset = residualOffset;
1503
group.mGroupBounds = groupBounds;
1504
group.mLayerBounds = layerBounds;
1505
group.mVisibleRect = visibleRect;
1506
group.mActualBounds = IntRect();
1507
group.mPreservedRect =
1508
group.mVisibleRect.Intersect(group.mLastVisibleRect).ToUnknownRect();
1509
group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
1510
group.mClippedImageBounds = layerBounds.ToUnknownRect();
1511
1512
g.mTransform = Matrix::Scaling(scale.width, scale.height)
1513
.PostTranslate(residualOffset.x, residualOffset.y);
1514
group.mScale = scale;
1515
group.mScrollId = scrollId;
1516
g.ConstructGroups(aDisplayListBuilder, this, aBuilder, aResources, &group,
1517
aList, aSc);
1518
mCurrentClipManager->EndList(aSc);
1519
}
1520
1521
void WebRenderCommandBuilder::Destroy() {
1522
mLastCanvasDatas.Clear();
1523
ClearCachedResources();
1524
}
1525
1526
void WebRenderCommandBuilder::EmptyTransaction() {
1527
// We need to update canvases that might have changed.
1528
for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
1529
RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
1530
WebRenderCanvasRendererAsync* canvas = canvasData->GetCanvasRenderer();
1531
if (canvas) {
1532
canvas->UpdateCompositableClientForEmptyTransaction();
1533
}
1534
}
1535
}
1536
1537
bool WebRenderCommandBuilder::NeedsEmptyTransaction() {
1538
return !mLastCanvasDatas.IsEmpty();
1539
}
1540
1541
void WebRenderCommandBuilder::BuildWebRenderCommands(
1542
wr::DisplayListBuilder& aBuilder,
1543
wr::IpcResourceUpdateQueue& aResourceUpdates, nsDisplayList* aDisplayList,
1544
nsDisplayListBuilder* aDisplayListBuilder,
1545
wr::RenderRootArray<WebRenderScrollData>& aScrollDatas,
1546
WrFiltersHolder&& aFilters) {
1547
AUTO_PROFILER_LABEL_CATEGORY_PAIR(GRAPHICS_WRDisplayList);
1548
wr::RenderRootArray<StackingContextHelper> rootScs;
1549
MOZ_ASSERT(aBuilder.GetRenderRoot() == wr::RenderRoot::Default);
1550
1551
for (auto renderRoot : wr::kRenderRoots) {
1552
aScrollDatas[renderRoot] = WebRenderScrollData(mManager);
1553
if (aBuilder.HasSubBuilder(renderRoot)) {
1554
mClipManagers[renderRoot].BeginBuild(mManager,
1555
aBuilder.SubBuilder(renderRoot));
1556
}
1557
mBuilderDumpIndex[renderRoot] = 0;
1558
}
1559
MOZ_ASSERT(mLayerScrollDatas.IsEmpty());
1560
mLastCanvasDatas.Clear();
1561
mLastAsr = nullptr;
1562
mContainsSVGGroup = false;
1563
MOZ_ASSERT(mDumpIndent == 0);
1564
1565
{
1566
nsPresContext* presContext =
1567
aDisplayListBuilder->RootReferenceFrame()->PresContext();
1568
bool isTopLevelContent =
1569
presContext->Document()->IsTopLevelContentDocument();
1570
1571
wr::RenderRootArray<Maybe<StackingContextHelper>> pageRootScs;
1572
for (auto renderRoot : wr::kRenderRoots) {
1573
if (aBuilder.HasSubBuilder(renderRoot)) {
1574
wr::StackingContextParams params;
1575
// Just making this explicit - we assume that we do not want any
1576
// filters traversing a RenderRoot boundary
1577
if (renderRoot == wr::RenderRoot::Default) {
1578
params.mFilters = std::move(aFilters.filters);
1579
params.mFilterDatas = std::move(aFilters.filter_datas);
1580
}
1581
params.cache_tiles = isTopLevelContent;
1582
params.clip = wr::WrStackingContextClip::ClipChain(
1583
aBuilder.SubBuilder(renderRoot).CurrentClipChainId());
1584
pageRootScs[renderRoot].emplace(
1585
rootScs[renderRoot], nullptr, nullptr, nullptr,
1586
aBuilder.SubBuilder(renderRoot), params);
1587
}
1588
}
1589
if (ShouldDumpDisplayList(aDisplayListBuilder)) {
1590
mBuilderDumpIndex[aBuilder.GetRenderRoot()] = aBuilder.Dump(
1591
mDumpIndent + 1, Some(mBuilderDumpIndex[aBuilder.GetRenderRoot()]),
1592
Nothing());
1593
}
1594
MOZ_ASSERT(mRootStackingContexts == nullptr);
1595
AutoRestore<wr::RenderRootArray<Maybe<StackingContextHelper>>*> rootScs(
1596
mRootStackingContexts);
1597
mRootStackingContexts = &pageRootScs;
1598
CreateWebRenderCommandsFromDisplayList(
1599
aDisplayList, nullptr, aDisplayListBuilder,
1600
*pageRootScs[wr::RenderRoot::Default], aBuilder, aResourceUpdates);
1601
}
1602
1603
auto callback =
1604
[&aScrollDatas](ScrollableLayerGuid::ViewID aScrollId) -> bool {
1605
for (auto renderRoot : wr::kRenderRoots) {
1606
if (aScrollDatas[renderRoot].HasMetadataFor(aScrollId).isSome()) {
1607
return true;
1608
}
1609
}
1610
return false;
1611
};
1612
Maybe<ScrollMetadata> rootMetadata = nsLayoutUtils::GetRootMetadata(
1613
aDisplayListBuilder, mManager, ContainerLayerParameters(), callback);
1614
1615
mLayerScrollDatas.AppendRoot(rootMetadata, aScrollDatas);
1616
1617
for (auto renderRoot : wr::kRenderRoots) {
1618
// Append the WebRenderLayerScrollData items into WebRenderScrollData
1619
// in reverse order, from topmost to bottommost. This is in keeping with
1620
// the semantics of WebRenderScrollData.
1621
for (auto it = mLayerScrollDatas[renderRoot].crbegin();
1622
it != mLayerScrollDatas[renderRoot].crend(); it++) {
1623
aScrollDatas[renderRoot].AddLayerData(*it);
1624
}
1625
if (aBuilder.HasSubBuilder(renderRoot)) {
1626
mClipManagers[renderRoot].EndBuild();
1627
}
1628
}
1629
mLayerScrollDatas.Clear();
1630
1631
// Remove the user data those are not displayed on the screen and
1632
// also reset the data to unused for next transaction.
1633
RemoveUnusedAndResetWebRenderUserData();
1634
}
1635
1636
bool WebRenderCommandBuilder::ShouldDumpDisplayList(
1637
nsDisplayListBuilder* aBuilder) {
1638
return aBuilder != nullptr && aBuilder->IsInActiveDocShell() &&
1639
((XRE_IsParentProcess() &&
1640
StaticPrefs::gfx_webrender_dl_dump_parent()) ||
1641
(XRE_IsContentProcess() &&
1642
StaticPrefs::gfx_webrender_dl_dump_content()));
1643
}
1644
1645
void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
1646
nsDisplayList* aDisplayList, nsDisplayItem* aWrappingItem,
1647
nsDisplayListBuilder* aDisplayListBuilder, const StackingContextHelper& aSc,
1648
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources) {
1649
AutoRestore<ClipManager*> prevClipManager(mCurrentClipManager);
1650
mCurrentClipManager = &mClipManagers[aBuilder.GetRenderRoot()];
1651
if (mDoGrouping) {
1652
MOZ_RELEASE_ASSERT(
1653
aWrappingItem,
1654
"Only the root list should have a null wrapping item, and mDoGrouping "
1655
"should never be true for the root list.");
1656
GP("actually entering the grouping code\n");
1657