From 7dd239eed97761b22ef635b6896a8f65c4939462 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 6 Feb 2014 15:29:15 +0100 Subject: Added new base class to handle viewBox and preserveAspectRatio. Updated sp-root, sp-symbol, sp-image, sp-pattern, marker to use new class. Fixed some viewport issues when % used. (bzr r13002) --- src/viewbox.cpp | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 src/viewbox.cpp (limited to 'src/viewbox.cpp') diff --git a/src/viewbox.cpp b/src/viewbox.cpp new file mode 100644 index 000000000..2314cbf6a --- /dev/null +++ b/src/viewbox.cpp @@ -0,0 +1,277 @@ +/* + * viewBox helper class, common code used by root, symbol, marker, pattern, image, view + * + * Authors: + * Lauris Kaplinski (code extracted from symbol.cpp) + * Tavmjong Bah + * + * Copyright (C) 2013 Tavmjong Bah, authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + * + */ + +#include <2geom/transforms.h> + +#include "viewbox.h" +#include "attributes.h" +#include "enums.h" +#include "sp-item.h" + +SPViewBox::SPViewBox() { + + this->viewBox_set = FALSE; + + this->aspect_set = FALSE; + this->aspect_align = SP_ASPECT_XMID_YMID; // Default per spec; + this->aspect_clip = SP_ASPECT_MEET; + + this->c2p = Geom::identity(); +} + +SPViewBox::~SPViewBox() { +} + +void SPViewBox::set_viewBox(const gchar* value) { + + if (value) { + double x, y, width, height; + char *eptr; + + eptr = (gchar *) value; + x = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + y = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + width = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + height = g_ascii_strtod (eptr, &eptr); + + while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { + eptr++; + } + + if ((width > 0) && (height > 0)) { + /* Set viewbox */ + this->viewBox = Geom::Rect::from_xywh(x, y, width, height); + this->viewBox_set = TRUE; + } else { + this->viewBox_set = FALSE; + } + } else { + this->viewBox_set = FALSE; + } + + // The C++ way? + // std::string sv( value ); + // std::replace( sv.begin(), sv.end(), ',', ' '); + // std::stringstream ss( sv ); + // double x, y, width, height; + // ss >> x >> y >> width >> height; +} + +void SPViewBox::set_preserveAspectRatio(const gchar* value) { + + /* Do setup before, so we can use break to escape */ + this->aspect_set = FALSE; + this->aspect_align = SP_ASPECT_XMID_YMID; // Default per spec + this->aspect_clip = SP_ASPECT_MEET; + + if (value) { + int len; + gchar c[256]; + const gchar *p, *e; + unsigned int align, clip; + p = value; + + while (*p && *p == 32) { + p += 1; + } + + if (!*p) { + return; + } + + e = p; + + while (*e && *e != 32) { + e += 1; + } + + len = e - p; + + if (len > 8) { + return; + } + + memcpy (c, value, len); + + c[len] = 0; + + /* Now the actual part */ + if (!strcmp (c, "none")) { + align = SP_ASPECT_NONE; + } else if (!strcmp (c, "xMinYMin")) { + align = SP_ASPECT_XMIN_YMIN; + } else if (!strcmp (c, "xMidYMin")) { + align = SP_ASPECT_XMID_YMIN; + } else if (!strcmp (c, "xMaxYMin")) { + align = SP_ASPECT_XMAX_YMIN; + } else if (!strcmp (c, "xMinYMid")) { + align = SP_ASPECT_XMIN_YMID; + } else if (!strcmp (c, "xMidYMid")) { + align = SP_ASPECT_XMID_YMID; + } else if (!strcmp (c, "xMaxYMid")) { + align = SP_ASPECT_XMAX_YMID; + } else if (!strcmp (c, "xMinYMax")) { + align = SP_ASPECT_XMIN_YMAX; + } else if (!strcmp (c, "xMidYMax")) { + align = SP_ASPECT_XMID_YMAX; + } else if (!strcmp (c, "xMaxYMax")) { + align = SP_ASPECT_XMAX_YMAX; + } else { + return; + } + + clip = SP_ASPECT_MEET; + + while (*e && *e == 32) { + e += 1; + } + + if (*e) { + if (!strcmp (e, "meet")) { + clip = SP_ASPECT_MEET; + } else if (!strcmp (e, "slice")) { + clip = SP_ASPECT_SLICE; + } else { + return; + } + } + + this->aspect_set = TRUE; + this->aspect_align = align; + this->aspect_clip = clip; + } +} + +// Apply scaling from viewbox +void SPViewBox::apply_viewbox(const Geom::Rect& in) { + + /* Determine actual viewbox in viewport coordinates */ + double x = 0.0; + double y = 0.0; + double width = in.width(); + double height = in.height(); + // std::cout << " width: " << width << " height: " << height << std::endl; + + if (this->aspect_align != SP_ASPECT_NONE) { + double scalex, scaley, scale; + /* Things are getting interesting */ + scalex = in.width() / this->viewBox.width(); + scaley = in.height() / this->viewBox.height(); + scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); + width = this->viewBox.width() * scale; + height = this->viewBox.height() * scale; + + /* Now place viewbox to requested position */ + switch (this->aspect_align) { + case SP_ASPECT_XMIN_YMIN: + break; + case SP_ASPECT_XMID_YMIN: + x = 0.5 * (in.width() - width); + break; + case SP_ASPECT_XMAX_YMIN: + x = 1.0 * (in.width() - width); + break; + case SP_ASPECT_XMIN_YMID: + y = 0.5 * (in.height() - height); + break; + case SP_ASPECT_XMID_YMID: + x = 0.5 * (in.width() - width); + y = 0.5 * (in.height() - height); + break; + case SP_ASPECT_XMAX_YMID: + x = 1.0 * (in.width() - width); + y = 0.5 * (in.height() - height); + break; + case SP_ASPECT_XMIN_YMAX: + y = 1.0 * (in.height() - height); + break; + case SP_ASPECT_XMID_YMAX: + x = 0.5 * (in.width() - width); + y = 1.0 * (in.height() - height); + break; + case SP_ASPECT_XMAX_YMAX: + x = 1.0 * (in.width() - width); + y = 1.0 * (in.height() - height); + break; + default: + break; + } + } + + /* Viewbox transform from scale and position */ + Geom::Affine q; + q[0] = width / this->viewBox.width(); + q[1] = 0.0; + q[2] = 0.0; + q[3] = height / this->viewBox.height(); + q[4] = -this->viewBox.left() * q[0] + x; + q[5] = -this->viewBox.top() * q[3] + y; + + // std::cout << " q\n" << q << std::endl; + + /* Append viewbox transformation */ + this->c2p = q * this->c2p; +} + +SPItemCtx SPViewBox::get_rctx(const SPItemCtx* ictx) { + + /* Create copy of item context */ + SPItemCtx rctx = *ictx; + + /* Calculate child to parent transformation */ + /* Apply parent translation (set up as viewport) */ + this->c2p = Geom::Translate(rctx.viewport.min()); + + if (this->viewBox_set) { + // Adjusts c2p for viewbox + apply_viewbox( rctx.viewport ); + } + + rctx.i2doc = this->c2p * rctx.i2doc; + + /* If viewBox is set initialize child viewport */ + /* Otherwise it is already correct */ + if (this->viewBox_set) { + rctx.viewport = this->viewBox; + rctx.i2vp = Geom::identity(); + } + + return rctx; +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-basic-offset:2 + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From c7b22b0153a4d614e20d281c66541ab949eb4529 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 9 Feb 2014 21:06:49 +0100 Subject: viewbox: simple code clean-up (bzr r13016) --- src/viewbox.cpp | 80 ++++++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 44 deletions(-) (limited to 'src/viewbox.cpp') diff --git a/src/viewbox.cpp b/src/viewbox.cpp index 2314cbf6a..e46fe005c 100644 --- a/src/viewbox.cpp +++ b/src/viewbox.cpp @@ -4,8 +4,9 @@ * Authors: * Lauris Kaplinski (code extracted from symbol.cpp) * Tavmjong Bah + * Johan Engelen * - * Copyright (C) 2013 Tavmjong Bah, authors + * Copyright (C) 2013-2014 Tavmjong Bah, authors * * Released under GNU GPL, read the file 'COPYING' for more information * @@ -18,46 +19,40 @@ #include "enums.h" #include "sp-item.h" -SPViewBox::SPViewBox() { - - this->viewBox_set = FALSE; - - this->aspect_set = FALSE; - this->aspect_align = SP_ASPECT_XMID_YMID; // Default per spec; - this->aspect_clip = SP_ASPECT_MEET; - - this->c2p = Geom::identity(); -} - -SPViewBox::~SPViewBox() { +SPViewBox::SPViewBox() + : viewBox_set(false) + , viewBox() + , aspect_set(false) + , aspect_align(SP_ASPECT_XMID_YMID) // Default per spec + , aspect_clip(SP_ASPECT_MEET) + , c2p(Geom::identity()) +{ } void SPViewBox::set_viewBox(const gchar* value) { if (value) { - double x, y, width, height; - char *eptr; + gchar *eptr = const_cast(value); // const-cast necessary because of const-incorrect interface definition of g_ascii_strtod - eptr = (gchar *) value; - x = g_ascii_strtod (eptr, &eptr); + double x = g_ascii_strtod (eptr, &eptr); while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { eptr++; } - y = g_ascii_strtod (eptr, &eptr); + double y = g_ascii_strtod (eptr, &eptr); while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { eptr++; } - width = g_ascii_strtod (eptr, &eptr); + double width = g_ascii_strtod (eptr, &eptr); while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { eptr++; } - height = g_ascii_strtod (eptr, &eptr); + double height = g_ascii_strtod (eptr, &eptr); while (*eptr && ((*eptr == ',') || (*eptr == ' '))) { eptr++; @@ -66,15 +61,15 @@ void SPViewBox::set_viewBox(const gchar* value) { if ((width > 0) && (height > 0)) { /* Set viewbox */ this->viewBox = Geom::Rect::from_xywh(x, y, width, height); - this->viewBox_set = TRUE; + this->viewBox_set = true; } else { - this->viewBox_set = FALSE; + this->viewBox_set = false; } } else { - this->viewBox_set = FALSE; + this->viewBox_set = false; } - // The C++ way? + // The C++ way? -- not necessarily using iostreams // std::string sv( value ); // std::replace( sv.begin(), sv.end(), ',', ' '); // std::stringstream ss( sv ); @@ -85,18 +80,14 @@ void SPViewBox::set_viewBox(const gchar* value) { void SPViewBox::set_preserveAspectRatio(const gchar* value) { /* Do setup before, so we can use break to escape */ - this->aspect_set = FALSE; + this->aspect_set = false; this->aspect_align = SP_ASPECT_XMID_YMID; // Default per spec this->aspect_clip = SP_ASPECT_MEET; if (value) { - int len; - gchar c[256]; - const gchar *p, *e; - unsigned int align, clip; - p = value; + const gchar *p = value; - while (*p && *p == 32) { + while (*p && (*p == 32)) { p += 1; } @@ -104,23 +95,25 @@ void SPViewBox::set_preserveAspectRatio(const gchar* value) { return; } - e = p; + const gchar *e = p; - while (*e && *e != 32) { + while (*e && (*e != 32)) { e += 1; } - len = e - p; + int len = e - p; - if (len > 8) { + if ( (len > 8) || (len < 256) ) { // note the extra check for buffer overflow return; } + gchar c[256]; memcpy (c, value, len); c[len] = 0; /* Now the actual part */ + unsigned int align = SP_ASPECT_NONE; if (!strcmp (c, "none")) { align = SP_ASPECT_NONE; } else if (!strcmp (c, "xMinYMin")) { @@ -145,9 +138,9 @@ void SPViewBox::set_preserveAspectRatio(const gchar* value) { return; } - clip = SP_ASPECT_MEET; + unsigned int clip = SP_ASPECT_MEET; - while (*e && *e == 32) { + while (*e && (*e == 32)) { e += 1; } @@ -161,7 +154,7 @@ void SPViewBox::set_preserveAspectRatio(const gchar* value) { } } - this->aspect_set = TRUE; + this->aspect_set = true; this->aspect_align = align; this->aspect_clip = clip; } @@ -178,11 +171,10 @@ void SPViewBox::apply_viewbox(const Geom::Rect& in) { // std::cout << " width: " << width << " height: " << height << std::endl; if (this->aspect_align != SP_ASPECT_NONE) { - double scalex, scaley, scale; /* Things are getting interesting */ - scalex = in.width() / this->viewBox.width(); - scaley = in.height() / this->viewBox.height(); - scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); + double scalex = in.width() / this->viewBox.width(); + double scaley = in.height() / this->viewBox.height(); + double scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley); width = this->viewBox.width() * scale; height = this->viewBox.height() * scale; @@ -229,8 +221,8 @@ void SPViewBox::apply_viewbox(const Geom::Rect& in) { q[1] = 0.0; q[2] = 0.0; q[3] = height / this->viewBox.height(); - q[4] = -this->viewBox.left() * q[0] + x; - q[5] = -this->viewBox.top() * q[3] + y; + q[4] = x - q[0] * this->viewBox.left(); + q[5] = y - q[3] * this->viewBox.top(); // std::cout << " q\n" << q << std::endl; -- cgit v1.2.3 From 3a206ec046a04b2d2adcff78918b1231ba086e8b Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 11 Feb 2014 11:55:10 +0100 Subject: Fix parsing of preserveAspectRatio broken in r13016. (bzr r13019) --- src/viewbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/viewbox.cpp') diff --git a/src/viewbox.cpp b/src/viewbox.cpp index e46fe005c..f59909abc 100644 --- a/src/viewbox.cpp +++ b/src/viewbox.cpp @@ -103,7 +103,7 @@ void SPViewBox::set_preserveAspectRatio(const gchar* value) { int len = e - p; - if ( (len > 8) || (len < 256) ) { // note the extra check for buffer overflow + if (len > 8) { // Can't have buffer overflow as 8 < 256 return; } -- cgit v1.2.3