mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
common paint: refine the bounds() api to return the values after applying transformation.
Current paint::bounds() returns the coordinates under the raw status, the values are not quite useful if the paint object has the transformed children. Thus, we extends the feature and give an additional parameter "transformed" to return the coordinates values after transformation by user demands. This is also necessary for tvg format, since we need the exact view size of the scene information. The previous api is deprecated and we introduce a new api to replace it. @APIs: + Result Paint::bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept; - Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept; @Issues: https://github.com/Samsung/thorvg/issues/746
This commit is contained in:
parent
000d3ec2f0
commit
74954db56d
31 changed files with 123 additions and 24 deletions
22
inc/thorvg.h
22
inc/thorvg.h
|
@ -289,8 +289,28 @@ public:
|
|||
* @return Result::Success when succeed, Result::InsufficientCondition otherwise.
|
||||
*
|
||||
* @note The bounding box doesn't indicate the final rendered region. It's the smallest rectangle that encloses the object.
|
||||
* @see Paint::bounds(float* x, float* y, float* w, float* h, bool transformed);
|
||||
*/
|
||||
Result bounds(float* x, float* y, float* w, float* h) const noexcept;
|
||||
TVG_DEPRECATED Result bounds(float* x, float* y, float* w, float* h) const noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the axis-aligned bounding box of the paint 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, apply the transformation of the paint.
|
||||
*
|
||||
* @return Result::Success when succeed, Result::InsufficientCondition otherwise.
|
||||
*
|
||||
* @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object.
|
||||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
Result bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Duplicates the object.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/examples/images/ietf.tvg
Normal file
BIN
src/examples/images/ietf.tvg
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/examples/images/rotlines.tvg
Normal file
BIN
src/examples/images/rotlines.tvg
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -27,13 +27,12 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
|
||||
static inline bool FLT_SAME(float a, float b)
|
||||
{
|
||||
return (fabsf(a - b) < FLT_EPSILON);
|
||||
}
|
||||
|
||||
|
||||
static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport)
|
||||
{
|
||||
/* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
|
||||
|
@ -243,6 +242,60 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf
|
|||
return edata;
|
||||
}
|
||||
|
||||
bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed)
|
||||
{
|
||||
Matrix* m = nullptr;
|
||||
|
||||
//Case: No transformed, quick return!
|
||||
if (!transformed || !(m = this->transform())) return smethod->bounds(x, y, w, h);
|
||||
|
||||
//Case: Transformed
|
||||
auto tx = 0.0f;
|
||||
auto ty = 0.0f;
|
||||
auto tw = 0.0f;
|
||||
auto th = 0.0f;
|
||||
|
||||
auto ret = smethod->bounds(&tx, &ty, &tw, &th);
|
||||
|
||||
//Get vertices
|
||||
Point pt[4] = {{tx, ty}, {tx + tw, ty}, {tx + tw, ty + th}, {tx, ty + th}};
|
||||
|
||||
//New bounding box
|
||||
auto x1 = FLT_MAX;
|
||||
auto y1 = FLT_MAX;
|
||||
auto x2 = -FLT_MAX;
|
||||
auto y2 = -FLT_MAX;
|
||||
|
||||
//function = Point * Matrix
|
||||
auto multiply = [&](Point* pt, const Matrix* transform) {
|
||||
auto tx = pt->x * transform->e11 + pt->y * transform->e12 + transform->e13;
|
||||
auto ty = pt->x * transform->e21 + pt->y * transform->e22 + transform->e23;
|
||||
pt->x = tx;
|
||||
pt->y = ty;
|
||||
};
|
||||
|
||||
//Compute the AABB after transformation
|
||||
for (int i = 0; i < 4; i++) {
|
||||
multiply(&pt[i], m);
|
||||
|
||||
if (pt[i].x < x1) x1 = pt[i].x;
|
||||
if (pt[i].x > x2) x2 = pt[i].x;
|
||||
if (pt[i].y < y1) y1 = pt[i].y;
|
||||
if (pt[i].y > y2) y2 = pt[i].y;
|
||||
}
|
||||
|
||||
if (x) *x = x1;
|
||||
if (y) *y = y1;
|
||||
if (w) *w = x2 - x1;
|
||||
if (h) *h = y2 - y1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
Paint :: Paint() : pImpl(new Impl())
|
||||
{
|
||||
|
@ -255,10 +308,6 @@ Paint :: ~Paint()
|
|||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
Result Paint::rotate(float degree) noexcept
|
||||
{
|
||||
if (pImpl->rotate(degree)) return Result::Success;
|
||||
|
@ -286,6 +335,7 @@ Result Paint::transform(const Matrix& m) noexcept
|
|||
return Result::FailedAllocation;
|
||||
}
|
||||
|
||||
|
||||
Matrix Paint::transform() noexcept
|
||||
{
|
||||
auto pTransform = pImpl->transform();
|
||||
|
@ -293,9 +343,16 @@ Matrix Paint::transform() noexcept
|
|||
return {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
}
|
||||
|
||||
Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept
|
||||
|
||||
TVG_DEPRECATED Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept
|
||||
{
|
||||
if (pImpl->bounds(x, y, w, h)) return Result::Success;
|
||||
return this->bounds(x, y, w, h, false);
|
||||
}
|
||||
|
||||
|
||||
Result Paint::bounds(float* x, float* y, float* w, float* h, bool transform) const noexcept
|
||||
{
|
||||
if (pImpl->bounds(x, y, w, h, transform)) return Result::Success;
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace tvg
|
|||
virtual bool dispose(RenderMethod& renderer) = 0;
|
||||
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
|
||||
virtual bool render(RenderMethod& renderer) = 0;
|
||||
virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
|
||||
virtual bool bounds(float* x, float* y, float* w, float* h) = 0;
|
||||
virtual RenderRegion bounds(RenderMethod& renderer) const = 0;
|
||||
virtual Paint* duplicate() = 0;
|
||||
virtual Iterator* iterator() = 0;
|
||||
|
@ -89,11 +89,6 @@ namespace tvg
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h) const
|
||||
{
|
||||
return smethod->bounds(x, y, w, h);
|
||||
}
|
||||
|
||||
RenderRegion bounds(RenderMethod& renderer) const
|
||||
{
|
||||
return smethod->bounds(renderer);
|
||||
|
@ -122,6 +117,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);
|
||||
void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag);
|
||||
bool render(RenderMethod& renderer);
|
||||
Paint* duplicate();
|
||||
|
@ -136,7 +132,7 @@ namespace tvg
|
|||
PaintMethod(T* _inst) : inst(_inst) {}
|
||||
~PaintMethod() {}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h) const override
|
||||
bool bounds(float* x, float* y, float* w, float* h) override
|
||||
{
|
||||
return inst->bounds(x, y, w, h);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ Result Picture::load(const char* data, uint32_t size, const string& mimeType, bo
|
|||
return pImpl->load(data, size, mimeType, copy);
|
||||
}
|
||||
|
||||
Result Picture::load(const char* data, uint32_t size, bool copy) noexcept
|
||||
|
||||
TVG_DEPRECATED Result Picture::load(const char* data, uint32_t size, bool copy) noexcept
|
||||
{
|
||||
return load(data, size, "", copy);
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ struct Picture::Impl
|
|||
return true;
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h) const
|
||||
bool bounds(float* x, float* y, float* w, float* h)
|
||||
{
|
||||
if (x) *x = 0;
|
||||
if (y) *y = 0;
|
||||
|
|
|
@ -149,7 +149,7 @@ struct Scene::Impl
|
|||
return {x1, y1, (x2 - x1), (y2 - y1)};
|
||||
}
|
||||
|
||||
bool bounds(float* px, float* py, float* pw, float* ph) const
|
||||
bool bounds(float* px, float* py, float* pw, float* ph)
|
||||
{
|
||||
if (paints.count == 0) return false;
|
||||
|
||||
|
@ -164,7 +164,7 @@ struct Scene::Impl
|
|||
auto w = 0.0f;
|
||||
auto h = 0.0f;
|
||||
|
||||
if (!(*paint)->pImpl->bounds(&x, &y, &w, &h)) continue;
|
||||
if ((*paint)->bounds(&x, &y, &w, &h, true) != tvg::Result::Success) continue;
|
||||
|
||||
//Merge regions
|
||||
if (x < x1) x1 = x;
|
||||
|
|
|
@ -246,7 +246,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v
|
|||
if (style->fill.paint.none) {
|
||||
//Do nothing
|
||||
} else if (style->fill.paint.gradient) {
|
||||
if (!style->fill.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh);
|
||||
if (!style->fill.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh, false);
|
||||
|
||||
if (style->fill.paint.gradient->type == SvgGradientType::Linear) {
|
||||
auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, vx, vy, vw, vh, style->fill.opacity);
|
||||
|
@ -285,7 +285,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v
|
|||
if (style->stroke.paint.none) {
|
||||
//Do nothing
|
||||
} else if (style->stroke.paint.gradient) {
|
||||
if (!style->stroke.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh);
|
||||
if (!style->stroke.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh, false);
|
||||
|
||||
if (style->stroke.paint.gradient->type == SvgGradientType::Linear) {
|
||||
auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, vg, vx, vy, vw, vh, style->stroke.opacity);
|
||||
|
|
|
@ -697,7 +697,27 @@ TvgBinCounter TvgSaver::serialize(const Paint* paint, const Matrix* pTransform,
|
|||
void TvgSaver::run(unsigned tid)
|
||||
{
|
||||
if (!writeHeader()) return;
|
||||
if (serialize(paint, nullptr) == 0) return;
|
||||
|
||||
//Serialize Root Paint, without its transform.
|
||||
Matrix transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
|
||||
if (paint->opacity() > 0) {
|
||||
switch (paint->id()) {
|
||||
case TVG_CLASS_ID_SHAPE: {
|
||||
serializeShape(static_cast<const Shape*>(paint), nullptr, &transform);
|
||||
break;
|
||||
}
|
||||
case TVG_CLASS_ID_SCENE: {
|
||||
serializeScene(static_cast<const Scene*>(paint), nullptr, &transform);
|
||||
break;
|
||||
}
|
||||
case TVG_CLASS_ID_PICTURE: {
|
||||
serializePicture(static_cast<const Picture*>(paint), nullptr, &transform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!saveEncoding(path)) return;
|
||||
}
|
||||
|
||||
|
@ -736,7 +756,12 @@ bool TvgSaver::save(Paint* paint, const string& path, bool compress)
|
|||
this->path = strdup(path.c_str());
|
||||
if (!this->path) return false;
|
||||
|
||||
paint->bounds(nullptr, nullptr, &vsize[0], &vsize[1]);
|
||||
float x, y;
|
||||
paint->bounds(&x, &y, &vsize[0], &vsize[1], false);
|
||||
|
||||
//cut off the negative space
|
||||
if (x < 0) vsize[0] += x;
|
||||
if (y < 0) vsize[1] += y;
|
||||
|
||||
if (vsize[0] <= FLT_EPSILON || vsize[1] <= FLT_EPSILON) {
|
||||
TVGLOG("TVG_SAVER", "Saving paint(%p) has zero view size.", paint);
|
||||
|
|
Loading…
Add table
Reference in a new issue