Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/apz/src/APZUpdater.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/layers/APZUpdater.h"
8
9
#include "APZCTreeManager.h"
10
#include "AsyncPanZoomController.h"
11
#include "base/task.h"
12
#include "mozilla/ClearOnShutdown.h"
13
#include "mozilla/layers/APZThreadUtils.h"
14
#include "mozilla/layers/CompositorThread.h"
15
#include "mozilla/layers/SynchronousTask.h"
16
#include "mozilla/layers/WebRenderScrollDataWrapper.h"
17
#include "mozilla/webrender/WebRenderAPI.h"
18
19
namespace mozilla {
20
namespace layers {
21
22
StaticMutex APZUpdater::sWindowIdLock;
23
StaticAutoPtr<std::unordered_map<uint64_t, APZUpdater*>> APZUpdater::sWindowIdMap;
24
25
26
APZUpdater::APZUpdater(const RefPtr<APZCTreeManager>& aApz,
27
                       bool aIsUsingWebRender)
28
  : mApz(aApz)
29
  , mIsUsingWebRender(aIsUsingWebRender)
30
  , mThreadIdLock("APZUpdater::ThreadIdLock")
31
  , mQueueLock("APZUpdater::QueueLock")
32
0
{
33
0
  MOZ_ASSERT(aApz);
34
0
  mApz->SetUpdater(this);
35
0
}
36
37
APZUpdater::~APZUpdater()
38
0
{
39
0
  mApz->SetUpdater(nullptr);
40
0
41
0
  StaticMutexAutoLock lock(sWindowIdLock);
42
0
  if (mWindowId) {
43
0
    MOZ_ASSERT(sWindowIdMap);
44
0
    // Ensure that ClearTree was called and the task got run
45
0
    MOZ_ASSERT(sWindowIdMap->find(wr::AsUint64(*mWindowId)) == sWindowIdMap->end());
46
0
  }
47
0
}
48
49
bool
50
APZUpdater::HasTreeManager(const RefPtr<APZCTreeManager>& aApz)
51
0
{
52
0
  return aApz.get() == mApz.get();
53
0
}
54
55
void
56
APZUpdater::SetWebRenderWindowId(const wr::WindowId& aWindowId)
57
0
{
58
0
  StaticMutexAutoLock lock(sWindowIdLock);
59
0
  MOZ_ASSERT(!mWindowId);
60
0
  mWindowId = Some(aWindowId);
61
0
  if (!sWindowIdMap) {
62
0
    sWindowIdMap = new std::unordered_map<uint64_t, APZUpdater*>();
63
0
    NS_DispatchToMainThread(
64
0
      NS_NewRunnableFunction("APZUpdater::ClearOnShutdown", [] {
65
0
        ClearOnShutdown(&sWindowIdMap);
66
0
      }
67
0
    ));
68
0
  }
69
0
  (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
70
0
}
71
72
/*static*/ void
73
APZUpdater::SetUpdaterThread(const wr::WrWindowId& aWindowId)
74
0
{
75
0
  if (RefPtr<APZUpdater> updater = GetUpdater(aWindowId)) {
76
0
    MutexAutoLock lock(updater->mThreadIdLock);
77
0
    updater->mUpdaterThreadId = Some(PlatformThread::CurrentId());
78
0
  }
79
0
}
80
81
/*static*/ void
82
APZUpdater::PrepareForSceneSwap(const wr::WrWindowId& aWindowId)
83
0
{
84
0
  if (RefPtr<APZUpdater> updater = GetUpdater(aWindowId)) {
85
0
    updater->mApz->LockTree();
86
0
  }
87
0
}
88
89
/*static*/ void
90
APZUpdater::CompleteSceneSwap(const wr::WrWindowId& aWindowId,
91
                              const wr::WrPipelineInfo& aInfo)
92
0
{
93
0
  RefPtr<APZUpdater> updater = GetUpdater(aWindowId);
94
0
  if (!updater) {
95
0
    // This should only happen in cases where PrepareForSceneSwap also got a
96
0
    // null updater. No updater-thread tasks get run between PrepareForSceneSwap
97
0
    // and this function, so there is no opportunity for the updater mapping
98
0
    // to have gotten removed from sWindowIdMap in between the two calls.
99
0
    return;
100
0
  }
101
0
102
0
  for (uintptr_t i = 0; i < aInfo.removed_pipelines.length; i++) {
103
0
    LayersId layersId = wr::AsLayersId(aInfo.removed_pipelines.data[i]);
104
0
    updater->mEpochData.erase(layersId);
105
0
  }
106
0
  // Reset the built info for all pipelines, then put it back for the ones
107
0
  // that got built in this scene swap.
108
0
  for (auto& i : updater->mEpochData) {
109
0
    i.second.mBuilt = Nothing();
110
0
  }
111
0
  for (uintptr_t i = 0; i < aInfo.epochs.length; i++) {
112
0
    LayersId layersId = wr::AsLayersId(aInfo.epochs.data[i].pipeline_id);
113
0
    updater->mEpochData[layersId].mBuilt = Some(aInfo.epochs.data[i].epoch);
114
0
  }
115
0
116
0
  // Run any tasks that got unblocked, then unlock the tree. The order is
117
0
  // important because we want to run all the tasks up to and including the
118
0
  // UpdateHitTestingTree calls corresponding to the built epochs, and we
119
0
  // want to run those before we release the lock (i.e. atomically with the
120
0
  // scene swap). This ensures that any hit-tests always encounter a consistent
121
0
  // state between the APZ tree and the built scene in WR.
122
0
  //
123
0
  // While we could add additional information to the queued tasks to figure
124
0
  // out the minimal set of tasks we want to run here, it's easier and harmless
125
0
  // to just run all the queued and now-unblocked tasks inside the lock.
126
0
  //
127
0
  // Note that the ProcessQueue here might remove the window id -> APZUpdater
128
0
  // mapping from sWindowIdMap, but we still unlock the tree successfully to
129
0
  // leave things in a good state.
130
0
  updater->ProcessQueue();
131
0
132
0
  updater->mApz->UnlockTree();
133
0
}
134
135
/*static*/ void
136
APZUpdater::ProcessPendingTasks(const wr::WrWindowId& aWindowId)
137
0
{
138
0
  if (RefPtr<APZUpdater> updater = GetUpdater(aWindowId)) {
139
0
    updater->ProcessQueue();
140
0
  }
141
0
}
142
143
void
144
APZUpdater::ClearTree(LayersId aRootLayersId)
145
0
{
146
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
147
0
  RefPtr<APZUpdater> self = this;
148
0
  RunOnUpdaterThread(aRootLayersId, NS_NewRunnableFunction(
149
0
    "APZUpdater::ClearTree",
150
0
    [=]() {
151
0
      self->mApz->ClearTree();
152
0
153
0
      // Once ClearTree is called on the APZCTreeManager, we are in a shutdown
154
0
      // phase. After this point it's ok if WebRender cannot get a hold of the
155
0
      // updater via the window id, and it's a good point to remove the mapping
156
0
      // and avoid leaving a dangling pointer to this object.
157
0
      StaticMutexAutoLock lock(sWindowIdLock);
158
0
      if (self->mWindowId) {
159
0
        MOZ_ASSERT(sWindowIdMap);
160
0
        sWindowIdMap->erase(wr::AsUint64(*(self->mWindowId)));
161
0
      }
162
0
    }
163
0
  ));
164
0
}
165
166
void
167
APZUpdater::UpdateFocusState(LayersId aRootLayerTreeId,
168
                             LayersId aOriginatingLayersId,
169
                             const FocusTarget& aFocusTarget)
170
0
{
171
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
172
0
  RunOnUpdaterThread(aOriginatingLayersId, NewRunnableMethod<LayersId, LayersId, FocusTarget>(
173
0
      "APZUpdater::UpdateFocusState",
174
0
      mApz,
175
0
      &APZCTreeManager::UpdateFocusState,
176
0
      aRootLayerTreeId,
177
0
      aOriginatingLayersId,
178
0
      aFocusTarget));
179
0
}
180
181
void
182
APZUpdater::UpdateHitTestingTree(LayersId aRootLayerTreeId,
183
                                 Layer* aRoot,
184
                                 bool aIsFirstPaint,
185
                                 LayersId aOriginatingLayersId,
186
                                 uint32_t aPaintSequenceNumber)
187
0
{
188
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
189
0
  AssertOnUpdaterThread();
190
0
  mApz->UpdateHitTestingTree(aRootLayerTreeId, aRoot, aIsFirstPaint,
191
0
      aOriginatingLayersId, aPaintSequenceNumber);
192
0
}
193
194
void
195
APZUpdater::UpdateScrollDataAndTreeState(LayersId aRootLayerTreeId,
196
                                         LayersId aOriginatingLayersId,
197
                                         const wr::Epoch& aEpoch,
198
                                         WebRenderScrollData&& aScrollData)
199
0
{
200
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
201
0
  RefPtr<APZUpdater> self = this;
202
0
  // Insert an epoch requirement update into the queue, so that
203
0
  // tasks inserted into the queue after this point only get executed
204
0
  // once the epoch requirement is satisfied. In particular, the
205
0
  // UpdateHitTestingTree call below needs to wait until the epoch requirement
206
0
  // is satisfied, which is why it is a separate task in the queue.
207
0
  RunOnUpdaterThread(aOriginatingLayersId, NS_NewRunnableFunction(
208
0
    "APZUpdater::UpdateEpochRequirement",
209
0
    [=]() {
210
0
      if (aRootLayerTreeId == aOriginatingLayersId) {
211
0
        self->mEpochData[aOriginatingLayersId].mIsRoot = true;
212
0
      }
213
0
      self->mEpochData[aOriginatingLayersId].mRequired = aEpoch;
214
0
    }
215
0
  ));
216
0
  RunOnUpdaterThread(aOriginatingLayersId, NS_NewRunnableFunction(
217
0
    "APZUpdater::UpdateHitTestingTree",
218
0
    [=,aScrollData=std::move(aScrollData)]() {
219
0
      self->mApz->UpdateFocusState(aRootLayerTreeId,
220
0
          aOriginatingLayersId, aScrollData.GetFocusTarget());
221
0
222
0
      self->mScrollData[aOriginatingLayersId] = aScrollData;
223
0
      auto root = self->mScrollData.find(aRootLayerTreeId);
224
0
      if (root == self->mScrollData.end()) {
225
0
        return;
226
0
      }
227
0
      self->mApz->UpdateHitTestingTree(aRootLayerTreeId,
228
0
          WebRenderScrollDataWrapper(*self, &(root->second)),
229
0
          aScrollData.IsFirstPaint(), aOriginatingLayersId,
230
0
          aScrollData.GetPaintSequenceNumber());
231
0
    }
232
0
  ));
233
0
}
234
235
void
236
APZUpdater::UpdateScrollOffsets(LayersId aRootLayerTreeId,
237
                                LayersId aOriginatingLayersId,
238
                                ScrollUpdatesMap&& aUpdates,
239
                                uint32_t aPaintSequenceNumber)
240
0
{
241
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
242
0
  RefPtr<APZUpdater> self = this;
243
0
  RunOnUpdaterThread(aOriginatingLayersId, NS_NewRunnableFunction(
244
0
    "APZUpdater::UpdateScrollOffsets",
245
0
    [=,updates=std::move(aUpdates)]() {
246
0
      self->mScrollData[aOriginatingLayersId].ApplyUpdates(updates, aPaintSequenceNumber);
247
0
      auto root = self->mScrollData.find(aRootLayerTreeId);
248
0
      if (root == self->mScrollData.end()) {
249
0
        return;
250
0
      }
251
0
      self->mApz->UpdateHitTestingTree(aRootLayerTreeId,
252
0
          WebRenderScrollDataWrapper(*self, &(root->second)),
253
0
          /*isFirstPaint*/ false, aOriginatingLayersId,
254
0
          aPaintSequenceNumber);
255
0
    }
256
0
  ));
257
0
}
258
259
void
260
APZUpdater::NotifyLayerTreeAdopted(LayersId aLayersId,
261
                                   const RefPtr<APZUpdater>& aOldUpdater)
262
0
{
263
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
264
0
  RunOnUpdaterThread(aLayersId, NewRunnableMethod<LayersId, RefPtr<APZCTreeManager>>(
265
0
      "APZUpdater::NotifyLayerTreeAdopted",
266
0
      mApz,
267
0
      &APZCTreeManager::NotifyLayerTreeAdopted,
268
0
      aLayersId,
269
0
      aOldUpdater ? aOldUpdater->mApz : nullptr));
270
0
}
271
272
void
273
APZUpdater::NotifyLayerTreeRemoved(LayersId aLayersId)
274
0
{
275
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
276
0
  RefPtr<APZUpdater> self = this;
277
0
  RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction(
278
0
    "APZUpdater::NotifyLayerTreeRemoved",
279
0
    [=]() {
280
0
      self->mEpochData.erase(aLayersId);
281
0
      self->mScrollData.erase(aLayersId);
282
0
      self->mApz->NotifyLayerTreeRemoved(aLayersId);
283
0
    }
284
0
  ));
285
0
}
286
287
bool
288
APZUpdater::GetAPZTestData(LayersId aLayersId,
289
                           APZTestData* aOutData)
290
0
{
291
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
292
0
293
0
  RefPtr<APZCTreeManager> apz = mApz;
294
0
  bool ret = false;
295
0
  SynchronousTask waiter("APZUpdater::GetAPZTestData");
296
0
  RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction(
297
0
    "APZUpdater::GetAPZTestData",
298
0
    [&]() {
299
0
      AutoCompleteTask notifier(&waiter);
300
0
      ret = apz->GetAPZTestData(aLayersId, aOutData);
301
0
    }
302
0
  ));
303
0
304
0
  // Wait until the task posted above has run and populated aOutData and ret
305
0
  waiter.Wait();
306
0
307
0
  return ret;
308
0
}
309
310
void
311
APZUpdater::SetTestAsyncScrollOffset(LayersId aLayersId,
312
                                     const FrameMetrics::ViewID& aScrollId,
313
                                     const CSSPoint& aOffset)
314
0
{
315
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
316
0
  RefPtr<APZCTreeManager> apz = mApz;
317
0
  RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction(
318
0
    "APZUpdater::SetTestAsyncScrollOffset",
319
0
    [=]() {
320
0
      RefPtr<AsyncPanZoomController> apzc = apz->GetTargetAPZC(aLayersId, aScrollId);
321
0
      if (apzc) {
322
0
        apzc->SetTestAsyncScrollOffset(aOffset);
323
0
      } else {
324
0
        NS_WARNING("Unable to find APZC in SetTestAsyncScrollOffset");
325
0
      }
326
0
    }
327
0
  ));
328
0
}
329
330
void
331
APZUpdater::SetTestAsyncZoom(LayersId aLayersId,
332
                             const FrameMetrics::ViewID& aScrollId,
333
                             const LayerToParentLayerScale& aZoom)
334
0
{
335
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
336
0
  RefPtr<APZCTreeManager> apz = mApz;
337
0
  RunOnUpdaterThread(aLayersId, NS_NewRunnableFunction(
338
0
    "APZUpdater::SetTestAsyncZoom",
339
0
    [=]() {
340
0
      RefPtr<AsyncPanZoomController> apzc = apz->GetTargetAPZC(aLayersId, aScrollId);
341
0
      if (apzc) {
342
0
        apzc->SetTestAsyncZoom(aZoom);
343
0
      } else {
344
0
        NS_WARNING("Unable to find APZC in SetTestAsyncZoom");
345
0
      }
346
0
    }
347
0
  ));
348
0
}
349
350
const WebRenderScrollData*
351
APZUpdater::GetScrollData(LayersId aLayersId) const
352
0
{
353
0
  AssertOnUpdaterThread();
354
0
  auto it = mScrollData.find(aLayersId);
355
0
  return (it == mScrollData.end() ? nullptr : &(it->second));
356
0
}
357
358
void
359
APZUpdater::AssertOnUpdaterThread() const
360
0
{
361
0
  if (APZThreadUtils::GetThreadAssertionsEnabled()) {
362
0
    MOZ_ASSERT(IsUpdaterThread());
363
0
  }
364
0
}
365
366
void
367
APZUpdater::RunOnUpdaterThread(LayersId aLayersId, already_AddRefed<Runnable> aTask)
368
0
{
369
0
  RefPtr<Runnable> task = aTask;
370
0
371
0
  // In the scenario where UsingWebRenderUpdaterThread() is true, this function
372
0
  // might get called early (before mUpdaterThreadId is set). In that case
373
0
  // IsUpdaterThread() will return false and we'll queue the task onto
374
0
  // mUpdaterQueue. This is fine; the task is still guaranteed to run (barring
375
0
  // catastrophic failure) because the WakeSceneBuilder call will still trigger
376
0
  // the callback to run tasks.
377
0
378
0
  if (IsUpdaterThread()) {
379
0
    task->Run();
380
0
    return;
381
0
  }
382
0
383
0
  if (UsingWebRenderUpdaterThread()) {
384
0
    // If the updater thread is a WebRender thread, and we're not on it
385
0
    // right now, save the task in the queue. We will run tasks from the queue
386
0
    // during the callback from the updater thread, which we trigger by the
387
0
    // call to WakeSceneBuilder.
388
0
389
0
    bool sendWakeMessage = true;
390
0
    { // scope lock
391
0
      MutexAutoLock lock(mQueueLock);
392
0
      for (const auto& queuedTask : mUpdaterQueue) {
393
0
        if (queuedTask.mLayersId == aLayersId) {
394
0
          // If there's already a task in the queue with this layers id, then
395
0
          // we must have previously sent a WakeSceneBuilder message (when
396
0
          // adding the first task with this layers id to the queue). Either
397
0
          // that hasn't been fully processed yet, or the layers id is blocked
398
0
          // waiting for an epoch - in either case there's no point in sending
399
0
          // another WakeSceneBuilder message.
400
0
          sendWakeMessage = false;
401
0
          break;
402
0
        }
403
0
      }
404
0
      mUpdaterQueue.push_back(QueuedTask { aLayersId, task });
405
0
    }
406
0
    if (sendWakeMessage) {
407
0
      RefPtr<wr::WebRenderAPI> api = mApz->GetWebRenderAPI();
408
0
      if (api) {
409
0
        api->WakeSceneBuilder();
410
0
      } else {
411
0
        // Not sure if this can happen, but it might be possible. If it does,
412
0
        // the task is in the queue, but if we didn't get a WebRenderAPI it
413
0
        // might never run, or it might run later if we manage to get a
414
0
        // WebRenderAPI later. For now let's just emit a warning, this can
415
0
        // probably be upgraded to an assert later.
416
0
        NS_WARNING("Possibly dropping task posted to updater thread");
417
0
      }
418
0
    }
419
0
    return;
420
0
  }
421
0
422
0
  if (MessageLoop* loop = CompositorThreadHolder::Loop()) {
423
0
    loop->PostTask(task.forget());
424
0
  } else {
425
0
    // Could happen during startup
426
0
    NS_WARNING("Dropping task posted to updater thread");
427
0
  }
428
0
}
429
430
bool
431
APZUpdater::IsUpdaterThread() const
432
0
{
433
0
  if (UsingWebRenderUpdaterThread()) {
434
0
    // If the updater thread id isn't set yet then we cannot be running on the
435
0
    // updater thread (because we will have the thread id before we run any
436
0
    // C++ code on it, and this function is only ever invoked from C++ code),
437
0
    // so return false in that scenario.
438
0
    MutexAutoLock lock(mThreadIdLock);
439
0
    return mUpdaterThreadId && PlatformThread::CurrentId() == *mUpdaterThreadId;
440
0
  }
441
0
  return CompositorThreadHolder::IsInCompositorThread();
442
0
}
443
444
void
445
APZUpdater::RunOnControllerThread(LayersId aLayersId, already_AddRefed<Runnable> aTask)
446
0
{
447
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
448
0
449
0
  RunOnUpdaterThread(aLayersId, NewRunnableFunction(
450
0
      "APZUpdater::RunOnControllerThread",
451
0
      &APZThreadUtils::RunOnControllerThread,
452
0
      std::move(aTask)));
453
0
}
454
455
bool
456
APZUpdater::UsingWebRenderUpdaterThread() const
457
0
{
458
0
  return mIsUsingWebRender;
459
0
}
460
461
/*static*/ already_AddRefed<APZUpdater>
462
APZUpdater::GetUpdater(const wr::WrWindowId& aWindowId)
463
0
{
464
0
  RefPtr<APZUpdater> updater;
465
0
  StaticMutexAutoLock lock(sWindowIdLock);
466
0
  if (sWindowIdMap) {
467
0
    auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
468
0
    if (it != sWindowIdMap->end()) {
469
0
      updater = it->second;
470
0
    }
471
0
  }
472
0
  return updater.forget();
473
0
}
474
475
void
476
APZUpdater::ProcessQueue()
477
0
{
478
0
  { // scope lock to check for emptiness
479
0
    MutexAutoLock lock(mQueueLock);
480
0
    if (mUpdaterQueue.empty()) {
481
0
      return;
482
0
    }
483
0
  }
484
0
485
0
  std::deque<QueuedTask> blockedTasks;
486
0
  while (true) {
487
0
    QueuedTask task;
488
0
489
0
    { // scope lock to extract a task
490
0
      MutexAutoLock lock(mQueueLock);
491
0
      if (mUpdaterQueue.empty()) {
492
0
        // If we're done processing mUpdaterQueue, swap the tasks that are
493
0
        // still blocked back in and finish
494
0
        std::swap(mUpdaterQueue, blockedTasks);
495
0
        break;
496
0
      }
497
0
      task = mUpdaterQueue.front();
498
0
      mUpdaterQueue.pop_front();
499
0
    }
500
0
501
0
    // We check the task to see if it is blocked. Note that while this
502
0
    // ProcessQueue function is executing, a particular layers is cannot go
503
0
    // from blocked to unblocked, because only CompleteSceneSwap can unblock
504
0
    // a layers id, and that also runs on the updater thread. If somehow
505
0
    // a layers id gets unblocked while we're processing the queue, then it
506
0
    // might result in tasks getting executed out of order.
507
0
508
0
    auto it = mEpochData.find(task.mLayersId);
509
0
    if (it != mEpochData.end() && it->second.IsBlocked()) {
510
0
      // If this task is blocked, put it into the blockedTasks queue that
511
0
      // we will replace mUpdaterQueue with
512
0
      blockedTasks.push_back(task);
513
0
    } else {
514
0
      // Run and discard the task
515
0
      task.mRunnable->Run();
516
0
    }
517
0
  }
518
0
}
519
520
APZUpdater::EpochState::EpochState()
521
  : mRequired{0}
522
  , mIsRoot(false)
523
0
{
524
0
}
525
526
bool
527
APZUpdater::EpochState::IsBlocked() const
528
0
{
529
0
  // The root is a special case because we basically assume it is "visible"
530
0
  // even before it is built for the first time. This is because building the
531
0
  // scene automatically makes it visible, and we need to make sure the APZ
532
0
  // scroll data gets applied atomically with that happening.
533
0
  //
534
0
  // Layer subtrees on the other hand do not automatically become visible upon
535
0
  // being built, because there must be a another layer tree update to change
536
0
  // the visibility (i.e. an ancestor layer tree update that adds the necessary
537
0
  // reflayer to complete the chain of reflayers).
538
0
  //
539
0
  // So in the case of non-visible subtrees, we know that no hit-test will
540
0
  // actually end up hitting that subtree either before or after the scene swap,
541
0
  // because the subtree will remain non-visible. That in turns means that we
542
0
  // can apply the APZ scroll data for that subtree epoch before the scene is
543
0
  // built, because it's not going to get used anyway. And that means we don't
544
0
  // need to block the queue for non-visible subtrees. Which is a good thing,
545
0
  // because in practice it seems like we often have non-visible subtrees sent
546
0
  // to the compositor from content.
547
0
  if (mIsRoot && !mBuilt) {
548
0
    return true;
549
0
  }
550
0
  return mBuilt && (*mBuilt < mRequired);
551
0
}
552
553
} // namespace layers
554
} // namespace mozilla
555
556
// Rust callback implementations
557
558
void
559
apz_register_updater(mozilla::wr::WrWindowId aWindowId)
560
0
{
561
0
  mozilla::layers::APZUpdater::SetUpdaterThread(aWindowId);
562
0
}
563
564
void
565
apz_pre_scene_swap(mozilla::wr::WrWindowId aWindowId)
566
0
{
567
0
  mozilla::layers::APZUpdater::PrepareForSceneSwap(aWindowId);
568
0
}
569
570
void
571
apz_post_scene_swap(mozilla::wr::WrWindowId aWindowId,
572
                    mozilla::wr::WrPipelineInfo aInfo)
573
0
{
574
0
  mozilla::layers::APZUpdater::CompleteSceneSwap(aWindowId, aInfo);
575
0
  wr_pipeline_info_delete(aInfo);
576
0
}
577
578
void
579
apz_run_updater(mozilla::wr::WrWindowId aWindowId)
580
0
{
581
0
  mozilla::layers::APZUpdater::ProcessPendingTasks(aWindowId);
582
0
}
583
584
void
585
apz_deregister_updater(mozilla::wr::WrWindowId aWindowId)
586
0
{
587
0
  // Run anything that's still left.
588
0
  mozilla::layers::APZUpdater::ProcessPendingTasks(aWindowId);
589
0
}