summaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/Makefile_insert3
-rw-r--r--src/document.cpp10
-rw-r--r--src/marker.cpp257
-rw-r--r--src/marker.h14
-rw-r--r--src/sp-image.cpp347
-rw-r--r--src/sp-image.h14
-rw-r--r--src/sp-pattern.cpp55
-rw-r--r--src/sp-pattern.h6
-rw-r--r--src/sp-root.cpp327
-rw-r--r--src/sp-root.h15
-rw-r--r--src/sp-symbol.cpp234
-rw-r--r--src/sp-symbol.h15
-rw-r--r--src/viewbox.cpp277
-rw-r--r--src/viewbox.h66
15 files changed, 601 insertions, 1042 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 54b15d342..d1a3d194e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -78,7 +78,7 @@ set(sp_SRC
sp-use-reference.cpp
sp-use.cpp
splivarot.cpp
-
+ viewbox.cpp
# -------
# Headers
@@ -163,6 +163,7 @@ set(sp_SRC
sp-tspan.h
sp-use-reference.h
sp-use.h
+ viewbox.h
)
set(inkscape_SRC
diff --git a/src/Makefile_insert b/src/Makefile_insert
index 5e441560a..7aedb38ee 100644
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
@@ -228,7 +228,8 @@ ink_common_sources += \
uri-references.cpp uri-references.h \
vanishing-point.cpp vanishing-point.h \
verbs.cpp verbs.h \
- version.cpp version.h
+ version.cpp version.h \
+ viewbox.cpp viewbox.h
# Additional dependencies
diff --git a/src/document.cpp b/src/document.cpp
index 634462001..6f957cace 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -381,16 +381,6 @@ SPDocument *SPDocument::createDoc(Inkscape::XML::Document *rdoc,
rroot->setAttribute("inkscape:version", Inkscape::version_string);
/* fixme: Again, I moved these here to allow version determining in ::build (Lauris) */
- /* Quick hack 2 - get default image size into document */
- if (!rroot->attribute("width")) rroot->setAttribute("width", "100%");
- if (!rroot->attribute("height")) rroot->setAttribute("height", "100%");
- /* End of quick hack 2 */
-
- /* Quick hack 3 - Set uri attributes */
-// if (uri) { // this is done in do_change_uri()
-// rroot->setAttribute("sodipodi:docname", uri);
-// }
- /* End of quick hack 3 */
/* Eliminate obsolete sodipodi:docbase, for privacy reasons */
rroot->setAttribute("sodipodi:docbase", NULL);
diff --git a/src/marker.cpp b/src/marker.cpp
index b9464186d..f6e55b3ec 100644
--- a/src/marker.cpp
+++ b/src/marker.cpp
@@ -47,18 +47,15 @@ namespace {
bool markerRegistered = SPFactory::instance().registerObject("svg:marker", createMarker);
}
-SPMarker::SPMarker() : SPGroup() {
- this->aspect_clip = 0;
- this->aspect_align = 0;
- this->aspect_set = 0;
- this->markerUnits = 0;
- this->orient_auto = 0;
- this->markerUnits_set = 0;
- this->orient_set = 0;
- this->orient = 0;
-
- this->viewBox = Geom::OptRect();
- this->c2p.setIdentity();
+SPMarker::SPMarker() : SPGroup(), SPViewBox() {
+
+ this->markerUnits = 0;
+ this->markerUnits_set = 0;
+
+ this->orient_auto = 0;
+ this->orient_set = 0;
+ this->orient = 0;
+
this->views = NULL;
}
@@ -177,133 +174,14 @@ void SPMarker::set(unsigned int key, const gchar* value) {
break;
case SP_ATTR_VIEWBOX:
- this->viewBox = Geom::OptRect();
-
- if (value) {
- double x, y, width, height;
- char *eptr;
-
- /* fixme: We have to take original item affine into account */
- /* fixme: Think (Lauris) */
- 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(Geom::Point(x, y), Geom::Point(x + width, y + height));
- }
- }
-
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
- break;
+ set_viewBox( value );
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
+ break;
case SP_ATTR_PRESERVEASPECTRATIO:
- /* Do setup before, so we can use break to escape */
- this->aspect_set = FALSE;
- this->aspect_align = SP_ASPECT_NONE;
- this->aspect_clip = SP_ASPECT_MEET;
-
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
-
- 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) {
- break;
- }
-
- e = p;
-
- while (*e && *e != 32) {
- e += 1;
- }
-
- len = e - p;
-
- if (len > 8) {
- break;
- }
-
- 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 {
- break;
- }
-
- 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 {
- break;
- }
- }
-
- this->aspect_set = TRUE;
- this->aspect_align = align;
- this->aspect_clip = clip;
- }
- break;
+ set_preserveAspectRatio( value );
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
+ break;
default:
SPGroup::set(key, value);
@@ -312,112 +190,23 @@ void SPMarker::set(unsigned int key, const gchar* value) {
}
void SPMarker::update(SPCtx *ctx, guint flags) {
- SPItemCtx rctx;
- // fixme: We have to set up clip here too
+ SPItemCtx ictx;
// Copy parent context
- rctx.flags = ctx->flags;
+ ictx.flags = ctx->flags;
// Initialize transformations
- rctx.i2doc = Geom::identity();
- rctx.i2vp = Geom::identity();
+ ictx.i2doc = Geom::identity();
+ ictx.i2vp = Geom::identity();
// Set up viewport
- rctx.viewport = Geom::Rect::from_xywh(0, 0, this->markerWidth.computed, this->markerHeight.computed);
-
- // Start with identity transform
- this->c2p.setIdentity();
+ ictx.viewport = Geom::Rect::from_xywh(0, 0, this->markerWidth.computed, this->markerHeight.computed);
- // Viewbox is always present, either implicitly or explicitly
- Geom::Rect vb;
- if (this->viewBox) {
- vb = *this->viewBox;
- } else {
- vb = rctx.viewport;
- }
+ SPItemCtx rctx = get_rctx( &ictx );
- // Now set up viewbox transformation
-
- // Determine actual viewbox in viewport coordinates
- // double x = 0;
- // double y = 0;
- double width = 0;
- double height = 0;
-
- if (this->aspect_align == SP_ASPECT_NONE) {
- // x = 0.0;
- // y = 0.0;
- width = rctx.viewport.width();
- height = rctx.viewport.height();
- } else {
- double scalex, scaley, scale;
- // Things are getting interesting
- scalex = rctx.viewport.width() / (vb.width());
- scaley = rctx.viewport.height() / (vb.height());
- scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley);
- width = (vb.width()) * scale;
- height = (vb.height()) * scale;
-
- // Now place viewbox to requested position
- /*switch (marker->aspect_align) {
- case SP_ASPECT_XMIN_YMIN:
- x = 0.0;
- y = 0.0;
- break;
- case SP_ASPECT_XMID_YMIN:
- x = 0.5 * (rctx.viewport.width() - width);
- y = 0.0;
- break;
- case SP_ASPECT_XMAX_YMIN:
- x = 1.0 * (rctx.viewport.width() - width);
- y = 0.0;
- break;
- case SP_ASPECT_XMIN_YMID:
- x = 0.0;
- y = 0.5 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMID_YMID:
- x = 0.5 * (rctx.viewport.width() - width);
- y = 0.5 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMAX_YMID:
- x = 1.0 * (rctx.viewport.width() - width);
- y = 0.5 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMIN_YMAX:
- x = 0.0;
- y = 1.0 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMID_YMAX:
- x = 0.5 * (rctx.viewport.width() - width);
- y = 1.0 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMAX_YMAX:
- x = 1.0 * (rctx.viewport.width() - width);
- y = 1.0 * (rctx.viewport.height() - height);
- break;
- default:
- x = 0.0;
- y = 0.0;
- break;
- }*/
- }
-
- // TODO fixme: all that work is done to figure out x and y, which are just ignored. Check why.
-
- // viewbox transformation and reference translation
- this->c2p = Geom::Translate(-this->refX.computed, -this->refY.computed) *
- Geom::Scale(width / vb.width(), height / vb.height());
-
- rctx.i2doc = this->c2p * rctx.i2doc;
-
- // If viewBox is set reinitialize child viewport
- // Otherwise it already correct
- if (this->viewBox) {
- rctx.viewport = *this->viewBox;
- rctx.i2vp = Geom::identity();
- }
+ // Shift according to refX, refY
+ this->c2p = Geom::Translate(this->viewBox.left()-this->refX.computed, this->viewBox.top()-this->refY.computed) * this->c2p;
// And invoke parent method
SPGroup::update((SPCtx *) &rctx, flags);
diff --git a/src/marker.h b/src/marker.h
index b780950de..d41df69b4 100644
--- a/src/marker.h
+++ b/src/marker.h
@@ -31,8 +31,9 @@ struct SPMarkerView;
#include "sp-item-group.h"
#include "sp-marker-loc.h"
#include "uri-references.h"
+#include "viewbox.h"
-class SPMarker : public SPGroup {
+class SPMarker : public SPGroup, public SPViewBox {
public:
SPMarker();
virtual ~SPMarker();
@@ -54,17 +55,6 @@ public:
unsigned int orient_auto : 1;
float orient;
- /* viewBox; */
- Geom::OptRect viewBox;
-
- /* preserveAspectRatio */
- unsigned int aspect_set : 1;
- unsigned int aspect_align : 4;
- unsigned int aspect_clip : 1;
-
- /* Child to parent additional transform */
- Geom::Affine c2p;
-
/* Private views */
SPMarkerView *views;
diff --git a/src/sp-image.cpp b/src/sp-image.cpp
index 8f7a60ca6..5f630f7b7 100644
--- a/src/sp-image.cpp
+++ b/src/sp-image.cpp
@@ -119,14 +119,12 @@ SPObject* createImage() {
bool imageRegistered = SPFactory::instance().registerObject("svg:image", createImage);
}
-SPImage::SPImage() : SPItem() {
- this->aspect_clip = 0;
+SPImage::SPImage() : SPItem(), SPViewBox() {
this->x.unset();
this->y.unset();
this->width.unset();
this->height.unset();
- this->aspect_align = SP_ASPECT_NONE;
this->clipbox = Geom::Rect();
this->sx = this->sy = 1.0;
this->ox = this->oy = 0.0;
@@ -195,8 +193,8 @@ void SPImage::set(unsigned int key, const gchar* value) {
break;
case SP_ATTR_X:
- if (!this->x.readAbsolute(value)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
+ /* ex, em not handled correctly. */
+ if (!this->x.read(value)) {
this->x.unset();
}
@@ -204,8 +202,8 @@ void SPImage::set(unsigned int key, const gchar* value) {
break;
case SP_ATTR_Y:
- if (!this->y.readAbsolute(value)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
+ /* ex, em not handled correctly. */
+ if (!this->y.read(value)) {
this->y.unset();
}
@@ -213,8 +211,8 @@ void SPImage::set(unsigned int key, const gchar* value) {
break;
case SP_ATTR_WIDTH:
- if (!this->width.readAbsolute(value)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
+ /* ex, em not handled correctly. */
+ if (!this->width.read(value)) {
this->width.unset();
}
@@ -222,8 +220,8 @@ void SPImage::set(unsigned int key, const gchar* value) {
break;
case SP_ATTR_HEIGHT:
- if (!this->height.readAbsolute(value)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
+ /* ex, em not handled correctly. */
+ if (!this->height.read(value)) {
this->height.unset();
}
@@ -231,67 +229,8 @@ void SPImage::set(unsigned int key, const gchar* value) {
break;
case SP_ATTR_PRESERVEASPECTRATIO:
- /* Do setup before, so we can use break to escape */
- this->aspect_align = SP_ASPECT_NONE;
- this->aspect_clip = SP_ASPECT_MEET;
+ set_preserveAspectRatio( value );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
-
- 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) break;
- e = p;
- while (*e && *e != 32) e += 1;
- len = e - p;
- if (len > 8) break;
- 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 {
- break;
- }
-
- 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 {
- break;
- }
- }
-
- this->aspect_align = align;
- this->aspect_clip = clip;
- }
break;
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
@@ -322,7 +261,79 @@ void SPImage::set(unsigned int key, const gchar* value) {
sp_image_set_curve(this); //creates a curve at the image's boundary for snapping
}
+// BLIP
+#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+void SPImage::apply_profile(Inkscape::Pixbuf *pixbuf) {
+
+ // TODO: this will prevent using MIME data when exporting.
+ // Integrate color correction into loading.
+ pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_GDK);
+ int imagewidth = pixbuf->width();
+ int imageheight = pixbuf->height();
+ int rowstride = pixbuf->rowstride();;
+ guchar* px = pixbuf->pixels();
+
+ if ( px ) {
+ DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" );
+
+ guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN;
+ cmsHPROFILE prof = Inkscape::CMSSystem::getHandle( this->document,
+ &profIntent,
+ this->color_profile );
+ if ( prof ) {
+ cmsProfileClassSignature profileClass = cmsGetDeviceClass( prof );
+ if ( profileClass != cmsSigNamedColorClass ) {
+ int intent = INTENT_PERCEPTUAL;
+
+ switch ( profIntent ) {
+ case Inkscape::RENDERING_INTENT_RELATIVE_COLORIMETRIC:
+ intent = INTENT_RELATIVE_COLORIMETRIC;
+ break;
+ case Inkscape::RENDERING_INTENT_SATURATION:
+ intent = INTENT_SATURATION;
+ break;
+ case Inkscape::RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
+ intent = INTENT_ABSOLUTE_COLORIMETRIC;
+ break;
+ case Inkscape::RENDERING_INTENT_PERCEPTUAL:
+ case Inkscape::RENDERING_INTENT_UNKNOWN:
+ case Inkscape::RENDERING_INTENT_AUTO:
+ default:
+ intent = INTENT_PERCEPTUAL;
+ }
+
+ cmsHPROFILE destProf = cmsCreate_sRGBProfile();
+ cmsHTRANSFORM transf = cmsCreateTransform( prof,
+ TYPE_RGBA_8,
+ destProf,
+ TYPE_RGBA_8,
+ intent, 0 );
+ if ( transf ) {
+ guchar* currLine = px;
+ for ( int y = 0; y < imageheight; y++ ) {
+ // Since the types are the same size, we can do the transformation in-place
+ cmsDoTransform( transf, currLine, currLine, imagewidth );
+ currLine += rowstride;
+ }
+
+ cmsDeleteTransform( transf );
+ } else {
+ DEBUG_MESSAGE( lcmsSix, "in <image>'s sp_image_update. Unable to create LCMS transform." );
+ }
+
+ cmsCloseProfile( destProf );
+ } else {
+ DEBUG_MESSAGE( lcmsSeven, "in <image>'s sp_image_update. Profile type is named color. Can't transform." );
+ }
+ } else {
+ DEBUG_MESSAGE( lcmsEight, "in <image>'s sp_image_update. No profile found." );
+ }
+ }
+}
+#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+
void SPImage::update(SPCtx *ctx, unsigned int flags) {
+
SPDocument *doc = this->document;
SPItem::update(ctx, flags);
@@ -339,170 +350,84 @@ void SPImage::update(SPCtx *ctx, unsigned int flags) {
doc->getBase());
if (pixbuf) {
-// BLIP
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
- if ( this->color_profile )
- {
- // TODO: this will prevent using MIME data when exporting.
- // Integrate color correction into loading.
- pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_GDK);
- int imagewidth = pixbuf->width();
- int imageheight = pixbuf->height();
- int rowstride = pixbuf->rowstride();;
- guchar* px = pixbuf->pixels();
-
- if ( px ) {
- DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" );
-
- guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN;
- cmsHPROFILE prof = Inkscape::CMSSystem::getHandle( this->document,
- &profIntent,
- this->color_profile );
- if ( prof ) {
- cmsProfileClassSignature profileClass = cmsGetDeviceClass( prof );
- if ( profileClass != cmsSigNamedColorClass ) {
- int intent = INTENT_PERCEPTUAL;
-
- switch ( profIntent ) {
- case Inkscape::RENDERING_INTENT_RELATIVE_COLORIMETRIC:
- intent = INTENT_RELATIVE_COLORIMETRIC;
- break;
- case Inkscape::RENDERING_INTENT_SATURATION:
- intent = INTENT_SATURATION;
- break;
- case Inkscape::RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
- intent = INTENT_ABSOLUTE_COLORIMETRIC;
- break;
- case Inkscape::RENDERING_INTENT_PERCEPTUAL:
- case Inkscape::RENDERING_INTENT_UNKNOWN:
- case Inkscape::RENDERING_INTENT_AUTO:
- default:
- intent = INTENT_PERCEPTUAL;
- }
-
- cmsHPROFILE destProf = cmsCreate_sRGBProfile();
- cmsHTRANSFORM transf = cmsCreateTransform( prof,
- TYPE_RGBA_8,
- destProf,
- TYPE_RGBA_8,
- intent, 0 );
- if ( transf ) {
- guchar* currLine = px;
- for ( int y = 0; y < imageheight; y++ ) {
- // Since the types are the same size, we can do the transformation in-place
- cmsDoTransform( transf, currLine, currLine, imagewidth );
- currLine += rowstride;
- }
-
- cmsDeleteTransform( transf );
- } else {
- DEBUG_MESSAGE( lcmsSix, "in <image>'s sp_image_update. Unable to create LCMS transform." );
- }
-
- cmsCloseProfile( destProf );
- } else {
- DEBUG_MESSAGE( lcmsSeven, "in <image>'s sp_image_update. Profile type is named color. Can't transform." );
- }
- } else {
- DEBUG_MESSAGE( lcmsEight, "in <image>'s sp_image_update. No profile found." );
- }
- }
- }
-#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
-
+ if ( this->color_profile ) apply_profile( pixbuf );
+#endif
this->pixbuf = pixbuf;
}
}
}
+ SPItemCtx *ictx = (SPItemCtx *) ctx;
+
+ // Why continue without a pixbuf? So we can display "Missing Image" png.
+ // Eventually, we should properly support SVG image type (i.e. render it ourselves).
+
if (this->pixbuf) {
- /* fixme: We are slightly violating spec here (Lauris) */
+ if (!this->x._set) {
+ this->x.unit = SVGLength::PX;
+ this->x.computed = 0;
+ }
+
+ if (!this->y._set) {
+ this->y.unit = SVGLength::PX;
+ this->y.computed = 0;
+ }
+
if (!this->width._set) {
+ this->width.unit = SVGLength::PX;
this->width.computed = this->pixbuf->width();
}
if (!this->height._set) {
+ this->height.unit = SVGLength::PX;
this->height.computed = this->pixbuf->height();
}
}
- this->clipbox = Geom::Rect::from_xywh(
- this->x.computed, this->y.computed,
- this->width.computed, this->height.computed);
+
+ // Calculate x, y, width, height from parent/initial viewport, see sp-root.cpp
+ if (this->x.unit == SVGLength::PERCENT) {
+ this->x.computed = this->x.value * ictx->viewport.width();
+ }
+
+ if (this->y.unit == SVGLength::PERCENT) {
+ this->y.computed = this->y.value * ictx->viewport.height();
+ }
+
+ if (this->width.unit == SVGLength::PERCENT) {
+ this->width.computed = this->width.value * ictx->viewport.width();
+ }
+
+ if (this->height.unit == SVGLength::PERCENT) {
+ this->height.computed = this->height.value * ictx->viewport.height();
+ }
+
+ // Image creates a new viewport
+ ictx->viewport= Geom::Rect::from_xywh( this->x.computed, this->y.computed,
+ this->width.computed, this->height.computed);
+
+ this->clipbox = ictx->viewport;
this->ox = this->x.computed;
this->oy = this->y.computed;
if (this->pixbuf) {
- int pixwidth = this->pixbuf->width();
- int pixheight = this->pixbuf->height();
-
- this->sx = this->width.computed / pixwidth;
- this->sy = this->height.computed / pixheight;
-
- // preserveAspectRatio calculate bounds / clipping rectangle -- EAF
- if (this->aspect_align != SP_ASPECT_NONE) {
- double x, y;
-
- switch (this->aspect_align) {
- case SP_ASPECT_XMIN_YMIN:
- x = 0.0;
- y = 0.0;
- break;
- case SP_ASPECT_XMID_YMIN:
- x = 0.5;
- y = 0.0;
- break;
- case SP_ASPECT_XMAX_YMIN:
- x = 1.0;
- y = 0.0;
- break;
- case SP_ASPECT_XMIN_YMID:
- x = 0.0;
- y = 0.5;
- break;
- case SP_ASPECT_XMID_YMID:
- x = 0.5;
- y = 0.5;
- break;
- case SP_ASPECT_XMAX_YMID:
- x = 1.0;
- y = 0.5;
- break;
- case SP_ASPECT_XMIN_YMAX:
- x = 0.0;
- y = 1.0;
- break;
- case SP_ASPECT_XMID_YMAX:
- x = 0.5;
- y = 1.0;
- break;
- case SP_ASPECT_XMAX_YMAX:
- x = 1.0;
- y = 1.0;
- break;
- default:
- x = 0.0;
- y = 0.0;
- break;
- }
- if (this->aspect_clip == SP_ASPECT_SLICE) {
- double scale = std::max(this->sx, this->sy);
- this->sx = scale;
- this->sy = scale;
- } else {
- double scale = std::min(this->sx, this->sy);
- this->sx = scale;
- this->sy = scale;
- }
+ // Viewbox is either from SVG (not supported) or dimensions of pixbuf (PNG, JPG)
+ this->viewBox = Geom::Rect::from_xywh(0, 0, this->pixbuf->width(), this->pixbuf->height());
+ this->viewBox_set = true;
- double vw = pixwidth * this->sx;
- double vh = pixheight * this->sy;
- this->ox += x * (this->width.computed - vw);
- this->oy += y * (this->height.computed - vh);
- }
+ // SPItemCtx rctx =
+ get_rctx( ictx );
+
+ this->ox = c2p[4];
+ this->oy = c2p[5];
+ this->sx = c2p[0];
+ this->sy = c2p[3];
}
+
+ // TODO: eliminate ox, oy, sx, sy
sp_image_update_canvas_image ((SPImage *) this);
}
diff --git a/src/sp-image.h b/src/sp-image.h
index 3b7208487..50eb731d7 100644
--- a/src/sp-image.h
+++ b/src/sp-image.h
@@ -18,6 +18,7 @@
#include <glibmm/ustring.h>
#include "svg/svg-length.h"
#include "sp-shape.h"
+#include "viewbox.h"
#define SP_IMAGE(obj) (dynamic_cast<SPImage*>((SPObject*)obj))
#define SP_IS_IMAGE(obj) (dynamic_cast<const SPImage*>((SPObject*)obj) != NULL)
@@ -25,7 +26,7 @@
#define SP_IMAGE_HREF_MODIFIED_FLAG SP_OBJECT_USER_MODIFIED_FLAG_A
namespace Inkscape { class Pixbuf; }
-class SPImage : public SPItem {
+class SPImage : public SPItem, public SPViewBox {
public:
SPImage();
virtual ~SPImage();
@@ -39,13 +40,6 @@ public:
double sx, sy;
double ox, oy;
- // Added by EAF
- /* preserveAspectRatio */
- unsigned int aspect_align : 4;
- unsigned int aspect_clip : 1;
- //int trimx, trimy, trimwidth, trimheight;
- //double viewx, viewy, viewwidth, viewheight;
-
SPCurve *curve; // This curve is at the image's boundary for snapping
gchar *href;
@@ -69,6 +63,10 @@ public:
virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags);
virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const;
virtual Geom::Affine set_transform(Geom::Affine const &transform);
+
+#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+ void apply_profile(Inkscape::Pixbuf *pixbuf);
+#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
};
/* Return duplicate of curve or NULL */
diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp
index ad5449f34..711f26428 100644
--- a/src/sp-pattern.cpp
+++ b/src/sp-pattern.cpp
@@ -53,7 +53,7 @@ namespace {
bool patternRegistered = SPFactory::instance().registerObject("svg:pattern", createPattern);
}
-SPPattern::SPPattern() : SPPaintServer() {
+SPPattern::SPPattern() : SPPaintServer(), SPViewBox() {
this->href = NULL;
this->ref = new SPPatternReference(this);
@@ -72,8 +72,6 @@ SPPattern::SPPattern() : SPPaintServer() {
this->y.unset();
this->width.unset();
this->height.unset();
-
- this->viewBox_set = FALSE;
}
SPPattern::~SPPattern() {
@@ -90,6 +88,7 @@ void SPPattern::build(SPDocument* doc, Inkscape::XML::Node* repr) {
this->readAttr( "width" );
this->readAttr( "height" );
this->readAttr( "viewBox" );
+ this->readAttr( "preserveAspectRatio" );
this->readAttr( "xlink:href" );
/* Register ourselves */
@@ -180,50 +179,16 @@ void SPPattern::set(unsigned int key, const gchar* value) {
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
- case SP_ATTR_VIEWBOX: {
- /* fixme: Think (Lauris) */
- double x, y, width, height;
- char *eptr;
-
- if (value) {
- 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++;
- }
+ case SP_ATTR_VIEWBOX:
+ set_viewBox( value );
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
+ break;
- if ((width > 0) && (height > 0)) {
- this->viewBox = Geom::Rect::from_xywh(x, y, width, height);
- this->viewBox_set = TRUE;
- } else {
- this->viewBox_set = FALSE;
- }
- } else {
- this->viewBox_set = FALSE;
- }
+ case SP_ATTR_PRESERVEASPECTRATIO:
+ set_preserveAspectRatio( value );
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
+ break;
- this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
- break;
- }
case SP_ATTR_XLINK_HREF:
if ( value && this->href && ( strcmp(value, this->href) == 0 ) ) {
/* Href unchanged, do nothing. */
diff --git a/src/sp-pattern.h b/src/sp-pattern.h
index 4e3657ccf..f69ba10b3 100644
--- a/src/sp-pattern.h
+++ b/src/sp-pattern.h
@@ -25,12 +25,13 @@ class SPPatternReference;
#include "svg/svg-length.h"
#include "sp-paint-server.h"
#include "uri-references.h"
+#include "viewbox.h"
#include <stddef.h>
#include <sigc++/connection.h>
-class SPPattern : public SPPaintServer {
+class SPPattern : public SPPaintServer, public SPViewBox {
public:
SPPattern();
virtual ~SPPattern();
@@ -52,9 +53,6 @@ public:
SVGLength y;
SVGLength width;
SVGLength height;
- /* VieBox */
- Geom::Rect viewBox;
- guint viewBox_set : 1;
sigc::connection modified_connection;
diff --git a/src/sp-root.cpp b/src/sp-root.cpp
index 5466649a2..bc870b116 100644
--- a/src/sp-root.cpp
+++ b/src/sp-root.cpp
@@ -42,12 +42,9 @@ SPObject *createRoot()
bool rootRegistered = SPFactory::instance().registerObject("svg:svg", createRoot);
}
-SPRoot::SPRoot() : SPGroup()
+SPRoot::SPRoot() : SPGroup(), SPViewBox()
{
- this->aspect_set = 0;
- this->aspect_align = 0;
this->onload = NULL;
- this->aspect_clip = 0;
static Inkscape::Version const zero_version(0, 0);
@@ -57,15 +54,11 @@ SPRoot::SPRoot() : SPGroup()
this->version.inkscape = zero_version;
this->original.inkscape = zero_version;
- this->x.unset();
- this->y.unset();
+ this->x.unset(SVGLength::PERCENT, 0.0, 0.0); // Ignored for root SVG element
+ this->y.unset(SVGLength::PERCENT, 0.0, 0.0);
this->width.unset(SVGLength::PERCENT, 1.0, 1.0);
this->height.unset(SVGLength::PERCENT, 1.0, 1.0);
- this->viewBox_set = false;
-
- this->c2p.setIdentity();
-
this->defs = NULL;
}
@@ -129,9 +122,9 @@ void SPRoot::set(unsigned int key, const gchar *value)
break;
case SP_ATTR_X:
- if (!this->x.readAbsolute(value)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
- this->x.unset();
+ /* Valid for non-root SVG elements; ex, em not handled correctly. */
+ if (!this->x.read(value)) {
+ this->x.unset(SVGLength::PERCENT, 0.0, 0.0);
}
/* fixme: I am almost sure these do not require viewport flag (Lauris) */
@@ -139,9 +132,9 @@ void SPRoot::set(unsigned int key, const gchar *value)
break;
case SP_ATTR_Y:
- if (!this->y.readAbsolute(value)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
- this->y.unset();
+ /* Valid for non-root SVG elements; ex, em not handled correctly. */
+ if (!this->y.read(value)) {
+ this->y.unset(SVGLength::PERCENT, 0.0, 0.0);
}
/* fixme: I am almost sure these do not require viewport flag (Lauris) */
@@ -149,153 +142,27 @@ void SPRoot::set(unsigned int key, const gchar *value)
break;
case SP_ATTR_WIDTH:
- if (!this->width.readAbsolute(value) || !(this->width.computed > 0.0)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
+ if (!this->width.read(value) || !(this->width.computed > 0.0)) {
this->width.unset(SVGLength::PERCENT, 1.0, 1.0);
}
-
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
break;
case SP_ATTR_HEIGHT:
- if (!this->height.readAbsolute(value) || !(this->height.computed > 0.0)) {
- /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
+ if (!this->height.read(value) || !(this->height.computed > 0.0)) {
this->height.unset(SVGLength::PERCENT, 1.0, 1.0);
}
-
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
break;
case SP_ATTR_VIEWBOX:
- if (value) {
- double x, y, width, height;
- char *eptr;
-
- /* fixme: We have to take original item affine into account */
- /* fixme: Think (Lauris) */
- 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;
- }
-
+ set_viewBox( value );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
break;
case SP_ATTR_PRESERVEASPECTRATIO:
- /* Do setup before, so we can use break to escape */
- this->aspect_set = FALSE;
- this->aspect_align = SP_ASPECT_XMID_YMID;
- this->aspect_clip = SP_ASPECT_MEET;
-
+ set_preserveAspectRatio( value );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
-
- if (value) {
- int len;
- gchar c[256];
- gchar const *p, *e;
- unsigned int align, clip;
- p = value;
-
- while (*p && *p == 32) {
- p += 1;
- }
-
- if (!*p) {
- break;
- }
-
- e = p;
-
- while (*e && *e != 32) {
- e += 1;
- }
-
- len = e - p;
-
- if (len > 8) {
- break;
- }
-
- 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 {
- break;
- }
-
- 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 {
- break;
- }
- }
-
- this->aspect_set = TRUE;
- this->aspect_align = align;
- this->aspect_clip = clip;
- }
break;
case SP_ATTR_ONLOAD:
@@ -356,141 +223,75 @@ void SPRoot::update(SPCtx *ctx, guint flags)
{
SPItemCtx *ictx = (SPItemCtx *) ctx;
- /* fixme: This will be invoked too often (Lauris) */
- /* fixme: We should calculate only if parent viewport has changed (Lauris) */
- /* If position is specified as percentage, calculate actual values */
- if (this->x.unit == SVGLength::PERCENT) {
- this->x.computed = this->x.value * ictx->viewport.width();
- }
-
- if (this->y.unit == SVGLength::PERCENT) {
- this->y.computed = this->y.value * ictx->viewport.height();
- }
-
- if (this->width.unit == SVGLength::PERCENT) {
- this->width.computed = this->width.value * ictx->viewport.width();
- }
-
- if (this->height.unit == SVGLength::PERCENT) {
- this->height.computed = this->height.value * ictx->viewport.height();
- }
-
- /* Create copy of item context */
- SPItemCtx rctx = *ictx;
-
- /* Calculate child to parent transformation */
- this->c2p.setIdentity();
+ if( !this->parent ) {
- if (this->parent) {
/*
- * fixme: I am not sure whether setting x and y does or does not
- * fixme: translate the content of inner SVG.
- * fixme: Still applying translation and setting viewport to width and
- * fixme: height seems natural, as this makes the inner svg element
- * fixme: self-contained. The spec is vague here.
+ * This is the root SVG element:
+ *
+ * x, y, width, and height apply to positioning the SVG element inside a parent.
+ * For the root SVG in Inkscape there is no parent, thus special rules apply:
+ * If width, height not set, width = 100%, height = 100% (as always).
+ * If width and height are in percent, they are percent of viewBox width/height.
+ * If width, height, and viewBox are not set... pick "random" width/height.
+ * x, y are ignored.
+ * initial viewport = (0 0 width height)
*/
- this->c2p = Geom::Affine(Geom::Translate(this->x.computed, this->y.computed));
- }
-
- if (this->viewBox_set) {
- double x, y, width, height;
- /* Determine actual viewbox in viewport coordinates */
- if (this->aspect_align == SP_ASPECT_NONE) {
- x = 0.0;
- y = 0.0;
- width = this->width.computed;
- height = this->height.computed;
- } else {
- double scalex, scaley, scale;
- /* Things are getting interesting */
- scalex = this->width.computed / this->viewBox.width();
- scaley = this->height.computed / 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 */
- /* todo: Use an array lookup to find the 0.0/0.5/1.0 coefficients,
- as is done for dialogs/align.cpp. */
- switch (this->aspect_align) {
- case SP_ASPECT_XMIN_YMIN:
- x = 0.0;
- y = 0.0;
- break;
-
- case SP_ASPECT_XMID_YMIN:
- x = 0.5 * (this->width.computed - width);
- y = 0.0;
- break;
-
- case SP_ASPECT_XMAX_YMIN:
- x = 1.0 * (this->width.computed - width);
- y = 0.0;
- break;
-
- case SP_ASPECT_XMIN_YMID:
- x = 0.0;
- y = 0.5 * (this->height.computed - height);
- break;
-
- case SP_ASPECT_XMID_YMID:
- x = 0.5 * (this->width.computed - width);
- y = 0.5 * (this->height.computed - height);
- break;
+ if( this->viewBox_set ) {
- case SP_ASPECT_XMAX_YMID:
- x = 1.0 * (this->width.computed - width);
- y = 0.5 * (this->height.computed - height);
- break;
+ if( this->width._set ) {
+ // Check if this is necessary
+ if (this->width.unit == SVGLength::PERCENT) {
+ this->width.computed = this->width.value * this->viewBox.width();
+ }
+ } else {
+ this->width.set( SVGLength::PX, this->viewBox.width(), this->viewBox.width() );
+ }
- case SP_ASPECT_XMIN_YMAX:
- x = 0.0;
- y = 1.0 * (this->height.computed - height);
- break;
+ if( this->height._set ) {
+ if (this->height.unit == SVGLength::PERCENT) {
+ this->height.computed = this->height.value * this->viewBox.height();
+ }
+ } else {
+ this->height.set(SVGLength::PX, this->viewBox.height(), this->viewBox.height() );
+ }
- case SP_ASPECT_XMID_YMAX:
- x = 0.5 * (this->width.computed - width);
- y = 1.0 * (this->height.computed - height);
- break;
+ } else {
- case SP_ASPECT_XMAX_YMAX:
- x = 1.0 * (this->width.computed - width);
- y = 1.0 * (this->height.computed - height);
- break;
+ if( !this->width._set ) {
+ this->width.set( SVGLength::PX, 100, 100 ); // Random default
+ }
- default:
- x = 0.0;
- y = 0.0;
- break;
+ if( !this->height._set ) {
+ this->height.set( SVGLength::PX, 100, 100 ); // Random default
}
}
- /* Compose additional transformation from scale and position */
- Geom::Scale const viewBox_length(this->viewBox.dimensions());
- Geom::Scale const new_length(width, height);
+ // Ignore x, y values for root element
+ this->x.unset(SVGLength::PERCENT, 0.0, 0.0);
+ this->y.unset(SVGLength::PERCENT, 0.0, 0.0);
+ }
- /* Append viewbox transformation */
- /* TODO: The below looks suspicious to me (pjrm): I wonder whether the RHS
- expression should have c2p at the beginning rather than at the end. Test it. */
- this->c2p = Geom::Translate(-this->viewBox.min()) * (new_length * viewBox_length.inverse()) * Geom::Translate(x, y) * this->c2p;
+ // Calculate x, y, width, height from parent/initial viewport
+ if (this->x.unit == SVGLength::PERCENT) {
+ this->x.computed = this->x.value * ictx->viewport.width();
}
- rctx.i2doc = this->c2p * rctx.i2doc;
+ if (this->y.unit == SVGLength::PERCENT) {
+ this->y.computed = this->y.value * ictx->viewport.height();
+ }
- /* Initialize child viewport */
- if (this->viewBox_set) {
- rctx.viewport = this->viewBox;
- } else {
- /* fixme: I wonder whether this logic is correct (Lauris) */
- Geom::Point minp(0, 0);
- if (this->parent) {
- minp = Geom::Point(this->x.computed, this->y.computed);
- }
+ if (this->width.unit == SVGLength::PERCENT) {
+ this->width.computed = this->width.value * ictx->viewport.width();
+ }
- rctx.viewport = Geom::Rect::from_xywh(minp[Geom::X], minp[Geom::Y], this->width.computed, this->height.computed);
+ if (this->height.unit == SVGLength::PERCENT) {
+ this->height.computed = this->height.value * ictx->viewport.height();
}
- rctx.i2vp = Geom::identity();
+ // Calculate new viewport
+ ictx->viewport = Geom::Rect::from_xywh( this->x.computed, this->y.computed,
+ this->width.computed, this->height.computed );
+ SPItemCtx rctx = get_rctx( ictx );
/* And invoke parent method */
SPGroup::update((SPCtx *) &rctx, flags);
diff --git a/src/sp-root.h b/src/sp-root.h
index 2931391ff..1c9faed9b 100644
--- a/src/sp-root.h
+++ b/src/sp-root.h
@@ -18,6 +18,7 @@
#include "svg/svg-length.h"
#include "enums.h"
#include "sp-item-group.h"
+#include "viewbox.h"
#define SP_ROOT(obj) (dynamic_cast<SPRoot*>((SPObject*)obj))
#define SP_IS_ROOT(obj) (dynamic_cast<const SPRoot*>((SPObject*)obj) != NULL)
@@ -25,7 +26,7 @@
class SPDefs;
/** \<svg\> element */
-class SPRoot : public SPGroup {
+class SPRoot : public SPGroup, public SPViewBox {
public:
SPRoot();
virtual ~SPRoot();
@@ -40,18 +41,6 @@ public:
SVGLength width;
SVGLength height;
- /* viewBox; */
- bool viewBox_set;
- Geom::Rect viewBox;
-
- /* preserveAspectRatio */
- unsigned int aspect_set : 1;
- unsigned int aspect_align : 4;
- unsigned int aspect_clip : 1;
-
- /** Child to parent additional transform. */
- Geom::Affine c2p;
-
gchar *onload;
/**
diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp
index 8ffc2ab2c..817411a32 100644
--- a/src/sp-symbol.cpp
+++ b/src/sp-symbol.cpp
@@ -36,13 +36,7 @@ namespace {
bool symbolRegistered = SPFactory::instance().registerObject("svg:symbol", createSymbol);
}
-SPSymbol::SPSymbol() : SPGroup() {
- this->aspect_align = 0;
- this->aspect_clip = 0;
- this->aspect_set = 0;
-
- this->viewBox_set = FALSE;
- this->c2p = Geom::identity();
+SPSymbol::SPSymbol() : SPGroup(), SPViewBox() {
}
SPSymbol::~SPSymbol() {
@@ -62,134 +56,15 @@ void SPSymbol::release() {
void SPSymbol::set(unsigned int key, const gchar* value) {
switch (key) {
case SP_ATTR_VIEWBOX:
- if (value) {
- double x, y, width, height;
- char *eptr;
-
- /* fixme: We have to take original item affine into account */
- /* fixme: Think (Lauris) */
- 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;
- }
-
+ set_viewBox( value );
+ std::cout << "Symbol: ViewBox: " << viewBox << std::endl;
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
break;
case SP_ATTR_PRESERVEASPECTRATIO:
- /* Do setup before, so we can use break to escape */
- this->aspect_set = FALSE;
- this->aspect_align = SP_ASPECT_NONE;
- this->aspect_clip = SP_ASPECT_MEET;
+ set_preserveAspectRatio( value );
+ std::cout << "Symbol: Preserve aspect ratio: " << aspect_align << ", " << aspect_clip << std::endl;
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
-
- 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) {
- break;
- }
-
- e = p;
-
- while (*e && *e != 32) {
- e += 1;
- }
-
- len = e - p;
-
- if (len > 8) {
- break;
- }
-
- 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 {
- break;
- }
-
- 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 {
- break;
- }
- }
-
- this->aspect_set = TRUE;
- this->aspect_align = align;
- this->aspect_clip = clip;
- }
break;
default:
@@ -204,105 +79,10 @@ void SPSymbol::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
void SPSymbol::update(SPCtx *ctx, guint flags) {
- SPItemCtx *ictx = (SPItemCtx *) ctx;
- SPItemCtx rctx;
-
if (this->cloned) {
- /* Cloned <symbol> is actually renderable */
-
- /* fixme: We have to set up clip here too */
-
- /* Create copy of item context */
- rctx = *ictx;
-
- /* Calculate child to parent transformation */
- /* Apply parent <use> translation (set up as vewport) */
- this->c2p = Geom::Translate(rctx.viewport.min());
-
- if (this->viewBox_set) {
- double x, y, width, height;
-
- /* Determine actual viewbox in viewport coordinates */
- if (this->aspect_align == SP_ASPECT_NONE) {
- x = 0.0;
- y = 0.0;
- width = rctx.viewport.width();
- height = rctx.viewport.height();
- } else {
- double scalex, scaley, scale;
- /* Things are getting interesting */
- scalex = rctx.viewport.width() / this->viewBox.width();
- scaley = rctx.viewport.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:
- x = 0.0;
- y = 0.0;
- break;
- case SP_ASPECT_XMID_YMIN:
- x = 0.5 * (rctx.viewport.width() - width);
- y = 0.0;
- break;
- case SP_ASPECT_XMAX_YMIN:
- x = 1.0 * (rctx.viewport.width() - width);
- y = 0.0;
- break;
- case SP_ASPECT_XMIN_YMID:
- x = 0.0;
- y = 0.5 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMID_YMID:
- x = 0.5 * (rctx.viewport.width() - width);
- y = 0.5 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMAX_YMID:
- x = 1.0 * (rctx.viewport.width() - width);
- y = 0.5 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMIN_YMAX:
- x = 0.0;
- y = 1.0 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMID_YMAX:
- x = 0.5 * (rctx.viewport.width() - width);
- y = 1.0 * (rctx.viewport.height() - height);
- break;
- case SP_ASPECT_XMAX_YMAX:
- x = 1.0 * (rctx.viewport.width() - width);
- y = 1.0 * (rctx.viewport.height() - height);
- break;
- default:
- x = 0.0;
- y = 0.0;
- break;
- }
- }
-
- /* Compose additional transformation 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;
-
- /* Append viewbox transformation */
- this->c2p = q * this->c2p;
- }
- rctx.i2doc = this->c2p * (Geom::Affine)rctx.i2doc;
-
- /* If viewBox is set initialize child viewport */
- /* Otherwise <use> has set it up already */
- if (this->viewBox_set) {
- rctx.viewport = this->viewBox;
- rctx.i2vp = Geom::identity();
- }
+ SPItemCtx *ictx = (SPItemCtx *) ctx;
+ SPItemCtx rctx = get_rctx( ictx );
// And invoke parent method
SPGroup::update((SPCtx *) &rctx, flags);
diff --git a/src/sp-symbol.h b/src/sp-symbol.h
index 7a43ed658..d1e62e923 100644
--- a/src/sp-symbol.h
+++ b/src/sp-symbol.h
@@ -25,24 +25,13 @@
#include "svg/svg-length.h"
#include "enums.h"
#include "sp-item-group.h"
+#include "viewbox.h"
-class SPSymbol : public SPGroup {
+class SPSymbol : public SPGroup, public SPViewBox {
public:
SPSymbol();
virtual ~SPSymbol();
- /* viewBox; */
- unsigned int viewBox_set : 1;
- Geom::Rect viewBox;
-
- /* preserveAspectRatio */
- unsigned int aspect_set : 1;
- unsigned int aspect_align : 4;
- unsigned int aspect_clip : 1;
-
- /* Child to parent additional transform */
- Geom::Affine c2p;
-
virtual void build(SPDocument *document, Inkscape::XML::Node *repr);
virtual void release();
virtual void set(unsigned int key, gchar const* value);
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 :
diff --git a/src/viewbox.h b/src/viewbox.h
new file mode 100644
index 000000000..24356ed17
--- /dev/null
+++ b/src/viewbox.h
@@ -0,0 +1,66 @@
+#ifndef __SP_VIEWBOX_H__
+#define __SP_VIEWBOX_H__
+
+/*
+ * viewBox helper class, common code used by root, symbol, marker, pattern, image, view
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com> (code extracted from sp-symbol.h)
+ * Tavmjong Bah
+ *
+ * Copyright (C) 2013 Tavmjong Bah, authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ */
+
+#include <2geom/rect.h>
+#include <glib.h>
+
+namespace Geom {
+class Rect;
+}
+class SPItemCtx;
+
+class SPViewBox {
+
+ public:
+
+ SPViewBox();
+ ~SPViewBox();
+
+ /* viewBox; */
+ unsigned int viewBox_set : 1;
+ Geom::Rect viewBox; // Could use optrect
+
+ /* preserveAspectRatio */
+ unsigned int aspect_set : 1;
+ unsigned int aspect_align : 4;
+ unsigned int aspect_clip : 1;
+
+ /* Child to parent additional transform */
+ Geom::Affine c2p;
+
+ void set_viewBox(const gchar* value);
+ void set_preserveAspectRatio(const gchar* value);
+
+ /* Adjusts c2p for viewbox */
+ void apply_viewbox(const Geom::Rect& in);
+
+ SPItemCtx get_rctx( const SPItemCtx* ictx);
+
+};
+
+#endif
+
+/*
+ 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 :