/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "pipeline/skia/SkiaDisplayList.h" #include "canvas/CanvasOpBuffer.h" #include #include namespace android { namespace uirenderer { namespace VectorDrawable { class Tree; }; typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; class SkiaDisplayListWrapper { public: // Constructs an empty (invalid) DisplayList explicit SkiaDisplayListWrapper() {} // Constructs a DisplayList from a SkiaDisplayList explicit SkiaDisplayListWrapper(std::unique_ptr impl) : mImpl(std::move(impl)) {} // Move support SkiaDisplayListWrapper(SkiaDisplayListWrapper&& other) : mImpl(std::move(other.mImpl)) {} SkiaDisplayListWrapper& operator=(SkiaDisplayListWrapper&& other) { mImpl = std::move(other.mImpl); return *this; } // No copy support SkiaDisplayListWrapper(const SkiaDisplayListWrapper& other) = delete; SkiaDisplayListWrapper& operator=(const SkiaDisplayListWrapper&) = delete; void updateChildren(std::function updateFn) { mImpl->updateChildren(std::move(updateFn)); } [[nodiscard]] explicit operator bool() const { return mImpl.get() != nullptr; } // If true this DisplayList contains a backing content, even if that content is empty // If false, there this DisplayList is in an "empty" state [[nodiscard]] bool isValid() const { return mImpl.get() != nullptr; } [[nodiscard]] bool isEmpty() const { return !hasContent(); } [[nodiscard]] bool hasContent() const { return mImpl && !(mImpl->isEmpty()); } [[nodiscard]] bool hasHolePunches() const { return mImpl && mImpl->hasHolePunches(); } [[nodiscard]] bool containsProjectionReceiver() const { return mImpl && mImpl->containsProjectionReceiver(); } [[nodiscard]] skiapipeline::SkiaDisplayList* asSkiaDl() { return mImpl.get(); } [[nodiscard]] const skiapipeline::SkiaDisplayList* asSkiaDl() const { return mImpl.get(); } [[nodiscard]] bool hasVectorDrawables() const { return mImpl && mImpl->hasVectorDrawables(); } void clear(RenderNode* owningNode = nullptr) { if (mImpl && owningNode && mImpl->reuseDisplayList(owningNode)) { // TODO: This is a bit sketchy to have a unique_ptr temporarily owned twice // Do something to cleanup reuseDisplayList passing itself to the RenderNode mImpl.release(); } else { mImpl = nullptr; } } [[nodiscard]] size_t getUsedSize() const { return mImpl ? mImpl->getUsedSize() : 0; } [[nodiscard]] size_t getAllocatedSize() const { return mImpl ? mImpl->getAllocatedSize() : 0; } void output(std::ostream& output, uint32_t level) const { if (mImpl) { mImpl->output(output, level); } } [[nodiscard]] bool hasFunctor() const { return mImpl && mImpl->hasFunctor(); } bool prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, std::function childFn) { return mImpl && mImpl->prepareListAndChildren( observer, info, functorsNeedLayer, std::move(childFn)); } void syncContents(const WebViewSyncData& data) { if (mImpl) { mImpl->syncContents(data); } } void onRemovedFromTree() { if (mImpl) { mImpl->onRemovedFromTree(); } } [[nodiscard]] bool hasText() const { return mImpl && mImpl->hasText(); } void applyColorTransform(ColorTransform transform) { if (mImpl) { mImpl->applyColorTransform(transform); } } private: std::unique_ptr mImpl; }; /** * Data structure that holds the list of commands used in display list stream */ //using DisplayList = skiapipeline::SkiaDisplayList; class MultiDisplayList { private: using SkiaDisplayList = skiapipeline::SkiaDisplayList; struct EmptyList { bool hasText() const { return false; } void updateChildren(std::function updateFn) {} bool isEmpty() const { return true; } bool containsProjectionReceiver() const { return false; } bool hasVectorDrawables() const { return false; } size_t getUsedSize() const { return 0; } size_t getAllocatedSize() const { return 0; } void output(std::ostream& output, uint32_t level) const { } bool hasFunctor() const { return false; } bool prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, std::function childFn) { return false; } void syncContents(const WebViewSyncData& data) { } void onRemovedFromTree() { } void applyColorTransform(ColorTransform transform) { } }; std::variant, CanvasOpBuffer> mImpls; template static constexpr T& get(T& t) { return t; } template static constexpr const T& get(const T& t) { return t; } template static constexpr T& get(std::unique_ptr& t) { return *t; } template static constexpr const T& get(const std::unique_ptr& t) { return *t; } template auto apply(T&& t) { return std::visit([&t](auto& it) -> auto { return t(get(it)); }, mImpls); } template auto apply(T&& t) const { return std::visit([&t](const auto& it) -> auto { return t(get(it)); }, mImpls); } public: // Constructs an empty (invalid) DisplayList explicit MultiDisplayList() {} // Constructs a DisplayList from a SkiaDisplayList explicit MultiDisplayList(std::unique_ptr impl) : mImpls(std::move(impl)) {} explicit MultiDisplayList(CanvasOpBuffer&& opBuffer) : mImpls(std::move(opBuffer)) {} // Move support MultiDisplayList(MultiDisplayList&& other) : mImpls(std::move(other.mImpls)) {} MultiDisplayList& operator=(MultiDisplayList&& other) { mImpls = std::move(other.mImpls); return *this; } // No copy support MultiDisplayList(const MultiDisplayList& other) = delete; MultiDisplayList& operator=(const MultiDisplayList&) = delete; void updateChildren(std::function updateFn) { apply([&](auto& it) { it.updateChildren(std::move(updateFn)); }); } [[nodiscard]] explicit operator bool() const { return isValid(); } // If true this DisplayList contains a backing content, even if that content is empty // If false, there this DisplayList is in an "empty" state [[nodiscard]] bool isValid() const { return mImpls.index() != 0; } [[nodiscard]] bool isEmpty() const { return apply([](const auto& it) -> auto { return it.isEmpty(); }); } [[nodiscard]] bool hasContent() const { return !isEmpty(); } [[nodiscard]] bool containsProjectionReceiver() const { return apply([](const auto& it) -> auto { return it.containsProjectionReceiver(); }); } [[nodiscard]] SkiaDisplayList* asSkiaDl() { return std::get<1>(mImpls).get(); } [[nodiscard]] const SkiaDisplayList* asSkiaDl() const { return std::get<1>(mImpls).get(); } [[nodiscard]] bool hasVectorDrawables() const { return apply([](const auto& it) -> auto { return it.hasVectorDrawables(); }); } void clear(RenderNode* owningNode = nullptr) { if (owningNode && mImpls.index() == 1) { auto& skiaDl = std::get<1>(mImpls); if (skiaDl->reuseDisplayList(owningNode)) { skiaDl.release(); } } mImpls = EmptyList{}; } [[nodiscard]] size_t getUsedSize() const { return apply([](const auto& it) -> auto { return it.getUsedSize(); }); } [[nodiscard]] size_t getAllocatedSize() const { return apply([](const auto& it) -> auto { return it.getAllocatedSize(); }); } void output(std::ostream& output, uint32_t level) const { apply([&](const auto& it) { it.output(output, level); }); } [[nodiscard]] bool hasFunctor() const { return apply([](const auto& it) -> auto { return it.hasFunctor(); }); } bool prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, std::function childFn) { return apply([&](auto& it) -> auto { return it.prepareListAndChildren(observer, info, functorsNeedLayer, std::move(childFn)); }); } void syncContents(const WebViewSyncData& data) { apply([&](auto& it) { it.syncContents(data); }); } void onRemovedFromTree() { apply([&](auto& it) { it.onRemovedFromTree(); }); } [[nodiscard]] bool hasText() const { return apply([](const auto& it) -> auto { return it.hasText(); }); } void applyColorTransform(ColorTransform transform) { apply([=](auto& it) { it.applyColorTransform(transform); }); } [[nodiscard]] CanvasOpBuffer& asOpBuffer() { return std::get(mImpls); } }; // For now stick to the original single-type container to avoid any regressions using DisplayList = SkiaDisplayListWrapper; } // namespace uirenderer } // namespace android