|  | /* | 
|  | * 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 <memory> | 
|  | #include <variant> | 
|  |  | 
|  | 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<skiapipeline::SkiaDisplayList> 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<void(RenderNode*)> updateFn) { | 
|  | mImpl->updateChildren(std::move(updateFn)); | 
|  | } | 
|  |  | 
|  | void visit(std::function<void(const RenderNode&)> func) const { mImpl->visit(std::move(func)); } | 
|  |  | 
|  | [[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<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> 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(); | 
|  | } | 
|  |  | 
|  | [[nodiscard]] bool hasFill() const { return mImpl && mImpl->hasFill(); } | 
|  |  | 
|  | void applyColorTransform(ColorTransform transform) { | 
|  | if (mImpl) { | 
|  | mImpl->applyColorTransform(transform); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::unique_ptr<skiapipeline::SkiaDisplayList> 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<void(RenderNode*)> 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<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { | 
|  | return false; | 
|  | } | 
|  | void syncContents(const WebViewSyncData& data) { } | 
|  | void onRemovedFromTree() { } | 
|  | void applyColorTransform(ColorTransform transform) { } | 
|  | }; | 
|  |  | 
|  | std::variant<EmptyList, std::unique_ptr<SkiaDisplayList>, CanvasOpBuffer> mImpls; | 
|  |  | 
|  | template <typename T> | 
|  | static constexpr T& get(T& t) { return t; } | 
|  | template <typename T> | 
|  | static constexpr const T& get(const T& t) { return t; } | 
|  |  | 
|  | template <typename T> | 
|  | static constexpr T& get(std::unique_ptr<T>& t) { return *t; } | 
|  | template <typename T> | 
|  | static constexpr const T& get(const std::unique_ptr<T>& t) { return *t; } | 
|  |  | 
|  | template <typename T> | 
|  | auto apply(T&& t) { | 
|  | return std::visit([&t](auto& it) -> auto { | 
|  | return t(get(it)); | 
|  | }, mImpls); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | 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<SkiaDisplayList> 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<void(RenderNode*)> 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<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> 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<CanvasOpBuffer>(mImpls); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // For now stick to the original single-type container to avoid any regressions | 
|  | using DisplayList = SkiaDisplayListWrapper; | 
|  |  | 
|  | }  // namespace uirenderer | 
|  | }  // namespace android |