Commit 2c93e5fb authored by Tavmjong Bah's avatar Tavmjong Bah Committed by Tavmjong Bah

Add handling filter primitive subregion to filter primitive classes.

More correct handling of image placement in feImage filter primitive.

(bzr r10092)
parent fae3b50a
......@@ -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() {
......
......@@ -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;
};
......
......@@ -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;
}
......
......@@ -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;
};
......
......@@ -61,6 +61,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.
*/
......
......@@ -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;
......
......@@ -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.
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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 );
}
......
......@@ -30,6 +30,9 @@ class SPFilterPrimitiveClass;
struct SPFilterPrimitive : public SPObject {
int image_in, image_out;
/* filter primitive subregion */
SVGLength x, y, height, width;
};