tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebRenderAPI.cpp (74829B)


      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 "WebRenderAPI.h"
      8 
      9 #include "mozilla/Logging.h"
     10 #include "mozilla/ipc/ByteBuf.h"
     11 #include "mozilla/webrender/RendererOGL.h"
     12 #include "mozilla/gfx/gfxVars.h"
     13 #include "mozilla/layers/CompositorThread.h"
     14 #include "mozilla/HelperMacros.h"
     15 #include "mozilla/StaticPrefs_gfx.h"
     16 #include "mozilla/StaticPrefs_webgl.h"
     17 #include "mozilla/ToString.h"
     18 #include "mozilla/webrender/RenderCompositor.h"
     19 #include "mozilla/widget/CompositorWidget.h"
     20 #include "mozilla/layers/SynchronousTask.h"
     21 #include "nsDisplayList.h"
     22 #include "nsThreadUtils.h"
     23 #include "TextDrawTarget.h"
     24 #include "malloc_decls.h"
     25 #include "GLContext.h"
     26 
     27 #include "source-repo.h"
     28 
     29 #ifdef MOZ_SOURCE_STAMP
     30 #  define MOZ_SOURCE_STAMP_VALUE MOZ_STRINGIFY(MOZ_SOURCE_STAMP)
     31 #else
     32 #  define MOZ_SOURCE_STAMP_VALUE nullptr
     33 #endif
     34 
     35 static mozilla::LazyLogModule sWrDLLog("wr.dl");
     36 #define WRDL_LOG(...) \
     37  MOZ_LOG(sWrDLLog, LogLevel::Debug, ("WRDL(%p): " __VA_ARGS__))
     38 
     39 namespace mozilla {
     40 using namespace layers;
     41 
     42 namespace wr {
     43 
     44 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderMallocSizeOf)
     45 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(WebRenderMallocEnclosingSizeOf)
     46 
     47 class NewRenderer : public RendererEvent {
     48 public:
     49  NewRenderer(wr::DocumentHandle** aDocHandle,
     50              layers::CompositorBridgeParent* aBridge,
     51              WebRenderBackend* aBackend, WebRenderCompositor* aCompositor,
     52              int32_t* aMaxTextureSize, bool* aUseANGLE, bool* aUseDComp,
     53              bool* aUseLayerCompositor, bool* aUseTripleBuffering,
     54              bool* aSupportsExternalBufferTextures,
     55              RefPtr<widget::CompositorWidget>&& aWidget,
     56              layers::SynchronousTask* aTask, LayoutDeviceIntSize aSize,
     57              layers::WindowKind aWindowKind, layers::SyncHandle* aHandle,
     58              nsACString* aError)
     59      : mDocHandle(aDocHandle),
     60        mBackend(aBackend),
     61        mCompositor(aCompositor),
     62        mMaxTextureSize(aMaxTextureSize),
     63        mUseANGLE(aUseANGLE),
     64        mUseDComp(aUseDComp),
     65        mUseLayerCompositor(aUseLayerCompositor),
     66        mUseTripleBuffering(aUseTripleBuffering),
     67        mSupportsExternalBufferTextures(aSupportsExternalBufferTextures),
     68        mBridge(aBridge),
     69        mCompositorWidget(std::move(aWidget)),
     70        mTask(aTask),
     71        mSize(aSize),
     72        mWindowKind(aWindowKind),
     73        mSyncHandle(aHandle),
     74        mError(aError) {
     75    MOZ_COUNT_CTOR(NewRenderer);
     76  }
     77 
     78  MOZ_COUNTED_DTOR(NewRenderer)
     79 
     80  void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
     81    layers::AutoCompleteTask complete(mTask);
     82 
     83    UniquePtr<RenderCompositor> compositor =
     84        RenderCompositor::Create(std::move(mCompositorWidget), *mError);
     85    if (!compositor) {
     86      if (!mError->IsEmpty()) {
     87        gfxCriticalNote << mError->BeginReading();
     88      }
     89      return;
     90    }
     91 
     92    compositor->MakeCurrent();
     93 
     94    *mBackend = compositor->BackendType();
     95    *mCompositor = compositor->CompositorType();
     96    *mUseANGLE = compositor->UseANGLE();
     97    *mUseDComp = compositor->UseDComp();
     98    *mUseLayerCompositor = compositor->ShouldUseLayerCompositor();
     99    *mUseTripleBuffering = compositor->UseTripleBuffering();
    100    *mSupportsExternalBufferTextures =
    101        compositor->SupportsExternalBufferTextures();
    102 
    103    // Only allow the panic on GL error functionality in nightly builds,
    104    // since it (deliberately) crashes the GPU process if any GL call
    105    // returns an error code.
    106    bool panic_on_gl_error = false;
    107 #ifdef NIGHTLY_BUILD
    108    panic_on_gl_error =
    109        StaticPrefs::gfx_webrender_panic_on_gl_error_AtStartup();
    110 #endif
    111 
    112    bool isMainWindow = true;  // TODO!
    113    bool supportLowPriorityTransactions = isMainWindow;
    114    bool supportLowPriorityThreadpool =
    115        supportLowPriorityTransactions &&
    116        StaticPrefs::gfx_webrender_enable_low_priority_pool();
    117    wr::Renderer* wrRenderer = nullptr;
    118    char* errorMessage = nullptr;
    119    int picTileWidth = StaticPrefs::gfx_webrender_picture_tile_width();
    120    int picTileHeight = StaticPrefs::gfx_webrender_picture_tile_height();
    121    auto* swgl = compositor->swgl();
    122    auto* gl = (compositor->gl() && !swgl) ? compositor->gl() : nullptr;
    123    auto* progCache = (aRenderThread.GetProgramCache() && !swgl)
    124                          ? aRenderThread.GetProgramCache()->Raw()
    125                          : nullptr;
    126    auto* shaders = (aRenderThread.GetShaders() && !swgl)
    127                        ? aRenderThread.GetShaders()->RawShaders()
    128                        : nullptr;
    129 
    130    // Check That if we are not using SWGL, we have at least a GL or GLES 3.0
    131    // context.
    132    if (gl && !swgl) {
    133      bool versionCheck =
    134          gl->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
    135          gl->IsAtLeast(gl::ContextProfile::OpenGLCompatibility, 300) ||
    136          gl->IsAtLeast(gl::ContextProfile::OpenGLES, 300);
    137 
    138      if (!versionCheck) {
    139        gfxCriticalNote << "GL context version (" << gl->Version()
    140                        << ") insufficent for hardware WebRender";
    141 
    142        mError->AssignASCII("GL context version insufficient");
    143        return;
    144      }
    145    }
    146 
    147    if (!wr_window_new(
    148            aWindowId, mSize.width, mSize.height,
    149            mWindowKind == WindowKind::MAIN, supportLowPriorityTransactions,
    150            supportLowPriorityThreadpool, gfx::gfxVars::UseGLSwizzle(),
    151            gfx::gfxVars::UseWebRenderScissoredCacheClears(), swgl, gl,
    152            compositor->SurfaceOriginIsTopLeft(), progCache, shaders,
    153            aRenderThread.ThreadPool().Raw(),
    154            aRenderThread.ThreadPoolLP().Raw(), aRenderThread.MemoryChunkPool(),
    155            aRenderThread.GlyphRasterThread().Raw(), &WebRenderMallocSizeOf,
    156            &WebRenderMallocEnclosingSizeOf, 0, compositor.get(),
    157            compositor->ShouldUseNativeCompositor(),
    158            compositor->UsePartialPresent(),
    159            compositor->GetMaxPartialPresentRects(),
    160            compositor->ShouldDrawPreviousPartialPresentRegions(), mDocHandle,
    161            &wrRenderer, mMaxTextureSize, &errorMessage,
    162            StaticPrefs::gfx_webrender_enable_gpu_markers_AtStartup(),
    163            panic_on_gl_error, picTileWidth, picTileHeight,
    164            gfx::gfxVars::WebRenderRequiresHardwareDriver(),
    165            StaticPrefs::gfx_webrender_low_quality_pinch_zoom_AtStartup(),
    166            StaticPrefs::gfx_webrender_max_shared_surface_size_AtStartup(),
    167            StaticPrefs::gfx_webrender_enable_subpixel_aa_AtStartup(),
    168            compositor->ShouldUseLayerCompositor())) {
    169      // wr_window_new puts a message into gfxCriticalNote if it returns false
    170      MOZ_ASSERT(errorMessage);
    171      mError->AssignASCII(errorMessage);
    172      wr_api_free_error_msg(errorMessage);
    173      return;
    174    }
    175    MOZ_ASSERT(wrRenderer);
    176 
    177    RefPtr<RenderThread> thread = &aRenderThread;
    178    auto renderer =
    179        MakeUnique<RendererOGL>(std::move(thread), std::move(compositor),
    180                                aWindowId, wrRenderer, mBridge);
    181    if (wrRenderer && renderer) {
    182      wr::WrExternalImageHandler handler = renderer->GetExternalImageHandler();
    183      wr_renderer_set_external_image_handler(wrRenderer, &handler);
    184    }
    185 
    186    if (renderer) {
    187      layers::SyncObjectHost* syncObj = renderer->GetSyncObject();
    188      if (syncObj) {
    189        *mSyncHandle = syncObj->GetSyncHandle();
    190      }
    191    }
    192 
    193    aRenderThread.AddRenderer(aWindowId, std::move(renderer));
    194 
    195    // Kick off shader warmup, outside this NewRenderer task so that any
    196    // threads which block on the NewRenderer work can proceed immediately.
    197    aRenderThread.BeginShaderWarmupIfNeeded();
    198  }
    199 
    200  const char* Name() override { return "NewRenderer"; }
    201 
    202 private:
    203  wr::DocumentHandle** mDocHandle;
    204  WebRenderBackend* mBackend;
    205  WebRenderCompositor* mCompositor;
    206  int32_t* mMaxTextureSize;
    207  bool* mUseANGLE;
    208  bool* mUseDComp;
    209  bool* mUseLayerCompositor;
    210  bool* mUseTripleBuffering;
    211  bool* mSupportsExternalBufferTextures;
    212  layers::CompositorBridgeParent* mBridge;
    213  RefPtr<widget::CompositorWidget> mCompositorWidget;
    214  layers::SynchronousTask* mTask;
    215  LayoutDeviceIntSize mSize;
    216  layers::WindowKind mWindowKind;
    217  layers::SyncHandle* mSyncHandle;
    218  nsACString* mError;
    219 };
    220 
    221 class RemoveRenderer : public RendererEvent {
    222 public:
    223  explicit RemoveRenderer(layers::SynchronousTask* aTask) : mTask(aTask) {
    224    MOZ_COUNT_CTOR(RemoveRenderer);
    225  }
    226 
    227  MOZ_COUNTED_DTOR_OVERRIDE(RemoveRenderer)
    228 
    229  void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    230    aRenderThread.RemoveRenderer(aWindowId);
    231    layers::AutoCompleteTask complete(mTask);
    232  }
    233 
    234  const char* Name() override { return "RemoveRenderer"; }
    235 
    236 private:
    237  layers::SynchronousTask* mTask;
    238 };
    239 
    240 TransactionBuilder::TransactionBuilder(
    241    WebRenderAPI* aApi, bool aUseSceneBuilderThread,
    242    layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler,
    243    layers::RemoteTextureTxnId aRemoteTextureTxnId)
    244    : mRemoteTextureTxnScheduler(aRemoteTextureTxnScheduler),
    245      mRemoteTextureTxnId(aRemoteTextureTxnId),
    246      mUseSceneBuilderThread(aUseSceneBuilderThread),
    247      mApiBackend(aApi->GetBackendType()),
    248      mOwnsData(true) {
    249  mTxn = wr_transaction_new(mUseSceneBuilderThread);
    250 }
    251 
    252 TransactionBuilder::TransactionBuilder(
    253    WebRenderAPI* aApi, Transaction* aTxn, bool aUseSceneBuilderThread,
    254    bool aOwnsData,
    255    layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler,
    256    layers::RemoteTextureTxnId aRemoteTextureTxnId)
    257    : mRemoteTextureTxnScheduler(aRemoteTextureTxnScheduler),
    258      mRemoteTextureTxnId(aRemoteTextureTxnId),
    259      mTxn(aTxn),
    260      mUseSceneBuilderThread(aUseSceneBuilderThread),
    261      mApiBackend(aApi->GetBackendType()),
    262      mOwnsData(aOwnsData) {}
    263 
    264 TransactionBuilder::~TransactionBuilder() {
    265  if (mOwnsData) {
    266    wr_transaction_delete(mTxn);
    267  }
    268 }
    269 
    270 void TransactionBuilder::SetLowPriority(bool aIsLowPriority) {
    271  wr_transaction_set_low_priority(mTxn, aIsLowPriority);
    272 }
    273 
    274 void TransactionBuilder::UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch) {
    275  wr_transaction_update_epoch(mTxn, aPipelineId, aEpoch);
    276 }
    277 
    278 void TransactionBuilder::SetRootPipeline(PipelineId aPipelineId) {
    279  wr_transaction_set_root_pipeline(mTxn, aPipelineId);
    280 }
    281 
    282 void TransactionBuilder::RemovePipeline(PipelineId aPipelineId) {
    283  wr_transaction_remove_pipeline(mTxn, aPipelineId);
    284 }
    285 
    286 void TransactionBuilder::SetDisplayList(
    287    Epoch aEpoch, wr::WrPipelineId pipeline_id,
    288    wr::BuiltDisplayListDescriptor dl_descriptor,
    289    wr::Vec<uint8_t>& dl_items_data, wr::Vec<uint8_t>& dl_cache_data,
    290    wr::Vec<uint8_t>& dl_spatial_tree) {
    291  wr_transaction_set_display_list(mTxn, aEpoch, pipeline_id, dl_descriptor,
    292                                  &dl_items_data.inner, &dl_cache_data.inner,
    293                                  &dl_spatial_tree.inner);
    294 }
    295 
    296 void TransactionBuilder::ClearDisplayList(Epoch aEpoch,
    297                                          wr::WrPipelineId aPipelineId) {
    298  wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId);
    299 }
    300 
    301 void TransactionBuilder::GenerateFrame(const VsyncId& aVsyncId, bool aPresent,
    302                                       bool aTracked,
    303                                       wr::RenderReasons aReasons) {
    304  wr_transaction_generate_frame(mTxn, aVsyncId.mId, aPresent, aTracked,
    305                                aReasons);
    306 }
    307 
    308 void TransactionBuilder::InvalidateRenderedFrame(wr::RenderReasons aReasons) {
    309  wr_transaction_invalidate_rendered_frame(mTxn, aReasons);
    310 }
    311 
    312 bool TransactionBuilder::IsEmpty() const {
    313  return wr_transaction_is_empty(mTxn);
    314 }
    315 
    316 bool TransactionBuilder::IsResourceUpdatesEmpty() const {
    317  return wr_transaction_resource_updates_is_empty(mTxn);
    318 }
    319 
    320 bool TransactionBuilder::IsRenderedFrameInvalidated() const {
    321  return wr_transaction_is_rendered_frame_invalidated(mTxn);
    322 }
    323 
    324 void TransactionBuilder::SetDocumentView(
    325    const LayoutDeviceIntRect& aDocumentRect) {
    326  wr::DeviceIntRect wrDocRect;
    327  wrDocRect.min.x = aDocumentRect.x;
    328  wrDocRect.min.y = aDocumentRect.y;
    329  wrDocRect.max.x = aDocumentRect.x + aDocumentRect.width;
    330  wrDocRect.max.y = aDocumentRect.y + aDocumentRect.height;
    331  wr_transaction_set_document_view(mTxn, &wrDocRect);
    332 }
    333 
    334 void TransactionBuilder::RenderOffscreen(wr::WrPipelineId aPipelineId) {
    335  wr_transaction_render_offscreen(mTxn, aPipelineId);
    336 }
    337 
    338 TransactionWrapper::TransactionWrapper(Transaction* aTxn) : mTxn(aTxn) {}
    339 
    340 void TransactionWrapper::AppendDynamicProperties(
    341    const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
    342    const nsTArray<wr::WrTransformProperty>& aTransformArray,
    343    const nsTArray<wr::WrColorProperty>& aColorArray) {
    344  wr_transaction_append_dynamic_properties(
    345      mTxn, aOpacityArray.IsEmpty() ? nullptr : aOpacityArray.Elements(),
    346      aOpacityArray.Length(),
    347      aTransformArray.IsEmpty() ? nullptr : aTransformArray.Elements(),
    348      aTransformArray.Length(),
    349      aColorArray.IsEmpty() ? nullptr : aColorArray.Elements(),
    350      aColorArray.Length());
    351 }
    352 
    353 void TransactionWrapper::AppendTransformProperties(
    354    const nsTArray<wr::WrTransformProperty>& aTransformArray) {
    355  wr_transaction_append_transform_properties(
    356      mTxn, aTransformArray.IsEmpty() ? nullptr : aTransformArray.Elements(),
    357      aTransformArray.Length());
    358 }
    359 
    360 void TransactionWrapper::UpdateScrollPosition(
    361    const wr::ExternalScrollId& aScrollId,
    362    const nsTArray<wr::SampledScrollOffset>& aSampledOffsets) {
    363  wr_transaction_scroll_layer(mTxn, aScrollId, &aSampledOffsets);
    364 }
    365 
    366 void TransactionWrapper::UpdateIsTransformAsyncZooming(uint64_t aAnimationId,
    367                                                       bool aIsZooming) {
    368  wr_transaction_set_is_transform_async_zooming(mTxn, aAnimationId, aIsZooming);
    369 }
    370 
    371 void TransactionWrapper::AddMinimapData(const wr::ExternalScrollId& aScrollId,
    372                                        const MinimapData& aMinimapData) {
    373  wr_transaction_add_minimap_data(mTxn, aScrollId, aMinimapData);
    374 }
    375 
    376 /*static*/
    377 already_AddRefed<WebRenderAPI> WebRenderAPI::Create(
    378    layers::CompositorBridgeParent* aBridge,
    379    RefPtr<widget::CompositorWidget>&& aWidget, const wr::WrWindowId& aWindowId,
    380    LayoutDeviceIntSize aSize, layers::WindowKind aWindowKind,
    381    nsACString& aError) {
    382  MOZ_ASSERT(aBridge);
    383  MOZ_ASSERT(aWidget);
    384  static_assert(
    385      sizeof(size_t) == sizeof(uintptr_t),
    386      "The FFI bindings assume size_t is the same size as uintptr_t!");
    387 
    388  wr::DocumentHandle* docHandle = nullptr;
    389  WebRenderBackend backend = WebRenderBackend::HARDWARE;
    390  WebRenderCompositor compositor = WebRenderCompositor::DRAW;
    391  int32_t maxTextureSize = 0;
    392  bool useANGLE = false;
    393  bool useDComp = false;
    394  bool useLayerCompositor = false;
    395  bool useTripleBuffering = false;
    396  bool supportsExternalBufferTextures = false;
    397  layers::SyncHandle syncHandle = {};
    398 
    399  // Dispatch a synchronous task because the DocumentHandle object needs to be
    400  // created on the render thread. If need be we could delay waiting on this
    401  // task until the next time we need to access the DocumentHandle object.
    402  layers::SynchronousTask task("Create Renderer");
    403  auto event = MakeUnique<NewRenderer>(
    404      &docHandle, aBridge, &backend, &compositor, &maxTextureSize, &useANGLE,
    405      &useDComp, &useLayerCompositor, &useTripleBuffering,
    406      &supportsExternalBufferTextures, std::move(aWidget), &task, aSize,
    407      aWindowKind, &syncHandle, &aError);
    408  RenderThread::Get()->PostEvent(aWindowId, std::move(event));
    409 
    410  task.Wait();
    411 
    412  if (!docHandle) {
    413    return nullptr;
    414  }
    415 
    416  return RefPtr<WebRenderAPI>(
    417             new WebRenderAPI(docHandle, aWindowId, backend, compositor,
    418                              maxTextureSize, useANGLE, useDComp,
    419                              useLayerCompositor, useTripleBuffering,
    420                              supportsExternalBufferTextures, syncHandle))
    421      .forget();
    422 }
    423 
    424 already_AddRefed<WebRenderAPI> WebRenderAPI::Clone() {
    425  wr::DocumentHandle* docHandle = nullptr;
    426  wr_api_clone(mDocHandle, &docHandle);
    427 
    428  RefPtr<WebRenderAPI> renderApi = new WebRenderAPI(
    429      docHandle, mId, mBackend, mCompositor, mMaxTextureSize, mUseANGLE,
    430      mUseDComp, mUseLayerCompositor, mUseTripleBuffering,
    431      mSupportsExternalBufferTextures, mSyncHandle, this, this);
    432 
    433  return renderApi.forget();
    434 }
    435 
    436 wr::WrIdNamespace WebRenderAPI::GetNamespace() {
    437  return wr_api_get_namespace(mDocHandle);
    438 }
    439 
    440 WebRenderAPI::WebRenderAPI(
    441    wr::DocumentHandle* aHandle, wr::WindowId aId, WebRenderBackend aBackend,
    442    WebRenderCompositor aCompositor, uint32_t aMaxTextureSize, bool aUseANGLE,
    443    bool aUseDComp, bool aUseLayerCompositor, bool aUseTripleBuffering,
    444    bool aSupportsExternalBufferTextures, layers::SyncHandle aSyncHandle,
    445    wr::WebRenderAPI* aRootApi, wr::WebRenderAPI* aRootDocumentApi)
    446    : mDocHandle(aHandle),
    447      mId(aId),
    448      mBackend(aBackend),
    449      mCompositor(aCompositor),
    450      mMaxTextureSize(aMaxTextureSize),
    451      mUseANGLE(aUseANGLE),
    452      mUseDComp(aUseDComp),
    453      mUseLayerCompositor(aUseLayerCompositor),
    454      mUseTripleBuffering(aUseTripleBuffering),
    455      mSupportsExternalBufferTextures(aSupportsExternalBufferTextures),
    456      mCaptureSequence(false),
    457      mSyncHandle(aSyncHandle),
    458      mRendererDestroyed(false),
    459      mRootApi(aRootApi),
    460      mRootDocumentApi(aRootDocumentApi) {}
    461 
    462 WebRenderAPI::~WebRenderAPI() {
    463  if (!mRootDocumentApi) {
    464    wr_api_delete_document(mDocHandle);
    465  }
    466 
    467  if (!mRootApi) {
    468    MOZ_RELEASE_ASSERT(mRendererDestroyed);
    469    wr_api_shut_down(mDocHandle);
    470  }
    471 
    472  wr_api_delete(mDocHandle);
    473 }
    474 
    475 void WebRenderAPI::DestroyRenderer() {
    476  MOZ_RELEASE_ASSERT(!mRootApi);
    477 
    478  RenderThread::Get()->SetDestroyed(GetId());
    479  // Call wr_api_stop_render_backend() before RemoveRenderer.
    480  wr_api_stop_render_backend(mDocHandle);
    481 
    482  layers::SynchronousTask task("Destroy WebRenderAPI");
    483  auto event = MakeUnique<RemoveRenderer>(&task);
    484  RunOnRenderThread(std::move(event));
    485  task.Wait();
    486 
    487  mRendererDestroyed = true;
    488 }
    489 
    490 wr::WebRenderAPI* WebRenderAPI::GetRootAPI() {
    491  if (mRootApi) {
    492    return mRootApi;
    493  }
    494  return this;
    495 }
    496 
    497 void WebRenderAPI::UpdateDebugFlags(uint64_t aFlags) {
    498  wr_api_set_debug_flags(mDocHandle, wr::DebugFlags{aFlags});
    499 }
    500 
    501 void WebRenderAPI::SendTransaction(TransactionBuilder& aTxn) {
    502  if (mRootApi && mRootApi->mRendererDestroyed) {
    503    return;
    504  }
    505 
    506  if (mPendingRemoteTextureInfoList &&
    507      !mPendingRemoteTextureInfoList->mList.empty()) {
    508    mPendingWrTransactionEvents.emplace(
    509        WrTransactionEvent::PendingRemoteTextures(
    510            std::move(mPendingRemoteTextureInfoList)));
    511  }
    512 
    513  if (mPendingAsyncImagePipelineOps &&
    514      !mPendingAsyncImagePipelineOps->mList.empty()) {
    515    mPendingWrTransactionEvents.emplace(
    516        WrTransactionEvent::PendingAsyncImagePipelineOps(
    517            std::move(mPendingAsyncImagePipelineOps), this, aTxn));
    518  }
    519 
    520  if (!mPendingWrTransactionEvents.empty()) {
    521    mPendingWrTransactionEvents.emplace(
    522        WrTransactionEvent::Transaction(this, aTxn));
    523    HandleWrTransactionEvents(RemoteTextureWaitType::AsyncWait);
    524  } else {
    525    wr_api_send_transaction(mDocHandle, aTxn.Raw(),
    526                            aTxn.UseSceneBuilderThread());
    527    if (aTxn.mRemoteTextureTxnScheduler) {
    528      aTxn.mRemoteTextureTxnScheduler->NotifyTxn(aTxn.mRemoteTextureTxnId);
    529    }
    530  }
    531 }
    532 
    533 layers::RemoteTextureInfoList* WebRenderAPI::GetPendingRemoteTextureInfoList() {
    534  if (!mRootApi) {
    535    // root api does not support async wait RemoteTexture.
    536    return nullptr;
    537  }
    538 
    539  if (!mPendingRemoteTextureInfoList) {
    540    mPendingRemoteTextureInfoList = MakeUnique<layers::RemoteTextureInfoList>();
    541  }
    542  return mPendingRemoteTextureInfoList.get();
    543 }
    544 
    545 layers::AsyncImagePipelineOps* WebRenderAPI::GetPendingAsyncImagePipelineOps(
    546    TransactionBuilder& aTxn) {
    547  if (!mRootApi) {
    548    // root api does not support async wait RemoteTexture.
    549    return nullptr;
    550  }
    551 
    552  if (!mPendingAsyncImagePipelineOps ||
    553      mPendingAsyncImagePipelineOps->mTransaction != aTxn.Raw()) {
    554    if (mPendingAsyncImagePipelineOps &&
    555        !mPendingAsyncImagePipelineOps->mList.empty()) {
    556      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    557      gfxCriticalNoteOnce << "Invalid AsyncImagePipelineOps";
    558    }
    559    mPendingAsyncImagePipelineOps =
    560        MakeUnique<layers::AsyncImagePipelineOps>(aTxn.Raw());
    561  } else {
    562    MOZ_RELEASE_ASSERT(mPendingAsyncImagePipelineOps->mTransaction ==
    563                       aTxn.Raw());
    564  }
    565 
    566  return mPendingAsyncImagePipelineOps.get();
    567 }
    568 
    569 bool WebRenderAPI::CheckIsRemoteTextureReady(
    570    layers::RemoteTextureInfoList* aList, const TimeStamp& aTimeStamp) {
    571  MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
    572  MOZ_ASSERT(aList);
    573 
    574  RefPtr<WebRenderAPI> self = this;
    575  auto callback = [self](const layers::RemoteTextureInfo&) {
    576    RefPtr<nsIRunnable> runnable = NewRunnableMethod<RemoteTextureWaitType>(
    577        "WebRenderAPI::HandleWrTransactionEvents", self,
    578        &WebRenderAPI::HandleWrTransactionEvents,
    579        RemoteTextureWaitType::AsyncWait);
    580    layers::CompositorThread()->Dispatch(runnable.forget());
    581  };
    582 
    583  bool isReady = true;
    584  while (!aList->mList.empty() && isReady) {
    585    auto& front = aList->mList.front();
    586    isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady(
    587        front, callback);
    588    if (isReady) {
    589      aList->mList.pop();
    590    }
    591  }
    592 
    593  if (isReady) {
    594    return true;
    595  }
    596 
    597 #ifndef DEBUG
    598  const auto maxWaitDurationMs = 10000;
    599 #else
    600  const auto maxWaitDurationMs = 30000;
    601 #endif
    602  const auto now = TimeStamp::Now();
    603  const auto waitDurationMs =
    604      static_cast<uint32_t>((now - aTimeStamp).ToMilliseconds());
    605 
    606  const auto isTimeout = waitDurationMs > maxWaitDurationMs;
    607  if (isTimeout) {
    608    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    609    gfxCriticalNote << "RemoteTexture ready timeout";
    610  }
    611 
    612  return false;
    613 }
    614 
    615 void WebRenderAPI::WaitRemoteTextureReady(
    616    layers::RemoteTextureInfoList* aList) {
    617  MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
    618  MOZ_ASSERT(aList);
    619 
    620  while (!aList->mList.empty()) {
    621    auto& front = aList->mList.front();
    622    layers::RemoteTextureMap::Get()->WaitRemoteTextureReady(front);
    623    aList->mList.pop();
    624  }
    625 }
    626 
    627 void WebRenderAPI::FlushPendingWrTransactionEventsWithoutWait() {
    628  HandleWrTransactionEvents(RemoteTextureWaitType::FlushWithoutWait);
    629 }
    630 
    631 void WebRenderAPI::FlushPendingWrTransactionEventsWithWait() {
    632  HandleWrTransactionEvents(RemoteTextureWaitType::FlushWithWait);
    633 }
    634 
    635 void WebRenderAPI::HandleWrTransactionEvents(RemoteTextureWaitType aType) {
    636  auto& events = mPendingWrTransactionEvents;
    637 
    638  while (!events.empty()) {
    639    auto& front = events.front();
    640    switch (front.mTag) {
    641      case WrTransactionEvent::Tag::Transaction:
    642        wr_api_send_transaction(mDocHandle, front.RawTransaction(),
    643                                front.UseSceneBuilderThread());
    644        if (front.GetTransactionBuilder()->mRemoteTextureTxnScheduler) {
    645          front.GetTransactionBuilder()->mRemoteTextureTxnScheduler->NotifyTxn(
    646              front.GetTransactionBuilder()->mRemoteTextureTxnId);
    647        }
    648        break;
    649      case WrTransactionEvent::Tag::PendingRemoteTextures: {
    650        bool isReady = true;
    651        if (aType == RemoteTextureWaitType::AsyncWait) {
    652          isReady = CheckIsRemoteTextureReady(front.RemoteTextureInfoList(),
    653                                              front.mTimeStamp);
    654        } else if (aType == RemoteTextureWaitType::FlushWithWait) {
    655          WaitRemoteTextureReady(front.RemoteTextureInfoList());
    656        } else {
    657          MOZ_ASSERT(aType == RemoteTextureWaitType::FlushWithoutWait);
    658          auto* list = front.RemoteTextureInfoList();
    659          while (!list->mList.empty()) {
    660            auto& front = list->mList.front();
    661            layers::RemoteTextureMap::Get()->SuppressRemoteTextureReadyCheck(
    662                front);
    663            list->mList.pop();
    664          }
    665        }
    666        if (!isReady && (aType != RemoteTextureWaitType::FlushWithoutWait)) {
    667          return;
    668        }
    669        break;
    670      }
    671      case WrTransactionEvent::Tag::PendingAsyncImagePipelineOps: {
    672        auto* list = front.AsyncImagePipelineOps();
    673        TransactionBuilder& txn = *front.GetTransactionBuilder();
    674 
    675        list->HandleOps(txn);
    676        break;
    677      }
    678    }
    679    events.pop();
    680  }
    681 }
    682 
    683 std::vector<WrHitResult> WebRenderAPI::HitTest(const wr::WorldPoint& aPoint) {
    684  static_assert(gfx::DoesCompositorHitTestInfoFitIntoBits<12>(),
    685                "CompositorHitTestFlags MAX value has to be less than number "
    686                "of bits in uint16_t minus 4 for SideBitsPacked");
    687 
    688  nsTArray<wr::HitResult> wrResults;
    689  wr_api_hit_test(mDocHandle, aPoint, &wrResults);
    690 
    691  std::vector<WrHitResult> geckoResults;
    692  for (wr::HitResult wrResult : wrResults) {
    693    WrHitResult geckoResult;
    694    geckoResult.mLayersId = wr::AsLayersId(wrResult.pipeline_id);
    695    geckoResult.mScrollId =
    696        static_cast<layers::ScrollableLayerGuid::ViewID>(wrResult.scroll_id);
    697    geckoResult.mHitInfo.deserialize(wrResult.hit_info & 0x0fff);
    698    geckoResult.mSideBits = static_cast<SideBits>(wrResult.hit_info >> 12);
    699 
    700    if (wrResult.animation_id != 0) {
    701      geckoResult.mAnimationId = Some(wrResult.animation_id);
    702    } else {
    703      geckoResult.mAnimationId = Nothing();
    704    }
    705    geckoResults.push_back(geckoResult);
    706  }
    707  return geckoResults;
    708 }
    709 
    710 void WebRenderAPI::Readback(const TimeStamp& aStartTime, gfx::IntSize size,
    711                            const gfx::SurfaceFormat& aFormat,
    712                            const Range<uint8_t>& buffer, bool* aNeedsYFlip) {
    713  class Readback : public RendererEvent {
    714   public:
    715    explicit Readback(layers::SynchronousTask* aTask, TimeStamp aStartTime,
    716                      gfx::IntSize aSize, const gfx::SurfaceFormat& aFormat,
    717                      const Range<uint8_t>& aBuffer, bool* aNeedsYFlip)
    718        : mTask(aTask),
    719          mStartTime(aStartTime),
    720          mSize(aSize),
    721          mFormat(aFormat),
    722          mBuffer(aBuffer),
    723          mNeedsYFlip(aNeedsYFlip) {
    724      MOZ_COUNT_CTOR(Readback);
    725    }
    726 
    727    MOZ_COUNTED_DTOR_OVERRIDE(Readback)
    728 
    729    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    730      RendererStats stats = {0};
    731      wr::FrameReadyParams params = {
    732          .present = true,
    733          .render = true,
    734          .scrolled = false,
    735          .tracked = false,
    736      };
    737      aRenderThread.UpdateAndRender(aWindowId, VsyncId(), mStartTime, params,
    738                                    Some(mSize),
    739                                    wr::SurfaceFormatToImageFormat(mFormat),
    740                                    Some(mBuffer), &stats, mNeedsYFlip);
    741      layers::AutoCompleteTask complete(mTask);
    742    }
    743 
    744    const char* Name() override { return "Readback"; }
    745 
    746   private:
    747    layers::SynchronousTask* mTask;
    748    TimeStamp mStartTime;
    749    gfx::IntSize mSize;
    750    gfx::SurfaceFormat mFormat;
    751    const Range<uint8_t>& mBuffer;
    752    bool* mNeedsYFlip;
    753  };
    754 
    755  // Disable debug flags during readback. See bug 1436020.
    756  UpdateDebugFlags(0);
    757 
    758  layers::SynchronousTask task("Readback");
    759  auto event = MakeUnique<Readback>(&task, aStartTime, size, aFormat, buffer,
    760                                    aNeedsYFlip);
    761  // This event will be passed from wr_backend thread to renderer thread. That
    762  // implies that all frame data have been processed when the renderer runs this
    763  // read-back event. Then, we could make sure this read-back event gets the
    764  // latest result.
    765  RunOnRenderThread(std::move(event));
    766 
    767  task.Wait();
    768 
    769  UpdateDebugFlags(gfx::gfxVars::WebRenderDebugFlags());
    770 }
    771 
    772 void WebRenderAPI::ClearAllCaches() { wr_api_clear_all_caches(mDocHandle); }
    773 
    774 void WebRenderAPI::EnableNativeCompositor(bool aEnable) {
    775  wr_api_enable_native_compositor(mDocHandle, aEnable);
    776 }
    777 
    778 void WebRenderAPI::SetBatchingLookback(uint32_t aCount) {
    779  wr_api_set_batching_lookback(mDocHandle, aCount);
    780 }
    781 
    782 void WebRenderAPI::SetBool(wr::BoolParameter aKey, bool aValue) {
    783  wr_api_set_bool(mDocHandle, aKey, aValue);
    784 }
    785 
    786 void WebRenderAPI::SetInt(wr::IntParameter aKey, int32_t aValue) {
    787  wr_api_set_int(mDocHandle, aKey, aValue);
    788 }
    789 
    790 void WebRenderAPI::SetFloat(wr::FloatParameter aKey, float aValue) {
    791  wr_api_set_float(mDocHandle, aKey, aValue);
    792 }
    793 
    794 void WebRenderAPI::SetClearColor(const gfx::DeviceColor& aColor) {
    795  RenderThread::Get()->SetClearColor(mId, ToColorF(aColor));
    796 }
    797 
    798 void WebRenderAPI::SetProfilerUI(const nsACString& aUIString) {
    799  RenderThread::Get()->SetProfilerUI(mId, aUIString);
    800 }
    801 
    802 void WebRenderAPI::Pause() {
    803  class PauseEvent : public RendererEvent {
    804   public:
    805    explicit PauseEvent(layers::SynchronousTask* aTask) : mTask(aTask) {
    806      MOZ_COUNT_CTOR(PauseEvent);
    807    }
    808 
    809    MOZ_COUNTED_DTOR_OVERRIDE(PauseEvent)
    810 
    811    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    812      aRenderThread.Pause(aWindowId);
    813      layers::AutoCompleteTask complete(mTask);
    814    }
    815 
    816    const char* Name() override { return "PauseEvent"; }
    817 
    818   private:
    819    layers::SynchronousTask* mTask;
    820  };
    821 
    822  layers::SynchronousTask task("Pause");
    823  auto event = MakeUnique<PauseEvent>(&task);
    824  RenderThread::Get()->PostEvent(mId, std::move(event));
    825 
    826  task.Wait();
    827 }
    828 
    829 bool WebRenderAPI::Resume() {
    830  class ResumeEvent : public RendererEvent {
    831   public:
    832    explicit ResumeEvent(layers::SynchronousTask* aTask, bool* aResult)
    833        : mTask(aTask), mResult(aResult) {
    834      MOZ_COUNT_CTOR(ResumeEvent);
    835    }
    836 
    837    MOZ_COUNTED_DTOR_OVERRIDE(ResumeEvent)
    838 
    839    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    840      *mResult = aRenderThread.Resume(aWindowId);
    841      layers::AutoCompleteTask complete(mTask);
    842    }
    843 
    844    const char* Name() override { return "ResumeEvent"; }
    845 
    846   private:
    847    layers::SynchronousTask* mTask;
    848    bool* mResult;
    849  };
    850 
    851  bool result = false;
    852  layers::SynchronousTask task("Resume");
    853  auto event = MakeUnique<ResumeEvent>(&task, &result);
    854  RenderThread::Get()->PostEvent(mId, std::move(event));
    855 
    856  task.Wait();
    857  return result;
    858 }
    859 
    860 void WebRenderAPI::NotifyMemoryPressure() {
    861  wr_api_notify_memory_pressure(mDocHandle);
    862 }
    863 
    864 void WebRenderAPI::AccumulateMemoryReport(MemoryReport* aReport) {
    865  wr_api_accumulate_memory_report(mDocHandle, aReport, &WebRenderMallocSizeOf,
    866                                  &WebRenderMallocEnclosingSizeOf);
    867 }
    868 
    869 void WebRenderAPI::WakeSceneBuilder() { wr_api_wake_scene_builder(mDocHandle); }
    870 
    871 void WebRenderAPI::FlushSceneBuilder() {
    872  wr_api_flush_scene_builder(mDocHandle);
    873 }
    874 
    875 void WebRenderAPI::WaitUntilPresentationFlushed() {
    876  class WaitFlushedEvent : public RendererEvent {
    877   public:
    878    explicit WaitFlushedEvent(layers::SynchronousTask* aTask) : mTask(aTask) {
    879      MOZ_COUNT_CTOR(WaitFlushedEvent);
    880    }
    881 
    882    MOZ_COUNTED_DTOR_OVERRIDE(WaitFlushedEvent)
    883 
    884    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    885      if (RendererOGL* renderer = aRenderThread.GetRenderer(aWindowId)) {
    886        if (RenderCompositor* compositor = renderer->GetCompositor()) {
    887          compositor->WaitUntilPresentationFlushed();
    888        }
    889      }
    890      layers::AutoCompleteTask complete(mTask);
    891    }
    892 
    893    const char* Name() override { return "WaitFlushedEvent"; }
    894 
    895   private:
    896    layers::SynchronousTask* mTask;
    897  };
    898 
    899  layers::SynchronousTask task("WaitUntilPresentationFlushed");
    900  auto event = MakeUnique<WaitFlushedEvent>(&task);
    901  // This event will be passed from wr_backend thread to renderer thread. That
    902  // implies that all frame data have been processed when the renderer runs this
    903  // event.
    904  RunOnRenderThread(std::move(event));
    905 
    906  task.Wait();
    907 }
    908 
    909 void WebRenderAPI::Capture() {
    910  // see CaptureBits
    911  // SCENE | FRAME | TILE_CACHE
    912  uint8_t bits = 15;                // TODO: get from JavaScript
    913  const char* path = "wr-capture";  // TODO: get from JavaScript
    914  const char* revision = MOZ_SOURCE_STAMP_VALUE;
    915  wr_api_capture(mDocHandle, path, revision, bits);
    916 }
    917 
    918 void WebRenderAPI::StartCaptureSequence(const nsACString& aPath,
    919                                        uint32_t aFlags) {
    920  if (mCaptureSequence) {
    921    wr_api_stop_capture_sequence(mDocHandle);
    922  }
    923 
    924  wr_api_start_capture_sequence(mDocHandle, PromiseFlatCString(aPath).get(),
    925                                MOZ_SOURCE_STAMP_VALUE, aFlags);
    926 
    927  mCaptureSequence = true;
    928 }
    929 
    930 void WebRenderAPI::StopCaptureSequence() {
    931  if (mCaptureSequence) {
    932    wr_api_stop_capture_sequence(mDocHandle);
    933  }
    934 
    935  mCaptureSequence = false;
    936 }
    937 
    938 void WebRenderAPI::BeginRecording(const TimeStamp& aRecordingStart,
    939                                  wr::PipelineId aRootPipelineId) {
    940  class BeginRecordingEvent final : public RendererEvent {
    941   public:
    942    explicit BeginRecordingEvent(const TimeStamp& aRecordingStart,
    943                                 wr::PipelineId aRootPipelineId)
    944        : mRecordingStart(aRecordingStart), mRootPipelineId(aRootPipelineId) {
    945      MOZ_COUNT_CTOR(BeginRecordingEvent);
    946    }
    947 
    948    ~BeginRecordingEvent() { MOZ_COUNT_DTOR(BeginRecordingEvent); }
    949 
    950    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    951      aRenderThread.BeginRecordingForWindow(aWindowId, mRecordingStart,
    952                                            mRootPipelineId);
    953    }
    954 
    955    const char* Name() override { return "BeginRecordingEvent"; }
    956 
    957   private:
    958    TimeStamp mRecordingStart;
    959    wr::PipelineId mRootPipelineId;
    960  };
    961 
    962  auto event =
    963      MakeUnique<BeginRecordingEvent>(aRecordingStart, aRootPipelineId);
    964  RunOnRenderThread(std::move(event));
    965 }
    966 
    967 RefPtr<WebRenderAPI::EndRecordingPromise> WebRenderAPI::EndRecording() {
    968  class EndRecordingEvent final : public RendererEvent {
    969   public:
    970    explicit EndRecordingEvent() { MOZ_COUNT_CTOR(EndRecordingEvent); }
    971 
    972    MOZ_COUNTED_DTOR(EndRecordingEvent);
    973 
    974    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
    975      Maybe<layers::FrameRecording> recording =
    976          aRenderThread.EndRecordingForWindow(aWindowId);
    977 
    978      if (recording) {
    979        mPromise.Resolve(recording.extract(), __func__);
    980      } else {
    981        mPromise.Reject(NS_ERROR_UNEXPECTED, __func__);
    982      }
    983    }
    984 
    985    RefPtr<WebRenderAPI::EndRecordingPromise> GetPromise() {
    986      return mPromise.Ensure(__func__);
    987    }
    988 
    989    const char* Name() override { return "EndRecordingEvent"; }
    990 
    991   private:
    992    MozPromiseHolder<WebRenderAPI::EndRecordingPromise> mPromise;
    993  };
    994 
    995  auto event = MakeUnique<EndRecordingEvent>();
    996  auto promise = event->GetPromise();
    997 
    998  RunOnRenderThread(std::move(event));
    999  return promise;
   1000 }
   1001 
   1002 void TransactionBuilder::Clear() { wr_resource_updates_clear(mTxn); }
   1003 
   1004 Transaction* TransactionBuilder::Take() {
   1005  if (!mOwnsData) {
   1006    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   1007    return nullptr;
   1008  }
   1009  Transaction* txn = mTxn;
   1010  mTxn = wr_transaction_new(mUseSceneBuilderThread);
   1011  return txn;
   1012 }
   1013 
   1014 void TransactionBuilder::Notify(wr::Checkpoint aWhen,
   1015                                UniquePtr<NotificationHandler> aEvent) {
   1016  wr_transaction_notify(mTxn, aWhen,
   1017                        reinterpret_cast<uintptr_t>(aEvent.release()));
   1018 }
   1019 
   1020 void TransactionBuilder::AddImage(ImageKey key,
   1021                                  const ImageDescriptor& aDescriptor,
   1022                                  wr::Vec<uint8_t>& aBytes) {
   1023  wr_resource_updates_add_image(mTxn, key, &aDescriptor, &aBytes.inner);
   1024 }
   1025 
   1026 void TransactionBuilder::AddBlobImage(BlobImageKey key,
   1027                                      const ImageDescriptor& aDescriptor,
   1028                                      uint16_t aTileSize,
   1029                                      wr::Vec<uint8_t>& aBytes,
   1030                                      const wr::DeviceIntRect& aVisibleRect) {
   1031  wr_resource_updates_add_blob_image(mTxn, key, &aDescriptor, aTileSize,
   1032                                     &aBytes.inner, aVisibleRect);
   1033 }
   1034 
   1035 void TransactionBuilder::AddExternalImage(ImageKey key,
   1036                                          const ImageDescriptor& aDescriptor,
   1037                                          ExternalImageId aExtID,
   1038                                          wr::ExternalImageType aImageType,
   1039                                          uint8_t aChannelIndex,
   1040                                          bool aNormalizedUvs) {
   1041  wr_resource_updates_add_external_image(mTxn, key, &aDescriptor, aExtID,
   1042                                         &aImageType, aChannelIndex,
   1043                                         aNormalizedUvs);
   1044 }
   1045 
   1046 void TransactionBuilder::AddExternalImageBuffer(
   1047    ImageKey aKey, const ImageDescriptor& aDescriptor,
   1048    ExternalImageId aHandle) {
   1049  auto channelIndex = 0;
   1050  AddExternalImage(aKey, aDescriptor, aHandle, wr::ExternalImageType::Buffer(),
   1051                   channelIndex);
   1052 }
   1053 
   1054 void TransactionBuilder::UpdateImageBuffer(ImageKey aKey,
   1055                                           const ImageDescriptor& aDescriptor,
   1056                                           wr::Vec<uint8_t>& aBytes) {
   1057  wr_resource_updates_update_image(mTxn, aKey, &aDescriptor, &aBytes.inner);
   1058 }
   1059 
   1060 void TransactionBuilder::UpdateBlobImage(BlobImageKey aKey,
   1061                                         const ImageDescriptor& aDescriptor,
   1062                                         wr::Vec<uint8_t>& aBytes,
   1063                                         const wr::DeviceIntRect& aVisibleRect,
   1064                                         const wr::LayoutIntRect& aDirtyRect) {
   1065  wr_resource_updates_update_blob_image(mTxn, aKey, &aDescriptor, &aBytes.inner,
   1066                                        aVisibleRect, aDirtyRect);
   1067 }
   1068 
   1069 void TransactionBuilder::UpdateExternalImage(ImageKey aKey,
   1070                                             const ImageDescriptor& aDescriptor,
   1071                                             ExternalImageId aExtID,
   1072                                             wr::ExternalImageType aImageType,
   1073                                             uint8_t aChannelIndex,
   1074                                             bool aNormalizedUvs) {
   1075  wr_resource_updates_update_external_image(mTxn, aKey, &aDescriptor, aExtID,
   1076                                            &aImageType, aChannelIndex,
   1077                                            aNormalizedUvs);
   1078 }
   1079 
   1080 void TransactionBuilder::UpdateExternalImageWithDirtyRect(
   1081    ImageKey aKey, const ImageDescriptor& aDescriptor, ExternalImageId aExtID,
   1082    wr::ExternalImageType aImageType, const wr::DeviceIntRect& aDirtyRect,
   1083    uint8_t aChannelIndex, bool aNormalizedUvs) {
   1084  wr_resource_updates_update_external_image_with_dirty_rect(
   1085      mTxn, aKey, &aDescriptor, aExtID, &aImageType, aChannelIndex,
   1086      aNormalizedUvs, aDirtyRect);
   1087 }
   1088 
   1089 void TransactionBuilder::SetBlobImageVisibleArea(
   1090    BlobImageKey aKey, const wr::DeviceIntRect& aArea) {
   1091  wr_resource_updates_set_blob_image_visible_area(mTxn, aKey, &aArea);
   1092 }
   1093 
   1094 void TransactionBuilder::DeleteImage(ImageKey aKey) {
   1095  wr_resource_updates_delete_image(mTxn, aKey);
   1096 }
   1097 
   1098 void TransactionBuilder::DeleteBlobImage(BlobImageKey aKey) {
   1099  wr_resource_updates_delete_blob_image(mTxn, aKey);
   1100 }
   1101 
   1102 void TransactionBuilder::AddSnapshotImage(wr::SnapshotImageKey aKey) {
   1103  wr_resource_updates_add_snapshot_image(mTxn, aKey);
   1104 }
   1105 
   1106 void TransactionBuilder::DeleteSnapshotImage(wr::SnapshotImageKey aKey) {
   1107  wr_resource_updates_delete_snapshot_image(mTxn, aKey);
   1108 }
   1109 
   1110 void TransactionBuilder::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes,
   1111                                    uint32_t aIndex) {
   1112  wr_resource_updates_add_raw_font(mTxn, aKey, &aBytes.inner, aIndex);
   1113 }
   1114 
   1115 void TransactionBuilder::AddFontDescriptor(wr::FontKey aKey,
   1116                                           wr::Vec<uint8_t>& aBytes,
   1117                                           uint32_t aIndex) {
   1118  wr_resource_updates_add_font_descriptor(mTxn, aKey, &aBytes.inner, aIndex);
   1119 }
   1120 
   1121 void TransactionBuilder::DeleteFont(wr::FontKey aKey) {
   1122  wr_resource_updates_delete_font(mTxn, aKey);
   1123 }
   1124 
   1125 void TransactionBuilder::AddFontInstance(
   1126    wr::FontInstanceKey aKey, wr::FontKey aFontKey, float aGlyphSize,
   1127    const wr::FontInstanceOptions* aOptions,
   1128    const wr::FontInstancePlatformOptions* aPlatformOptions,
   1129    wr::Vec<uint8_t>& aVariations) {
   1130  wr_resource_updates_add_font_instance(mTxn, aKey, aFontKey, aGlyphSize,
   1131                                        aOptions, aPlatformOptions,
   1132                                        &aVariations.inner);
   1133 }
   1134 
   1135 void TransactionBuilder::DeleteFontInstance(wr::FontInstanceKey aKey) {
   1136  wr_resource_updates_delete_font_instance(mTxn, aKey);
   1137 }
   1138 
   1139 void TransactionBuilder::UpdateQualitySettings(
   1140    bool aForceSubpixelAAWherePossible) {
   1141  wr_transaction_set_quality_settings(mTxn, aForceSubpixelAAWherePossible);
   1142 }
   1143 
   1144 class FrameStartTime : public RendererEvent {
   1145 public:
   1146  explicit FrameStartTime(const TimeStamp& aTime) : mTime(aTime) {
   1147    MOZ_COUNT_CTOR(FrameStartTime);
   1148  }
   1149 
   1150  MOZ_COUNTED_DTOR_OVERRIDE(FrameStartTime)
   1151 
   1152  void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
   1153    auto renderer = aRenderThread.GetRenderer(aWindowId);
   1154    if (renderer) {
   1155      renderer->SetFrameStartTime(mTime);
   1156    }
   1157  }
   1158 
   1159  const char* Name() override { return "FrameStartTime"; }
   1160 
   1161 private:
   1162  TimeStamp mTime;
   1163 };
   1164 
   1165 void WebRenderAPI::SetFrameStartTime(const TimeStamp& aTime) {
   1166  auto event = MakeUnique<FrameStartTime>(aTime);
   1167  RunOnRenderThread(std::move(event));
   1168 }
   1169 
   1170 void WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent) {
   1171  auto event = reinterpret_cast<uintptr_t>(aEvent.release());
   1172  wr_api_send_external_event(mDocHandle, event);
   1173 }
   1174 
   1175 DisplayListBuilder::DisplayListBuilder(PipelineId aId,
   1176                                       WebRenderBackend aBackend)
   1177    : mCurrentSpaceAndClipChain(wr::RootScrollNodeWithChain()),
   1178      mActiveFixedPosTracker(nullptr),
   1179      mPipelineId(aId),
   1180      mBackend(aBackend),
   1181      mDisplayItemCache(nullptr) {
   1182  MOZ_COUNT_CTOR(DisplayListBuilder);
   1183  mWrState = wr_state_new(aId);
   1184 
   1185  if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) {
   1186    mDisplayItemCache->SetPipelineId(aId);
   1187  }
   1188 }
   1189 
   1190 DisplayListBuilder::~DisplayListBuilder() {
   1191  MOZ_COUNT_DTOR(DisplayListBuilder);
   1192  wr_state_delete(mWrState);
   1193 }
   1194 
   1195 void DisplayListBuilder::Save() { wr_dp_save(mWrState); }
   1196 void DisplayListBuilder::Restore() { wr_dp_restore(mWrState); }
   1197 void DisplayListBuilder::ClearSave() { wr_dp_clear_save(mWrState); }
   1198 
   1199 usize DisplayListBuilder::Dump(usize aIndent, const Maybe<usize>& aStart,
   1200                               const Maybe<usize>& aEnd) {
   1201  return wr_dump_display_list(mWrState, aIndent, aStart.ptrOr(nullptr),
   1202                              aEnd.ptrOr(nullptr));
   1203 }
   1204 
   1205 void DisplayListBuilder::DumpSerializedDisplayList() {
   1206  wr_dump_serialized_display_list(mWrState);
   1207 }
   1208 
   1209 void DisplayListBuilder::Begin(layers::DisplayItemCache* aCache) {
   1210  wr_api_begin_builder(mWrState);
   1211 
   1212  mScrollIds.clear();
   1213  mASRToSpatialIdMap.clear();
   1214  mCurrentSpaceAndClipChain = wr::RootScrollNodeWithChain();
   1215  mClipChainLeaf = Nothing();
   1216  mSuspendedSpaceAndClipChain = Nothing();
   1217  mSuspendedClipChainLeaf = Nothing();
   1218  mCachedTextDT = nullptr;
   1219  mCachedContext = nullptr;
   1220  mActiveFixedPosTracker = nullptr;
   1221  mDisplayItemCache = aCache;
   1222  mCurrentCacheSlot = Nothing();
   1223 }
   1224 
   1225 void DisplayListBuilder::End(BuiltDisplayList& aOutDisplayList) {
   1226  wr_api_end_builder(
   1227      mWrState, &aOutDisplayList.dl_desc, &aOutDisplayList.dl_items.inner,
   1228      &aOutDisplayList.dl_cache.inner, &aOutDisplayList.dl_spatial_tree.inner);
   1229 
   1230  mDisplayItemCache = nullptr;
   1231 }
   1232 
   1233 void DisplayListBuilder::End(layers::DisplayListData& aOutTransaction) {
   1234  if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) {
   1235    wr_dp_set_cache_size(mWrState, mDisplayItemCache->CurrentSize());
   1236  }
   1237 
   1238  wr::VecU8 dlItems, dlCache, dlSpatialTree;
   1239  wr_api_end_builder(mWrState, &aOutTransaction.mDLDesc, &dlItems.inner,
   1240                     &dlCache.inner, &dlSpatialTree.inner);
   1241  aOutTransaction.mDLItems.emplace(dlItems.inner.data, dlItems.inner.length,
   1242                                   dlItems.inner.capacity);
   1243  aOutTransaction.mDLCache.emplace(dlCache.inner.data, dlCache.inner.length,
   1244                                   dlCache.inner.capacity);
   1245  aOutTransaction.mDLSpatialTree.emplace(dlSpatialTree.inner.data,
   1246                                         dlSpatialTree.inner.length,
   1247                                         dlSpatialTree.inner.capacity);
   1248  dlItems.inner.capacity = 0;
   1249  dlItems.inner.data = nullptr;
   1250  dlCache.inner.capacity = 0;
   1251  dlCache.inner.data = nullptr;
   1252  dlSpatialTree.inner.capacity = 0;
   1253  dlSpatialTree.inner.data = nullptr;
   1254 }
   1255 
   1256 Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext(
   1257    const wr::StackingContextParams& aParams, const wr::LayoutRect& aBounds,
   1258    const wr::RasterSpace& aRasterSpace) {
   1259  MOZ_ASSERT(mClipChainLeaf.isNothing(),
   1260             "Non-empty leaf from clip chain given, but not used with SC!");
   1261 
   1262  WRDL_LOG(
   1263      "PushStackingContext b=%s t=%s id=0x%" PRIx64 "\n", mWrState,
   1264      ToString(aBounds).c_str(),
   1265      aParams.mTransformPtr ? ToString(*aParams.mTransformPtr).c_str() : "none",
   1266      aParams.animation ? aParams.animation->id : 0);
   1267 
   1268  auto spatialId = wr_dp_push_stacking_context(
   1269      mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aParams,
   1270      aParams.mTransformPtr, aParams.mFilters.Elements(),
   1271      aParams.mFilters.Length(), aParams.mFilterDatas.Elements(),
   1272      aParams.mFilterDatas.Length(), aRasterSpace);
   1273 
   1274  return spatialId.id != 0 ? Some(spatialId) : Nothing();
   1275 }
   1276 
   1277 void DisplayListBuilder::PopStackingContext(bool aIsReferenceFrame) {
   1278  WRDL_LOG("PopStackingContext\n", mWrState);
   1279  wr_dp_pop_stacking_context(mWrState, aIsReferenceFrame);
   1280 }
   1281 
   1282 wr::WrClipChainId DisplayListBuilder::DefineClipChain(
   1283    Span<const wr::WrClipId> aClips, const Maybe<wr::WrClipChainId>& aParent) {
   1284  CancelGroup();
   1285 
   1286  const uint64_t* parent = aParent ? &aParent->id : nullptr;
   1287  uint64_t clipchainId = wr_dp_define_clipchain(
   1288      mWrState, parent, aClips.Elements(), aClips.Length());
   1289  if (MOZ_LOG_TEST(sWrDLLog, LogLevel::Debug)) {
   1290    nsCString message;
   1291    message.AppendPrintf("DefineClipChain id=%" PRIu64
   1292                         " clipCount=%zu clipIds=[",
   1293                         clipchainId, aClips.Length());
   1294    for (const auto& clip : aClips) {
   1295      message.AppendPrintf("%" PRIuPTR ",", clip.id);
   1296    }
   1297    message.Append("]");
   1298    WRDL_LOG("%s", mWrState, message.get());
   1299  }
   1300  return wr::WrClipChainId{clipchainId};
   1301 }
   1302 
   1303 wr::WrClipId DisplayListBuilder::DefineImageMaskClip(
   1304    const wr::ImageMask& aMask, const nsTArray<wr::LayoutPoint>& aPoints,
   1305    wr::FillRule aFillRule) {
   1306  CancelGroup();
   1307 
   1308  WrClipId clipId = wr_dp_define_image_mask_clip_with_parent_clip_chain(
   1309      mWrState, mCurrentSpaceAndClipChain.space, aMask, aPoints.Elements(),
   1310      aPoints.Length(), aFillRule);
   1311 
   1312  return clipId;
   1313 }
   1314 
   1315 wr::WrClipId DisplayListBuilder::DefineRoundedRectClip(
   1316    Maybe<wr::WrSpatialId> aSpace, const wr::ComplexClipRegion& aComplex) {
   1317  CancelGroup();
   1318 
   1319  WrClipId clipId;
   1320  if (aSpace) {
   1321    clipId = wr_dp_define_rounded_rect_clip(mWrState, *aSpace, aComplex);
   1322  } else {
   1323    clipId = wr_dp_define_rounded_rect_clip(
   1324        mWrState, mCurrentSpaceAndClipChain.space, aComplex);
   1325  }
   1326 
   1327  return clipId;
   1328 }
   1329 
   1330 wr::WrClipId DisplayListBuilder::DefineRectClip(Maybe<wr::WrSpatialId> aSpace,
   1331                                                wr::LayoutRect aClipRect) {
   1332  CancelGroup();
   1333 
   1334  WrClipId clipId;
   1335  if (aSpace) {
   1336    clipId = wr_dp_define_rect_clip(mWrState, *aSpace, aClipRect);
   1337  } else {
   1338    clipId = wr_dp_define_rect_clip(mWrState, mCurrentSpaceAndClipChain.space,
   1339                                    aClipRect);
   1340  }
   1341 
   1342  return clipId;
   1343 }
   1344 
   1345 wr::WrSpatialId DisplayListBuilder::DefineStickyFrame(
   1346    const ActiveScrolledRoot* aStickyAsr,
   1347    Maybe<wr::WrSpatialId> aParentSpatialId, const wr::LayoutRect& aContentRect,
   1348    const float* aTopMargin, const float* aRightMargin,
   1349    const float* aBottomMargin, const float* aLeftMargin,
   1350    const StickyOffsetBounds& aVerticalBounds,
   1351    const StickyOffsetBounds& aHorizontalBounds,
   1352    const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey,
   1353    const WrAnimationProperty* aAnimation) {
   1354  auto spatialId = wr_dp_define_sticky_frame(
   1355      mWrState, aParentSpatialId.valueOr(mCurrentSpaceAndClipChain.space),
   1356      aContentRect, aTopMargin, aRightMargin, aBottomMargin, aLeftMargin,
   1357      aVerticalBounds, aHorizontalBounds, aAppliedOffset, aKey, aAnimation);
   1358 
   1359  mASRToSpatialIdMap.emplace(aStickyAsr, spatialId);
   1360 
   1361  WRDL_LOG("DefineSticky id=%zu c=%s t=%s r=%s b=%s l=%s v=%s h=%s a=%s\n",
   1362           mWrState, spatialId.id, ToString(aContentRect).c_str(),
   1363           aTopMargin ? ToString(*aTopMargin).c_str() : "none",
   1364           aRightMargin ? ToString(*aRightMargin).c_str() : "none",
   1365           aBottomMargin ? ToString(*aBottomMargin).c_str() : "none",
   1366           aLeftMargin ? ToString(*aLeftMargin).c_str() : "none",
   1367           ToString(aVerticalBounds).c_str(),
   1368           ToString(aHorizontalBounds).c_str(),
   1369           ToString(aAppliedOffset).c_str());
   1370 
   1371  return spatialId;
   1372 }
   1373 
   1374 Maybe<wr::WrSpatialId> DisplayListBuilder::GetScrollIdForDefinedScrollLayer(
   1375    layers::ScrollableLayerGuid::ViewID aViewId) const {
   1376  if (aViewId == layers::ScrollableLayerGuid::NULL_SCROLL_ID) {
   1377    return Some(wr::RootScrollNode());
   1378  }
   1379 
   1380  auto it = mScrollIds.find(aViewId);
   1381  if (it == mScrollIds.end()) {
   1382    return Nothing();
   1383  }
   1384 
   1385  return Some(it->second);
   1386 }
   1387 
   1388 Maybe<wr::WrSpatialId> DisplayListBuilder::GetSpatialIdForDefinedStickyLayer(
   1389    const ActiveScrolledRoot* aASR) const {
   1390  MOZ_ASSERT(aASR->mKind == ActiveScrolledRoot::ASRKind::Sticky);
   1391  auto it = mASRToSpatialIdMap.find(aASR);
   1392  if (it == mASRToSpatialIdMap.end()) {
   1393    return Nothing();
   1394  }
   1395 
   1396  return Some(it->second);
   1397 }
   1398 
   1399 wr::WrSpatialId DisplayListBuilder::DefineScrollLayer(
   1400    const layers::ScrollableLayerGuid::ViewID& aViewId,
   1401    const Maybe<wr::WrSpatialId>& aParent, const wr::LayoutRect& aContentRect,
   1402    const wr::LayoutRect& aClipRect, const wr::LayoutVector2D& aScrollOffset,
   1403    wr::APZScrollGeneration aScrollOffsetGeneration,
   1404    wr::HasScrollLinkedEffect aHasScrollLinkedEffect,
   1405    wr::SpatialTreeItemKey aKey) {
   1406  auto it = mScrollIds.find(aViewId);
   1407  if (it != mScrollIds.end()) {
   1408    return it->second;
   1409  }
   1410 
   1411  // We haven't defined aViewId before, so let's define it now.
   1412  wr::WrSpatialId defaultParent = mCurrentSpaceAndClipChain.space;
   1413 
   1414  auto space = wr_dp_define_scroll_layer(
   1415      mWrState, aViewId, aParent ? aParent.ptr() : &defaultParent, aContentRect,
   1416      aClipRect, aScrollOffset, aScrollOffsetGeneration, aHasScrollLinkedEffect,
   1417      aKey);
   1418 
   1419  WRDL_LOG("DefineScrollLayer id=%" PRIu64
   1420           "/%zu p=%s co=%s cl=%s generation=%s hasScrollLinkedEffect=%s\n",
   1421           mWrState, aViewId, space.id,
   1422           aParent ? ToString(aParent->id).c_str() : "(nil)",
   1423           ToString(aContentRect).c_str(), ToString(aClipRect).c_str(),
   1424           ToString(aScrollOffsetGeneration).c_str(),
   1425           ToString(aHasScrollLinkedEffect).c_str());
   1426 
   1427  mScrollIds[aViewId] = space;
   1428  return space;
   1429 }
   1430 
   1431 void DisplayListBuilder::PushRect(const wr::LayoutRect& aBounds,
   1432                                  const wr::LayoutRect& aClip,
   1433                                  bool aIsBackfaceVisible,
   1434                                  bool aForceAntiAliasing, bool aIsCheckerboard,
   1435                                  const wr::ColorF& aColor) {
   1436  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1437  WRDL_LOG("PushRect b=%s cl=%s c=%s\n", mWrState, ToString(aBounds).c_str(),
   1438           ToString(clip).c_str(), ToString(aColor).c_str());
   1439  wr_dp_push_rect(mWrState, aBounds, clip, aIsBackfaceVisible,
   1440                  aForceAntiAliasing, aIsCheckerboard,
   1441                  &mCurrentSpaceAndClipChain, aColor);
   1442 }
   1443 
   1444 void DisplayListBuilder::PushRoundedRect(const wr::LayoutRect& aBounds,
   1445                                         const wr::LayoutRect& aClip,
   1446                                         bool aIsBackfaceVisible,
   1447                                         const wr::ColorF& aColor) {
   1448  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1449  WRDL_LOG("PushRoundedRect b=%s cl=%s c=%s\n", mWrState,
   1450           ToString(aBounds).c_str(), ToString(clip).c_str(),
   1451           ToString(aColor).c_str());
   1452 
   1453  // Draw the rounded rectangle as a border with rounded corners. We could also
   1454  // draw this as a rectangle clipped to a rounded rectangle, but:
   1455  // - clips are not cached; borders are
   1456  // - a simple border like this will be drawn as an image
   1457  // - Processing lots of clips is not WebRender's strong point.
   1458  //
   1459  // Made the borders thicker than one half the width/height, to avoid
   1460  // little white dots at the center at some magnifications.
   1461  wr::BorderSide side = {aColor, wr::BorderStyle::Solid};
   1462  float h = aBounds.width() * 0.6f;
   1463  float v = aBounds.height() * 0.6f;
   1464  wr::LayoutSideOffsets widths = {v, h, v, h};
   1465  wr::BorderRadius radii = {{h, v}, {h, v}, {h, v}, {h, v}};
   1466 
   1467  // Anti-aliased borders are required for rounded borders.
   1468  wr_dp_push_border(mWrState, aBounds, clip, aIsBackfaceVisible,
   1469                    &mCurrentSpaceAndClipChain, wr::AntialiasBorder::Yes,
   1470                    widths, side, side, side, side, radii);
   1471 }
   1472 
   1473 void DisplayListBuilder::PushHitTest(
   1474    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1475    bool aIsBackfaceVisible,
   1476    const layers::ScrollableLayerGuid::ViewID& aScrollId,
   1477    const gfx::CompositorHitTestInfo& aHitInfo, SideBits aSideBits) {
   1478  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1479  WRDL_LOG("PushHitTest b=%s cl=%s\n", mWrState, ToString(aBounds).c_str(),
   1480           ToString(clip).c_str());
   1481 
   1482  static_assert(gfx::DoesCompositorHitTestInfoFitIntoBits<12>(),
   1483                "CompositorHitTestFlags MAX value has to be less than number "
   1484                "of bits in uint16_t minus 4 for SideBitsPacked");
   1485 
   1486  uint16_t hitInfoBits = static_cast<uint16_t>(aHitInfo.serialize()) |
   1487                         (static_cast<uint16_t>(aSideBits) << 12);
   1488 
   1489  wr_dp_push_hit_test(mWrState, aBounds, clip, aIsBackfaceVisible,
   1490                      &mCurrentSpaceAndClipChain, aScrollId, hitInfoBits);
   1491 }
   1492 
   1493 void DisplayListBuilder::PushRectWithAnimation(
   1494    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1495    bool aIsBackfaceVisible, const wr::ColorF& aColor,
   1496    const WrAnimationProperty* aAnimation) {
   1497  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1498  WRDL_LOG("PushRectWithAnimation b=%s cl=%s c=%s\n", mWrState,
   1499           ToString(aBounds).c_str(), ToString(clip).c_str(),
   1500           ToString(aColor).c_str());
   1501 
   1502  wr_dp_push_rect_with_animation(mWrState, aBounds, clip, aIsBackfaceVisible,
   1503                                 &mCurrentSpaceAndClipChain, aColor,
   1504                                 aAnimation);
   1505 }
   1506 
   1507 void DisplayListBuilder::PushBackdropFilter(
   1508    const wr::LayoutRect& aBounds, const wr::ComplexClipRegion& aRegion,
   1509    const nsTArray<wr::FilterOp>& aFilters,
   1510    const nsTArray<wr::WrFilterData>& aFilterDatas, bool aIsBackfaceVisible) {
   1511  wr::LayoutRect clip = MergeClipLeaf(aBounds);
   1512  WRDL_LOG("PushBackdropFilter b=%s c=%s\n", mWrState,
   1513           ToString(aBounds).c_str(), ToString(clip).c_str());
   1514 
   1515  auto clipId = DefineRoundedRectClip(Nothing(), aRegion);
   1516  auto clipChainId =
   1517      DefineClipChain({&clipId, 1}, CurrentClipChainIdIfNotRoot());
   1518  auto spaceAndClip =
   1519      WrSpaceAndClipChain{mCurrentSpaceAndClipChain.space, clipChainId.id};
   1520 
   1521  wr_dp_push_backdrop_filter(mWrState, aBounds, clip, aIsBackfaceVisible,
   1522                             &spaceAndClip, aFilters.Elements(),
   1523                             aFilters.Length(), aFilterDatas.Elements(),
   1524                             aFilterDatas.Length());
   1525 }
   1526 
   1527 void DisplayListBuilder::PushLinearGradient(
   1528    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1529    bool aIsBackfaceVisible, const wr::LayoutPoint& aStartPoint,
   1530    const wr::LayoutPoint& aEndPoint, const nsTArray<wr::GradientStop>& aStops,
   1531    wr::ExtendMode aExtendMode, const wr::LayoutSize aTileSize,
   1532    const wr::LayoutSize aTileSpacing) {
   1533  wr_dp_push_linear_gradient(
   1534      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1535      &mCurrentSpaceAndClipChain, aStartPoint, aEndPoint, aStops.Elements(),
   1536      aStops.Length(), aExtendMode, aTileSize, aTileSpacing);
   1537 }
   1538 
   1539 void DisplayListBuilder::PushRadialGradient(
   1540    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1541    bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter,
   1542    const wr::LayoutSize& aRadius, const nsTArray<wr::GradientStop>& aStops,
   1543    wr::ExtendMode aExtendMode, const wr::LayoutSize aTileSize,
   1544    const wr::LayoutSize aTileSpacing) {
   1545  wr_dp_push_radial_gradient(
   1546      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1547      &mCurrentSpaceAndClipChain, aCenter, aRadius, aStops.Elements(),
   1548      aStops.Length(), aExtendMode, aTileSize, aTileSpacing);
   1549 }
   1550 
   1551 void DisplayListBuilder::PushConicGradient(
   1552    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1553    bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter, const float aAngle,
   1554    const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
   1555    const wr::LayoutSize aTileSize, const wr::LayoutSize aTileSpacing) {
   1556  wr_dp_push_conic_gradient(mWrState, aBounds, MergeClipLeaf(aClip),
   1557                            aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
   1558                            aCenter, aAngle, aStops.Elements(), aStops.Length(),
   1559                            aExtendMode, aTileSize, aTileSpacing);
   1560 }
   1561 
   1562 void DisplayListBuilder::PushImage(
   1563    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1564    bool aIsBackfaceVisible, bool aForceAntiAliasing,
   1565    wr::ImageRendering aFilter, wr::ImageKey aImage, bool aPremultipliedAlpha,
   1566    const wr::ColorF& aColor, bool aPreferCompositorSurface,
   1567    bool aSupportsExternalCompositing) {
   1568  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1569  WRDL_LOG("PushImage b=%s cl=%s\n", mWrState, ToString(aBounds).c_str(),
   1570           ToString(clip).c_str());
   1571  wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible,
   1572                   aForceAntiAliasing, &mCurrentSpaceAndClipChain, aFilter,
   1573                   aImage, aPremultipliedAlpha, aColor,
   1574                   aPreferCompositorSurface, aSupportsExternalCompositing);
   1575 }
   1576 
   1577 void DisplayListBuilder::PushRepeatingImage(
   1578    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1579    bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize,
   1580    const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter,
   1581    wr::ImageKey aImage, bool aPremultipliedAlpha, const wr::ColorF& aColor) {
   1582  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1583  WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState,
   1584           ToString(aBounds).c_str(), ToString(clip).c_str(),
   1585           ToString(aStretchSize).c_str(), ToString(aTileSpacing).c_str());
   1586  wr_dp_push_repeating_image(
   1587      mWrState, aBounds, clip, aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
   1588      aStretchSize, aTileSpacing, aFilter, aImage, aPremultipliedAlpha, aColor);
   1589 }
   1590 
   1591 void DisplayListBuilder::PushYCbCrPlanarImage(
   1592    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1593    bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
   1594    wr::ImageKey aImageChannel1, wr::ImageKey aImageChannel2,
   1595    wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace,
   1596    wr::WrColorRange aColorRange, wr::ImageRendering aRendering,
   1597    bool aPreferCompositorSurface, bool aSupportsExternalCompositing) {
   1598  wr_dp_push_yuv_planar_image(
   1599      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1600      &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1,
   1601      aImageChannel2, aColorDepth, aColorSpace, aColorRange, aRendering,
   1602      aPreferCompositorSurface, aSupportsExternalCompositing);
   1603 }
   1604 
   1605 void DisplayListBuilder::PushNV12Image(
   1606    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1607    bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
   1608    wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
   1609    wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange,
   1610    wr::ImageRendering aRendering, bool aPreferCompositorSurface,
   1611    bool aSupportsExternalCompositing) {
   1612  wr_dp_push_yuv_NV12_image(
   1613      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1614      &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth,
   1615      aColorSpace, aColorRange, aRendering, aPreferCompositorSurface,
   1616      aSupportsExternalCompositing);
   1617 }
   1618 
   1619 void DisplayListBuilder::PushP010Image(
   1620    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1621    bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
   1622    wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
   1623    wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange,
   1624    wr::ImageRendering aRendering, bool aPreferCompositorSurface,
   1625    bool aSupportsExternalCompositing) {
   1626  wr_dp_push_yuv_P010_image(
   1627      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1628      &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth,
   1629      aColorSpace, aColorRange, aRendering, aPreferCompositorSurface,
   1630      aSupportsExternalCompositing);
   1631 }
   1632 
   1633 void DisplayListBuilder::PushNV16Image(
   1634    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1635    bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
   1636    wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
   1637    wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange,
   1638    wr::ImageRendering aRendering, bool aPreferCompositorSurface,
   1639    bool aSupportsExternalCompositing) {
   1640  wr_dp_push_yuv_NV16_image(
   1641      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1642      &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth,
   1643      aColorSpace, aColorRange, aRendering, aPreferCompositorSurface,
   1644      aSupportsExternalCompositing);
   1645 }
   1646 
   1647 void DisplayListBuilder::PushYCbCrInterleavedImage(
   1648    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1649    bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
   1650    wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace,
   1651    wr::WrColorRange aColorRange, wr::ImageRendering aRendering,
   1652    bool aPreferCompositorSurface, bool aSupportsExternalCompositing) {
   1653  wr_dp_push_yuv_interleaved_image(
   1654      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1655      &mCurrentSpaceAndClipChain, aImageChannel0, aColorDepth, aColorSpace,
   1656      aColorRange, aRendering, aPreferCompositorSurface,
   1657      aSupportsExternalCompositing);
   1658 }
   1659 
   1660 void DisplayListBuilder::PushIFrame(const LayoutDeviceRect& aDevPxBounds,
   1661                                    bool aIsBackfaceVisible,
   1662                                    PipelineId aPipeline,
   1663                                    bool aIgnoreMissingPipeline) {
   1664  // If the incoming bounds size has decimals (As it could when zoom is
   1665  // involved), and is pushed straight through here, the compositor would end up
   1666  // calculating the destination rect to paint the rendered iframe into
   1667  // with those decimal values, rounding the result, instead of snapping. This
   1668  // can cause the rendered iframe rect and its destination rect to be
   1669  // mismatched, resulting in interpolation artifacts.
   1670  auto snapped = aDevPxBounds;
   1671  auto tl = snapped.TopLeft().Round();
   1672  auto br = snapped.BottomRight().Round();
   1673 
   1674  snapped.SizeTo(LayoutDeviceSize(br.x - tl.x, br.y - tl.y));
   1675 
   1676  const auto bounds = wr::ToLayoutRect(snapped);
   1677  wr_dp_push_iframe(mWrState, bounds, MergeClipLeaf(bounds), aIsBackfaceVisible,
   1678                    &mCurrentSpaceAndClipChain, aPipeline,
   1679                    aIgnoreMissingPipeline);
   1680 }
   1681 
   1682 void DisplayListBuilder::PushBorder(const wr::LayoutRect& aBounds,
   1683                                    const wr::LayoutRect& aClip,
   1684                                    bool aIsBackfaceVisible,
   1685                                    const wr::LayoutSideOffsets& aWidths,
   1686                                    const Range<const wr::BorderSide>& aSides,
   1687                                    const wr::BorderRadius& aRadius,
   1688                                    wr::AntialiasBorder aAntialias) {
   1689  MOZ_ASSERT(aSides.length() == 4);
   1690  if (aSides.length() != 4) {
   1691    return;
   1692  }
   1693  wr_dp_push_border(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1694                    &mCurrentSpaceAndClipChain, aAntialias, aWidths, aSides[0],
   1695                    aSides[1], aSides[2], aSides[3], aRadius);
   1696 }
   1697 
   1698 void DisplayListBuilder::PushBorderImage(const wr::LayoutRect& aBounds,
   1699                                         const wr::LayoutRect& aClip,
   1700                                         bool aIsBackfaceVisible,
   1701                                         const wr::WrBorderImage& aParams) {
   1702  wr_dp_push_border_image(mWrState, aBounds, MergeClipLeaf(aClip),
   1703                          aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
   1704                          &aParams);
   1705 }
   1706 
   1707 void DisplayListBuilder::PushBorderGradient(
   1708    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1709    bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths,
   1710    const int32_t aWidth, const int32_t aHeight, bool aFill,
   1711    const wr::DeviceIntSideOffsets& aSlice, const wr::LayoutPoint& aStartPoint,
   1712    const wr::LayoutPoint& aEndPoint, const nsTArray<wr::GradientStop>& aStops,
   1713    wr::ExtendMode aExtendMode) {
   1714  wr_dp_push_border_gradient(
   1715      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1716      &mCurrentSpaceAndClipChain, aWidths, aWidth, aHeight, aFill, aSlice,
   1717      aStartPoint, aEndPoint, aStops.Elements(), aStops.Length(), aExtendMode);
   1718 }
   1719 
   1720 void DisplayListBuilder::PushBorderRadialGradient(
   1721    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1722    bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
   1723    const wr::LayoutPoint& aCenter, const wr::LayoutSize& aRadius,
   1724    const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode) {
   1725  wr_dp_push_border_radial_gradient(
   1726      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1727      &mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aRadius,
   1728      aStops.Elements(), aStops.Length(), aExtendMode);
   1729 }
   1730 
   1731 void DisplayListBuilder::PushBorderConicGradient(
   1732    const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
   1733    bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
   1734    const wr::LayoutPoint& aCenter, const float aAngle,
   1735    const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode) {
   1736  wr_dp_push_border_conic_gradient(
   1737      mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1738      &mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aAngle,
   1739      aStops.Elements(), aStops.Length(), aExtendMode);
   1740 }
   1741 
   1742 void DisplayListBuilder::PushText(const wr::LayoutRect& aBounds,
   1743                                  const wr::LayoutRect& aClip,
   1744                                  bool aIsBackfaceVisible,
   1745                                  const wr::ColorF& aColor,
   1746                                  wr::FontInstanceKey aFontKey,
   1747                                  Range<const wr::GlyphInstance> aGlyphBuffer,
   1748                                  const wr::GlyphOptions* aGlyphOptions) {
   1749  wr_dp_push_text(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
   1750                  &mCurrentSpaceAndClipChain, aColor, aFontKey,
   1751                  &aGlyphBuffer[0], aGlyphBuffer.length(), aGlyphOptions);
   1752 }
   1753 
   1754 void DisplayListBuilder::PushLine(const wr::LayoutRect& aClip,
   1755                                  bool aIsBackfaceVisible,
   1756                                  const wr::Line& aLine) {
   1757  wr::LayoutRect clip = MergeClipLeaf(aClip);
   1758  wr_dp_push_line(mWrState, &clip, aIsBackfaceVisible,
   1759                  &mCurrentSpaceAndClipChain, &aLine.bounds,
   1760                  aLine.wavyLineThickness, aLine.orientation, &aLine.color,
   1761                  aLine.style);
   1762 }
   1763 
   1764 void DisplayListBuilder::PushShadow(const wr::LayoutRect& aRect,
   1765                                    const wr::LayoutRect& aClip,
   1766                                    bool aIsBackfaceVisible,
   1767                                    const wr::Shadow& aShadow,
   1768                                    bool aShouldInflate) {
   1769  // Local clip_rects are translated inside of shadows, as they are assumed to
   1770  // be part of the element drawing itself, and not a parent frame clipping it.
   1771  // As such, it is not sound to apply the MergeClipLeaf optimization inside of
   1772  // shadows. So we disable the optimization when we encounter a shadow.
   1773  // Shadows don't span frames, so we don't have to worry about MergeClipLeaf
   1774  // being re-enabled mid-shadow. The optimization is restored in PopAllShadows.
   1775  SuspendClipLeafMerging();
   1776  wr_dp_push_shadow(mWrState, aRect, aClip, aIsBackfaceVisible,
   1777                    &mCurrentSpaceAndClipChain, aShadow, aShouldInflate);
   1778 }
   1779 
   1780 void DisplayListBuilder::PopAllShadows() {
   1781  wr_dp_pop_all_shadows(mWrState);
   1782  ResumeClipLeafMerging();
   1783 }
   1784 
   1785 void DisplayListBuilder::SuspendClipLeafMerging() {
   1786  if (mClipChainLeaf) {
   1787    // No one should reinitialize mClipChainLeaf while we're suspended
   1788    MOZ_ASSERT(!mSuspendedClipChainLeaf);
   1789 
   1790    mSuspendedClipChainLeaf = mClipChainLeaf;
   1791    mSuspendedSpaceAndClipChain = Some(mCurrentSpaceAndClipChain);
   1792 
   1793    auto clipId = DefineRectClip(Nothing(), *mClipChainLeaf);
   1794    auto clipChainId =
   1795        DefineClipChain({&clipId, 1}, CurrentClipChainIdIfNotRoot());
   1796 
   1797    mCurrentSpaceAndClipChain.clip_chain = clipChainId.id;
   1798    mClipChainLeaf = Nothing();
   1799  }
   1800 }
   1801 
   1802 void DisplayListBuilder::ResumeClipLeafMerging() {
   1803  if (mSuspendedClipChainLeaf) {
   1804    mCurrentSpaceAndClipChain = *mSuspendedSpaceAndClipChain;
   1805    mClipChainLeaf = mSuspendedClipChainLeaf;
   1806 
   1807    mSuspendedClipChainLeaf = Nothing();
   1808    mSuspendedSpaceAndClipChain = Nothing();
   1809  }
   1810 }
   1811 
   1812 void DisplayListBuilder::PushBoxShadow(
   1813    const wr::LayoutRect& aRect, const wr::LayoutRect& aClip,
   1814    bool aIsBackfaceVisible, const wr::LayoutRect& aBoxBounds,
   1815    const wr::LayoutVector2D& aOffset, const wr::ColorF& aColor,
   1816    const float& aBlurRadius, const float& aSpreadRadius,
   1817    const wr::BorderRadius& aBorderRadius,
   1818    const wr::BoxShadowClipMode& aClipMode) {
   1819  wr_dp_push_box_shadow(mWrState, aRect, MergeClipLeaf(aClip),
   1820                        aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
   1821                        aBoxBounds, aOffset, aColor, aBlurRadius, aSpreadRadius,
   1822                        aBorderRadius, aClipMode);
   1823 }
   1824 
   1825 void DisplayListBuilder::PushDebug(uint32_t aVal) {
   1826  wr_dp_push_debug(mWrState, aVal);
   1827 }
   1828 
   1829 void DisplayListBuilder::StartGroup(nsPaintedDisplayItem* aItem) {
   1830  if (!mDisplayItemCache || mDisplayItemCache->IsFull()) {
   1831    return;
   1832  }
   1833 
   1834  MOZ_ASSERT(!mCurrentCacheSlot);
   1835  mCurrentCacheSlot = mDisplayItemCache->AssignSlot(aItem);
   1836 
   1837  if (mCurrentCacheSlot) {
   1838    wr_dp_start_item_group(mWrState);
   1839  }
   1840 }
   1841 
   1842 void DisplayListBuilder::CancelGroup(const bool aDiscard) {
   1843  if (!mDisplayItemCache || !mCurrentCacheSlot) {
   1844    return;
   1845  }
   1846 
   1847  wr_dp_cancel_item_group(mWrState, aDiscard);
   1848  mCurrentCacheSlot = Nothing();
   1849 }
   1850 
   1851 void DisplayListBuilder::FinishGroup() {
   1852  if (!mDisplayItemCache || !mCurrentCacheSlot) {
   1853    return;
   1854  }
   1855 
   1856  MOZ_ASSERT(mCurrentCacheSlot);
   1857 
   1858  if (wr_dp_finish_item_group(mWrState, mCurrentCacheSlot.ref())) {
   1859    mDisplayItemCache->MarkSlotOccupied(mCurrentCacheSlot.ref(),
   1860                                        CurrentSpaceAndClipChain());
   1861    mDisplayItemCache->Stats().AddCached();
   1862  }
   1863 
   1864  mCurrentCacheSlot = Nothing();
   1865 }
   1866 
   1867 bool DisplayListBuilder::ReuseItem(nsPaintedDisplayItem* aItem) {
   1868  if (!mDisplayItemCache) {
   1869    return false;
   1870  }
   1871 
   1872  mDisplayItemCache->Stats().AddTotal();
   1873 
   1874  if (mDisplayItemCache->IsEmpty()) {
   1875    return false;
   1876  }
   1877 
   1878  Maybe<uint16_t> slot =
   1879      mDisplayItemCache->CanReuseItem(aItem, CurrentSpaceAndClipChain());
   1880 
   1881  if (slot) {
   1882    mDisplayItemCache->Stats().AddReused();
   1883    wr_dp_push_reuse_items(mWrState, slot.ref());
   1884    return true;
   1885  }
   1886 
   1887  return false;
   1888 }
   1889 
   1890 Maybe<layers::ScrollableLayerGuid::ViewID>
   1891 DisplayListBuilder::GetContainingFixedPosScrollTarget(
   1892    const ActiveScrolledRoot* aAsr) {
   1893  return mActiveFixedPosTracker
   1894             ? mActiveFixedPosTracker->GetScrollTargetForASR(aAsr)
   1895             : Nothing();
   1896 }
   1897 
   1898 Maybe<SideBits> DisplayListBuilder::GetContainingFixedPosSideBits(
   1899    const ActiveScrolledRoot* aAsr) {
   1900  return mActiveFixedPosTracker
   1901             ? mActiveFixedPosTracker->GetSideBitsForASR(aAsr)
   1902             : Nothing();
   1903 }
   1904 
   1905 DisplayListBuilder::FixedPosScrollTargetTracker::FixedPosScrollTargetTracker(
   1906    DisplayListBuilder& aBuilder, const ActiveScrolledRoot* aAsr,
   1907    layers::ScrollableLayerGuid::ViewID aScrollId, SideBits aSideBits)
   1908    : mParentTracker(aBuilder.mActiveFixedPosTracker),
   1909      mBuilder(aBuilder),
   1910      mAsr(aAsr),
   1911      mScrollId(aScrollId),
   1912      mSideBits(aSideBits) {
   1913  aBuilder.mActiveFixedPosTracker = this;
   1914 }
   1915 
   1916 DisplayListBuilder::FixedPosScrollTargetTracker::
   1917    ~FixedPosScrollTargetTracker() {
   1918  mBuilder.mActiveFixedPosTracker = mParentTracker;
   1919 }
   1920 
   1921 Maybe<layers::ScrollableLayerGuid::ViewID>
   1922 DisplayListBuilder::FixedPosScrollTargetTracker::GetScrollTargetForASR(
   1923    const ActiveScrolledRoot* aAsr) {
   1924  return aAsr == mAsr ? Some(mScrollId) : Nothing();
   1925 }
   1926 
   1927 Maybe<SideBits>
   1928 DisplayListBuilder::FixedPosScrollTargetTracker::GetSideBitsForASR(
   1929    const ActiveScrolledRoot* aAsr) {
   1930  return aAsr == mAsr ? Some(mSideBits) : Nothing();
   1931 }
   1932 
   1933 gfxContext* DisplayListBuilder::GetTextContext(
   1934    wr::IpcResourceUpdateQueue& aResources,
   1935    const layers::StackingContextHelper& aSc,
   1936    layers::RenderRootStateManager* aManager, nsDisplayItem* aItem,
   1937    nsRect& aBounds, const gfx::Point& aDeviceOffset) {
   1938  if (!mCachedTextDT) {
   1939    mCachedTextDT = new layout::TextDrawTarget(*this, aResources, aSc, aManager,
   1940                                               aItem, aBounds);
   1941    if (mCachedTextDT->IsValid()) {
   1942      mCachedContext = MakeUnique<gfxContext>(mCachedTextDT, aDeviceOffset);
   1943    }
   1944  } else {
   1945    mCachedTextDT->Reinitialize(aResources, aSc, aManager, aItem, aBounds);
   1946    mCachedContext->SetDeviceOffset(aDeviceOffset);
   1947    mCachedContext->SetMatrix(gfx::Matrix());
   1948  }
   1949 
   1950  return mCachedContext.get();
   1951 }
   1952 
   1953 void DisplayListBuilder::PushInheritedClipChain(
   1954    nsDisplayListBuilder* aBuilder, const DisplayItemClipChain* aClipChain) {
   1955  if (!aClipChain || mInheritedClipChain == aClipChain) {
   1956    return;
   1957  }
   1958  if (!mInheritedClipChain) {
   1959    mInheritedClipChain = aClipChain;
   1960    return;
   1961  }
   1962 
   1963  mInheritedClipChain =
   1964      aBuilder->CreateClipChainIntersection(mInheritedClipChain, aClipChain);
   1965 }
   1966 
   1967 }  // namespace wr
   1968 }  // namespace mozilla
   1969 
   1970 extern "C" {
   1971 
   1972 void wr_transaction_notification_notified(uintptr_t aHandler,
   1973                                          mozilla::wr::Checkpoint aWhen) {
   1974  auto handler = reinterpret_cast<mozilla::wr::NotificationHandler*>(aHandler);
   1975  handler->Notify(aWhen);
   1976  // TODO: it would be better to get a callback when the object is destroyed on
   1977  // the rust side and delete then.
   1978  delete handler;
   1979 }
   1980 
   1981 void wr_register_thread_local_arena() {
   1982 #ifdef MOZ_MEMORY
   1983  jemalloc_thread_local_arena(true);
   1984 #endif
   1985 }
   1986 
   1987 }  // extern C