diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /gfx/webrender_bindings/WebRenderAPI.cpp | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/webrender_bindings/WebRenderAPI.cpp')
-rw-r--r-- | gfx/webrender_bindings/WebRenderAPI.cpp | 1867 |
1 files changed, 1867 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp new file mode 100644 index 0000000000..09a024a897 --- /dev/null +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -0,0 +1,1867 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WebRenderAPI.h" + +#include "mozilla/Logging.h" +#include "mozilla/ipc/ByteBuf.h" +#include "mozilla/webrender/RendererOGL.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/layers/CompositorThread.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "mozilla/ToString.h" +#include "mozilla/webrender/RenderCompositor.h" +#include "mozilla/widget/CompositorWidget.h" +#include "mozilla/layers/SynchronousTask.h" +#include "nsThreadUtils.h" +#include "TextDrawTarget.h" +#include "malloc_decls.h" +#include "GLContext.h" + +static mozilla::LazyLogModule sWrDLLog("wr.dl"); +#define WRDL_LOG(...) \ + MOZ_LOG(sWrDLLog, LogLevel::Debug, ("WRDL(%p): " __VA_ARGS__)) + +namespace mozilla { +using namespace layers; + +namespace wr { + +MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderMallocSizeOf) +MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(WebRenderMallocEnclosingSizeOf) + +class NewRenderer : public RendererEvent { + public: + NewRenderer(wr::DocumentHandle** aDocHandle, + layers::CompositorBridgeParent* aBridge, + WebRenderBackend* aBackend, WebRenderCompositor* aCompositor, + int32_t* aMaxTextureSize, bool* aUseANGLE, bool* aUseDComp, + bool* aUseTripleBuffering, bool* aSupportsExternalBufferTextures, + RefPtr<widget::CompositorWidget>&& aWidget, + layers::SynchronousTask* aTask, LayoutDeviceIntSize aSize, + layers::WindowKind aWindowKind, layers::SyncHandle* aHandle, + nsACString* aError) + : mDocHandle(aDocHandle), + mBackend(aBackend), + mCompositor(aCompositor), + mMaxTextureSize(aMaxTextureSize), + mUseANGLE(aUseANGLE), + mUseDComp(aUseDComp), + mUseTripleBuffering(aUseTripleBuffering), + mSupportsExternalBufferTextures(aSupportsExternalBufferTextures), + mBridge(aBridge), + mCompositorWidget(std::move(aWidget)), + mTask(aTask), + mSize(aSize), + mWindowKind(aWindowKind), + mSyncHandle(aHandle), + mError(aError) { + MOZ_COUNT_CTOR(NewRenderer); + } + + MOZ_COUNTED_DTOR(NewRenderer) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + layers::AutoCompleteTask complete(mTask); + + UniquePtr<RenderCompositor> compositor = + RenderCompositor::Create(std::move(mCompositorWidget), *mError); + if (!compositor) { + if (!mError->IsEmpty()) { + gfxCriticalNote << mError->BeginReading(); + } + return; + } + + compositor->MakeCurrent(); + + *mBackend = compositor->BackendType(); + *mCompositor = compositor->CompositorType(); + *mUseANGLE = compositor->UseANGLE(); + *mUseDComp = compositor->UseDComp(); + *mUseTripleBuffering = compositor->UseTripleBuffering(); + *mSupportsExternalBufferTextures = + compositor->SupportsExternalBufferTextures(); + + // Only allow the panic on GL error functionality in nightly builds, + // since it (deliberately) crashes the GPU process if any GL call + // returns an error code. + bool panic_on_gl_error = false; +#ifdef NIGHTLY_BUILD + panic_on_gl_error = + StaticPrefs::gfx_webrender_panic_on_gl_error_AtStartup(); +#endif + + bool isMainWindow = true; // TODO! + bool supportLowPriorityTransactions = isMainWindow; + bool supportLowPriorityThreadpool = + supportLowPriorityTransactions && + StaticPrefs::gfx_webrender_enable_low_priority_pool(); + wr::Renderer* wrRenderer = nullptr; + char* errorMessage = nullptr; + int picTileWidth = StaticPrefs::gfx_webrender_picture_tile_width(); + int picTileHeight = StaticPrefs::gfx_webrender_picture_tile_height(); + auto* swgl = compositor->swgl(); + auto* gl = (compositor->gl() && !swgl) ? compositor->gl() : nullptr; + auto* progCache = (aRenderThread.GetProgramCache() && !swgl) + ? aRenderThread.GetProgramCache()->Raw() + : nullptr; + auto* shaders = (aRenderThread.GetShaders() && !swgl) + ? aRenderThread.GetShaders()->RawShaders() + : nullptr; + + // Check That if we are not using SWGL, we have at least a GL or GLES 3.0 + // context. + if (gl && !swgl) { + bool versionCheck = + gl->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) || + gl->IsAtLeast(gl::ContextProfile::OpenGLCompatibility, 300) || + gl->IsAtLeast(gl::ContextProfile::OpenGLES, 300); + + if (!versionCheck) { + gfxCriticalNote << "GL context version (" << gl->Version() + << ") insufficent for hardware WebRender"; + + mError->AssignASCII("GL context version insufficient"); + return; + } + } + + if (!wr_window_new( + aWindowId, mSize.width, mSize.height, + mWindowKind == WindowKind::MAIN, supportLowPriorityTransactions, + supportLowPriorityThreadpool, gfx::gfxVars::UseGLSwizzle(), + gfx::gfxVars::UseWebRenderScissoredCacheClears(), swgl, gl, + compositor->SurfaceOriginIsTopLeft(), progCache, shaders, + aRenderThread.ThreadPool().Raw(), + aRenderThread.ThreadPoolLP().Raw(), &WebRenderMallocSizeOf, + &WebRenderMallocEnclosingSizeOf, 0, compositor.get(), + compositor->ShouldUseNativeCompositor(), + compositor->UsePartialPresent(), + compositor->GetMaxPartialPresentRects(), + compositor->ShouldDrawPreviousPartialPresentRegions(), mDocHandle, + &wrRenderer, mMaxTextureSize, &errorMessage, + StaticPrefs::gfx_webrender_enable_gpu_markers_AtStartup(), + panic_on_gl_error, picTileWidth, picTileHeight, + gfx::gfxVars::WebRenderRequiresHardwareDriver(), + StaticPrefs::gfx_webrender_low_quality_pinch_zoom_AtStartup(), + StaticPrefs::gfx_webrender_max_shared_surface_size_AtStartup(), + StaticPrefs::gfx_webrender_enable_subpixel_aa_AtStartup())) { + // wr_window_new puts a message into gfxCriticalNote if it returns false + MOZ_ASSERT(errorMessage); + mError->AssignASCII(errorMessage); + wr_api_free_error_msg(errorMessage); + return; + } + MOZ_ASSERT(wrRenderer); + + RefPtr<RenderThread> thread = &aRenderThread; + auto renderer = + MakeUnique<RendererOGL>(std::move(thread), std::move(compositor), + aWindowId, wrRenderer, mBridge); + if (wrRenderer && renderer) { + wr::WrExternalImageHandler handler = renderer->GetExternalImageHandler(); + wr_renderer_set_external_image_handler(wrRenderer, &handler); + } + + if (renderer) { + layers::SyncObjectHost* syncObj = renderer->GetSyncObject(); + if (syncObj) { + *mSyncHandle = syncObj->GetSyncHandle(); + } + } + + aRenderThread.AddRenderer(aWindowId, std::move(renderer)); + } + + private: + wr::DocumentHandle** mDocHandle; + WebRenderBackend* mBackend; + WebRenderCompositor* mCompositor; + int32_t* mMaxTextureSize; + bool* mUseANGLE; + bool* mUseDComp; + bool* mUseTripleBuffering; + bool* mSupportsExternalBufferTextures; + layers::CompositorBridgeParent* mBridge; + RefPtr<widget::CompositorWidget> mCompositorWidget; + layers::SynchronousTask* mTask; + LayoutDeviceIntSize mSize; + layers::WindowKind mWindowKind; + layers::SyncHandle* mSyncHandle; + nsACString* mError; +}; + +class RemoveRenderer : public RendererEvent { + public: + explicit RemoveRenderer(layers::SynchronousTask* aTask) : mTask(aTask) { + MOZ_COUNT_CTOR(RemoveRenderer); + } + + MOZ_COUNTED_DTOR_OVERRIDE(RemoveRenderer) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + aRenderThread.RemoveRenderer(aWindowId); + layers::AutoCompleteTask complete(mTask); + } + + private: + layers::SynchronousTask* mTask; +}; + +TransactionBuilder::TransactionBuilder(WebRenderAPI* aApi, + bool aUseSceneBuilderThread) + : mUseSceneBuilderThread(aUseSceneBuilderThread), + mApiBackend(aApi->GetBackendType()), + mOwnsData(true) { + mTxn = wr_transaction_new(mUseSceneBuilderThread); +} + +TransactionBuilder::TransactionBuilder(WebRenderAPI* aApi, Transaction* aTxn, + bool aUseSceneBuilderThread, + bool aOwnsData) + : mTxn(aTxn), + mUseSceneBuilderThread(aUseSceneBuilderThread), + mApiBackend(aApi->GetBackendType()), + mOwnsData(aOwnsData) {} + +TransactionBuilder::~TransactionBuilder() { + if (mOwnsData) { + wr_transaction_delete(mTxn); + } +} + +void TransactionBuilder::SetLowPriority(bool aIsLowPriority) { + wr_transaction_set_low_priority(mTxn, aIsLowPriority); +} + +void TransactionBuilder::UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch) { + wr_transaction_update_epoch(mTxn, aPipelineId, aEpoch); +} + +void TransactionBuilder::SetRootPipeline(PipelineId aPipelineId) { + wr_transaction_set_root_pipeline(mTxn, aPipelineId); +} + +void TransactionBuilder::RemovePipeline(PipelineId aPipelineId) { + wr_transaction_remove_pipeline(mTxn, aPipelineId); +} + +void TransactionBuilder::SetDisplayList( + Epoch aEpoch, wr::WrPipelineId pipeline_id, + wr::BuiltDisplayListDescriptor dl_descriptor, + wr::Vec<uint8_t>& dl_items_data, wr::Vec<uint8_t>& dl_cache_data, + wr::Vec<uint8_t>& dl_spatial_tree) { + wr_transaction_set_display_list(mTxn, aEpoch, pipeline_id, dl_descriptor, + &dl_items_data.inner, &dl_cache_data.inner, + &dl_spatial_tree.inner); +} + +void TransactionBuilder::ClearDisplayList(Epoch aEpoch, + wr::WrPipelineId aPipelineId) { + wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId); +} + +void TransactionBuilder::GenerateFrame(const VsyncId& aVsyncId, + wr::RenderReasons aReasons) { + wr_transaction_generate_frame(mTxn, aVsyncId.mId, aReasons); +} + +void TransactionBuilder::InvalidateRenderedFrame(wr::RenderReasons aReasons) { + wr_transaction_invalidate_rendered_frame(mTxn, aReasons); +} + +bool TransactionBuilder::IsEmpty() const { + return wr_transaction_is_empty(mTxn); +} + +bool TransactionBuilder::IsResourceUpdatesEmpty() const { + return wr_transaction_resource_updates_is_empty(mTxn); +} + +bool TransactionBuilder::IsRenderedFrameInvalidated() const { + return wr_transaction_is_rendered_frame_invalidated(mTxn); +} + +void TransactionBuilder::SetDocumentView( + const LayoutDeviceIntRect& aDocumentRect) { + wr::DeviceIntRect wrDocRect; + wrDocRect.min.x = aDocumentRect.x; + wrDocRect.min.y = aDocumentRect.y; + wrDocRect.max.x = aDocumentRect.x + aDocumentRect.width; + wrDocRect.max.y = aDocumentRect.y + aDocumentRect.height; + wr_transaction_set_document_view(mTxn, &wrDocRect); +} + +TransactionWrapper::TransactionWrapper(Transaction* aTxn) : mTxn(aTxn) {} + +void TransactionWrapper::AppendDynamicProperties( + const nsTArray<wr::WrOpacityProperty>& aOpacityArray, + const nsTArray<wr::WrTransformProperty>& aTransformArray, + const nsTArray<wr::WrColorProperty>& aColorArray) { + wr_transaction_append_dynamic_properties( + mTxn, aOpacityArray.IsEmpty() ? nullptr : aOpacityArray.Elements(), + aOpacityArray.Length(), + aTransformArray.IsEmpty() ? nullptr : aTransformArray.Elements(), + aTransformArray.Length(), + aColorArray.IsEmpty() ? nullptr : aColorArray.Elements(), + aColorArray.Length()); +} + +void TransactionWrapper::AppendTransformProperties( + const nsTArray<wr::WrTransformProperty>& aTransformArray) { + wr_transaction_append_transform_properties( + mTxn, aTransformArray.IsEmpty() ? nullptr : aTransformArray.Elements(), + aTransformArray.Length()); +} + +void TransactionWrapper::UpdateScrollPosition( + const wr::ExternalScrollId& aScrollId, + const nsTArray<wr::SampledScrollOffset>& aSampledOffsets) { + wr_transaction_scroll_layer(mTxn, aScrollId, &aSampledOffsets); +} + +void TransactionWrapper::UpdateIsTransformAsyncZooming(uint64_t aAnimationId, + bool aIsZooming) { + wr_transaction_set_is_transform_async_zooming(mTxn, aAnimationId, aIsZooming); +} + +void TransactionWrapper::AddMinimapData(const wr::ExternalScrollId& aScrollId, + const MinimapData& aMinimapData) { + wr_transaction_add_minimap_data(mTxn, aScrollId, aMinimapData); +} + +/*static*/ +already_AddRefed<WebRenderAPI> WebRenderAPI::Create( + layers::CompositorBridgeParent* aBridge, + RefPtr<widget::CompositorWidget>&& aWidget, const wr::WrWindowId& aWindowId, + LayoutDeviceIntSize aSize, layers::WindowKind aWindowKind, + nsACString& aError) { + MOZ_ASSERT(aBridge); + MOZ_ASSERT(aWidget); + static_assert( + sizeof(size_t) == sizeof(uintptr_t), + "The FFI bindings assume size_t is the same size as uintptr_t!"); + + wr::DocumentHandle* docHandle = nullptr; + WebRenderBackend backend = WebRenderBackend::HARDWARE; + WebRenderCompositor compositor = WebRenderCompositor::DRAW; + int32_t maxTextureSize = 0; + bool useANGLE = false; + bool useDComp = false; + bool useTripleBuffering = false; + bool supportsExternalBufferTextures = false; + layers::SyncHandle syncHandle = {}; + + // Dispatch a synchronous task because the DocumentHandle object needs to be + // created on the render thread. If need be we could delay waiting on this + // task until the next time we need to access the DocumentHandle object. + layers::SynchronousTask task("Create Renderer"); + auto event = MakeUnique<NewRenderer>( + &docHandle, aBridge, &backend, &compositor, &maxTextureSize, &useANGLE, + &useDComp, &useTripleBuffering, &supportsExternalBufferTextures, + std::move(aWidget), &task, aSize, aWindowKind, &syncHandle, &aError); + RenderThread::Get()->PostEvent(aWindowId, std::move(event)); + + task.Wait(); + + if (!docHandle) { + return nullptr; + } + + return RefPtr<WebRenderAPI>( + new WebRenderAPI(docHandle, aWindowId, backend, compositor, + maxTextureSize, useANGLE, useDComp, + useTripleBuffering, + supportsExternalBufferTextures, syncHandle)) + .forget(); +} + +already_AddRefed<WebRenderAPI> WebRenderAPI::Clone() { + wr::DocumentHandle* docHandle = nullptr; + wr_api_clone(mDocHandle, &docHandle); + + RefPtr<WebRenderAPI> renderApi = new WebRenderAPI( + docHandle, mId, mBackend, mCompositor, mMaxTextureSize, mUseANGLE, + mUseDComp, mUseTripleBuffering, mSupportsExternalBufferTextures, + mSyncHandle, this, this); + + return renderApi.forget(); +} + +wr::WrIdNamespace WebRenderAPI::GetNamespace() { + return wr_api_get_namespace(mDocHandle); +} + +WebRenderAPI::WebRenderAPI( + wr::DocumentHandle* aHandle, wr::WindowId aId, WebRenderBackend aBackend, + WebRenderCompositor aCompositor, uint32_t aMaxTextureSize, bool aUseANGLE, + bool aUseDComp, bool aUseTripleBuffering, + bool aSupportsExternalBufferTextures, layers::SyncHandle aSyncHandle, + wr::WebRenderAPI* aRootApi, wr::WebRenderAPI* aRootDocumentApi) + : mDocHandle(aHandle), + mId(aId), + mBackend(aBackend), + mCompositor(aCompositor), + mMaxTextureSize(aMaxTextureSize), + mUseANGLE(aUseANGLE), + mUseDComp(aUseDComp), + mUseTripleBuffering(aUseTripleBuffering), + mSupportsExternalBufferTextures(aSupportsExternalBufferTextures), + mCaptureSequence(false), + mSyncHandle(aSyncHandle), + mRendererDestroyed(false), + mRootApi(aRootApi), + mRootDocumentApi(aRootDocumentApi) {} + +WebRenderAPI::~WebRenderAPI() { + if (!mRootDocumentApi) { + wr_api_delete_document(mDocHandle); + } + + if (!mRootApi) { + MOZ_RELEASE_ASSERT(mRendererDestroyed); + wr_api_shut_down(mDocHandle); + } + + wr_api_delete(mDocHandle); +} + +void WebRenderAPI::DestroyRenderer() { + MOZ_RELEASE_ASSERT(!mRootApi); + + RenderThread::Get()->SetDestroyed(GetId()); + // Call wr_api_stop_render_backend() before RemoveRenderer. + wr_api_stop_render_backend(mDocHandle); + + layers::SynchronousTask task("Destroy WebRenderAPI"); + auto event = MakeUnique<RemoveRenderer>(&task); + RunOnRenderThread(std::move(event)); + task.Wait(); + + mRendererDestroyed = true; +} + +wr::WebRenderAPI* WebRenderAPI::GetRootAPI() { + if (mRootApi) { + return mRootApi; + } + return this; +} + +void WebRenderAPI::UpdateDebugFlags(uint32_t aFlags) { + wr_api_set_debug_flags(mDocHandle, wr::DebugFlags{aFlags}); +} + +void WebRenderAPI::SendTransaction(TransactionBuilder& aTxn) { + if (mRootApi && mRootApi->mRendererDestroyed) { + return; + } + + if (mPendingRemoteTextureInfoList && + !mPendingRemoteTextureInfoList->mList.empty()) { + mPendingWrTransactionEvents.emplace( + WrTransactionEvent::PendingRemoteTextures( + std::move(mPendingRemoteTextureInfoList))); + } + + if (mPendingAsyncImagePipelineOps && + !mPendingAsyncImagePipelineOps->mList.empty()) { + mPendingWrTransactionEvents.emplace( + WrTransactionEvent::PendingAsyncImagePipelineOps( + std::move(mPendingAsyncImagePipelineOps), this, aTxn.Raw(), + aTxn.UseSceneBuilderThread())); + } + + if (!mPendingWrTransactionEvents.empty()) { + mPendingWrTransactionEvents.emplace(WrTransactionEvent::Transaction( + this, aTxn.Take(), aTxn.UseSceneBuilderThread())); + HandleWrTransactionEvents(RemoteTextureWaitType::AsyncWait); + } else { + wr_api_send_transaction(mDocHandle, aTxn.Raw(), + aTxn.UseSceneBuilderThread()); + } +} + +layers::RemoteTextureInfoList* WebRenderAPI::GetPendingRemoteTextureInfoList() { + if (!mRootApi) { + // root api does not support async wait RemoteTexture. + return nullptr; + } + + if (!mPendingRemoteTextureInfoList) { + mPendingRemoteTextureInfoList = MakeUnique<layers::RemoteTextureInfoList>(); + } + return mPendingRemoteTextureInfoList.get(); +} + +layers::AsyncImagePipelineOps* WebRenderAPI::GetPendingAsyncImagePipelineOps( + TransactionBuilder& aTxn) { + if (!mRootApi) { + // root api does not support async wait RemoteTexture. + return nullptr; + } + + if (!mPendingAsyncImagePipelineOps || + mPendingAsyncImagePipelineOps->mTransaction != aTxn.Raw()) { + if (mPendingAsyncImagePipelineOps && + !mPendingAsyncImagePipelineOps->mList.empty()) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Invalid AsyncImagePipelineOps"; + } + mPendingAsyncImagePipelineOps = + MakeUnique<layers::AsyncImagePipelineOps>(aTxn.Raw()); + } else { + MOZ_RELEASE_ASSERT(mPendingAsyncImagePipelineOps->mTransaction == + aTxn.Raw()); + } + + return mPendingAsyncImagePipelineOps.get(); +} + +bool WebRenderAPI::CheckIsRemoteTextureReady( + layers::RemoteTextureInfoList* aList, const TimeStamp& aTimeStamp) { + MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aList); + + RefPtr<WebRenderAPI> self = this; + auto callback = [self](const layers::RemoteTextureInfo&) { + RefPtr<nsIRunnable> runnable = NewRunnableMethod<RemoteTextureWaitType>( + "WebRenderAPI::HandleWrTransactionEvents", self, + &WebRenderAPI::HandleWrTransactionEvents, + RemoteTextureWaitType::AsyncWait); + layers::CompositorThread()->Dispatch(runnable.forget()); + }; + + const auto maxWaitDurationMs = 10000; + const auto now = TimeStamp::Now(); + const auto waitDurationMs = + static_cast<uint32_t>((now - aTimeStamp).ToMilliseconds()); + + const auto isTimeout = waitDurationMs > maxWaitDurationMs; + if (isTimeout) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNote << "RemoteTexture ready timeout"; + } + + bool isReady = true; + while (!aList->mList.empty() && isReady) { + auto& front = aList->mList.front(); + isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady( + front, callback); + if (isTimeout) { + isReady = true; + } + if (isReady) { + aList->mList.pop(); + } + } + + return isReady; +} + +void WebRenderAPI::WaitRemoteTextureReady( + layers::RemoteTextureInfoList* aList) { + MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aList); + + while (!aList->mList.empty()) { + auto& front = aList->mList.front(); + layers::RemoteTextureMap::Get()->WaitRemoteTextureReady(front); + aList->mList.pop(); + } +} + +void WebRenderAPI::FlushPendingWrTransactionEventsWithoutWait() { + HandleWrTransactionEvents(RemoteTextureWaitType::FlushWithoutWait); +} + +void WebRenderAPI::FlushPendingWrTransactionEventsWithWait() { + HandleWrTransactionEvents(RemoteTextureWaitType::FlushWithWait); +} + +void WebRenderAPI::HandleWrTransactionEvents(RemoteTextureWaitType aType) { + auto& events = mPendingWrTransactionEvents; + + while (!events.empty()) { + auto& front = events.front(); + switch (front.mTag) { + case WrTransactionEvent::Tag::Transaction: + wr_api_send_transaction(mDocHandle, front.RawTransaction(), + front.UseSceneBuilderThread()); + break; + case WrTransactionEvent::Tag::PendingRemoteTextures: { + bool isReady = true; + if (aType == RemoteTextureWaitType::AsyncWait) { + isReady = CheckIsRemoteTextureReady(front.RemoteTextureInfoList(), + front.mTimeStamp); + } else if (aType == RemoteTextureWaitType::FlushWithWait) { + WaitRemoteTextureReady(front.RemoteTextureInfoList()); + } else { + MOZ_ASSERT(aType == RemoteTextureWaitType::FlushWithoutWait); + auto* list = front.RemoteTextureInfoList(); + while (!list->mList.empty()) { + auto& front = list->mList.front(); + layers::RemoteTextureMap::Get()->SuppressRemoteTextureReadyCheck( + front.mTextureId, front.mForPid); + list->mList.pop(); + } + } + if (!isReady && (aType != RemoteTextureWaitType::FlushWithoutWait)) { + return; + } + break; + } + case WrTransactionEvent::Tag::PendingAsyncImagePipelineOps: { + auto* list = front.AsyncImagePipelineOps(); + TransactionBuilder& txn = *front.GetTransactionBuilder(); + + list->HandleOps(txn); + break; + } + } + events.pop(); + } +} + +std::vector<WrHitResult> WebRenderAPI::HitTest(const wr::WorldPoint& aPoint) { + static_assert(gfx::DoesCompositorHitTestInfoFitIntoBits<12>(), + "CompositorHitTestFlags MAX value has to be less than number " + "of bits in uint16_t minus 4 for SideBitsPacked"); + + nsTArray<wr::HitResult> wrResults; + wr_api_hit_test(mDocHandle, aPoint, &wrResults); + + std::vector<WrHitResult> geckoResults; + for (wr::HitResult wrResult : wrResults) { + WrHitResult geckoResult; + geckoResult.mLayersId = wr::AsLayersId(wrResult.pipeline_id); + geckoResult.mScrollId = + static_cast<layers::ScrollableLayerGuid::ViewID>(wrResult.scroll_id); + geckoResult.mHitInfo.deserialize(wrResult.hit_info & 0x0fff); + geckoResult.mSideBits = static_cast<SideBits>(wrResult.hit_info >> 12); + + if (wrResult.animation_id != 0) { + geckoResult.mAnimationId = Some(wrResult.animation_id); + } else { + geckoResult.mAnimationId = Nothing(); + } + geckoResults.push_back(geckoResult); + } + return geckoResults; +} + +void WebRenderAPI::Readback(const TimeStamp& aStartTime, gfx::IntSize size, + const gfx::SurfaceFormat& aFormat, + const Range<uint8_t>& buffer, bool* aNeedsYFlip) { + class Readback : public RendererEvent { + public: + explicit Readback(layers::SynchronousTask* aTask, TimeStamp aStartTime, + gfx::IntSize aSize, const gfx::SurfaceFormat& aFormat, + const Range<uint8_t>& aBuffer, bool* aNeedsYFlip) + : mTask(aTask), + mStartTime(aStartTime), + mSize(aSize), + mFormat(aFormat), + mBuffer(aBuffer), + mNeedsYFlip(aNeedsYFlip) { + MOZ_COUNT_CTOR(Readback); + } + + MOZ_COUNTED_DTOR_OVERRIDE(Readback) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + aRenderThread.UpdateAndRender(aWindowId, VsyncId(), mStartTime, + /* aRender */ true, Some(mSize), + wr::SurfaceFormatToImageFormat(mFormat), + Some(mBuffer), mNeedsYFlip); + layers::AutoCompleteTask complete(mTask); + } + + layers::SynchronousTask* mTask; + TimeStamp mStartTime; + gfx::IntSize mSize; + gfx::SurfaceFormat mFormat; + const Range<uint8_t>& mBuffer; + bool* mNeedsYFlip; + }; + + // Disable debug flags during readback. See bug 1436020. + UpdateDebugFlags(0); + + layers::SynchronousTask task("Readback"); + auto event = MakeUnique<Readback>(&task, aStartTime, size, aFormat, buffer, + aNeedsYFlip); + // This event will be passed from wr_backend thread to renderer thread. That + // implies that all frame data have been processed when the renderer runs this + // read-back event. Then, we could make sure this read-back event gets the + // latest result. + RunOnRenderThread(std::move(event)); + + task.Wait(); + + UpdateDebugFlags(gfx::gfxVars::WebRenderDebugFlags()); +} + +void WebRenderAPI::ClearAllCaches() { wr_api_clear_all_caches(mDocHandle); } + +void WebRenderAPI::EnableNativeCompositor(bool aEnable) { + wr_api_enable_native_compositor(mDocHandle, aEnable); +} + +void WebRenderAPI::SetBatchingLookback(uint32_t aCount) { + wr_api_set_batching_lookback(mDocHandle, aCount); +} + +void WebRenderAPI::SetBool(wr::BoolParameter aKey, bool aValue) { + wr_api_set_bool(mDocHandle, aKey, aValue); +} + +void WebRenderAPI::SetInt(wr::IntParameter aKey, int32_t aValue) { + wr_api_set_int(mDocHandle, aKey, aValue); +} + +void WebRenderAPI::SetClearColor(const gfx::DeviceColor& aColor) { + RenderThread::Get()->SetClearColor(mId, ToColorF(aColor)); +} + +void WebRenderAPI::SetProfilerUI(const nsACString& aUIString) { + RenderThread::Get()->SetProfilerUI(mId, aUIString); +} + +void WebRenderAPI::Pause() { + class PauseEvent : public RendererEvent { + public: + explicit PauseEvent(layers::SynchronousTask* aTask) : mTask(aTask) { + MOZ_COUNT_CTOR(PauseEvent); + } + + MOZ_COUNTED_DTOR_OVERRIDE(PauseEvent) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + aRenderThread.Pause(aWindowId); + layers::AutoCompleteTask complete(mTask); + } + + layers::SynchronousTask* mTask; + }; + + layers::SynchronousTask task("Pause"); + auto event = MakeUnique<PauseEvent>(&task); + // This event will be passed from wr_backend thread to renderer thread. That + // implies that all frame data have been processed when the renderer runs this + // event. + RunOnRenderThread(std::move(event)); + + task.Wait(); +} + +bool WebRenderAPI::Resume() { + class ResumeEvent : public RendererEvent { + public: + explicit ResumeEvent(layers::SynchronousTask* aTask, bool* aResult) + : mTask(aTask), mResult(aResult) { + MOZ_COUNT_CTOR(ResumeEvent); + } + + MOZ_COUNTED_DTOR_OVERRIDE(ResumeEvent) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + *mResult = aRenderThread.Resume(aWindowId); + layers::AutoCompleteTask complete(mTask); + } + + layers::SynchronousTask* mTask; + bool* mResult; + }; + + bool result = false; + layers::SynchronousTask task("Resume"); + auto event = MakeUnique<ResumeEvent>(&task, &result); + // This event will be passed from wr_backend thread to renderer thread. That + // implies that all frame data have been processed when the renderer runs this + // event. + RunOnRenderThread(std::move(event)); + + task.Wait(); + return result; +} + +void WebRenderAPI::NotifyMemoryPressure() { + wr_api_notify_memory_pressure(mDocHandle); +} + +void WebRenderAPI::AccumulateMemoryReport(MemoryReport* aReport) { + wr_api_accumulate_memory_report(mDocHandle, aReport, &WebRenderMallocSizeOf, + &WebRenderMallocEnclosingSizeOf); +} + +void WebRenderAPI::WakeSceneBuilder() { wr_api_wake_scene_builder(mDocHandle); } + +void WebRenderAPI::FlushSceneBuilder() { + wr_api_flush_scene_builder(mDocHandle); +} + +void WebRenderAPI::WaitFlushed() { + class WaitFlushedEvent : public RendererEvent { + public: + explicit WaitFlushedEvent(layers::SynchronousTask* aTask) : mTask(aTask) { + MOZ_COUNT_CTOR(WaitFlushedEvent); + } + + MOZ_COUNTED_DTOR_OVERRIDE(WaitFlushedEvent) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + layers::AutoCompleteTask complete(mTask); + } + + layers::SynchronousTask* mTask; + }; + + layers::SynchronousTask task("WaitFlushed"); + auto event = MakeUnique<WaitFlushedEvent>(&task); + // This event will be passed from wr_backend thread to renderer thread. That + // implies that all frame data have been processed when the renderer runs this + // event. + RunOnRenderThread(std::move(event)); + + task.Wait(); +} + +void WebRenderAPI::Capture() { + // see CaptureBits + // SCENE | FRAME | TILE_CACHE + uint8_t bits = 15; // TODO: get from JavaScript + const char* path = "wr-capture"; // TODO: get from JavaScript + wr_api_capture(mDocHandle, path, bits); +} + +void WebRenderAPI::StartCaptureSequence(const nsACString& aPath, + uint32_t aFlags) { + if (mCaptureSequence) { + wr_api_stop_capture_sequence(mDocHandle); + } + + wr_api_start_capture_sequence(mDocHandle, PromiseFlatCString(aPath).get(), + aFlags); + + mCaptureSequence = true; +} + +void WebRenderAPI::StopCaptureSequence() { + if (mCaptureSequence) { + wr_api_stop_capture_sequence(mDocHandle); + } + + mCaptureSequence = false; +} + +void WebRenderAPI::BeginRecording(const TimeStamp& aRecordingStart, + wr::PipelineId aRootPipelineId) { + class BeginRecordingEvent final : public RendererEvent { + public: + explicit BeginRecordingEvent(const TimeStamp& aRecordingStart, + wr::PipelineId aRootPipelineId) + : mRecordingStart(aRecordingStart), mRootPipelineId(aRootPipelineId) { + MOZ_COUNT_CTOR(BeginRecordingEvent); + } + + ~BeginRecordingEvent() { MOZ_COUNT_DTOR(BeginRecordingEvent); } + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + aRenderThread.BeginRecordingForWindow(aWindowId, mRecordingStart, + mRootPipelineId); + } + + private: + TimeStamp mRecordingStart; + wr::PipelineId mRootPipelineId; + }; + + auto event = + MakeUnique<BeginRecordingEvent>(aRecordingStart, aRootPipelineId); + RunOnRenderThread(std::move(event)); +} + +RefPtr<WebRenderAPI::EndRecordingPromise> WebRenderAPI::EndRecording() { + class EndRecordingEvent final : public RendererEvent { + public: + explicit EndRecordingEvent() { MOZ_COUNT_CTOR(EndRecordingEvent); } + + MOZ_COUNTED_DTOR(EndRecordingEvent); + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + Maybe<layers::FrameRecording> recording = + aRenderThread.EndRecordingForWindow(aWindowId); + + if (recording) { + mPromise.Resolve(recording.extract(), __func__); + } else { + mPromise.Reject(NS_ERROR_UNEXPECTED, __func__); + } + } + + RefPtr<WebRenderAPI::EndRecordingPromise> GetPromise() { + return mPromise.Ensure(__func__); + } + + private: + MozPromiseHolder<WebRenderAPI::EndRecordingPromise> mPromise; + }; + + auto event = MakeUnique<EndRecordingEvent>(); + auto promise = event->GetPromise(); + + RunOnRenderThread(std::move(event)); + return promise; +} + +void TransactionBuilder::Clear() { wr_resource_updates_clear(mTxn); } + +Transaction* TransactionBuilder::Take() { + if (!mOwnsData) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return nullptr; + } + Transaction* txn = mTxn; + mTxn = wr_transaction_new(mUseSceneBuilderThread); + return txn; +} + +void TransactionBuilder::Notify(wr::Checkpoint aWhen, + UniquePtr<NotificationHandler> aEvent) { + wr_transaction_notify(mTxn, aWhen, + reinterpret_cast<uintptr_t>(aEvent.release())); +} + +void TransactionBuilder::AddImage(ImageKey key, + const ImageDescriptor& aDescriptor, + wr::Vec<uint8_t>& aBytes) { + wr_resource_updates_add_image(mTxn, key, &aDescriptor, &aBytes.inner); +} + +void TransactionBuilder::AddBlobImage(BlobImageKey key, + const ImageDescriptor& aDescriptor, + uint16_t aTileSize, + wr::Vec<uint8_t>& aBytes, + const wr::DeviceIntRect& aVisibleRect) { + wr_resource_updates_add_blob_image(mTxn, key, &aDescriptor, aTileSize, + &aBytes.inner, aVisibleRect); +} + +void TransactionBuilder::AddExternalImage(ImageKey key, + const ImageDescriptor& aDescriptor, + ExternalImageId aExtID, + wr::ExternalImageType aImageType, + uint8_t aChannelIndex) { + wr_resource_updates_add_external_image(mTxn, key, &aDescriptor, aExtID, + &aImageType, aChannelIndex); +} + +void TransactionBuilder::AddExternalImageBuffer( + ImageKey aKey, const ImageDescriptor& aDescriptor, + ExternalImageId aHandle) { + auto channelIndex = 0; + AddExternalImage(aKey, aDescriptor, aHandle, wr::ExternalImageType::Buffer(), + channelIndex); +} + +void TransactionBuilder::UpdateImageBuffer(ImageKey aKey, + const ImageDescriptor& aDescriptor, + wr::Vec<uint8_t>& aBytes) { + wr_resource_updates_update_image(mTxn, aKey, &aDescriptor, &aBytes.inner); +} + +void TransactionBuilder::UpdateBlobImage(BlobImageKey aKey, + const ImageDescriptor& aDescriptor, + wr::Vec<uint8_t>& aBytes, + const wr::DeviceIntRect& aVisibleRect, + const wr::LayoutIntRect& aDirtyRect) { + wr_resource_updates_update_blob_image(mTxn, aKey, &aDescriptor, &aBytes.inner, + aVisibleRect, aDirtyRect); +} + +void TransactionBuilder::UpdateExternalImage(ImageKey aKey, + const ImageDescriptor& aDescriptor, + ExternalImageId aExtID, + wr::ExternalImageType aImageType, + uint8_t aChannelIndex) { + wr_resource_updates_update_external_image(mTxn, aKey, &aDescriptor, aExtID, + &aImageType, aChannelIndex); +} + +void TransactionBuilder::UpdateExternalImageWithDirtyRect( + ImageKey aKey, const ImageDescriptor& aDescriptor, ExternalImageId aExtID, + wr::ExternalImageType aImageType, const wr::DeviceIntRect& aDirtyRect, + uint8_t aChannelIndex) { + wr_resource_updates_update_external_image_with_dirty_rect( + mTxn, aKey, &aDescriptor, aExtID, &aImageType, aChannelIndex, aDirtyRect); +} + +void TransactionBuilder::SetBlobImageVisibleArea( + BlobImageKey aKey, const wr::DeviceIntRect& aArea) { + wr_resource_updates_set_blob_image_visible_area(mTxn, aKey, &aArea); +} + +void TransactionBuilder::DeleteImage(ImageKey aKey) { + wr_resource_updates_delete_image(mTxn, aKey); +} + +void TransactionBuilder::DeleteBlobImage(BlobImageKey aKey) { + wr_resource_updates_delete_blob_image(mTxn, aKey); +} + +void TransactionBuilder::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, + uint32_t aIndex) { + wr_resource_updates_add_raw_font(mTxn, aKey, &aBytes.inner, aIndex); +} + +void TransactionBuilder::AddFontDescriptor(wr::FontKey aKey, + wr::Vec<uint8_t>& aBytes, + uint32_t aIndex) { + wr_resource_updates_add_font_descriptor(mTxn, aKey, &aBytes.inner, aIndex); +} + +void TransactionBuilder::DeleteFont(wr::FontKey aKey) { + wr_resource_updates_delete_font(mTxn, aKey); +} + +void TransactionBuilder::AddFontInstance( + wr::FontInstanceKey aKey, wr::FontKey aFontKey, float aGlyphSize, + const wr::FontInstanceOptions* aOptions, + const wr::FontInstancePlatformOptions* aPlatformOptions, + wr::Vec<uint8_t>& aVariations) { + wr_resource_updates_add_font_instance(mTxn, aKey, aFontKey, aGlyphSize, + aOptions, aPlatformOptions, + &aVariations.inner); +} + +void TransactionBuilder::DeleteFontInstance(wr::FontInstanceKey aKey) { + wr_resource_updates_delete_font_instance(mTxn, aKey); +} + +void TransactionBuilder::UpdateQualitySettings( + bool aForceSubpixelAAWherePossible) { + wr_transaction_set_quality_settings(mTxn, aForceSubpixelAAWherePossible); +} + +class FrameStartTime : public RendererEvent { + public: + explicit FrameStartTime(const TimeStamp& aTime) : mTime(aTime) { + MOZ_COUNT_CTOR(FrameStartTime); + } + + MOZ_COUNTED_DTOR_OVERRIDE(FrameStartTime) + + void Run(RenderThread& aRenderThread, WindowId aWindowId) override { + auto renderer = aRenderThread.GetRenderer(aWindowId); + if (renderer) { + renderer->SetFrameStartTime(mTime); + } + } + + private: + TimeStamp mTime; +}; + +void WebRenderAPI::SetFrameStartTime(const TimeStamp& aTime) { + auto event = MakeUnique<FrameStartTime>(aTime); + RunOnRenderThread(std::move(event)); +} + +void WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent) { + auto event = reinterpret_cast<uintptr_t>(aEvent.release()); + wr_api_send_external_event(mDocHandle, event); +} + +DisplayListBuilder::DisplayListBuilder(PipelineId aId, + WebRenderBackend aBackend) + : mCurrentSpaceAndClipChain(wr::RootScrollNodeWithChain()), + mActiveFixedPosTracker(nullptr), + mPipelineId(aId), + mBackend(aBackend), + mDisplayItemCache(nullptr) { + MOZ_COUNT_CTOR(DisplayListBuilder); + mWrState = wr_state_new(aId); + + if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) { + mDisplayItemCache->SetPipelineId(aId); + } +} + +DisplayListBuilder::~DisplayListBuilder() { + MOZ_COUNT_DTOR(DisplayListBuilder); + wr_state_delete(mWrState); +} + +void DisplayListBuilder::Save() { wr_dp_save(mWrState); } +void DisplayListBuilder::Restore() { wr_dp_restore(mWrState); } +void DisplayListBuilder::ClearSave() { wr_dp_clear_save(mWrState); } + +usize DisplayListBuilder::Dump(usize aIndent, const Maybe<usize>& aStart, + const Maybe<usize>& aEnd) { + return wr_dump_display_list(mWrState, aIndent, aStart.ptrOr(nullptr), + aEnd.ptrOr(nullptr)); +} + +void DisplayListBuilder::DumpSerializedDisplayList() { + wr_dump_serialized_display_list(mWrState); +} + +void DisplayListBuilder::Begin(layers::DisplayItemCache* aCache) { + wr_api_begin_builder(mWrState); + + mScrollIds.clear(); + mCurrentSpaceAndClipChain = wr::RootScrollNodeWithChain(); + mClipChainLeaf = Nothing(); + mSuspendedSpaceAndClipChain = Nothing(); + mSuspendedClipChainLeaf = Nothing(); + mCachedTextDT = nullptr; + mCachedContext = nullptr; + mActiveFixedPosTracker = nullptr; + mDisplayItemCache = aCache; + mCurrentCacheSlot = Nothing(); +} + +void DisplayListBuilder::End(BuiltDisplayList& aOutDisplayList) { + wr_api_end_builder( + mWrState, &aOutDisplayList.dl_desc, &aOutDisplayList.dl_items.inner, + &aOutDisplayList.dl_cache.inner, &aOutDisplayList.dl_spatial_tree.inner); + + mDisplayItemCache = nullptr; +} + +void DisplayListBuilder::End(layers::DisplayListData& aOutTransaction) { + if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) { + wr_dp_set_cache_size(mWrState, mDisplayItemCache->CurrentSize()); + } + + wr::VecU8 dlItems, dlCache, dlSpatialTree; + wr_api_end_builder(mWrState, &aOutTransaction.mDLDesc, &dlItems.inner, + &dlCache.inner, &dlSpatialTree.inner); + aOutTransaction.mDLItems.emplace(dlItems.inner.data, dlItems.inner.length, + dlItems.inner.capacity); + aOutTransaction.mDLCache.emplace(dlCache.inner.data, dlCache.inner.length, + dlCache.inner.capacity); + aOutTransaction.mDLSpatialTree.emplace(dlSpatialTree.inner.data, + dlSpatialTree.inner.length, + dlSpatialTree.inner.capacity); + dlItems.inner.capacity = 0; + dlItems.inner.data = nullptr; + dlCache.inner.capacity = 0; + dlCache.inner.data = nullptr; + dlSpatialTree.inner.capacity = 0; + dlSpatialTree.inner.data = nullptr; +} + +Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext( + const wr::StackingContextParams& aParams, const wr::LayoutRect& aBounds, + const wr::RasterSpace& aRasterSpace) { + MOZ_ASSERT(mClipChainLeaf.isNothing(), + "Non-empty leaf from clip chain given, but not used with SC!"); + + WRDL_LOG( + "PushStackingContext b=%s t=%s id=0x%" PRIx64 "\n", mWrState, + ToString(aBounds).c_str(), + aParams.mTransformPtr ? ToString(*aParams.mTransformPtr).c_str() : "none", + aParams.animation ? aParams.animation->id : 0); + + auto spatialId = wr_dp_push_stacking_context( + mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aParams, + aParams.mTransformPtr, aParams.mFilters.Elements(), + aParams.mFilters.Length(), aParams.mFilterDatas.Elements(), + aParams.mFilterDatas.Length(), aRasterSpace); + + return spatialId.id != 0 ? Some(spatialId) : Nothing(); +} + +void DisplayListBuilder::PopStackingContext(bool aIsReferenceFrame) { + WRDL_LOG("PopStackingContext\n", mWrState); + wr_dp_pop_stacking_context(mWrState, aIsReferenceFrame); +} + +wr::WrClipChainId DisplayListBuilder::DefineClipChain( + const nsTArray<wr::WrClipId>& aClips, bool aParentWithCurrentChain) { + CancelGroup(); + + const uint64_t* parent = nullptr; + if (aParentWithCurrentChain && + mCurrentSpaceAndClipChain.clip_chain != wr::ROOT_CLIP_CHAIN) { + parent = &mCurrentSpaceAndClipChain.clip_chain; + } + uint64_t clipchainId = wr_dp_define_clipchain( + mWrState, parent, aClips.Elements(), aClips.Length()); + if (MOZ_LOG_TEST(sWrDLLog, LogLevel::Debug)) { + nsCString message; + message.AppendPrintf("DefineClipChain id=%" PRIu64 + " clipCount=%zu clipIds=[", + clipchainId, aClips.Length()); + for (const auto& clip : aClips) { + message.AppendPrintf("%" PRIuPTR ",", clip.id); + } + message.Append("]"); + WRDL_LOG("%s", mWrState, message.get()); + } + return wr::WrClipChainId{clipchainId}; +} + +wr::WrClipId DisplayListBuilder::DefineImageMaskClip( + const wr::ImageMask& aMask, const nsTArray<wr::LayoutPoint>& aPoints, + wr::FillRule aFillRule) { + CancelGroup(); + + WrClipId clipId = wr_dp_define_image_mask_clip_with_parent_clip_chain( + mWrState, mCurrentSpaceAndClipChain.space, aMask, aPoints.Elements(), + aPoints.Length(), aFillRule); + + return clipId; +} + +wr::WrClipId DisplayListBuilder::DefineRoundedRectClip( + Maybe<wr::WrSpatialId> aSpace, const wr::ComplexClipRegion& aComplex) { + CancelGroup(); + + WrClipId clipId; + if (aSpace) { + clipId = wr_dp_define_rounded_rect_clip(mWrState, *aSpace, aComplex); + } else { + clipId = wr_dp_define_rounded_rect_clip( + mWrState, mCurrentSpaceAndClipChain.space, aComplex); + } + + return clipId; +} + +wr::WrClipId DisplayListBuilder::DefineRectClip(Maybe<wr::WrSpatialId> aSpace, + wr::LayoutRect aClipRect) { + CancelGroup(); + + WrClipId clipId; + if (aSpace) { + clipId = wr_dp_define_rect_clip(mWrState, *aSpace, aClipRect); + } else { + clipId = wr_dp_define_rect_clip(mWrState, mCurrentSpaceAndClipChain.space, + aClipRect); + } + + return clipId; +} + +wr::WrSpatialId DisplayListBuilder::DefineStickyFrame( + const wr::LayoutRect& aContentRect, const float* aTopMargin, + const float* aRightMargin, const float* aBottomMargin, + const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds, + const StickyOffsetBounds& aHorizontalBounds, + const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey) { + auto spatialId = wr_dp_define_sticky_frame( + mWrState, mCurrentSpaceAndClipChain.space, aContentRect, aTopMargin, + aRightMargin, aBottomMargin, aLeftMargin, aVerticalBounds, + aHorizontalBounds, aAppliedOffset, aKey); + + WRDL_LOG("DefineSticky id=%zu c=%s t=%s r=%s b=%s l=%s v=%s h=%s a=%s\n", + mWrState, spatialId.id, ToString(aContentRect).c_str(), + aTopMargin ? ToString(*aTopMargin).c_str() : "none", + aRightMargin ? ToString(*aRightMargin).c_str() : "none", + aBottomMargin ? ToString(*aBottomMargin).c_str() : "none", + aLeftMargin ? ToString(*aLeftMargin).c_str() : "none", + ToString(aVerticalBounds).c_str(), + ToString(aHorizontalBounds).c_str(), + ToString(aAppliedOffset).c_str()); + + return spatialId; +} + +Maybe<wr::WrSpatialId> DisplayListBuilder::GetScrollIdForDefinedScrollLayer( + layers::ScrollableLayerGuid::ViewID aViewId) const { + if (aViewId == layers::ScrollableLayerGuid::NULL_SCROLL_ID) { + return Some(wr::RootScrollNode()); + } + + auto it = mScrollIds.find(aViewId); + if (it == mScrollIds.end()) { + return Nothing(); + } + + return Some(it->second); +} + +wr::WrSpatialId DisplayListBuilder::DefineScrollLayer( + const layers::ScrollableLayerGuid::ViewID& aViewId, + const Maybe<wr::WrSpatialId>& aParent, const wr::LayoutRect& aContentRect, + const wr::LayoutRect& aClipRect, const wr::LayoutVector2D& aScrollOffset, + wr::APZScrollGeneration aScrollOffsetGeneration, + wr::HasScrollLinkedEffect aHasScrollLinkedEffect, + wr::SpatialTreeItemKey aKey) { + auto it = mScrollIds.find(aViewId); + if (it != mScrollIds.end()) { + return it->second; + } + + // We haven't defined aViewId before, so let's define it now. + wr::WrSpatialId defaultParent = mCurrentSpaceAndClipChain.space; + + auto space = wr_dp_define_scroll_layer( + mWrState, aViewId, aParent ? aParent.ptr() : &defaultParent, aContentRect, + aClipRect, aScrollOffset, aScrollOffsetGeneration, aHasScrollLinkedEffect, + aKey); + + WRDL_LOG("DefineScrollLayer id=%" PRIu64 + "/%zu p=%s co=%s cl=%s generation=%s hasScrollLinkedEffect=%s\n", + mWrState, aViewId, space.id, + aParent ? ToString(aParent->id).c_str() : "(nil)", + ToString(aContentRect).c_str(), ToString(aClipRect).c_str(), + ToString(aScrollOffsetGeneration).c_str(), + ToString(aHasScrollLinkedEffect).c_str()); + + mScrollIds[aViewId] = space; + return space; +} + +void DisplayListBuilder::PushRect(const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + bool aForceAntiAliasing, bool aIsCheckerboard, + const wr::ColorF& aColor) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + WRDL_LOG("PushRect b=%s cl=%s c=%s\n", mWrState, ToString(aBounds).c_str(), + ToString(clip).c_str(), ToString(aColor).c_str()); + wr_dp_push_rect(mWrState, aBounds, clip, aIsBackfaceVisible, + aForceAntiAliasing, aIsCheckerboard, + &mCurrentSpaceAndClipChain, aColor); +} + +void DisplayListBuilder::PushRoundedRect(const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const wr::ColorF& aColor) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + WRDL_LOG("PushRoundedRect b=%s cl=%s c=%s\n", mWrState, + ToString(aBounds).c_str(), ToString(clip).c_str(), + ToString(aColor).c_str()); + + // Draw the rounded rectangle as a border with rounded corners. We could also + // draw this as a rectangle clipped to a rounded rectangle, but: + // - clips are not cached; borders are + // - a simple border like this will be drawn as an image + // - Processing lots of clips is not WebRender's strong point. + // + // Made the borders thicker than one half the width/height, to avoid + // little white dots at the center at some magnifications. + wr::BorderSide side = {aColor, wr::BorderStyle::Solid}; + float h = aBounds.width() * 0.6f; + float v = aBounds.height() * 0.6f; + wr::LayoutSideOffsets widths = {v, h, v, h}; + wr::BorderRadius radii = {{h, v}, {h, v}, {h, v}, {h, v}}; + + // Anti-aliased borders are required for rounded borders. + wr_dp_push_border(mWrState, aBounds, clip, aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, wr::AntialiasBorder::Yes, + widths, side, side, side, side, radii); +} + +void DisplayListBuilder::PushHitTest( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const layers::ScrollableLayerGuid::ViewID& aScrollId, + const gfx::CompositorHitTestInfo& aHitInfo, SideBits aSideBits) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + WRDL_LOG("PushHitTest b=%s cl=%s\n", mWrState, ToString(aBounds).c_str(), + ToString(clip).c_str()); + + static_assert(gfx::DoesCompositorHitTestInfoFitIntoBits<12>(), + "CompositorHitTestFlags MAX value has to be less than number " + "of bits in uint16_t minus 4 for SideBitsPacked"); + + uint16_t hitInfoBits = static_cast<uint16_t>(aHitInfo.serialize()) | + (static_cast<uint16_t>(aSideBits) << 12); + + wr_dp_push_hit_test(mWrState, aBounds, clip, aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aScrollId, hitInfoBits); +} + +void DisplayListBuilder::PushRectWithAnimation( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::ColorF& aColor, + const WrAnimationProperty* aAnimation) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + WRDL_LOG("PushRectWithAnimation b=%s cl=%s c=%s\n", mWrState, + ToString(aBounds).c_str(), ToString(clip).c_str(), + ToString(aColor).c_str()); + + wr_dp_push_rect_with_animation(mWrState, aBounds, clip, aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aColor, + aAnimation); +} + +void DisplayListBuilder::PushClearRect(const wr::LayoutRect& aBounds) { + wr::LayoutRect clip = MergeClipLeaf(aBounds); + WRDL_LOG("PushClearRect b=%s c=%s\n", mWrState, ToString(aBounds).c_str(), + ToString(clip).c_str()); + wr_dp_push_clear_rect(mWrState, aBounds, clip, &mCurrentSpaceAndClipChain); +} + +void DisplayListBuilder::PushBackdropFilter( + const wr::LayoutRect& aBounds, const wr::ComplexClipRegion& aRegion, + const nsTArray<wr::FilterOp>& aFilters, + const nsTArray<wr::WrFilterData>& aFilterDatas, bool aIsBackfaceVisible) { + wr::LayoutRect clip = MergeClipLeaf(aBounds); + WRDL_LOG("PushBackdropFilter b=%s c=%s\n", mWrState, + ToString(aBounds).c_str(), ToString(clip).c_str()); + + auto clipId = DefineRoundedRectClip(Nothing(), aRegion); + auto clipChainId = DefineClipChain({clipId}, true); + auto spaceAndClip = + WrSpaceAndClipChain{mCurrentSpaceAndClipChain.space, clipChainId.id}; + + wr_dp_push_backdrop_filter(mWrState, aBounds, clip, aIsBackfaceVisible, + &spaceAndClip, aFilters.Elements(), + aFilters.Length(), aFilterDatas.Elements(), + aFilterDatas.Length()); +} + +void DisplayListBuilder::PushLinearGradient( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutPoint& aStartPoint, + const wr::LayoutPoint& aEndPoint, const nsTArray<wr::GradientStop>& aStops, + wr::ExtendMode aExtendMode, const wr::LayoutSize aTileSize, + const wr::LayoutSize aTileSpacing) { + wr_dp_push_linear_gradient( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aStartPoint, aEndPoint, aStops.Elements(), + aStops.Length(), aExtendMode, aTileSize, aTileSpacing); +} + +void DisplayListBuilder::PushRadialGradient( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter, + const wr::LayoutSize& aRadius, const nsTArray<wr::GradientStop>& aStops, + wr::ExtendMode aExtendMode, const wr::LayoutSize aTileSize, + const wr::LayoutSize aTileSpacing) { + wr_dp_push_radial_gradient( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aCenter, aRadius, aStops.Elements(), + aStops.Length(), aExtendMode, aTileSize, aTileSpacing); +} + +void DisplayListBuilder::PushConicGradient( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter, const float aAngle, + const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode, + const wr::LayoutSize aTileSize, const wr::LayoutSize aTileSpacing) { + wr_dp_push_conic_gradient(mWrState, aBounds, MergeClipLeaf(aClip), + aIsBackfaceVisible, &mCurrentSpaceAndClipChain, + aCenter, aAngle, aStops.Elements(), aStops.Length(), + aExtendMode, aTileSize, aTileSpacing); +} + +void DisplayListBuilder::PushImage( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, bool aForceAntiAliasing, + wr::ImageRendering aFilter, wr::ImageKey aImage, bool aPremultipliedAlpha, + const wr::ColorF& aColor, bool aPreferCompositorSurface, + bool aSupportsExternalCompositing) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + WRDL_LOG("PushImage b=%s cl=%s\n", mWrState, ToString(aBounds).c_str(), + ToString(clip).c_str()); + wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible, + aForceAntiAliasing, &mCurrentSpaceAndClipChain, aFilter, + aImage, aPremultipliedAlpha, aColor, + aPreferCompositorSurface, aSupportsExternalCompositing); +} + +void DisplayListBuilder::PushRepeatingImage( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize, + const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter, + wr::ImageKey aImage, bool aPremultipliedAlpha, const wr::ColorF& aColor) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState, + ToString(aBounds).c_str(), ToString(clip).c_str(), + ToString(aStretchSize).c_str(), ToString(aTileSpacing).c_str()); + wr_dp_push_repeating_image( + mWrState, aBounds, clip, aIsBackfaceVisible, &mCurrentSpaceAndClipChain, + aStretchSize, aTileSpacing, aFilter, aImage, aPremultipliedAlpha, aColor); +} + +void DisplayListBuilder::PushYCbCrPlanarImage( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, wr::ImageKey aImageChannel0, + wr::ImageKey aImageChannel1, wr::ImageKey aImageChannel2, + wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace, + wr::WrColorRange aColorRange, wr::ImageRendering aRendering, + bool aPreferCompositorSurface, bool aSupportsExternalCompositing) { + wr_dp_push_yuv_planar_image( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, + aImageChannel2, aColorDepth, aColorSpace, aColorRange, aRendering, + aPreferCompositorSurface, aSupportsExternalCompositing); +} + +void DisplayListBuilder::PushNV12Image( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, wr::ImageKey aImageChannel0, + wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth, + wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange, + wr::ImageRendering aRendering, bool aPreferCompositorSurface, + bool aSupportsExternalCompositing) { + wr_dp_push_yuv_NV12_image( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth, + aColorSpace, aColorRange, aRendering, aPreferCompositorSurface, + aSupportsExternalCompositing); +} + +void DisplayListBuilder::PushP010Image( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, wr::ImageKey aImageChannel0, + wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth, + wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange, + wr::ImageRendering aRendering, bool aPreferCompositorSurface, + bool aSupportsExternalCompositing) { + wr_dp_push_yuv_P010_image( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth, + aColorSpace, aColorRange, aRendering, aPreferCompositorSurface, + aSupportsExternalCompositing); +} + +void DisplayListBuilder::PushYCbCrInterleavedImage( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, wr::ImageKey aImageChannel0, + wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace, + wr::WrColorRange aColorRange, wr::ImageRendering aRendering, + bool aPreferCompositorSurface, bool aSupportsExternalCompositing) { + wr_dp_push_yuv_interleaved_image( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aImageChannel0, aColorDepth, aColorSpace, + aColorRange, aRendering, aPreferCompositorSurface, + aSupportsExternalCompositing); +} + +void DisplayListBuilder::PushIFrame(const LayoutDeviceRect& aDevPxBounds, + bool aIsBackfaceVisible, + PipelineId aPipeline, + bool aIgnoreMissingPipeline) { + // If the incoming bounds size has decimals (As it could when zoom is + // involved), and is pushed straight through here, the compositor would end up + // calculating the destination rect to paint the rendered iframe into + // with those decimal values, rounding the result, instead of snapping. This + // can cause the rendered iframe rect and its destination rect to be + // mismatched, resulting in interpolation artifacts. + auto snapped = aDevPxBounds; + auto tl = snapped.TopLeft().Round(); + auto br = snapped.BottomRight().Round(); + + snapped.SizeTo(LayoutDeviceSize(br.x - tl.x, br.y - tl.y)); + + const auto bounds = wr::ToLayoutRect(snapped); + wr_dp_push_iframe(mWrState, bounds, MergeClipLeaf(bounds), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aPipeline, + aIgnoreMissingPipeline); +} + +void DisplayListBuilder::PushBorder(const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const wr::LayoutSideOffsets& aWidths, + const Range<const wr::BorderSide>& aSides, + const wr::BorderRadius& aRadius, + wr::AntialiasBorder aAntialias) { + MOZ_ASSERT(aSides.length() == 4); + if (aSides.length() != 4) { + return; + } + wr_dp_push_border(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aAntialias, aWidths, aSides[0], + aSides[1], aSides[2], aSides[3], aRadius); +} + +void DisplayListBuilder::PushBorderImage(const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const wr::WrBorderImage& aParams) { + wr_dp_push_border_image(mWrState, aBounds, MergeClipLeaf(aClip), + aIsBackfaceVisible, &mCurrentSpaceAndClipChain, + &aParams); +} + +void DisplayListBuilder::PushBorderGradient( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, + const int32_t aWidth, const int32_t aHeight, bool aFill, + const wr::DeviceIntSideOffsets& aSlice, const wr::LayoutPoint& aStartPoint, + const wr::LayoutPoint& aEndPoint, const nsTArray<wr::GradientStop>& aStops, + wr::ExtendMode aExtendMode) { + wr_dp_push_border_gradient( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aWidths, aWidth, aHeight, aFill, aSlice, + aStartPoint, aEndPoint, aStops.Elements(), aStops.Length(), aExtendMode); +} + +void DisplayListBuilder::PushBorderRadialGradient( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill, + const wr::LayoutPoint& aCenter, const wr::LayoutSize& aRadius, + const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode) { + wr_dp_push_border_radial_gradient( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aRadius, + aStops.Elements(), aStops.Length(), aExtendMode); +} + +void DisplayListBuilder::PushBorderConicGradient( + const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill, + const wr::LayoutPoint& aCenter, const float aAngle, + const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode) { + wr_dp_push_border_conic_gradient( + mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aAngle, + aStops.Elements(), aStops.Length(), aExtendMode); +} + +void DisplayListBuilder::PushText(const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const wr::ColorF& aColor, + wr::FontInstanceKey aFontKey, + Range<const wr::GlyphInstance> aGlyphBuffer, + const wr::GlyphOptions* aGlyphOptions) { + wr_dp_push_text(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aColor, aFontKey, + &aGlyphBuffer[0], aGlyphBuffer.length(), aGlyphOptions); +} + +void DisplayListBuilder::PushLine(const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const wr::Line& aLine) { + wr::LayoutRect clip = MergeClipLeaf(aClip); + wr_dp_push_line(mWrState, &clip, aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, &aLine.bounds, + aLine.wavyLineThickness, aLine.orientation, &aLine.color, + aLine.style); +} + +void DisplayListBuilder::PushShadow(const wr::LayoutRect& aRect, + const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, + const wr::Shadow& aShadow, + bool aShouldInflate) { + // Local clip_rects are translated inside of shadows, as they are assumed to + // be part of the element drawing itself, and not a parent frame clipping it. + // As such, it is not sound to apply the MergeClipLeaf optimization inside of + // shadows. So we disable the optimization when we encounter a shadow. + // Shadows don't span frames, so we don't have to worry about MergeClipLeaf + // being re-enabled mid-shadow. The optimization is restored in PopAllShadows. + SuspendClipLeafMerging(); + wr_dp_push_shadow(mWrState, aRect, aClip, aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aShadow, aShouldInflate); +} + +void DisplayListBuilder::PopAllShadows() { + wr_dp_pop_all_shadows(mWrState); + ResumeClipLeafMerging(); +} + +void DisplayListBuilder::SuspendClipLeafMerging() { + if (mClipChainLeaf) { + // No one should reinitialize mClipChainLeaf while we're suspended + MOZ_ASSERT(!mSuspendedClipChainLeaf); + + mSuspendedClipChainLeaf = mClipChainLeaf; + mSuspendedSpaceAndClipChain = Some(mCurrentSpaceAndClipChain); + + auto clipId = DefineRectClip(Nothing(), *mClipChainLeaf); + auto clipChainId = DefineClipChain({clipId}, true); + + mCurrentSpaceAndClipChain.clip_chain = clipChainId.id; + mClipChainLeaf = Nothing(); + } +} + +void DisplayListBuilder::ResumeClipLeafMerging() { + if (mSuspendedClipChainLeaf) { + mCurrentSpaceAndClipChain = *mSuspendedSpaceAndClipChain; + mClipChainLeaf = mSuspendedClipChainLeaf; + + mSuspendedClipChainLeaf = Nothing(); + mSuspendedSpaceAndClipChain = Nothing(); + } +} + +void DisplayListBuilder::PushBoxShadow( + const wr::LayoutRect& aRect, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutRect& aBoxBounds, + const wr::LayoutVector2D& aOffset, const wr::ColorF& aColor, + const float& aBlurRadius, const float& aSpreadRadius, + const wr::BorderRadius& aBorderRadius, + const wr::BoxShadowClipMode& aClipMode) { + wr_dp_push_box_shadow(mWrState, aRect, MergeClipLeaf(aClip), + aIsBackfaceVisible, &mCurrentSpaceAndClipChain, + aBoxBounds, aOffset, aColor, aBlurRadius, aSpreadRadius, + aBorderRadius, aClipMode); +} + +void DisplayListBuilder::StartGroup(nsPaintedDisplayItem* aItem) { + if (!mDisplayItemCache || mDisplayItemCache->IsFull()) { + return; + } + + MOZ_ASSERT(!mCurrentCacheSlot); + mCurrentCacheSlot = mDisplayItemCache->AssignSlot(aItem); + + if (mCurrentCacheSlot) { + wr_dp_start_item_group(mWrState); + } +} + +void DisplayListBuilder::CancelGroup(const bool aDiscard) { + if (!mDisplayItemCache || !mCurrentCacheSlot) { + return; + } + + wr_dp_cancel_item_group(mWrState, aDiscard); + mCurrentCacheSlot = Nothing(); +} + +void DisplayListBuilder::FinishGroup() { + if (!mDisplayItemCache || !mCurrentCacheSlot) { + return; + } + + MOZ_ASSERT(mCurrentCacheSlot); + + if (wr_dp_finish_item_group(mWrState, mCurrentCacheSlot.ref())) { + mDisplayItemCache->MarkSlotOccupied(mCurrentCacheSlot.ref(), + CurrentSpaceAndClipChain()); + mDisplayItemCache->Stats().AddCached(); + } + + mCurrentCacheSlot = Nothing(); +} + +bool DisplayListBuilder::ReuseItem(nsPaintedDisplayItem* aItem) { + if (!mDisplayItemCache) { + return false; + } + + mDisplayItemCache->Stats().AddTotal(); + + if (mDisplayItemCache->IsEmpty()) { + return false; + } + + Maybe<uint16_t> slot = + mDisplayItemCache->CanReuseItem(aItem, CurrentSpaceAndClipChain()); + + if (slot) { + mDisplayItemCache->Stats().AddReused(); + wr_dp_push_reuse_items(mWrState, slot.ref()); + return true; + } + + return false; +} + +Maybe<layers::ScrollableLayerGuid::ViewID> +DisplayListBuilder::GetContainingFixedPosScrollTarget( + const ActiveScrolledRoot* aAsr) { + return mActiveFixedPosTracker + ? mActiveFixedPosTracker->GetScrollTargetForASR(aAsr) + : Nothing(); +} + +Maybe<SideBits> DisplayListBuilder::GetContainingFixedPosSideBits( + const ActiveScrolledRoot* aAsr) { + return mActiveFixedPosTracker + ? mActiveFixedPosTracker->GetSideBitsForASR(aAsr) + : Nothing(); +} + +DisplayListBuilder::FixedPosScrollTargetTracker::FixedPosScrollTargetTracker( + DisplayListBuilder& aBuilder, const ActiveScrolledRoot* aAsr, + layers::ScrollableLayerGuid::ViewID aScrollId, SideBits aSideBits) + : mParentTracker(aBuilder.mActiveFixedPosTracker), + mBuilder(aBuilder), + mAsr(aAsr), + mScrollId(aScrollId), + mSideBits(aSideBits) { + aBuilder.mActiveFixedPosTracker = this; +} + +DisplayListBuilder::FixedPosScrollTargetTracker:: + ~FixedPosScrollTargetTracker() { + mBuilder.mActiveFixedPosTracker = mParentTracker; +} + +Maybe<layers::ScrollableLayerGuid::ViewID> +DisplayListBuilder::FixedPosScrollTargetTracker::GetScrollTargetForASR( + const ActiveScrolledRoot* aAsr) { + return aAsr == mAsr ? Some(mScrollId) : Nothing(); +} + +Maybe<SideBits> +DisplayListBuilder::FixedPosScrollTargetTracker::GetSideBitsForASR( + const ActiveScrolledRoot* aAsr) { + return aAsr == mAsr ? Some(mSideBits) : Nothing(); +} + +gfxContext* DisplayListBuilder::GetTextContext( + wr::IpcResourceUpdateQueue& aResources, + const layers::StackingContextHelper& aSc, + layers::RenderRootStateManager* aManager, nsDisplayItem* aItem, + nsRect& aBounds, const gfx::Point& aDeviceOffset) { + if (!mCachedTextDT) { + mCachedTextDT = new layout::TextDrawTarget(*this, aResources, aSc, aManager, + aItem, aBounds); + if (mCachedTextDT->IsValid()) { + mCachedContext = MakeUnique<gfxContext>(mCachedTextDT, aDeviceOffset); + } + } else { + mCachedTextDT->Reinitialize(aResources, aSc, aManager, aItem, aBounds); + mCachedContext->SetDeviceOffset(aDeviceOffset); + mCachedContext->SetMatrix(gfx::Matrix()); + } + + return mCachedContext.get(); +} + +void DisplayListBuilder::PushInheritedClipChain( + nsDisplayListBuilder* aBuilder, const DisplayItemClipChain* aClipChain) { + if (!aClipChain || mInheritedClipChain == aClipChain) { + return; + } + if (!mInheritedClipChain) { + mInheritedClipChain = aClipChain; + return; + } + + mInheritedClipChain = + aBuilder->CreateClipChainIntersection(mInheritedClipChain, aClipChain); +} + +} // namespace wr +} // namespace mozilla + +extern "C" { + +void wr_transaction_notification_notified(uintptr_t aHandler, + mozilla::wr::Checkpoint aWhen) { + auto handler = reinterpret_cast<mozilla::wr::NotificationHandler*>(aHandler); + handler->Notify(aWhen); + // TODO: it would be better to get a callback when the object is destroyed on + // the rust side and delete then. + delete handler; +} + +void wr_register_thread_local_arena() { +#ifdef MOZ_MEMORY + jemalloc_thread_local_arena(true); +#endif +} + +} // extern C |