summaryrefslogtreecommitdiffstats
path: root/src/viewbox.cpp
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2014-02-06 14:29:15 +0000
committertavmjong-free <tavmjong@free.fr>2014-02-06 14:29:15 +0000
commit7dd239eed97761b22ef635b6896a8f65c4939462 (patch)
treea9c4eb95e2ae1356cd584151683dc9373e4f1140 /src/viewbox.cpp
parentExtensions->Render submenu. Scaling of input parameters into document units, ... (diff)
downloadinkscape-7dd239eed97761b22ef635b6896a8f65c4939462.tar.gz
inkscape-7dd239eed97761b22ef635b6896a8f65c4939462.zip
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)
Diffstat (limited to 'src/viewbox.cpp')
-rw-r--r--src/viewbox.cpp277
1 files changed, 277 insertions, 0 deletions
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 <lauris@kaplinski.com> (code extracted from symbol.cpp)
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * 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 :