summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-filter-image.cpp156
-rw-r--r--src/display/nr-filter-image.h6
-rw-r--r--src/display/nr-filter-primitive.cpp112
-rw-r--r--src/display/nr-filter-primitive.h37
-rw-r--r--src/display/nr-filter-units.h20
-rw-r--r--src/display/nr-filter.cpp2
-rw-r--r--src/display/nr-filter.h6
-rw-r--r--src/filters/image.cpp88
-rw-r--r--src/filters/image.h6
-rw-r--r--src/sp-filter-primitive.cpp39
-rw-r--r--src/sp-filter-primitive.h3
11 files changed, 386 insertions, 89 deletions
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index cc6dc18fa..9ecec69bf 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -6,7 +6,7 @@
* Tavmjong Bah <tavmjong@free.fr>
* Abhishek Sharma
*
- * Copyright (C) 2007 authors
+ * Copyright (C) 2007-2011 authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -20,6 +20,8 @@
#include "libnr/nr-compose-transform.h"
#include "libnr/nr-rect-l.h"
#include "preferences.h"
+#include "svg/svg-length.h"
+#include "enums.h"
namespace Inkscape {
namespace Filters {
@@ -148,60 +150,139 @@ int FilterImage::render(FilterSlot &slot, FilterUnits const &units) {
image_pixbuf = image->get_pixels();
has_alpha = image->get_has_alpha();
}
- int w,x,y;
+
+ // Viewport is filter primitive area (in user coordinates).
+ Geom::Rect vp = filter_primitive_area( units );
+ double feImageX = vp.min()[Geom::X];
+ double feImageY = vp.min()[Geom::Y];
+ double feImageWidth = vp.width();
+ double feImageHeight = vp.height();
+
+ // Now that we have the viewport, we must map image inside.
+ // Partially copied from sp-image.cpp.
+
+ // Do nothing if preserveAspectRatio is "none".
+ if( aspect_align != SP_ASPECT_NONE ) {
+
+ // Check aspect ratio of image vs. viewport
+ double feAspect = feImageHeight/feImageWidth;
+ double aspect = (double)height/(double)width;
+ bool ratio = (feAspect < aspect);
+
+ double ax, ay; // Align side
+ switch( aspect_align ) {
+ case SP_ASPECT_XMIN_YMIN:
+ ax = 0.0;
+ ay = 0.0;
+ break;
+ case SP_ASPECT_XMID_YMIN:
+ ax = 0.5;
+ ay = 0.0;
+ break;
+ case SP_ASPECT_XMAX_YMIN:
+ ax = 1.0;
+ ay = 0.0;
+ break;
+ case SP_ASPECT_XMIN_YMID:
+ ax = 0.0;
+ ay = 0.5;
+ break;
+ case SP_ASPECT_XMID_YMID:
+ ax = 0.5;
+ ay = 0.5;
+ break;
+ case SP_ASPECT_XMAX_YMID:
+ ax = 1.0;
+ ay = 0.5;
+ break;
+ case SP_ASPECT_XMIN_YMAX:
+ ax = 0.0;
+ ay = 1.0;
+ break;
+ case SP_ASPECT_XMID_YMAX:
+ ax = 0.5;
+ ay = 1.0;
+ break;
+ case SP_ASPECT_XMAX_YMAX:
+ ax = 1.0;
+ ay = 1.0;
+ break;
+ default:
+ ax = 0.0;
+ ay = 0.0;
+ break;
+ }
+
+ if( aspect_clip == SP_ASPECT_SLICE ) {
+ // image clipped by viewbox
+
+ if( ratio ) {
+ // clip top/bottom
+ feImageY -= ay * (feImageWidth * aspect - feImageHeight);
+ feImageHeight = feImageWidth * aspect;
+ } else {
+ // clip sides
+ feImageX -= ax * (feImageHeight / aspect - feImageWidth);
+ feImageWidth = feImageHeight / aspect;
+ }
+
+ } else {
+ // image fits into viewbox
+
+ if( ratio ) {
+ // fit to height
+ feImageX += ax * (feImageWidth - feImageHeight / aspect );
+ feImageWidth = feImageHeight / aspect;
+ } else {
+ // fit to width
+ feImageY += ay * (feImageHeight - feImageWidth * aspect);
+ feImageHeight = feImageWidth * aspect;
+ }
+ }
+ }
+
+ // Set up user coordinates to pix block transforms
+ double scaleX = width/feImageWidth;
+ double scaleY = height/feImageHeight;
+ Geom::Affine unit_trans = units.get_matrix_user2pb().inverse();
+
+ // Region being drawn on screen. Corresponds to Filter Region in current screen coordinates.
+ // Note, that the screen is refreshed in horizontal slices with y-axis inverted.
NRPixBlock *in = slot.get(_input);
if (!in) {
g_warning("Missing source image for feImage (in=%d)", _input);
return 1;
}
-
- // This section needs to be fully tested!!
-
- // Region being drawn on screen
int x0 = in->area.x0, y0 = in->area.y0;
int x1 = in->area.x1, y1 = in->area.y1;
- NRPixBlock *out = new NRPixBlock;
- nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1, true);
- w = x1 - x0;
+ int w = x1 - x0;
- // Get the object bounding box. Image is placed with respect to box.
- // Array values: 0: width; 3: height; 4: -x; 5: -y.
- Geom::Affine object_bbox = units.get_matrix_user2filterunits().inverse();
-
- // feImage is suppose to use the same parameters as a normal SVG image.
- // If a width or height is set to zero, the image is not suppose to be displayed.
- // This does not seem to be what Firefox or Opera does, nor does the W3C displacement
- // filter test expect this behavior. If the width and/or height are zero, we use
- // the width and height of the object bounding box.
- if( feImageWidth == 0 ) feImageWidth = object_bbox[0];
- if( feImageHeight == 0 ) feImageHeight = object_bbox[3];
-
- double scaleX = width/feImageWidth;
- double scaleY = height/feImageHeight;
+ Geom::Affine d2s = Geom::Translate(x0, y0) * unit_trans * Geom::Translate(-feImageX,-feImageY) * Geom::Scale(scaleX, scaleY);
- int coordx,coordy;
+ // Set up pix block
+ NRPixBlock *out = new NRPixBlock;
+ nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1, true);
unsigned char *out_data = NR_PIXBLOCK_PX(out);
- Geom::Affine unit_trans = units.get_matrix_primitiveunits2pb().inverse();
- Geom::Affine d2s = Geom::Translate(x0, y0) * unit_trans * Geom::Translate(object_bbox[4]-feImageX, object_bbox[5]-feImageY) * Geom::Scale(scaleX, scaleY);
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int nr_arena_image_x_sample = prefs->getInt("/options/bitmapoversample/value", 1);
int nr_arena_image_y_sample = nr_arena_image_x_sample;
+
if (has_alpha) {
nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM(out_data, x1-x0, y1-y0, 4*w, image_pixbuf, width, height, rowstride, d2s, 255, nr_arena_image_x_sample, nr_arena_image_y_sample);
} else {
- for (x=x0; x < x1; x++){
- for (y=y0; y < y1; y++){
+ for (int x=x0; x < x1; x++){
+ for (int y=y0; y < y1; y++){
//TODO: use interpolation
// Temporarily add 0.5 so we sample center of "cell"
- double indexX = scaleX * (((x+0.5) * unit_trans[0] + unit_trans[4]) - feImageX + object_bbox[4]);
- double indexY = scaleY * (((y+0.5) * unit_trans[3] + unit_trans[5]) - feImageY + object_bbox[5]);
+ double indexX = scaleX * (((x+0.5) * unit_trans[0] + unit_trans[4]) - feImageX);
+ double indexY = scaleY * (((y+0.5) * unit_trans[3] + unit_trans[5]) - feImageY);
// coordx == 0 and coordy == 0 must be included, but we protect
// against negative numbers which round up to 0 with (int).
- coordx = ( indexX >= 0 ? int( indexX ) : -1 );
- coordy = ( indexY >= 0 ? int( indexY ) : -1 );
+ int coordx = ( indexX >= 0 ? int( indexX ) : -1 );
+ int coordy = ( indexY >= 0 ? int( indexY ) : -1 );
if (coordx >= 0 && coordx < width && coordy >= 0 && coordy < height){
out_data[4*((x - x0)+w*(y - y0)) ] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy ]; //Red
out_data[4*((x - x0)+w*(y - y0)) + 1] = (unsigned char) image_pixbuf[3*coordx + rowstride*coordy + 1]; //Green
@@ -230,11 +311,12 @@ void FilterImage::set_document(SPDocument *doc){
document = doc;
}
-void FilterImage::set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height){
- feImageX=x.computed;
- feImageY=y.computed;
- feImageWidth=width.computed;
- feImageHeight=height.computed;
+void FilterImage::set_align( unsigned int align ) {
+ aspect_align = align;
+}
+
+void FilterImage::set_clip( unsigned int clip ) {
+ aspect_clip = clip;
}
FilterTraits FilterImage::get_input_traits() {
diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h
index 7b2fa8bc7..ecbc9597d 100644
--- a/src/display/nr-filter-image.h
+++ b/src/display/nr-filter-image.h
@@ -31,7 +31,8 @@ public:
virtual FilterTraits get_input_traits();
void set_document( SPDocument *document );
void set_href(const gchar *href);
- void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height);
+ void set_align( unsigned int align );
+ void set_clip( unsigned int clip );
bool from_element;
SPItem* SVGElem;
@@ -41,7 +42,8 @@ private:
guint8* image_pixbuf;
Glib::RefPtr<Gdk::Pixbuf> image;
int width, height, rowstride;
- float feImageX,feImageY,feImageWidth,feImageHeight;
+ unsigned int aspect_align : 4;
+ unsigned int aspect_clip : 1;
bool has_alpha;
};
diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp
index f53ff4a7f..1af86ec3e 100644
--- a/src/display/nr-filter-primitive.cpp
+++ b/src/display/nr-filter-primitive.cpp
@@ -5,6 +5,7 @@
*
* Author:
* Niko Kiirala <niko@kiirala.com>
+ * Tavmjong Bah <tavmjong@free.fr> (primitive subregion)
*
* Copyright (C) 2006 Niko Kiirala
*
@@ -19,17 +20,27 @@
namespace Inkscape {
namespace Filters {
+using Geom::X;
+using Geom::Y;
+
FilterPrimitive::FilterPrimitive()
{
_input = NR_FILTER_SLOT_NOT_SET;
_output = NR_FILTER_SLOT_NOT_SET;
- // These defaults are according to SVG standard.
+ // Primitive subregion, should default to the union of all subregions of referenced nodes
+ // (i.e. other filter primitives except feTile). If no referenced nodes, defaults to filter
+ // region expressed in percent. At the moment, we do not check referenced nodes.
+
+ // We must keep track if a value is set or not, if not set then the region defaults to 0%, 0%,
+ // 100%, 100% ("x", "y", "width", "height") of the -> filter <- region. If set, then
+ // percentages are in terms of bounding box or viewbox, depending on value of "primitiveUnits".
+
// NB: SVGLength.set takes prescaled percent values: 1 means 100%
- _region_x.set(SVGLength::PERCENT, 0, 0);
- _region_y.set(SVGLength::PERCENT, 0, 0);
- _region_width.set(SVGLength::PERCENT, 1, 0);
- _region_height.set(SVGLength::PERCENT, 1, 0);
+ _subregion_x.unset(SVGLength::PERCENT, 0, 0);
+ _subregion_y.unset(SVGLength::PERCENT, 0, 0);
+ _subregion_width.unset(SVGLength::PERCENT, 1, 0);
+ _subregion_height.unset(SVGLength::PERCENT, 1, 0);
}
FilterPrimitive::~FilterPrimitive()
@@ -54,6 +65,97 @@ void FilterPrimitive::set_output(int slot) {
if (slot >= 0) _output = slot;
}
+// We need to copy reference even if unset as we need to know if
+// someone has unset a value.
+void FilterPrimitive::set_x(SVGLength const &length)
+{
+ _subregion_x = length;
+}
+
+void FilterPrimitive::set_y(SVGLength const &length)
+{
+ _subregion_y = length;
+}
+void FilterPrimitive::set_width(SVGLength const &length)
+{
+ _subregion_width = length;
+}
+void FilterPrimitive::set_height(SVGLength const &length)
+{
+ _subregion_height = length;
+}
+
+void FilterPrimitive::set_subregion(SVGLength const &x, SVGLength const &y,
+ SVGLength const &width, SVGLength const &height) {
+ _subregion_x = x;
+ _subregion_y = y;
+ _subregion_width = width;
+ _subregion_height = height;
+}
+
+Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
+{
+ Geom::OptRect bb = units.get_item_bbox();
+ Geom::OptRect fa = units.get_filter_area();
+
+ /* Update computed values for ex, em, %. For %, assumes primitive unit is objectBoundingBox. */
+ /* TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. */
+ double len_x = bb->width();
+ double len_y = bb->height();
+ _subregion_x.update(12, 6, len_x);
+ _subregion_y.update(12, 6, len_y);
+ _subregion_width.update(12, 6, len_x);
+ _subregion_height.update(12, 6, len_y);
+
+ // x, y, width, and height are independently defined (i.e. one can be defined, by default, to
+ // the filter area while another is defined relative to the bounding box). It is better to keep
+ // track of them separately and then compose the Rect at the end.
+ double x = 0;
+ double y = 0;
+ double width = 0;
+ double height = 0;
+
+ // If subregion not set, by special case use filter region.
+ if( !_subregion_x._set ) x = fa->min()[X];
+ if( !_subregion_y._set ) y = fa->min()[Y];
+ if( !_subregion_width._set ) width = fa->width();
+ if( !_subregion_height._set ) height = fa->height();
+
+ if( units.get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) {
+ // Values are in terms of fraction of bounding box.
+ if( _subregion_x._set && _subregion_x.unit != SVGLength::PERCENT ) x = bb->min()[X] + bb->width() * _subregion_x.value;
+ if( _subregion_y._set && _subregion_y.unit != SVGLength::PERCENT ) y = bb->min()[Y] + bb->height() * _subregion_y.value;
+ if( _subregion_width._set && _subregion_width.unit != SVGLength::PERCENT ) width = bb->width() * _subregion_width.value;
+ if( _subregion_height._set && _subregion_height.unit != SVGLength::PERCENT ) height = bb->height() * _subregion_height.value;
+ // Values are in terms of percent
+ if( _subregion_x._set && _subregion_x.unit == SVGLength::PERCENT ) x = bb->min()[X] + _subregion_x.computed;
+ if( _subregion_y._set && _subregion_y.unit == SVGLength::PERCENT ) y = bb->min()[Y] + _subregion_y.computed;
+ if( _subregion_width._set && _subregion_width.unit == SVGLength::PERCENT ) width = _subregion_width.computed;
+ if( _subregion_height._set && _subregion_height.unit == SVGLength::PERCENT ) height = _subregion_height.computed;
+ } else {
+ // Values are in terms of user space coordinates or percent of viewbox (yuck!),
+ // which is usually the size of SVG drawing. Default.
+ if( _subregion_x._set && _subregion_x.unit != SVGLength::PERCENT ) x = _subregion_x.computed;
+ if( _subregion_y._set && _subregion_y.unit != SVGLength::PERCENT ) y = _subregion_y.computed;
+ if( _subregion_width._set && _subregion_width.unit != SVGLength::PERCENT ) width = _subregion_width.computed;
+ if( _subregion_height._set && _subregion_height.unit != SVGLength::PERCENT ) height = _subregion_height.computed;
+ // TODO: add percent of viewport TEMPORARY HACK FOR TESTING...
+ if( _subregion_x._set && _subregion_x.unit == SVGLength::PERCENT ) x = _subregion_x.value * 480; // viewport_x
+ if( _subregion_y._set && _subregion_y.unit == SVGLength::PERCENT ) y = _subregion_y.value * 360;
+ if( _subregion_width._set && _subregion_width.unit == SVGLength::PERCENT ) width = _subregion_width.value * 480;
+ if( _subregion_height._set && _subregion_height.unit == SVGLength::PERCENT ) height = _subregion_height.value * 360;
+ }
+
+ Geom::Point minp, maxp;
+ minp[X] = x;
+ minp[Y] = y;
+ maxp[X] = x + width;
+ maxp[Y] = y + height;
+
+ Geom::Rect area(minp, maxp);
+ return area;
+}
+
FilterTraits FilterPrimitive::get_input_traits() {
return TRAIT_ANYTHING;
}
diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h
index 7639a9d1d..0e8df3813 100644
--- a/src/display/nr-filter-primitive.h
+++ b/src/display/nr-filter-primitive.h
@@ -78,27 +78,27 @@ public:
*/
virtual void set_output(int slot);
- void set_x(SVGLength &length);
- void set_y(SVGLength &length);
- void set_width(SVGLength &length);
- void set_height(SVGLength &length);
-
/**
* Sets the filter primitive subregion. Passing an unset length
- * (length._set == false) as any parameter results in that parameter
- * not being changed.
- * Filter primitive will not hold any references to the passed
- * SVGLength object after function returns.
- * If any of the parameters does not get set the default value, as
- * defined in SVG standard, for that parameter is used instead.
+ * (length._set == false) WILL change the parameter as it is
+ * important to know if a parameter is unset.
*/
- void set_region(SVGLength &x, SVGLength &y,
- SVGLength &width, SVGLength &height);
+ void set_x(SVGLength const &length);
+ void set_y(SVGLength const &length);
+ void set_width(SVGLength const &length);
+ void set_height(SVGLength const &length);
+ void set_subregion(SVGLength const &x, SVGLength const &y,
+ SVGLength const &width, SVGLength const &height);
/**
* Resets the filter primitive subregion to its default value
*/
- void reset_region();
+ void reset_subregion(); // Not implemented
+
+ /**
+ * Returns the filter primitive area in user coordinate system.
+ */
+ Geom::Rect filter_primitive_area(FilterUnits const &units);
/**
* Queries the filter, which traits it needs from its input buffers.
@@ -112,10 +112,11 @@ protected:
int _input;
int _output;
- SVGLength _region_x;
- SVGLength _region_y;
- SVGLength _region_width;
- SVGLength _region_height;
+ /* Filter primitive subregion */
+ SVGLength _subregion_x;
+ SVGLength _subregion_y;
+ SVGLength _subregion_width;
+ SVGLength _subregion_height;
};
diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h
index 9a0d8ea83..b78e102cd 100644
--- a/src/display/nr-filter-units.h
+++ b/src/display/nr-filter-units.h
@@ -62,6 +62,26 @@ public:
void set_automatic_resolution(bool const automatic);
/**
+ * Gets the item bounding box in user coordinates
+ */
+ Geom::OptRect get_item_bbox() const { return item_bbox; };
+
+ /**
+ * Gets the filter effects area in user coordinates
+ */
+ Geom::OptRect get_filter_area() const { return filter_area; };
+
+ /**
+ * Gets Filter Units (userSpaceOnUse or objectBoundingBox)
+ */
+ SPFilterUnits get_filter_units() const { return filterUnits; };
+
+ /**
+ * Gets Primitive Units (userSpaceOnUse or objectBoundingBox)
+ */
+ SPFilterUnits get_primitive_units() const { return primitiveUnits; };
+
+ /**
* Gets the user coordinates to pixblock coordinates transformation matrix.
*/
Geom::Affine get_matrix_user2pb() const;
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index ea9b4f7da..85815c31a 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -326,7 +326,7 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
minp[Y] = _region_y.computed;
maxp[Y] = minp[Y] + _region_height.computed;
} else {
- g_warning("Error in Inkscape::Filters::Filter::bbox_enlarge: unrecognized value of _filter_units");
+ g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units");
}
Geom::Rect area(minp, maxp);
return area;
diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h
index 23acea99f..ae5f96420 100644
--- a/src/display/nr-filter.h
+++ b/src/display/nr-filter.h
@@ -92,8 +92,8 @@ public:
* If any of these parameters does not get set, the default value, as
* defined in SVG standard, for that parameter is used instead.
*/
- void set_region(SVGLength &x, SVGLength &y,
- SVGLength &width, SVGLength &height);
+ void set_region(SVGLength const &x, SVGLength const &y,
+ SVGLength const &width, SVGLength const &height);
/**
* Resets the filter effects region to its default value as defined
@@ -131,7 +131,7 @@ public:
void set_filter_units(SPFilterUnits unit);
/**
- * Set the primitiveUnits-properterty. If not set, the default value of
+ * Set the primitiveUnits-property. If not set, the default value of
* userSpaceOnUse is used. If the parameter value is not a valid
* enumeration value from SPFilterUnits, no changes to filter state
* are made.
diff --git a/src/filters/image.cpp b/src/filters/image.cpp
index ebad7a002..f6ef310f7 100644
--- a/src/filters/image.cpp
+++ b/src/filters/image.cpp
@@ -19,6 +19,7 @@
#endif
#include "uri.h"
#include "uri-references.h"
+#include "enums.h"
#include "attributes.h"
#include "svg/svg.h"
#include "image.h"
@@ -78,8 +79,10 @@ static void sp_feImage_class_init(SPFeImageClass *klass)
sp_primitive_class->build_renderer = sp_feImage_build_renderer;
}
-static void sp_feImage_init(SPFeImage */*feImage*/)
+static void sp_feImage_init(SPFeImage *feImage)
{
+ feImage->aspect_align = SP_ASPECT_XMID_YMID; // Default
+ feImage->aspect_clip = SP_ASPECT_MEET; // Default
}
/**
@@ -99,10 +102,7 @@ static void sp_feImage_build(SPObject *object, SPDocument *document, Inkscape::X
/*LOAD ATTRIBUTES FROM REPR HERE*/
- object->readAttr( "x" );
- object->readAttr( "y" );
- object->readAttr( "width" );
- object->readAttr( "height" );
+ object->readAttr( "preserveAspectRatio" );
object->readAttr( "xlink:href" );
}
@@ -185,22 +185,67 @@ static void sp_feImage_set(SPObject *object, unsigned int key, gchar const *valu
}
break;
- case SP_ATTR_X:
- feImage->x.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
- break;
- case SP_ATTR_Y:
- feImage->y.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
- break;
- case SP_ATTR_WIDTH:
- feImage->width.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
- break;
- case SP_ATTR_HEIGHT:
- feImage->height.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ case SP_ATTR_PRESERVEASPECTRATIO:
+ /* Copied from sp-image.cpp */
+ /* Do setup before, so we can use break to escape */
+ feImage->aspect_align = SP_ASPECT_XMID_YMID; // Default
+ feImage->aspect_clip = SP_ASPECT_MEET; // Default
+ object->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 {
+ g_warning("Illegal preserveAspectRatio: %s", c);
+ 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;
+ }
+ }
+ feImage->aspect_align = align;
+ feImage->aspect_clip = clip;
+ }
break;
+
default:
if (((SPObjectClass *) feImage_parent_class)->set)
((SPObjectClass *) feImage_parent_class)->set(object, key, value);
@@ -259,7 +304,8 @@ static void sp_feImage_build_renderer(SPFilterPrimitive *primitive, Inkscape::Fi
nr_image->from_element = sp_image->from_element;
nr_image->SVGElem = sp_image->SVGElem;
- nr_image->set_region(sp_image->x, sp_image->y, sp_image->width, sp_image->height);
+ nr_image->set_align( sp_image->aspect_align );
+ nr_image->set_clip( sp_image->aspect_clip );
nr_image->set_href(sp_image->href);
nr_image->set_document(sp_image->document);
}
diff --git a/src/filters/image.h b/src/filters/image.h
index 2445da5c6..535dd80fa 100644
--- a/src/filters/image.h
+++ b/src/filters/image.h
@@ -26,7 +26,11 @@ class SPFeImageClass;
struct SPFeImage : public SPFilterPrimitive {
/** IMAGE ATTRIBUTES HERE */
gchar *href;
- SVGLength x, y, height, width;
+
+ /* preserveAspectRatio */
+ unsigned int aspect_align : 4;
+ unsigned int aspect_clip : 1;
+
SPDocument *document;
bool from_element;
SPItem* SVGElem;
diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp
index 87f96fb90..c186c7fd9 100644
--- a/src/sp-filter-primitive.cpp
+++ b/src/sp-filter-primitive.cpp
@@ -84,6 +84,16 @@ sp_filter_primitive_init(SPFilterPrimitive *filter_primitive)
{
filter_primitive->image_in = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
filter_primitive->image_out = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+
+ // We must keep track if a value is set or not, if not set then the region defaults to 0%, 0%,
+ // 100%, 100% ("x", "y", "width", "height") of the -> filter <- region. If set then
+ // percentages are in terms of bounding box or viewbox, depending on value of "primitiveUnits"
+
+ // NB: SVGLength.set takes prescaled percent values: 1 means 100%
+ filter_primitive->x.unset(SVGLength::PERCENT, 0, 0);
+ filter_primitive->y.unset(SVGLength::PERCENT, 0, 0);
+ filter_primitive->width.unset(SVGLength::PERCENT, 1, 0);
+ filter_primitive->height.unset(SVGLength::PERCENT, 1, 0);
}
/**
@@ -100,6 +110,10 @@ sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML:
object->readAttr( "in" );
object->readAttr( "result" );
+ object->readAttr( "x" );
+ object->readAttr( "y" );
+ object->readAttr( "width" );
+ object->readAttr( "height" );
}
/**
@@ -121,7 +135,6 @@ sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value)
{
SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object);
(void)filter_primitive;
-
int image_nr;
switch (key) {
case SP_ATTR_IN:
@@ -146,6 +159,24 @@ sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value)
object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
break;
+
+ /* Filter primitive sub-region */
+ case SP_ATTR_X:
+ filter_primitive->x.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_Y:
+ filter_primitive->y.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_WIDTH:
+ filter_primitive->width.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ case SP_ATTR_HEIGHT:
+ filter_primitive->height.readOrUnset(value);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
}
/* See if any parents need this value. */
@@ -165,6 +196,10 @@ sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags)
if (flags & SP_OBJECT_MODIFIED_FLAG) {
object->readAttr( "in" );
object->readAttr( "result" );
+ object->readAttr( "x" );
+ object->readAttr( "y" );
+ object->readAttr( "width" );
+ object->readAttr( "height" );
}
if (((SPObjectClass *) filter_primitive_parent_class)->update) {
@@ -191,6 +226,7 @@ sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inksca
gchar const *out_name = sp_filter_name_for_image(parent, prim->image_out);
repr->setAttribute("result", out_name);
+ /* Do we need to add x,y,width,height? */
if (((SPObjectClass *) filter_primitive_parent_class)->write) {
((SPObjectClass *) filter_primitive_parent_class)->write(object, doc, repr, flags);
}
@@ -279,6 +315,7 @@ void sp_filter_primitive_renderer_common(SPFilterPrimitive *sp_prim, Inkscape::F
nr_prim->set_output(sp_prim->image_out);
/* TODO: place here code to handle input images, filter area etc. */
+ nr_prim->set_subregion( sp_prim->x, sp_prim->y, sp_prim->width, sp_prim->height );
}
diff --git a/src/sp-filter-primitive.h b/src/sp-filter-primitive.h
index 92f36e7ae..8922ac20a 100644
--- a/src/sp-filter-primitive.h
+++ b/src/sp-filter-primitive.h
@@ -30,6 +30,9 @@ class SPFilterPrimitiveClass;
struct SPFilterPrimitive : public SPObject {
int image_in, image_out;
+
+ /* filter primitive subregion */
+ SVGLength x, y, height, width;
};
struct SPFilterPrimitiveClass {