diff --git a/inc/thorvg.h b/inc/thorvg.h index 32e44c62..ede30c29 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -373,15 +373,16 @@ public: /** * @brief Gets the axis-aligned bounding box of the paint object. * - * In case @p transform is @c true, all object's transformations are applied first, and then the bounding box is established. Otherwise, the bounding box is determined before any transformations. - * - * @param[out] x The x coordinate of the upper left corner of the object. - * @param[out] y The y coordinate of the upper left corner of the object. + * @param[out] x The x-coordinate of the upper-left corner of the object. + * @param[out] y The y-coordinate of the upper-left corner of the object. * @param[out] w The width of the object. * @param[out] h The height of the object. - * @param[in] transformed If @c true, the paint's transformations are taken into account, otherwise they aren't. + * @param[in] transformed If @c true, the paint's transformations are taken into account in the scene it belongs to. Otherwise they aren't. * + * @note This is useful when you need to figure out the bounding box of the paint in the canvas space. * @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object. + * @note If @p transformed is @c true, the paint needs to be pushed into a canvas and updated before this api is called. + * @see Canvas::update() */ Result bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept; diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index e0608a6f..bd66851a 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -934,12 +934,15 @@ TVG_API Tvg_Paint* tvg_paint_duplicate(Tvg_Paint* paint); * \param[out] y The y coordinate of the upper left corner of the object. * \param[out] w The width of the object. * \param[out] h The height of the object. -* \param[in] transformed If @c true, the transformation of the paint is taken into account, otherwise it isn't. +* \param[in] transformed If @c true, the paint's transformations are taken into account in the scene it belongs to. Otherwise they aren't. * * \return Tvg_Result enumeration. * \retval TVG_RESULT_INVALID_ARGUMENT An invalid Tvg_Paint pointer. * +* \note This is useful when you need to figure out the bounding box of the paint in the canvas space. * \note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object. +* \note If @p transformed is @c true, the paint needs to be pushed into a canvas and updated before this api is called. +* \see tvg_canvas_update_paint() */ TVG_API Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed); diff --git a/src/renderer/tvgPaint.cpp b/src/renderer/tvgPaint.cpp index 5e4f9499..85bb6b87 100644 --- a/src/renderer/tvgPaint.cpp +++ b/src/renderer/tvgPaint.cpp @@ -292,8 +292,9 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Arrayopacity); RenderData rd = nullptr; - auto m = pm * tr.m; - PAINT_METHOD(rd, update(renderer, m, clips, opacity, newFlag, clipper)); + + tr.cm = pm * tr.m; + PAINT_METHOD(rd, update(renderer, tr.cm, clips, opacity, newFlag, clipper)); /* 3. Composition Post Processing */ if (compFastTrack == Result::Success) renderer->viewport(viewport); @@ -303,10 +304,10 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Arraytransform(); + const auto& m = this->transform(origin); //Case: No transformed, quick return! if (!transformed || mathIdentity(&m)) { @@ -407,7 +408,7 @@ TVG_DEPRECATED Result Paint::bounds(float* x, float* y, float* w, float* h) cons Result Paint::bounds(float* x, float* y, float* w, float* h, bool transform) const noexcept { - if (pImpl->bounds(x, y, w, h, transform, true)) return Result::Success; + if (pImpl->bounds(x, y, w, h, transform, true, true)) return Result::Success; return Result::InsufficientCondition; } diff --git a/src/renderer/tvgPaint.h b/src/renderer/tvgPaint.h index 09afc07a..4dcf3927 100644 --- a/src/renderer/tvgPaint.h +++ b/src/renderer/tvgPaint.h @@ -52,7 +52,8 @@ namespace tvg RenderMethod* renderer = nullptr; BlendMethod blendMethod = BlendMethod::Normal; //uint8_t struct { - Matrix m; + Matrix m; //input matrix + Matrix cm; //multipled parents matrix float degree = 0.0f; //rotation degree float scale = 1.0f; //scale factor bool overriding = false; //user transform? @@ -112,10 +113,11 @@ namespace tvg return true; } - Matrix& transform() + Matrix& transform(bool origin = false) { //update transform if (renderFlag & RenderUpdateFlag::Transform) tr.update(); + if (origin) return tr.cm; return tr.m; } @@ -151,7 +153,7 @@ namespace tvg bool rotate(float degree); bool scale(float factor); bool translate(float x, float y); - bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking); + bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin = false); RenderData update(RenderMethod* renderer, const Matrix& pm, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false); bool render(RenderMethod* renderer); Paint* duplicate(Paint* ret = nullptr); diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index 0a64f050..d1675fca 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -111,7 +111,6 @@ struct RenderRegion } }; - struct RenderStroke { float width = 0.0f; diff --git a/test/capi/capiPaint.cpp b/test/capi/capiPaint.cpp index 379e5ffe..a330f6a2 100644 --- a/test/capi/capiPaint.cpp +++ b/test/capi/capiPaint.cpp @@ -137,11 +137,17 @@ TEST_CASE("Paint Opacity", "[capiPaint]") TEST_CASE("Paint Bounds", "[capiPaint]") { + tvg_engine_init(TVG_ENGINE_SW, 0); + Tvg_Canvas* canvas = tvg_swcanvas_create(); + Tvg_Paint* paint = tvg_shape_new(); REQUIRE(paint); + REQUIRE(tvg_canvas_push(canvas, paint) == TVG_RESULT_SUCCESS); + float x, y, w, h; + REQUIRE(tvg_canvas_update_paint(canvas, paint) == TVG_RESULT_SUCCESS); REQUIRE(tvg_shape_append_rect(paint, 0, 10, 20, 100, 0, 0) == TVG_RESULT_SUCCESS); REQUIRE(tvg_paint_get_bounds(paint, &x, &y, &w, &h, true) == TVG_RESULT_SUCCESS); @@ -164,6 +170,7 @@ TEST_CASE("Paint Bounds", "[capiPaint]") REQUIRE(w == 20); REQUIRE(h == 100); + REQUIRE(tvg_canvas_update_paint(canvas, paint) == TVG_RESULT_SUCCESS); REQUIRE(tvg_paint_get_bounds(paint, &x, &y, &w, &h, true) == TVG_RESULT_SUCCESS); REQUIRE(x == Approx(100.0f).margin(0.000001)); @@ -171,7 +178,8 @@ TEST_CASE("Paint Bounds", "[capiPaint]") REQUIRE(w == Approx(40.0f).margin(0.000001)); REQUIRE(h == Approx(200.0f).margin(0.000001)); - REQUIRE(tvg_paint_del(paint) == TVG_RESULT_SUCCESS); + tvg_canvas_destroy(canvas); + tvg_engine_term(TVG_ENGINE_SW); } TEST_CASE("Paint Dupliction", "[capiPaint]") diff --git a/test/testPaint.cpp b/test/testPaint.cpp index 8d5fdf2e..a7942a86 100644 --- a/test/testPaint.cpp +++ b/test/testPaint.cpp @@ -118,8 +118,12 @@ TEST_CASE("Opacity", "[tvgPaint]") TEST_CASE("Bounding Box", "[tvgPaint]") { - auto shape = Shape::gen(); - REQUIRE(shape); + Initializer::init(tvg::CanvasEngine::Sw, 0); + + auto canvas = SwCanvas::gen(); + auto shape = Shape::gen().release(); + canvas->push(tvg::cast(shape)); + canvas->sync(); //Negative float x = 0, y = 0, w = 0, h = 0; @@ -133,6 +137,8 @@ TEST_CASE("Bounding Box", "[tvgPaint]") REQUIRE(y == 10.0f); REQUIRE(w == 20.0f); REQUIRE(h == 100.0f); + + REQUIRE(canvas->update(shape) == Result::Success); REQUIRE(shape->bounds(&x, &y, &w, &h, true) == Result::Success); REQUIRE(x == 100.0f); REQUIRE(y == 121.0f); @@ -150,11 +156,15 @@ TEST_CASE("Bounding Box", "[tvgPaint]") REQUIRE(y == 10.0f); REQUIRE(w == 20.0f); REQUIRE(h == 200.0f); + + REQUIRE(canvas->update(shape) == Result::Success); REQUIRE(shape->bounds(&x, &y, &w, &h, true) == Result::Success); REQUIRE(x == 0.0f); REQUIRE(y == 10.0f); REQUIRE(w == 20.0f); REQUIRE(h == 200.0f); + + Initializer::term(tvg::CanvasEngine::Sw); } TEST_CASE("Duplication", "[tvgPaint]")