don’t defer updates when a shape/path is used for hit detect Fixes issue reported by Duolingo. https://2dimensions.slack.com/archives/C029X99PETE/p1717700429867579 Diffs= a10b1e61e don’t defer updates when a shape/path is used for hit detect (#7392) Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com> Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head index 8bafa52..de25b58 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -8486c344528d5f7f84de1984510064a7d0788e73 +a10b1e61edfd5a5d01801f78d9ee76a064c9c7ce
diff --git a/include/rive/animation/state_machine_listener.hpp b/include/rive/animation/state_machine_listener.hpp index 244eb27..2867188 100644 --- a/include/rive/animation/state_machine_listener.hpp +++ b/include/rive/animation/state_machine_listener.hpp
@@ -14,26 +14,23 @@ { friend class StateMachineListenerImporter; -private: - std::vector<uint32_t> m_HitShapesIds; - std::vector<std::unique_ptr<ListenerAction>> m_Actions; - void addAction(std::unique_ptr<ListenerAction>); - public: StateMachineListener(); ~StateMachineListener() override; ListenerType listenerType() const { return (ListenerType)listenerTypeValue(); } - size_t actionCount() const { return m_Actions.size(); } + size_t actionCount() const { return m_actions.size(); } const ListenerAction* action(size_t index) const; StatusCode import(ImportStack& importStack) override; - StatusCode onAddedClean(CoreContext* context) override; - const std::vector<uint32_t>& hitShapeIds() const { return m_HitShapesIds; } void performChanges(StateMachineInstance* stateMachineInstance, Vec2D position, Vec2D previousPosition) const; + +private: + void addAction(std::unique_ptr<ListenerAction>); + std::vector<std::unique_ptr<ListenerAction>> m_actions; }; } // namespace rive
diff --git a/include/rive/component.hpp b/include/rive/component.hpp index 0aee6ee..7c26099 100644 --- a/include/rive/component.hpp +++ b/include/rive/component.hpp
@@ -4,6 +4,7 @@ #include "rive/generated/component_base.hpp" #include <vector> +#include <functional> namespace rive { @@ -55,6 +56,8 @@ { return (m_Dirt & ComponentDirt::Collapsed) == ComponentDirt::Collapsed; } + + virtual bool forAll(std::function<bool(Component*)> predicate); }; } // namespace rive
diff --git a/include/rive/container_component.hpp b/include/rive/container_component.hpp index f187926..e340a17 100644 --- a/include/rive/container_component.hpp +++ b/include/rive/container_component.hpp
@@ -2,17 +2,23 @@ #define _RIVE_CONTAINER_COMPONENT_HPP_ #include "rive/generated/container_component_base.hpp" #include <vector> +#include <functional> + namespace rive { class ContainerComponent : public ContainerComponentBase { -private: - std::vector<Component*> m_children; - public: const std::vector<Component*>& children() const { return m_children; } virtual void addChild(Component* component); bool collapse(bool value) override; + + // Returns true if it searched through all of its children. predicate can + // return false to stop searching. + bool forAll(std::function<bool(Component*)> predicate) override; + +private: + std::vector<Component*> m_children; }; } // namespace rive
diff --git a/include/rive/shapes/paint/fill.hpp b/include/rive/shapes/paint/fill.hpp index 97291e6..a9a0a64 100644 --- a/include/rive/shapes/paint/fill.hpp +++ b/include/rive/shapes/paint/fill.hpp
@@ -1,14 +1,14 @@ #ifndef _RIVE_FILL_HPP_ #define _RIVE_FILL_HPP_ #include "rive/generated/shapes/paint/fill_base.hpp" -#include "rive/shapes/path_space.hpp" +#include "rive/shapes/path_flags.hpp" namespace rive { class Fill : public FillBase { public: RenderPaint* initRenderPaint(ShapePaintMutator* mutator) override; - PathSpace pathSpace() const override; + PathFlags pathFlags() const override; void draw(Renderer* renderer, CommandPath* path, const RawPath* rawPath,
diff --git a/include/rive/shapes/paint/shape_paint.hpp b/include/rive/shapes/paint/shape_paint.hpp index 388fb13..67e9660 100644 --- a/include/rive/shapes/paint/shape_paint.hpp +++ b/include/rive/shapes/paint/shape_paint.hpp
@@ -4,7 +4,7 @@ #include "rive/renderer.hpp" #include "rive/shapes/paint/blend_mode.hpp" #include "rive/shapes/paint/shape_paint_mutator.hpp" -#include "rive/shapes/path_space.hpp" +#include "rive/shapes/path_flags.hpp" #include "rive/math/raw_path.hpp" namespace rive @@ -30,7 +30,8 @@ /// lifecycle of the RenderPaint. virtual RenderPaint* initRenderPaint(ShapePaintMutator* mutator); - virtual PathSpace pathSpace() const = 0; + virtual PathFlags pathFlags() const = 0; + bool isFlagged(PathFlags flags) const { return (int)(pathFlags() & flags) != 0x00; } void draw(Renderer* renderer, CommandPath* path, const RawPath* rawPath = nullptr) {
diff --git a/include/rive/shapes/paint/stroke.hpp b/include/rive/shapes/paint/stroke.hpp index 7663669..99a7a0a 100644 --- a/include/rive/shapes/paint/stroke.hpp +++ b/include/rive/shapes/paint/stroke.hpp
@@ -1,7 +1,7 @@ #ifndef _RIVE_STROKE_HPP_ #define _RIVE_STROKE_HPP_ #include "rive/generated/shapes/paint/stroke_base.hpp" -#include "rive/shapes/path_space.hpp" +#include "rive/shapes/path_flags.hpp" namespace rive { class StrokeEffect; @@ -12,7 +12,7 @@ public: RenderPaint* initRenderPaint(ShapePaintMutator* mutator) override; - PathSpace pathSpace() const override; + PathFlags pathFlags() const override; void draw(Renderer* renderer, CommandPath* path, const RawPath* rawPath,
diff --git a/include/rive/shapes/path.hpp b/include/rive/shapes/path.hpp index d5ba979..59cc59b 100644 --- a/include/rive/shapes/path.hpp +++ b/include/rive/shapes/path.hpp
@@ -40,7 +40,7 @@ Shape* m_Shape = nullptr; std::vector<PathVertex*> m_Vertices; bool m_deferredPathDirt = false; - PathSpace m_DefaultPathSpace = PathSpace::Neither; + PathFlags m_pathFlags = PathFlags::none; RawPath m_rawPath; public: @@ -52,7 +52,9 @@ const RawPath& rawPath() const { return m_rawPath; } void update(ComponentDirt value) override; - void addDefaultPathSpace(PathSpace space); + void addFlags(PathFlags flags); + bool isFlagged(PathFlags flags) const; + bool canDeferPathUpdate(); void addVertex(PathVertex* vertex);
diff --git a/include/rive/shapes/path_flags.hpp b/include/rive/shapes/path_flags.hpp new file mode 100644 index 0000000..172ed42 --- /dev/null +++ b/include/rive/shapes/path_flags.hpp
@@ -0,0 +1,66 @@ +#ifndef _RIVE_PATH_FLAGS_HPP_ +#define _RIVE_PATH_FLAGS_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +enum class PathFlags : uint8_t +{ + none = 0, + local = 1 << 1, + world = 1 << 2, + clipping = 1 << 3, + followPath = 1 << 4, + neverDeferUpdate = 1 << 5, +}; + +inline constexpr PathFlags operator&(PathFlags lhs, PathFlags rhs) +{ + return static_cast<PathFlags>(static_cast<std::underlying_type<PathFlags>::type>(lhs) & + static_cast<std::underlying_type<PathFlags>::type>(rhs)); +} + +inline constexpr PathFlags operator^(PathFlags lhs, PathFlags rhs) +{ + return static_cast<PathFlags>(static_cast<std::underlying_type<PathFlags>::type>(lhs) ^ + static_cast<std::underlying_type<PathFlags>::type>(rhs)); +} + +inline constexpr PathFlags operator|(PathFlags lhs, PathFlags rhs) +{ + return static_cast<PathFlags>(static_cast<std::underlying_type<PathFlags>::type>(lhs) | + static_cast<std::underlying_type<PathFlags>::type>(rhs)); +} + +inline constexpr PathFlags operator~(PathFlags rhs) +{ + return static_cast<PathFlags>(~static_cast<std::underlying_type<PathFlags>::type>(rhs)); +} + +inline PathFlags& operator|=(PathFlags& lhs, PathFlags rhs) +{ + lhs = static_cast<PathFlags>(static_cast<std::underlying_type<PathFlags>::type>(lhs) | + static_cast<std::underlying_type<PathFlags>::type>(rhs)); + + return lhs; +} + +inline PathFlags& operator&=(PathFlags& lhs, PathFlags rhs) +{ + lhs = static_cast<PathFlags>(static_cast<std::underlying_type<PathFlags>::type>(lhs) & + static_cast<std::underlying_type<PathFlags>::type>(rhs)); + + return lhs; +} + +inline PathFlags& operator^=(PathFlags& lhs, PathFlags rhs) +{ + lhs = static_cast<PathFlags>(static_cast<std::underlying_type<PathFlags>::type>(lhs) ^ + static_cast<std::underlying_type<PathFlags>::type>(rhs)); + + return lhs; +} +} // namespace rive + +#endif
diff --git a/include/rive/shapes/path_space.hpp b/include/rive/shapes/path_space.hpp deleted file mode 100644 index d44e5c7..0000000 --- a/include/rive/shapes/path_space.hpp +++ /dev/null
@@ -1,65 +0,0 @@ -#ifndef _RIVE_PATH_SPACE_HPP_ -#define _RIVE_PATH_SPACE_HPP_ - -#include "rive/rive_types.hpp" - -namespace rive -{ -enum class PathSpace : unsigned char -{ - Neither = 0, - Local = 1 << 1, - World = 1 << 2, - Clipping = 1 << 3, - FollowPath = 1 << 4 -}; - -inline constexpr PathSpace operator&(PathSpace lhs, PathSpace rhs) -{ - return static_cast<PathSpace>(static_cast<std::underlying_type<PathSpace>::type>(lhs) & - static_cast<std::underlying_type<PathSpace>::type>(rhs)); -} - -inline constexpr PathSpace operator^(PathSpace lhs, PathSpace rhs) -{ - return static_cast<PathSpace>(static_cast<std::underlying_type<PathSpace>::type>(lhs) ^ - static_cast<std::underlying_type<PathSpace>::type>(rhs)); -} - -inline constexpr PathSpace operator|(PathSpace lhs, PathSpace rhs) -{ - return static_cast<PathSpace>(static_cast<std::underlying_type<PathSpace>::type>(lhs) | - static_cast<std::underlying_type<PathSpace>::type>(rhs)); -} - -inline constexpr PathSpace operator~(PathSpace rhs) -{ - return static_cast<PathSpace>(~static_cast<std::underlying_type<PathSpace>::type>(rhs)); -} - -inline PathSpace& operator|=(PathSpace& lhs, PathSpace rhs) -{ - lhs = static_cast<PathSpace>(static_cast<std::underlying_type<PathSpace>::type>(lhs) | - static_cast<std::underlying_type<PathSpace>::type>(rhs)); - - return lhs; -} - -inline PathSpace& operator&=(PathSpace& lhs, PathSpace rhs) -{ - lhs = static_cast<PathSpace>(static_cast<std::underlying_type<PathSpace>::type>(lhs) & - static_cast<std::underlying_type<PathSpace>::type>(rhs)); - - return lhs; -} - -inline PathSpace& operator^=(PathSpace& lhs, PathSpace rhs) -{ - lhs = static_cast<PathSpace>(static_cast<std::underlying_type<PathSpace>::type>(lhs) ^ - static_cast<std::underlying_type<PathSpace>::type>(rhs)); - - return lhs; -} -} // namespace rive - -#endif
diff --git a/include/rive/shapes/shape.hpp b/include/rive/shapes/shape.hpp index 587d4aa..e55f794 100644 --- a/include/rive/shapes/shape.hpp +++ b/include/rive/shapes/shape.hpp
@@ -44,7 +44,8 @@ PathComposer* pathComposer() { return &m_PathComposer; } void pathChanged(); - void addDefaultPathSpace(PathSpace space); + void addFlags(PathFlags flags); + bool isFlagged(PathFlags flags) const; StatusCode onAddedDirty(CoreContext* context) override; bool isEmpty(); void pathCollapseChanged();
diff --git a/include/rive/shapes/shape_paint_container.hpp b/include/rive/shapes/shape_paint_container.hpp index 7ba4d76..8d394ce 100644 --- a/include/rive/shapes/shape_paint_container.hpp +++ b/include/rive/shapes/shape_paint_container.hpp
@@ -1,7 +1,7 @@ #ifndef _RIVE_SHAPE_PAINT_CONTAINER_HPP_ #define _RIVE_SHAPE_PAINT_CONTAINER_HPP_ #include "rive/refcnt.hpp" -#include "rive/shapes/path_space.hpp" +#include "rive/shapes/path_flags.hpp" #include <vector> namespace rive @@ -21,7 +21,7 @@ // as a Shape or Artboard, so both of those will override this. virtual Artboard* getArtboard() = 0; - PathSpace m_DefaultPathSpace = PathSpace::Neither; + PathFlags m_pathFlags = PathFlags::none; std::vector<ShapePaint*> m_ShapePaints; void addPaint(ShapePaint* paint); @@ -31,7 +31,7 @@ virtual ~ShapePaintContainer() {} - PathSpace pathSpace() const; + PathFlags pathFlags() const; void invalidateStrokeEffects();
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp index dd3f785..11225a1 100644 --- a/src/animation/state_machine_instance.cpp +++ b/src/animation/state_machine_instance.cpp
@@ -631,37 +631,33 @@ // Initialize listeners. Store a lookup table of shape id to hit shape // representation (an object that stores all the listeners triggered by the // shape producing a listener). - std::unordered_map<uint32_t, HitShape*> hitShapeLookup; + std::unordered_map<Component*, HitShape*> hitShapeLookup; for (std::size_t i = 0; i < machine->listenerCount(); i++) { auto listener = machine->listener(i); - - // Iterate actual leaf hittable shapes tied to this listener and resolve - // corresponding ones in the artboard instance. - for (auto id : listener->hitShapeIds()) + auto target = m_artboardInstance->resolve(listener->targetId()); + if (target != nullptr && target->is<Component>()) { - HitShape* hitShape; - auto itr = hitShapeLookup.find(id); - if (itr == hitShapeLookup.end()) - { - auto shape = m_artboardInstance->resolve(id); - if (shape != nullptr && shape->is<Shape>()) + target->as<Component>()->forAll([&](Component* component) { + if (component->is<Shape>()) { - auto hs = rivestd::make_unique<HitShape>(shape->as<Component>(), this); - hitShapeLookup[id] = hitShape = hs.get(); - m_hitComponents.push_back(std::move(hs)); + HitShape* hitShape; + auto itr = hitShapeLookup.find(component); + if (itr == hitShapeLookup.end()) + { + component->as<Shape>()->addFlags(PathFlags::neverDeferUpdate); + auto hs = rivestd::make_unique<HitShape>(component, this); + hitShapeLookup[component] = hitShape = hs.get(); + m_hitComponents.push_back(std::move(hs)); + } + else + { + hitShape = itr->second; + } + hitShape->listeners.push_back(listener); } - else - { - // No object or not a shape... - continue; - } - } - else - { - hitShape = itr->second; - } - hitShape->listeners.push_back(listener); + return true; + }); } } @@ -669,7 +665,6 @@ { if (nestedArtboard->hasNestedStateMachines()) { - auto hn = rivestd::make_unique<HitNestedArtboard>(nestedArtboard->as<Component>(), this); m_hitComponents.push_back(std::move(hn));
diff --git a/src/animation/state_machine_listener.cpp b/src/animation/state_machine_listener.cpp index f943f82..7abf521 100644 --- a/src/animation/state_machine_listener.cpp +++ b/src/animation/state_machine_listener.cpp
@@ -14,7 +14,7 @@ void StateMachineListener::addAction(std::unique_ptr<ListenerAction> action) { - m_Actions.push_back(std::move(action)); + m_actions.push_back(std::move(action)); } StatusCode StateMachineListener::import(ImportStack& importStack) @@ -31,54 +31,18 @@ const ListenerAction* StateMachineListener::action(size_t index) const { - if (index < m_Actions.size()) + if (index < m_actions.size()) { - return m_Actions[index].get(); + return m_actions[index].get(); } return nullptr; } -StatusCode StateMachineListener::onAddedClean(CoreContext* context) -{ - auto artboard = static_cast<Artboard*>(context); - auto target = artboard->resolve(targetId()); - - for (auto core : artboard->objects()) - { - if (core == nullptr) - { - continue; - } - - // Iterate artboard to find Shapes that are parented to the target - if (core->is<Shape>()) - { - auto shape = core->as<Shape>(); - - for (ContainerComponent* component = shape; component != nullptr; - component = component->parent()) - { - if (component == target) - { - auto index = artboard->idOf(shape); - if (index != 0) - { - m_HitShapesIds.push_back(index); - } - break; - } - } - } - } - - return Super::onAddedClean(context); -} - void StateMachineListener::performChanges(StateMachineInstance* stateMachineInstance, Vec2D position, Vec2D previousPosition) const { - for (auto& action : m_Actions) + for (auto& action : m_actions) { action->perform(stateMachineInstance, position, previousPosition); }
diff --git a/src/component.cpp b/src/component.cpp index b68ffdf..eaf7003 100644 --- a/src/component.cpp +++ b/src/component.cpp
@@ -99,4 +99,6 @@ onDirty(m_Dirt); m_Artboard->onComponentDirty(this); return true; -} \ No newline at end of file +} + +bool Component::forAll(std::function<bool(Component*)> predicate) { return predicate(this); } \ No newline at end of file
diff --git a/src/constraints/follow_path_constraint.cpp b/src/constraints/follow_path_constraint.cpp index 199a0db..8c74d9a 100644 --- a/src/constraints/follow_path_constraint.cpp +++ b/src/constraints/follow_path_constraint.cpp
@@ -167,12 +167,12 @@ if (m_Target->is<Shape>()) { Shape* shape = static_cast<Shape*>(m_Target); - shape->addDefaultPathSpace(PathSpace::FollowPath); + shape->addFlags(PathFlags::followPath); } else if (m_Target->is<Path>()) { Path* path = static_cast<Path*>(m_Target); - path->addDefaultPathSpace(PathSpace::FollowPath); + path->addFlags(PathFlags::followPath); } } return Super::onAddedClean(context);
diff --git a/src/container_component.cpp b/src/container_component.cpp index 0a25260..af03348 100644 --- a/src/container_component.cpp +++ b/src/container_component.cpp
@@ -14,4 +14,24 @@ child->collapse(value); } return true; +} + +bool ContainerComponent::forAll(std::function<bool(Component*)> predicate) +{ + if (!Super::forAll(predicate)) + { + return false; + } + for (Component* child : m_children) + { + if (!predicate(child)) + { + return false; + } + if (child->is<ContainerComponent>() && !child->as<ContainerComponent>()->forAll(predicate)) + { + return false; + } + } + return true; } \ No newline at end of file
diff --git a/src/shapes/clipping_shape.cpp b/src/shapes/clipping_shape.cpp index cfa7f90..e795a6c 100644 --- a/src/shapes/clipping_shape.cpp +++ b/src/shapes/clipping_shape.cpp
@@ -47,7 +47,7 @@ if (component == m_Source) { auto shape = core->as<Shape>(); - shape->addDefaultPathSpace(PathSpace::World | PathSpace::Clipping); + shape->addFlags(PathFlags::world | PathFlags::clipping); m_Shapes.push_back(shape); break; }
diff --git a/src/shapes/paint/fill.cpp b/src/shapes/paint/fill.cpp index 466b61a..d0af7ef 100644 --- a/src/shapes/paint/fill.cpp +++ b/src/shapes/paint/fill.cpp
@@ -2,7 +2,7 @@ using namespace rive; -PathSpace Fill::pathSpace() const { return PathSpace::Local; } +PathFlags Fill::pathFlags() const { return PathFlags::local; } RenderPaint* Fill::initRenderPaint(ShapePaintMutator* mutator) {
diff --git a/src/shapes/paint/linear_gradient.cpp b/src/shapes/paint/linear_gradient.cpp index aa49c94..0bcc1c6 100644 --- a/src/shapes/paint/linear_gradient.cpp +++ b/src/shapes/paint/linear_gradient.cpp
@@ -84,7 +84,7 @@ ComponentDirt::Paint | ComponentDirt::RenderOpacity | ComponentDirt::Transform) || ( // paints in world space - parent()->as<ShapePaint>()->pathSpace() == PathSpace::World && + parent()->as<ShapePaint>()->isFlagged(PathFlags::world) && // and had a world transform change hasDirt(value, ComponentDirt::WorldTransform)); if (rebuildGradient) @@ -95,7 +95,7 @@ void LinearGradient::applyTo(RenderPaint* renderPaint, float opacityModifier) const { - bool paintsInWorldSpace = parent()->as<ShapePaint>()->pathSpace() == PathSpace::World; + bool paintsInWorldSpace = parent()->as<ShapePaint>()->isFlagged(PathFlags::world); Vec2D start(startX(), startY()); Vec2D end(endX(), endY()); // Check if we need to update the world space gradient (if there's no
diff --git a/src/shapes/paint/stroke.cpp b/src/shapes/paint/stroke.cpp index b0d7348..a76adae 100644 --- a/src/shapes/paint/stroke.cpp +++ b/src/shapes/paint/stroke.cpp
@@ -6,11 +6,10 @@ using namespace rive; -PathSpace Stroke::pathSpace() const +PathFlags Stroke::pathFlags() const { - return transformAffectsStroke() ? PathSpace::Local : PathSpace::World; + return transformAffectsStroke() ? PathFlags::local : PathFlags::world; } - RenderPaint* Stroke::initRenderPaint(ShapePaintMutator* mutator) { auto renderPaint = Super::initRenderPaint(mutator);
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp index cdf45aa..fd5af98 100644 --- a/src/shapes/path.cpp +++ b/src/shapes/path.cpp
@@ -51,7 +51,8 @@ void Path::addVertex(PathVertex* vertex) { m_Vertices.push_back(vertex); } -void Path::addDefaultPathSpace(PathSpace space) { m_DefaultPathSpace |= space; } +void Path::addFlags(PathFlags flags) { m_pathFlags |= flags; } +bool Path::isFlagged(PathFlags flags) const { return (int)(m_pathFlags & flags) != 0x00; } bool Path::canDeferPathUpdate() { @@ -60,10 +61,9 @@ // (meaning all child paths need to follow path). This doesn't mean the // Shape is necessarily forced to update put the paths are, which is why we // explicitly also check the shape's path space. - return m_Shape->canDeferPathUpdate() && - (m_Shape->pathSpace() & PathSpace::FollowPath) != PathSpace::FollowPath && - ((m_DefaultPathSpace & PathSpace::Clipping) != PathSpace::Clipping) && - ((m_DefaultPathSpace & PathSpace::FollowPath) != PathSpace::FollowPath); + + return m_Shape->canDeferPathUpdate() && !m_Shape->isFlagged(PathFlags::followPath) && + !isFlagged(PathFlags::followPath | PathFlags::clipping); } const Mat2D& Path::pathTransform() const { return worldTransform(); }
diff --git a/src/shapes/path_composer.cpp b/src/shapes/path_composer.cpp index 71a4c00..5efda24 100644 --- a/src/shapes/path_composer.cpp +++ b/src/shapes/path_composer.cpp
@@ -41,8 +41,7 @@ } m_deferredPathDirt = false; - auto space = m_shape->pathSpace(); - if ((space & PathSpace::Local) == PathSpace::Local) + if (m_shape->isFlagged(PathFlags::local)) { if (m_localPath == nullptr) { @@ -68,7 +67,7 @@ // TODO: add a CommandPath::copy(RawPath) m_localRawPath.addTo(m_localPath.get()); } - if ((space & PathSpace::World) == PathSpace::World) + if (m_shape->isFlagged(PathFlags::world)) { if (m_worldPath == nullptr) {
diff --git a/src/shapes/shape.cpp b/src/shapes/shape.cpp index 01310ed..6a22160 100644 --- a/src/shapes/shape.cpp +++ b/src/shapes/shape.cpp
@@ -22,10 +22,13 @@ m_Paths.push_back(path); } +void Shape::addFlags(PathFlags flags) { m_pathFlags |= flags; } +bool Shape::isFlagged(PathFlags flags) const { return (int)(pathFlags() & flags) != 0x00; } + bool Shape::canDeferPathUpdate() { auto canDefer = - renderOpacity() == 0 && (pathSpace() & PathSpace::Clipping) != PathSpace::Clipping; + renderOpacity() == 0 && !isFlagged(PathFlags::clipping | PathFlags::neverDeferUpdate); if (canDefer) { // If we have a dependent Skin, don't defer the update @@ -72,8 +75,7 @@ void Shape::addToRenderPath(RenderPath* path, const Mat2D& transform) { - auto space = pathSpace(); - if ((space & PathSpace::Local) == PathSpace::Local) + if (isFlagged(PathFlags::local)) { path->addPath(m_PathComposer.localPath(), transform * worldTransform()); } @@ -100,7 +102,7 @@ continue; } renderer->save(); - bool paintsInLocal = (shapePaint->pathSpace() & PathSpace::Local) == PathSpace::Local; + bool paintsInLocal = shapePaint->isFlagged(PathFlags::local); if (paintsInLocal) { renderer->transform(worldTransform()); @@ -143,7 +145,7 @@ // TODO: clip: - const bool shapeIsLocal = (pathSpace() & PathSpace::Local) == PathSpace::Local; + const bool shapeIsLocal = isFlagged(PathFlags::local); for (auto rit = m_ShapePaints.rbegin(); rit != m_ShapePaints.rend(); ++rit) { @@ -157,7 +159,7 @@ continue; } - auto paintIsLocal = (shapePaint->pathSpace() & PathSpace::Local) == PathSpace::Local; + auto paintIsLocal = shapePaint->isFlagged(PathFlags::local); auto mx = xform; if (paintIsLocal) @@ -204,8 +206,6 @@ } } -void Shape::addDefaultPathSpace(PathSpace space) { m_DefaultPathSpace |= space; } - StatusCode Shape::onAddedDirty(CoreContext* context) { auto code = Super::onAddedDirty(context);
diff --git a/src/shapes/shape_paint_container.cpp b/src/shapes/shape_paint_container.cpp index ab9057a..37e5853 100644 --- a/src/shapes/shape_paint_container.cpp +++ b/src/shapes/shape_paint_container.cpp
@@ -24,12 +24,12 @@ void ShapePaintContainer::addPaint(ShapePaint* paint) { m_ShapePaints.push_back(paint); } -PathSpace ShapePaintContainer::pathSpace() const +PathFlags ShapePaintContainer::pathFlags() const { - PathSpace space = m_DefaultPathSpace; + PathFlags space = m_pathFlags; for (auto paint : m_ShapePaints) { - space |= paint->pathSpace(); + space |= paint->pathFlags(); } return space; }