mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
renderer: added parent scene query api
added 2 more APIs for user convenience to allow backtracking tree traversal. API Additions: - const Paint* Paint::scene() const - const Tvg_Paint* tvg_paint_get_scene(const Tvg_Paint* paint)
This commit is contained in:
parent
0f20a4a1a8
commit
563f8b2f78
11 changed files with 115 additions and 57 deletions
18
inc/thorvg.h
18
inc/thorvg.h
|
@ -309,6 +309,21 @@ class TVG_API Paint
|
|||
public:
|
||||
virtual ~Paint();
|
||||
|
||||
/**
|
||||
* @brief Retrieves the parent paint object.
|
||||
*
|
||||
* This function returns a pointer to the parent object if the current paint
|
||||
* belongs to one. Otherwise, it returns @c nullptr.
|
||||
*
|
||||
* @return A pointer to the parent object if available, otherwise @c nullptr.
|
||||
*
|
||||
* @see Scene::push()
|
||||
* @see Canvas::push()
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
const Paint* parent() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the angle by which the object is rotated.
|
||||
*
|
||||
|
@ -381,6 +396,8 @@ public:
|
|||
*
|
||||
* @param[in] target The paint of the target object.
|
||||
* @param[in] method The method used to mask the source object with the target.
|
||||
*
|
||||
* @retval Result::InsufficientCondition if the target has already belonged to another paint.
|
||||
*/
|
||||
Result mask(Paint* target, MaskMethod method) noexcept;
|
||||
|
||||
|
@ -392,6 +409,7 @@ public:
|
|||
* @param[in] clipper The shape object as the clipper.
|
||||
*
|
||||
* @retval Result::NonSupport If the @p clipper type is not Shape.
|
||||
* @retval Result::InsufficientCondition if the target has already belonged to another paint.
|
||||
*
|
||||
* @note @p clipper only supports the Shape type.
|
||||
* @since 1.0
|
||||
|
|
|
@ -715,7 +715,6 @@ TVG_API Tvg_Result tvg_canvas_set_viewport(Tvg_Canvas* canvas, int32_t x, int32_
|
|||
|
||||
/** \} */ // end defgroup ThorVGCapi_Canvas
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup ThorVGCapi_Paint Paint
|
||||
* @brief A module for managing graphical elements. It enables duplication, transformation and composition.
|
||||
|
@ -964,6 +963,8 @@ TVG_API Tvg_Result tvg_paint_get_obb(const Tvg_Paint* paint, Tvg_Point* pt4);
|
|||
* @param[in] target The target object of the masking.
|
||||
* @param[in] method The method used to mask the source object with the target.
|
||||
*
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION if the target has already belonged to another paint.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
|
||||
*/
|
||||
|
@ -993,6 +994,7 @@ TVG_API Tvg_Result tvg_paint_get_mask_method(const Tvg_Paint* paint, const Tvg_P
|
|||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INVALID_ARGUMENT In case a @c nullptr is passed as the argument.
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION if the target has already belonged to another paint.
|
||||
* @retval TVG_RESULT_NOT_SUPPORTED If the @p clipper type is not Shape.
|
||||
*
|
||||
* @since 1.0
|
||||
|
@ -1000,6 +1002,24 @@ TVG_API Tvg_Result tvg_paint_get_mask_method(const Tvg_Paint* paint, const Tvg_P
|
|||
TVG_API Tvg_Result tvg_paint_clip(Tvg_Paint* paint, Tvg_Paint* clipper);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the parent paint object.
|
||||
*
|
||||
* This function returns a pointer to the parent object if the current paint
|
||||
* belongs to one. Otherwise, it returns @c nullptr.
|
||||
*
|
||||
* @param[in] paint The Tvg_Paint object of which to get the scene.
|
||||
*
|
||||
* @return A pointer to the parent object if available, otherwise @c nullptr.
|
||||
*
|
||||
* @see tvg_scene_push()
|
||||
* @see tvg_canvas_push()
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
TVG_API const Tvg_Paint* tvg_paint_get_parent(const Tvg_Paint* paint);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the unique value of the paint instance indicating the instance type.
|
||||
*
|
||||
|
|
|
@ -169,6 +169,12 @@ TVG_API Tvg_Result tvg_canvas_set_viewport(Tvg_Canvas* canvas, int32_t x, int32_
|
|||
/* Paint API */
|
||||
/************************************************************************/
|
||||
|
||||
TVG_API const Tvg_Paint* tvg_paint_get_parent(const Tvg_Paint* paint)
|
||||
{
|
||||
return (const Tvg_Paint*) reinterpret_cast<const Paint*>(paint)->parent();
|
||||
}
|
||||
|
||||
|
||||
TVG_API Tvg_Result tvg_paint_del(Tvg_Paint* paint)
|
||||
{
|
||||
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
||||
|
|
|
@ -51,10 +51,7 @@ struct Canvas::Impl
|
|||
Result push(Paint* target, Paint* at)
|
||||
{
|
||||
//You cannot push paints during rendering.
|
||||
if (status == Status::Drawing) {
|
||||
TVG_DELETE(target);
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
if (status == Status::Drawing) return Result::InsufficientCondition;
|
||||
|
||||
auto ret = scene->push(target, at);
|
||||
if (ret != Result::Success) return ret;
|
||||
|
|
|
@ -392,19 +392,15 @@ Result Paint::clip(Paint* clipper) noexcept
|
|||
{
|
||||
if (clipper && clipper->type() != Type::Shape) {
|
||||
TVGERR("RENDERER", "Clipping only supports the Shape!");
|
||||
TVG_DELETE(clipper);
|
||||
return Result::NonSupport;
|
||||
}
|
||||
pImpl->clip(clipper);
|
||||
return Result::Success;
|
||||
return pImpl->clip(clipper);
|
||||
}
|
||||
|
||||
|
||||
Result Paint::mask(Paint* target, MaskMethod method) noexcept
|
||||
{
|
||||
if (pImpl->mask(target, method)) return Result::Success;
|
||||
if (target) TVG_DELETE(target);
|
||||
return Result::InvalidArguments;
|
||||
return pImpl->mask(target, method);
|
||||
}
|
||||
|
||||
|
||||
|
@ -448,7 +444,7 @@ uint8_t Paint::ref() noexcept
|
|||
|
||||
uint8_t Paint::unref(bool free) noexcept
|
||||
{
|
||||
return pImpl->unref(free);
|
||||
return pImpl->unrefx(free);
|
||||
}
|
||||
|
||||
|
||||
|
@ -456,3 +452,9 @@ uint8_t Paint::refCnt() const noexcept
|
|||
{
|
||||
return pImpl->refCnt;
|
||||
}
|
||||
|
||||
|
||||
const Paint* Paint::parent() const noexcept
|
||||
{
|
||||
return pImpl->parent;
|
||||
}
|
|
@ -51,6 +51,7 @@ namespace tvg
|
|||
struct Paint::Impl
|
||||
{
|
||||
Paint* paint = nullptr;
|
||||
Paint* parent = nullptr;
|
||||
Mask* maskData = nullptr;
|
||||
Paint* clipper = nullptr;
|
||||
RenderMethod* renderer = nullptr;
|
||||
|
@ -91,11 +92,11 @@ namespace tvg
|
|||
virtual ~Impl()
|
||||
{
|
||||
if (maskData) {
|
||||
maskData->target->unref();
|
||||
PAINT(maskData->target)->unref();
|
||||
tvg::free(maskData);
|
||||
}
|
||||
|
||||
if (clipper) clipper->unref();
|
||||
if (clipper) PAINT(clipper)->unref();
|
||||
|
||||
if (renderer) {
|
||||
if (rd) renderer->dispose(rd);
|
||||
|
@ -110,13 +111,18 @@ namespace tvg
|
|||
return refCnt;
|
||||
}
|
||||
|
||||
uint8_t unref(bool free)
|
||||
uint8_t unref(bool free = true)
|
||||
{
|
||||
parent = nullptr;
|
||||
return unrefx(free);
|
||||
}
|
||||
|
||||
uint8_t unrefx(bool free)
|
||||
{
|
||||
if (refCnt > 0) --refCnt;
|
||||
else TVGERR("RENDERER", "Corrupted Reference Count!");
|
||||
|
||||
if (free && refCnt == 0) {
|
||||
//TODO: use the global dismiss function?
|
||||
delete(paint);
|
||||
return 0;
|
||||
}
|
||||
|
@ -146,37 +152,37 @@ namespace tvg
|
|||
return tr.m;
|
||||
}
|
||||
|
||||
void clip(Paint* clp)
|
||||
Result clip(Paint* clp)
|
||||
{
|
||||
if (clipper) clipper->unref(clipper != clp);
|
||||
if (PAINT(clp)->parent) return Result::InsufficientCondition;
|
||||
if (clipper) PAINT(clipper)->unref(clipper != clp);
|
||||
clipper = clp;
|
||||
if (!clp) return;
|
||||
|
||||
clipper->ref();
|
||||
if (clp) {
|
||||
clp->ref();
|
||||
PAINT(clp)->parent = parent;
|
||||
}
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
bool mask(Paint* target, MaskMethod method)
|
||||
Result mask(Paint* target, MaskMethod method)
|
||||
{
|
||||
//Invalid case
|
||||
if ((!target && method != MaskMethod::None) || (target && method == MaskMethod::None)) return false;
|
||||
if (target && PAINT(target)->parent) return Result::InsufficientCondition;
|
||||
|
||||
if (maskData) {
|
||||
maskData->target->unref(maskData->target != target);
|
||||
//Reset scenario
|
||||
if (!target && method == MaskMethod::None) {
|
||||
tvg::free(maskData);
|
||||
maskData = nullptr;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (!target && method == MaskMethod::None) return true;
|
||||
maskData = tvg::malloc<Mask*>(sizeof(Mask));
|
||||
PAINT(maskData->target)->unref(maskData->target != target);
|
||||
tvg::free(maskData);
|
||||
maskData = nullptr;
|
||||
}
|
||||
|
||||
if (!target && method == MaskMethod::None) return Result::Success;
|
||||
|
||||
maskData = tvg::malloc<Mask*>(sizeof(Mask));
|
||||
target->ref();
|
||||
maskData->target = target;
|
||||
PAINT(target)->parent = parent;
|
||||
maskData->source = paint;
|
||||
maskData->method = method;
|
||||
return true;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
MaskMethod mask(const Paint** target) const
|
||||
|
@ -193,12 +199,12 @@ namespace tvg
|
|||
void reset()
|
||||
{
|
||||
if (clipper) {
|
||||
clipper->unref();
|
||||
PAINT(clipper)->unref();
|
||||
clipper = nullptr;
|
||||
}
|
||||
|
||||
if (maskData) {
|
||||
maskData->target->unref();
|
||||
PAINT(maskData->target)->unref();
|
||||
tvg::free(maskData);
|
||||
maskData = nullptr;
|
||||
}
|
||||
|
@ -208,6 +214,7 @@ namespace tvg
|
|||
tr.scale = 1.0f;
|
||||
tr.overriding = false;
|
||||
|
||||
parent = nullptr;
|
||||
blendMethod = BlendMethod::Normal;
|
||||
renderFlag = RenderUpdateFlag::None;
|
||||
ctxFlag = ContextFlag::Default;
|
||||
|
|
|
@ -165,7 +165,10 @@ struct Picture::Impl : Paint::Impl
|
|||
auto picture = Picture::gen();
|
||||
auto dup = PICTURE(picture);
|
||||
|
||||
if (vector) dup->vector = vector->duplicate();
|
||||
if (vector) {
|
||||
dup->vector = vector->duplicate();
|
||||
PAINT(dup->vector)->parent = picture;
|
||||
}
|
||||
|
||||
if (loader) {
|
||||
dup->loader = loader;
|
||||
|
@ -211,6 +214,7 @@ struct Picture::Impl : Paint::Impl
|
|||
} else {
|
||||
vector = loader->paint();
|
||||
if (vector) {
|
||||
PAINT(vector)->parent = paint;
|
||||
if (w != loader->w || h != loader->h) {
|
||||
if (!resizing) {
|
||||
w = loader->w;
|
||||
|
|
|
@ -229,6 +229,7 @@ struct Scene::Impl : Paint::Impl
|
|||
|
||||
for (auto paint : paints) {
|
||||
auto cdup = paint->duplicate();
|
||||
PAINT(cdup)->parent = scene;
|
||||
cdup->ref();
|
||||
dup->paints.push_back(cdup);
|
||||
}
|
||||
|
@ -242,7 +243,7 @@ struct Scene::Impl : Paint::Impl
|
|||
{
|
||||
auto itr = paints.begin();
|
||||
while (itr != paints.end()) {
|
||||
(*itr)->unref();
|
||||
PAINT((*itr))->unref();
|
||||
paints.erase(itr++);
|
||||
}
|
||||
return Result::Success;
|
||||
|
@ -250,31 +251,24 @@ struct Scene::Impl : Paint::Impl
|
|||
|
||||
Result remove(Paint* paint)
|
||||
{
|
||||
owned(paint);
|
||||
paint->unref();
|
||||
if (PAINT(paint)->parent != this->paint) return Result::InsufficientCondition;
|
||||
PAINT(paint)->unref();
|
||||
paints.remove(paint);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
void owned(Paint* paint)
|
||||
{
|
||||
#ifdef THORVG_LOG_ENABLED
|
||||
for (auto p : paints) {
|
||||
if (p == paint) return;
|
||||
}
|
||||
TVGERR("RENDERER", "The paint(%p) is not existed from the scene(%p)", paint, this->paint);
|
||||
#endif
|
||||
}
|
||||
|
||||
Result insert(Paint* target, Paint* at)
|
||||
{
|
||||
if (!target) return Result::InvalidArguments;
|
||||
auto timpl = PAINT(target);
|
||||
if (timpl->parent) return Result::InsufficientCondition;
|
||||
|
||||
target->ref();
|
||||
|
||||
//Relocated the paint to the current scene space
|
||||
PAINT(target)->renderFlag |= RenderUpdateFlag::Transform;
|
||||
timpl->renderFlag |= RenderUpdateFlag::Transform;
|
||||
|
||||
if (at == nullptr) {
|
||||
if (!at) {
|
||||
paints.push_back(target);
|
||||
} else {
|
||||
//OPTIMIZE: Remove searching?
|
||||
|
@ -282,6 +276,9 @@ struct Scene::Impl : Paint::Impl
|
|||
if (itr == paints.end()) return Result::InvalidArguments;
|
||||
paints.insert(itr, target);
|
||||
}
|
||||
timpl->parent = paint;
|
||||
if (timpl->clipper) PAINT(timpl->clipper)->parent = paint;
|
||||
if (timpl->maskData) PAINT(timpl->maskData->target)->parent = paint;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ struct Text::Impl : Paint::Impl
|
|||
|
||||
Impl(Text* p) : Paint::Impl(p), shape(Shape::gen())
|
||||
{
|
||||
PAINT(shape)->parent = p;
|
||||
}
|
||||
|
||||
~Impl()
|
||||
|
@ -149,6 +150,8 @@ struct Text::Impl : Paint::Impl
|
|||
|
||||
auto text = Text::gen();
|
||||
auto dup = TEXT(text);
|
||||
dup->parent = text;
|
||||
|
||||
SHAPE(shape)->duplicate(dup->shape);
|
||||
|
||||
if (loader) {
|
||||
|
|
|
@ -218,11 +218,8 @@ TEST_CASE("Composition", "[tvgPaint]")
|
|||
//Negative
|
||||
REQUIRE(shape->mask(nullptr) == MaskMethod::None);
|
||||
|
||||
auto comp = Shape::gen();
|
||||
REQUIRE(shape->mask(comp, MaskMethod::None) == Result::InvalidArguments);
|
||||
|
||||
//Clipping
|
||||
comp = Shape::gen();
|
||||
auto comp = Shape::gen();
|
||||
REQUIRE(shape->clip(comp) == Result::Success);
|
||||
|
||||
//AlphaMask
|
||||
|
|
|
@ -39,18 +39,25 @@ TEST_CASE("Pushing Paints Into Scene", "[tvgScene]")
|
|||
{
|
||||
auto scene = unique_ptr<Scene>(Scene::gen());
|
||||
REQUIRE(scene);
|
||||
REQUIRE(scene->parent() == nullptr);
|
||||
|
||||
Paint* paints[3];
|
||||
|
||||
//Pushing Paints
|
||||
paints[0] = Shape::gen();
|
||||
REQUIRE(paints[0]->parent() == nullptr);
|
||||
REQUIRE(scene->push(paints[0]) == Result::Success);
|
||||
REQUIRE(paints[0]->parent() == scene.get());
|
||||
|
||||
paints[1] = Picture::gen();
|
||||
REQUIRE(paints[1]->parent() == nullptr);
|
||||
REQUIRE(scene->push(paints[1]) == Result::Success);
|
||||
REQUIRE(paints[1]->parent() == scene.get());
|
||||
|
||||
paints[2] = Picture::gen();
|
||||
REQUIRE(paints[2]->parent() == nullptr);
|
||||
REQUIRE(scene->push(paints[2]) == Result::Success);
|
||||
REQUIRE(paints[2]->parent() == scene.get());
|
||||
|
||||
//Pushing Null Pointer
|
||||
REQUIRE(scene->push(nullptr) == Result::InvalidArguments);
|
||||
|
|
Loading…
Add table
Reference in a new issue