From f3102cd6a844371dce7553d839066f70c215caf6 Mon Sep 17 00:00:00 2001 From: Hparty <420024556@qq.com> Date: Wed, 30 Oct 2024 19:56:22 +0800 Subject: [PATCH] Add LayerProperty class to manage layer properties and notify updates. --- include/tgfx/core/Surface.h | 9 ++-- include/tgfx/layers/Layer.h | 14 ++++-- include/tgfx/layers/LayerProperty.h | 50 +++++++++++++++++++ include/tgfx/layers/PathProvider.h | 17 +------ include/tgfx/layers/ShapeStyle.h | 15 +----- include/tgfx/layers/filters/LayerFilter.h | 19 +------ src/gpu/OpContext.cpp | 2 +- src/layers/Gradient.cpp | 2 +- src/layers/Layer.cpp | 14 +++++- .../{ShapeStyle.cpp => LayerProperty.cpp} | 20 ++++---- src/layers/PathProvider.cpp | 24 --------- src/layers/ShapeLayer.cpp | 24 +++------ src/layers/filters/LayerFilter.cpp | 23 --------- 13 files changed, 103 insertions(+), 130 deletions(-) create mode 100644 include/tgfx/layers/LayerProperty.h rename src/layers/{ShapeStyle.cpp => LayerProperty.cpp} (75%) diff --git a/include/tgfx/core/Surface.h b/include/tgfx/core/Surface.h index 47efd89..7c07000 100644 --- a/include/tgfx/core/Surface.h +++ b/include/tgfx/core/Surface.h @@ -168,13 +168,13 @@ class Surface { */ bool readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX = 0, int srcY = 0); + private: /** - * Returns the version of the content. The version is changed when the content is changed. - * The initial version is 1; - */ + * Returns the version of the content. The version is changed when the content is changed. + * The initial version is 1; + */ uint32_t contentVersion() const; - private: std::shared_ptr renderTargetProxy = nullptr; uint32_t _renderFlags = 0; RenderContext* renderContext = nullptr; @@ -190,5 +190,6 @@ class Surface { friend class RenderContext; friend class PictureImage; + friend class DisplayList; }; } // namespace tgfx \ No newline at end of file diff --git a/include/tgfx/layers/Layer.h b/include/tgfx/layers/Layer.h index 7a66b29..4a3947c 100644 --- a/include/tgfx/layers/Layer.h +++ b/include/tgfx/layers/Layer.h @@ -470,6 +470,16 @@ class Layer { */ virtual std::unique_ptr onUpdateContent(); + /** + * Attachs a property to this layer. + */ + void attachProperty(LayerProperty* property) const; + + /** + * Detaches a property from this layer. + */ + void detachProperty(LayerProperty* property) const; + private: /** * Marks the layer's children as changed and needing to be redrawn. @@ -528,8 +538,6 @@ class Layer { } bitFields = {}; friend class DisplayList; - friend class LayerFilter; - friend class ShapeStyle; - friend class PathProvider; + friend class LayerProperty; }; } // namespace tgfx diff --git a/include/tgfx/layers/LayerProperty.h b/include/tgfx/layers/LayerProperty.h new file mode 100644 index 0000000..6b2186e --- /dev/null +++ b/include/tgfx/layers/LayerProperty.h @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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 + +namespace tgfx { +class Layer; + +/** + * A property of a layer that may change the content of the layer. + */ +class LayerProperty { + public: + virtual ~LayerProperty() = default; + + protected: + /** + * Mark the property as dirty and notify the layer that the content needs to be updated. + */ + void invalidate(); + + bool dirty = true; + + private: + void attachToLayer(const Layer* layer); + + void detachFromLayer(const Layer* layer); + + std::vector> owners; + + friend class Layer; +}; + +} // namespace tgfx diff --git a/include/tgfx/layers/PathProvider.h b/include/tgfx/layers/PathProvider.h index 6da531f..063d109 100644 --- a/include/tgfx/layers/PathProvider.h +++ b/include/tgfx/layers/PathProvider.h @@ -19,23 +19,21 @@ #pragma once #include "tgfx/core/Path.h" +#include "tgfx/layers/LayerProperty.h" namespace tgfx { -class Layer; /** * PathProvider is an interface for classes that generates a Path. It defers the acquisition of the * Path until it is actually required, allowing the Path to be invalidated and regenerate if * necessary. Note: PathProvider is not thread-safe and should be accessed from a single thread. */ -class PathProvider { +class PathProvider : public LayerProperty { public: /** * Creates a new PathProvider that wraps the given Path. */ static std::shared_ptr Wrap(const Path& path); - virtual ~PathProvider() = default; - /** * Returns the Path provided by this object. */ @@ -49,20 +47,9 @@ class PathProvider { */ explicit PathProvider(Path path); - /** - * Invalidates the path, causing it to be re-computed the next time it is requested. - */ - void invalidate(); - virtual Path onGeneratePath(); private: - void attachToLayer(const Layer* layer); - void detachFromLayer(const Layer* layer); - bool dirty = true; Path path = {}; - - std::vector> owners; - friend class Layer; }; } // namespace tgfx diff --git a/include/tgfx/layers/ShapeStyle.h b/include/tgfx/layers/ShapeStyle.h index 978a82a..8007188 100644 --- a/include/tgfx/layers/ShapeStyle.h +++ b/include/tgfx/layers/ShapeStyle.h @@ -19,32 +19,21 @@ #pragma once #include "tgfx/core/Shader.h" +#include "tgfx/layers/LayerProperty.h" namespace tgfx { -class Layer; /** * ShapeStyle specifies the source color(s) for what is being drawn in a shape layer. There are * three types of ShapeStyle: SolidColor, Gradient, and ImagePattern. Note: All ShapeStyle objects * are not thread-safe and should only be accessed from a single thread. */ -class ShapeStyle { - public: - virtual ~ShapeStyle() = default; - +class ShapeStyle : public LayerProperty { protected: /** * Returns the current shader that will be used to draw the shape. */ virtual std::shared_ptr getShader() const = 0; - void invalidate(); - - void attachToLayer(const Layer* layer); - - void detachFromLayer(const Layer* layer); - - std::vector> owners; - friend class ShapeLayer; }; } // namespace tgfx diff --git a/include/tgfx/layers/filters/LayerFilter.h b/include/tgfx/layers/filters/LayerFilter.h index 7250331..dbbcd97 100644 --- a/include/tgfx/layers/filters/LayerFilter.h +++ b/include/tgfx/layers/filters/LayerFilter.h @@ -19,17 +19,15 @@ #pragma once #include "tgfx/core/ImageFilter.h" +#include "tgfx/layers/LayerProperty.h" namespace tgfx { -class Layer; /** * LayerFilter represents a filter that applies effects to a layer, such as blurs, shadows, or color * adjustments. LayerFilters are mutable and can be changed at any time. */ -class LayerFilter { +class LayerFilter : public LayerProperty { public: - virtual ~LayerFilter() = default; - /** * Returns the current image filter for the given scale factor. If the filter has not been * created yet, it will be created and cached. @@ -39,11 +37,6 @@ class LayerFilter { std::shared_ptr getImageFilter(float scale); protected: - /** - * Invalidates the filter, causing it to be re-computed the next time it is requested. - */ - void invalidate(); - /** * Creates a new image filter for the given scale factor. When it is necessary to recreate the * ImageFilter, the onCreateImageFilter method will be called. @@ -53,20 +46,12 @@ class LayerFilter { virtual std::shared_ptr onCreateImageFilter(float scale) = 0; private: - void attachToLayer(const Layer* layer); - - void detachFromLayer(const Layer* layer); - - bool dirty = true; - float lastScale = 1.0f; std::unique_ptr _clipBounds = nullptr; std::shared_ptr lastFilter; - std::vector> owners; - friend class Layer; }; } // namespace tgfx diff --git a/src/gpu/OpContext.cpp b/src/gpu/OpContext.cpp index b1672b4..d83edf0 100644 --- a/src/gpu/OpContext.cpp +++ b/src/gpu/OpContext.cpp @@ -46,8 +46,8 @@ void OpContext::addOp(std::unique_ptr op) { if (opsTask == nullptr || opsTask->isClosed()) { auto drawingManager = renderTargetProxy->getContext()->drawingManager(); opsTask = drawingManager->addOpsTask(renderTargetProxy); + _contentVersion++; } opsTask->addOp(std::move(op)); - _contentVersion++; } } // namespace tgfx diff --git a/src/layers/Gradient.cpp b/src/layers/Gradient.cpp index 9c555ea..b8133e1 100644 --- a/src/layers/Gradient.cpp +++ b/src/layers/Gradient.cpp @@ -17,7 +17,7 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "tgfx/layers/Gradient.h" -#include +#include "tgfx/layers/Layer.h" namespace tgfx { std::shared_ptr Gradient::MakeLinear(const Point& startPoint, diff --git a/src/layers/Layer.cpp b/src/layers/Layer.cpp index 8820513..76391fe 100644 --- a/src/layers/Layer.cpp +++ b/src/layers/Layer.cpp @@ -53,7 +53,7 @@ std::shared_ptr Layer::Make() { } Layer::~Layer() { - for (auto filter : _filters) { + for (const auto& filter : _filters) { filter->detachFromLayer(this); } } @@ -394,6 +394,18 @@ std::unique_ptr Layer::onUpdateContent() { return nullptr; } +void Layer::attachProperty(LayerProperty* property) const { + if (property) { + property->attachToLayer(this); + } +} + +void Layer::detachProperty(LayerProperty* property) const { + if (property) { + property->detachFromLayer(this); + } +} + void Layer::onAttachToRoot(Layer* owner) { _root = owner; for (auto& child : _children) { diff --git a/src/layers/ShapeStyle.cpp b/src/layers/LayerProperty.cpp similarity index 75% rename from src/layers/ShapeStyle.cpp rename to src/layers/LayerProperty.cpp index 581d187..767bd4e 100644 --- a/src/layers/ShapeStyle.cpp +++ b/src/layers/LayerProperty.cpp @@ -16,27 +16,27 @@ // ///////////////////////////////////////////////////////////////////////////////////////////////// -#include "tgfx/layers/ShapeStyle.h" +#include "tgfx/layers/LayerProperty.h" #include "tgfx/layers/Layer.h" namespace tgfx { -void ShapeStyle::invalidate() { + +void LayerProperty::invalidate() { + dirty = true; for (auto& owner : owners) { - auto layer = owner.lock(); - if (layer) { + if (auto layer = owner.lock()) { layer->invalidateContent(); } } } - -void ShapeStyle::attachToLayer(const Layer* layer) { +void LayerProperty::attachToLayer(const Layer* layer) { owners.push_back(layer->weakThis); } -void ShapeStyle::detachFromLayer(const Layer* layer) { - for (auto it = owners.begin(); it != owners.end(); ++it) { - if (it->lock().get() == layer) { - owners.erase(it); +void LayerProperty::detachFromLayer(const Layer* layer) { + for (auto owner = owners.begin(); owner != owners.end(); ++owner) { + if (owner->lock().get() == layer) { + owners.erase(owner); break; } } diff --git a/src/layers/PathProvider.cpp b/src/layers/PathProvider.cpp index 21ce281..2232335 100644 --- a/src/layers/PathProvider.cpp +++ b/src/layers/PathProvider.cpp @@ -38,31 +38,7 @@ Path PathProvider::getPath() { return path; } -void PathProvider::invalidate() { - dirty = true; - for (auto& owner : owners) { - auto layer = owner.lock(); - if (layer) { - layer->invalidateContent(); - } - } -} - Path PathProvider::onGeneratePath() { return path; } - -void PathProvider::attachToLayer(const Layer* layer) { - owners.push_back(layer->weakThis); -} - -void PathProvider::detachFromLayer(const Layer* layer) { - for (auto it = owners.begin(); it != owners.end(); ++it) { - if (it->lock().get() == layer) { - owners.erase(it); - break; - } - } -} - } // namespace tgfx diff --git a/src/layers/ShapeLayer.cpp b/src/layers/ShapeLayer.cpp index 4a539c1..bdd62bf 100644 --- a/src/layers/ShapeLayer.cpp +++ b/src/layers/ShapeLayer.cpp @@ -50,13 +50,9 @@ void ShapeLayer::setFillStyle(std::shared_ptr style) { if (_fillStyle == style) { return; } - if (_fillStyle) { - _fillStyle->detachFromLayer(this); - } + detachProperty(_fillStyle.get()); _fillStyle = std::move(style); - if (_fillStyle) { - _fillStyle->attachToLayer(this); - } + attachProperty(_fillStyle.get()); invalidateContent(); } @@ -64,13 +60,9 @@ void ShapeLayer::setStrokeStyle(std::shared_ptr style) { if (_strokeStyle == style) { return; } - if (_strokeStyle) { - _strokeStyle->detachFromLayer(this); - } + detachProperty(_strokeStyle.get()); _strokeStyle = std::move(style); - if (_strokeStyle) { - _strokeStyle->attachToLayer(this); - } + attachProperty(_strokeStyle.get()); invalidateContent(); } @@ -152,12 +144,8 @@ void ShapeLayer::setStrokeEnd(float end) { } ShapeLayer::~ShapeLayer() { - if (_strokeStyle) { - _strokeStyle->detachFromLayer(this); - } - if (_fillStyle) { - _fillStyle->detachFromLayer(this); - } + detachProperty(_strokeStyle.get()); + detachProperty(_fillStyle.get()); } std::unique_ptr ShapeLayer::onUpdateContent() { diff --git a/src/layers/filters/LayerFilter.cpp b/src/layers/filters/LayerFilter.cpp index 6804b7d..924efda 100644 --- a/src/layers/filters/LayerFilter.cpp +++ b/src/layers/filters/LayerFilter.cpp @@ -20,16 +20,6 @@ #include "tgfx/layers/Layer.h" namespace tgfx { -void LayerFilter::invalidate() { - dirty = true; - for (auto& owner : owners) { - auto layer = owner.lock(); - if (layer) { - layer->invalidateContent(); - } - } -} - std::shared_ptr LayerFilter::getImageFilter(float filterScale) { if (dirty || lastScale != filterScale) { lastFilter = onCreateImageFilter(filterScale); @@ -39,17 +29,4 @@ std::shared_ptr LayerFilter::getImageFilter(float filterScale) { return lastFilter; } -void LayerFilter::attachToLayer(const Layer* layer) { - owners.push_back(layer->weakThis); -} - -void LayerFilter::detachFromLayer(const Layer* layer) { - for (auto it = owners.begin(); it != owners.end(); ++it) { - if (it->lock().get() == layer) { - owners.erase(it); - break; - } - } -} - } // namespace tgfx \ No newline at end of file