summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2015-09-20 13:54:59 +0000
committertavmjong-free <tavmjong@free.fr>2015-09-20 13:54:59 +0000
commit27ca90885f3f4dde9886780ff0cc0f40a34f4e7e (patch)
tree8370fb902df688ad98bcd091aa40f0192d9a3437 /src
parentpackaging/macosx: fix for bug #1497020 (Inkscape.app (0.91) crashes when atte... (diff)
downloadinkscape-27ca90885f3f4dde9886780ff0cc0f40a34f4e7e.tar.gz
inkscape-27ca90885f3f4dde9886780ff0cc0f40a34f4e7e.zip
Crude partial implementation of feTile filter primitive.
(bzr r14377)
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-filter-image.cpp2
-rw-r--r--src/display/nr-filter-offset.cpp4
-rw-r--r--src/display/nr-filter-slot.cpp21
-rw-r--r--src/display/nr-filter-slot.h8
-rw-r--r--src/display/nr-filter-tile.cpp99
-rw-r--r--src/display/nr-filter-tile.h1
6 files changed, 130 insertions, 5 deletions
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index 179ba0e0a..af89d98e0 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -56,6 +56,8 @@ void FilterImage::render_cairo(FilterSlot &slot)
// Note: viewport calculation in non-trivial. Do not rely
// on get_matrix_primitiveunits2pb().
Geom::Rect vp = filter_primitive_area( slot.get_units() );
+ slot.set_primitive_area(_output, vp); // Needed for tiling
+
double feImageX = vp.min()[Geom::X];
double feImageY = vp.min()[Geom::Y];
double feImageWidth = vp.width();
diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp
index af1081abe..93bab7d39 100644
--- a/src/display/nr-filter-offset.cpp
+++ b/src/display/nr-filter-offset.cpp
@@ -37,9 +37,11 @@ void FilterOffset::render_cairo(FilterSlot &slot)
cairo_surface_t *out = ink_cairo_surface_create_identical(in);
// color_interpolation_filters for out same as in. See spec (DisplacementMap).
copy_cairo_surface_ci(in, out);
-
cairo_t *ct = cairo_create(out);
+ Geom::Rect vp = filter_primitive_area( slot.get_units() );
+ slot.set_primitive_area(_output, vp); // Needed for tiling
+
// Handle bounding box case
double x = dx;
double y = dy;
diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp
index e4c2f048e..a6e0c5c4e 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -232,6 +232,27 @@ void FilterSlot::set(int slot_nr, cairo_surface_t *surface)
_last_out = slot_nr;
}
+void FilterSlot::set_primitive_area(int slot_nr, Geom::Rect &area)
+{
+ if (slot_nr == NR_FILTER_SLOT_NOT_SET)
+ slot_nr = NR_FILTER_UNNAMED_SLOT;
+
+ _primitiveAreas[slot_nr] = area;
+}
+
+Geom::Rect FilterSlot::get_primitive_area(int slot_nr)
+{
+ if (slot_nr == NR_FILTER_SLOT_NOT_SET)
+ slot_nr = _last_out;
+
+ PrimitiveAreaMap::iterator s = _primitiveAreas.find(slot_nr);
+
+ if (s == _primitiveAreas.end()) {
+ return *(_units.get_filter_area());
+ }
+ return s->second;
+}
+
int FilterSlot::get_slot_count()
{
return _slots.size();
diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h
index 987dedfd1..166b2e718 100644
--- a/src/display/nr-filter-slot.h
+++ b/src/display/nr-filter-slot.h
@@ -54,6 +54,9 @@ public:
cairo_surface_t *get_result(int slot_nr);
+ void set_primitive_area(int slot, Geom::Rect &area);
+ Geom::Rect get_primitive_area(int slot);
+
/** Returns the number of slots in use. */
int get_slot_count();
@@ -75,6 +78,11 @@ public:
private:
typedef std::map<int, cairo_surface_t *> SlotMap;
SlotMap _slots;
+
+ // We need to keep track of the primitive area as this is needed in feTile
+ typedef std::map<int, Geom::Rect> PrimitiveAreaMap;
+ PrimitiveAreaMap _primitiveAreas;
+
DrawingItem *_item;
//Geom::Rect _source_bbox; ///< bounding box of source graphic surface
diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp
index 93ca50210..913812828 100644
--- a/src/display/nr-filter-tile.cpp
+++ b/src/display/nr-filter-tile.cpp
@@ -10,6 +10,8 @@
*/
#include <glib.h>
+
+#include "display/cairo-utils.h"
#include "display/nr-filter-tile.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-units.h"
@@ -30,16 +32,105 @@ FilterTile::~FilterTile()
void FilterTile::render_cairo(FilterSlot &slot)
{
+ // FIX ME!
static bool tile_warning = false;
-
-//IMPLEMENT ME!
if (!tile_warning) {
- g_warning("Renderer for feTile is not implemented.");
+ g_warning("Renderer for feTile has non-optimal implementation, expect slowness and bugs.");
tile_warning = true;
}
+ // Fixing isn't so easy as the Inkscape renderer breaks the canvas into "rendering" tiles for
+ // faster rendering. (The "rendering" tiles are not the same as the tiles in this primitive.)
+ // Only if the the feTile tile source falls inside the current "rendering" tile will the tile
+ // image be available.
+
+ // This input source contains only the "rendering" tile.
cairo_surface_t *in = slot.getcairo(_input);
- slot.set(_output, in);
+
+ // For debugging
+ // static int i = 0;
+ // ++i;
+ // std::stringstream filename;
+ // filename << "dump." << i << ".png";
+ // cairo_surface_write_to_png( in, filename.str().c_str() );
+
+ // This is the feTile source area as determined by the input primitive area (see SVG spec).
+ Geom::Rect tile_area = slot.get_primitive_area(_input);
+
+ if( tile_area.width() == 0.0 || tile_area.height() == 0.0 ) {
+
+ slot.set(_output, in);
+ std::cerr << "FileTile::render_cairo: tile has zero width or height" << std::endl;
+
+ } else {
+
+ cairo_surface_t *out = ink_cairo_surface_create_identical(in);
+ // color_interpolation_filters for out same as in.
+ copy_cairo_surface_ci(in, out);
+ cairo_t *ct = cairo_create(out);
+
+ // The rectangle of the "rendering" tile.
+ Geom::Rect sa = slot.get_slot_area();
+
+ Geom::Affine trans = slot.get_units().get_matrix_user2pb();
+
+ // Create feTile tile ----------------
+
+ // Get tile area in pixbuf units (tile transformed).
+ Geom::Rect tt = tile_area * trans;
+
+ // Shift between "rendering" tile and feTile tile
+ Geom::Point shift = sa.min() - tt.min();
+
+ // Create feTile tile surface
+ cairo_surface_t *tile = cairo_surface_create_similar(in, cairo_surface_get_content(in),
+ tt.width(), tt.height());
+ cairo_t *ct_tile = cairo_create(tile);
+ cairo_set_source_surface(ct_tile, in, shift[Geom::X], shift[Geom::Y]);
+ cairo_paint(ct_tile);
+
+ // Paint tiles ------------------
+
+ // For debugging
+ // std::stringstream filename;
+ // filename << "tile." << i << ".png";
+ // cairo_surface_write_to_png( tile, filename.str().c_str() );
+
+ // Determine number of feTile rows and columns
+ Geom::Rect pr = filter_primitive_area( slot.get_units() );
+ int tile_cols = ceil( pr.width() / tile_area.width() );
+ int tile_rows = ceil( pr.height() / tile_area.height() );
+
+ // Do tiling (TO DO: restrict to slot area.)
+ for( int col=0; col < tile_cols; ++col ) {
+ for( int row=0; row < tile_rows; ++row ) {
+
+ Geom::Point offset( col*tile_area.width(), row*tile_area.height() );
+ offset *= trans;
+ offset[Geom::X] -= trans[4];
+ offset[Geom::Y] -= trans[5];
+
+ cairo_set_source_surface(ct, tile, offset[Geom::X], offset[Geom::Y]);
+ cairo_paint(ct);
+ }
+ }
+ slot.set(_output, out);
+
+ // Clean up
+ cairo_destroy(ct);
+ cairo_surface_destroy(out);
+ cairo_destroy(ct_tile);
+ cairo_surface_destroy(tile);
+ }
+}
+
+void FilterTile::area_enlarge(Geom::IntRect &area, Geom::Affine const &trans)
+{
+ // We need to enlarge enough to get tile source... we don't the area of the source tile in this
+ // function so we guess. This is VERY inefficient.
+ Geom::Point enlarge(200, 200);
+ enlarge *= trans;
+ area.expandBy( enlarge[Geom::X] < 100 ? 100: enlarge[Geom::X] );
}
double FilterTile::complexity(Geom::Affine const &)
diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h
index 29087f2d6..239ecff4b 100644
--- a/src/display/nr-filter-tile.h
+++ b/src/display/nr-filter-tile.h
@@ -26,6 +26,7 @@ public:
virtual ~FilterTile();
virtual void render_cairo(FilterSlot &slot);
+ virtual void area_enlarge(Geom::IntRect &area, Geom::Affine const &trans);
virtual double complexity(Geom::Affine const &ctm);
};