summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-08-25 19:16:02 +0000
committerKrzysztof Kosinski <tweenk.pl@gmail.com>2011-08-25 19:16:02 +0000
commit093f4174abc07b4ea523617fccdd8028f2670fea (patch)
tree5aba6cd030bc6b0dbb59ec48e32a0b0364b516bd /src/display
parentGerman translation update (diff)
parentReduce default rendering cache size to 64 MiB (diff)
downloadinkscape-093f4174abc07b4ea523617fccdd8028f2670fea.tar.gz
inkscape-093f4174abc07b4ea523617fccdd8028f2670fea.zip
Merge rendering cache branch (GSoC 2011)
(bzr r10579)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/Makefile_insert28
-rw-r--r--src/display/cairo-templates.h4
-rw-r--r--src/display/canvas-arena.cpp302
-rw-r--r--src/display/canvas-arena.h23
-rw-r--r--src/display/display-forward.h18
-rw-r--r--src/display/drawing-context.cpp152
-rw-r--r--src/display/drawing-context.h128
-rw-r--r--src/display/drawing-group.cpp165
-rw-r--r--src/display/drawing-group.h62
-rw-r--r--src/display/drawing-image.cpp264
-rw-r--r--src/display/drawing-image.h67
-rw-r--r--src/display/drawing-item.cpp900
-rw-r--r--src/display/drawing-item.h212
-rw-r--r--src/display/drawing-shape.cpp343
-rw-r--r--src/display/drawing-shape.h63
-rw-r--r--src/display/drawing-surface.cpp354
-rw-r--r--src/display/drawing-surface.h93
-rw-r--r--src/display/drawing-text.cpp255
-rw-r--r--src/display/drawing-text.h83
-rw-r--r--src/display/drawing.cpp205
-rw-r--r--src/display/drawing.h113
-rw-r--r--src/display/grayscale.cpp2
-rw-r--r--src/display/nr-arena-forward.h51
-rw-r--r--src/display/nr-arena-glyphs.cpp476
-rw-r--r--src/display/nr-arena-glyphs.h108
-rw-r--r--src/display/nr-arena-group.cpp299
-rw-r--r--src/display/nr-arena-group.h61
-rw-r--r--src/display/nr-arena-image.cpp408
-rw-r--r--src/display/nr-arena-image.h66
-rw-r--r--src/display/nr-arena-item.cpp882
-rw-r--r--src/display/nr-arena-item.h200
-rw-r--r--src/display/nr-arena-shape.cpp610
-rw-r--r--src/display/nr-arena-shape.h81
-rw-r--r--src/display/nr-arena.cpp185
-rw-r--r--src/display/nr-arena.h69
-rw-r--r--src/display/nr-filter-blend.cpp16
-rw-r--r--src/display/nr-filter-blend.h2
-rw-r--r--src/display/nr-filter-colormatrix.cpp5
-rw-r--r--src/display/nr-filter-colormatrix.h1
-rw-r--r--src/display/nr-filter-component-transfer.cpp5
-rw-r--r--src/display/nr-filter-component-transfer.h1
-rw-r--r--src/display/nr-filter-composite.cpp5
-rw-r--r--src/display/nr-filter-composite.h1
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp5
-rw-r--r--src/display/nr-filter-convolve-matrix.h1
-rw-r--r--src/display/nr-filter-diffuselighting.cpp6
-rw-r--r--src/display/nr-filter-diffuselighting.h1
-rw-r--r--src/display/nr-filter-displacement-map.cpp5
-rw-r--r--src/display/nr-filter-displacement-map.h6
-rw-r--r--src/display/nr-filter-flood.cpp7
-rw-r--r--src/display/nr-filter-flood.h6
-rw-r--r--src/display/nr-filter-gaussian.cpp18
-rw-r--r--src/display/nr-filter-gaussian.h1
-rw-r--r--src/display/nr-filter-image.cpp52
-rw-r--r--src/display/nr-filter-image.h2
-rw-r--r--src/display/nr-filter-merge.cpp16
-rw-r--r--src/display/nr-filter-merge.h2
-rw-r--r--src/display/nr-filter-morphology.cpp7
-rw-r--r--src/display/nr-filter-morphology.h2
-rw-r--r--src/display/nr-filter-offset.cpp5
-rw-r--r--src/display/nr-filter-offset.h1
-rw-r--r--src/display/nr-filter-primitive.cpp4
-rw-r--r--src/display/nr-filter-primitive.h41
-rw-r--r--src/display/nr-filter-slot.cpp62
-rw-r--r--src/display/nr-filter-slot.h17
-rw-r--r--src/display/nr-filter-specularlighting.cpp135
-rw-r--r--src/display/nr-filter-specularlighting.h2
-rw-r--r--src/display/nr-filter-tile.cpp5
-rw-r--r--src/display/nr-filter-tile.h1
-rw-r--r--src/display/nr-filter-turbulence.cpp5
-rw-r--r--src/display/nr-filter-turbulence.h2
-rw-r--r--src/display/nr-filter-units.cpp4
-rw-r--r--src/display/nr-filter.cpp137
-rw-r--r--src/display/nr-filter.h21
-rw-r--r--src/display/nr-style.cpp40
-rw-r--r--src/display/nr-style.h13
-rw-r--r--src/display/rendermode.h8
-rw-r--r--src/display/sp-canvas-item.h2
-rw-r--r--src/display/sp-canvas.cpp27
79 files changed, 3972 insertions, 4065 deletions
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index fc7c8e9ab..1c7a21dae 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -23,6 +23,22 @@ ink_common_sources += \
display/canvas-text.h \
display/curve.cpp \
display/curve.h \
+ display/drawing.cpp \
+ display/drawing.h \
+ display/drawing-context.cpp \
+ display/drawing-context.h \
+ display/drawing-group.cpp \
+ display/drawing-group.h \
+ display/drawing-image.cpp \
+ display/drawing-image.h \
+ display/drawing-item.cpp \
+ display/drawing-item.h \
+ display/drawing-shape.cpp \
+ display/drawing-shape.h \
+ display/drawing-surface.cpp \
+ display/drawing-surface.h \
+ display/drawing-text.cpp \
+ display/drawing-text.h \
display/gnome-canvas-acetate.cpp \
display/gnome-canvas-acetate.h \
display/grayscale.cpp \
@@ -31,19 +47,7 @@ ink_common_sources += \
display/guideline.h \
display/nr-3dutils.cpp \
display/nr-3dutils.h \
- display/nr-arena.cpp \
display/nr-arena-forward.h \
- display/nr-arena-glyphs.cpp \
- display/nr-arena-glyphs.h \
- display/nr-arena-group.cpp \
- display/nr-arena-group.h \
- display/nr-arena.h \
- display/nr-arena-image.cpp \
- display/nr-arena-image.h \
- display/nr-arena-item.cpp \
- display/nr-arena-item.h \
- display/nr-arena-shape.cpp \
- display/nr-arena-shape.h \
display/nr-filter-blend.cpp \
display/nr-filter-blend.h \
display/nr-filter-colormatrix.cpp \
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index a79f58548..d4c8e1493 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -12,6 +12,10 @@
#ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H
#define SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#ifdef HAVE_OPENMP
#include <omp.h>
#include "preferences.h"
diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp
index dd4a4ed5c..4688a58e3 100644
--- a/src/display/canvas-arena.cpp
+++ b/src/display/canvas-arena.cpp
@@ -15,10 +15,15 @@
#include "display/display-forward.h"
#include "display/sp-canvas-util.h"
#include "helper/sp-marshal.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-group.h"
#include "display/canvas-arena.h"
#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
+#include "display/drawing-item.h"
+#include "display/drawing-group.h"
+#include "display/drawing-surface.h"
+#include "preferences.h"
+
+using namespace Inkscape;
enum {
ARENA_EVENT,
@@ -29,28 +34,42 @@ static void sp_canvas_arena_class_init(SPCanvasArenaClass *klass);
static void sp_canvas_arena_init(SPCanvasArena *group);
static void sp_canvas_arena_destroy(GtkObject *object);
+static void sp_canvas_arena_item_deleted(SPCanvasArena *arena, Inkscape::DrawingItem *item);
static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf);
-static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area);
-static void sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area);
static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
-static void sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area);
+static void sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area);
static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event);
static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event);
-static void sp_canvas_arena_request_update (NRArena *arena, NRArenaItem *item, void *data);
-static void sp_canvas_arena_request_render (NRArena *arena, NRRectL *area, void *data);
-
-NRArenaEventVector carenaev = {
- {NULL},
- sp_canvas_arena_request_update,
- sp_canvas_arena_request_render
-};
+static void sp_canvas_arena_request_update (SPCanvasArena *ca, DrawingItem *item);
+static void sp_canvas_arena_request_render (SPCanvasArena *ca, Geom::IntRect const &area);
static SPCanvasItemClass *parent_class;
static guint signals[LAST_SIGNAL] = {0};
+struct CachePrefObserver : public Inkscape::Preferences::Observer {
+ CachePrefObserver(SPCanvasArena *arena)
+ : Inkscape::Preferences::Observer("/options/renderingcache")
+ , _arena(arena)
+ {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ std::vector<Inkscape::Preferences::Entry> v = prefs->getAllEntries(observed_path);
+ for (unsigned i=0; i<v.size(); ++i) {
+ notify(v[i]);
+ }
+ prefs->addObserver(*this);
+ }
+ void notify(Preferences::Entry const &v) {
+ Glib::ustring name = v.getEntryName();
+ if (name == "size") {
+ _arena->drawing.setCacheBudget((1 << 20) * v.getIntLimited(64, 0, 4096));
+ }
+ }
+ SPCanvasArena *_arena;
+};
+
GType
sp_canvas_arena_get_type (void)
{
@@ -96,7 +115,7 @@ sp_canvas_arena_class_init (SPCanvasArenaClass *klass)
item_class->render = sp_canvas_arena_render;
item_class->point = sp_canvas_arena_point;
item_class->event = sp_canvas_arena_event;
- item_class->visible_area_changed = sp_canvas_arena_visible_area_changed;
+ item_class->viewbox_changed = sp_canvas_arena_viewbox_changed;
}
static void
@@ -104,17 +123,28 @@ sp_canvas_arena_init (SPCanvasArena *arena)
{
arena->sticky = FALSE;
- arena->arena = NRArena::create();
- arena->arena->canvasarena = arena;
- arena->root = NRArenaGroup::create(arena->arena);
- nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE);
+ new (&arena->drawing) Inkscape::Drawing(arena);
- arena->active = NULL;
- arena->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
- arena->cache_area = Geom::IntRect::from_xywh(0,0,1,1);
- arena->dirty = cairo_region_create();
+ Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing);
+ root->setPickChildren(true);
+ arena->drawing.setRoot(root);
+
+ arena->observer = new CachePrefObserver(arena);
+
+ arena->drawing.signal_request_update.connect(
+ sigc::bind<0>(
+ sigc::ptr_fun(&sp_canvas_arena_request_update),
+ arena));
+ arena->drawing.signal_request_render.connect(
+ sigc::bind<0>(
+ sigc::ptr_fun(&sp_canvas_arena_request_render),
+ arena));
+ arena->drawing.signal_item_deleted.connect(
+ sigc::bind<0>(
+ sigc::ptr_fun(&sp_canvas_arena_item_deleted),
+ arena));
- nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena);
+ arena->active = NULL;
}
static void
@@ -122,27 +152,8 @@ sp_canvas_arena_destroy (GtkObject *object)
{
SPCanvasArena *arena = SP_CANVAS_ARENA (object);
- if (arena->active) {
- nr_object_unref ((NRObject *) arena->active);
- arena->active = NULL;
- }
-
- if (arena->root) {
- nr_arena_item_unref (arena->root);
- arena->root = NULL;
- }
-
- if (arena->arena) {
- nr_active_object_remove_listener_by_data ((NRActiveObject *) arena->arena, arena);
-
- nr_object_unref ((NRObject *) arena->arena);
- arena->arena = NULL;
- }
- if (arena->cache) {
- cairo_surface_destroy(arena->cache);
- arena->cache = NULL;
- }
- cairo_region_destroy(arena->dirty);
+ delete arena->observer;
+ arena->drawing.~Drawing();
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
@@ -156,21 +167,22 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
if (((SPCanvasItemClass *) parent_class)->update)
(* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags);
- arena->gc.transform = affine;
+ arena->ctx.ctm = affine;
- guint reset;
- reset = (flags & SP_CANVAS_UPDATE_AFFINE)? NR_ARENA_ITEM_STATE_ALL : NR_ARENA_ITEM_STATE_NONE;
+ unsigned reset = flags & SP_CANVAS_UPDATE_AFFINE ? DrawingItem::STATE_ALL : 0;
+ arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, reset);
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset);
-
- item->x1 = arena->root->bbox.x0 - 1;
- item->y1 = arena->root->bbox.y0 - 1;
- item->x2 = arena->root->bbox.x1 + 1;
- item->y2 = arena->root->bbox.y1 + 1;
+ Geom::OptIntRect b = arena->drawing.root()->visualBounds();
+ if (b) {
+ item->x1 = b->left() - 1;
+ item->y1 = b->top() - 1;
+ item->x2 = b->right() + 1;
+ item->y2 = b->bottom() + 1;
+ }
if (arena->cursor) {
/* Mess with enter/leave notifiers */
- NRArenaItem *new_arena = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky);
+ DrawingItem *new_arena = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky);
if (new_arena != arena->active) {
GdkEventCrossing ec;
ec.window = GTK_WIDGET (item->canvas)->window;
@@ -184,10 +196,7 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
ec.type = GDK_LEAVE_NOTIFY;
sp_canvas_arena_send_event (arena, (GdkEvent *) &ec);
}
- /* fixme: This is not optimal - better track ::destroy (Lauris) */
- if (arena->active) nr_object_unref ((NRObject *) arena->active);
arena->active = new_arena;
- if (arena->active) nr_object_ref ((NRObject *) arena->active);
if (arena->active) {
ec.type = GDK_ENTER_NOTIFY;
sp_canvas_arena_send_event (arena, (GdkEvent *) &ec);
@@ -197,76 +206,26 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
}
static void
+sp_canvas_arena_item_deleted(SPCanvasArena *arena, Inkscape::DrawingItem *item)
+{
+ if (arena->active == item) {
+ arena->active = NULL;
+ }
+}
+
+static void
sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf)
{
+ // todo: handle NR_ARENA_ITEM_RENDER_NO_CACHE
SPCanvasArena *arena = SP_CANVAS_ARENA (item);
- //SPCanvas *canvas = item->canvas;
-
- //nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
- // NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER,
- // NR_ARENA_ITEM_STATE_NONE);
Geom::OptIntRect r = buf->rect;
if (!r || r->hasZeroArea()) return;
-
- cairo_rectangle_int_t crect;
- crect.x = r->left();
- crect.y = r->top();
- crect.width = r->width();
- crect.height = r->height();
- if (cairo_region_contains_rectangle(arena->dirty, &crect) != CAIRO_REGION_OVERLAP_OUT) {
- sp_canvas_arena_render_cache(item, *r);
- cairo_region_subtract_rectangle(arena->dirty, &crect);
- }
- cairo_save(buf->ct);
- cairo_translate(buf->ct, -r->left(), -r->top());
- //cairo_rectangle(buf->ct, r->left(), r->top(), r->width(), r->height());
- //cairo_clip(buf->ct);
- cairo_set_source_surface(buf->ct, arena->cache, arena->cache_area.left(), arena->cache_area.top());
- cairo_paint(buf->ct);
- //nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0);
- cairo_restore(buf->ct);
-}
+ Inkscape::DrawingContext ct(buf->ct, r->min());
-static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area)
-{
- SPCanvasArena *arena = SP_CANVAS_ARENA (item);
-
- Geom::OptIntRect r = Geom::intersect(arena->cache_area, area);
- if (!r || r->hasZeroArea()) return; // nothing to do
-
- cairo_t *ct = cairo_create(arena->cache);
- cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top());
-
- // clear area to paint
- cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height());
- cairo_clip(ct);
- cairo_save(ct);
- cairo_set_source_rgba(ct, 0,0,0,0);
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
- cairo_restore(ct);
-
- NRRectL nr_area(r);
-
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
- NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER,
- NR_ARENA_ITEM_STATE_NONE);
- nr_arena_item_invoke_render (ct, arena->root, &nr_area, NULL, 0);
-
- cairo_destroy(ct);
-}
-
-static void
-sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area)
-{
- cairo_rectangle_int_t rect;
- rect.x = area->x0;
- rect.y = area->y0;
- rect.width = area->x1 - area->x0;
- rect.height = area->y1 - area->y0;
- cairo_region_union_rectangle(arena->dirty, &rect);
+ arena->drawing.update(Geom::IntRect::infinite(), arena->ctx);
+ arena->drawing.render(ct, *r);
}
static double
@@ -274,11 +233,8 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_
{
SPCanvasArena *arena = SP_CANVAS_ARENA (item);
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
- NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK,
- NR_ARENA_ITEM_STATE_NONE);
-
- NRArenaItem *picked = nr_arena_item_invoke_pick (arena->root, p, arena->arena->delta, arena->sticky);
+ arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK);
+ DrawingItem *picked = arena->drawing.pick(p, arena->drawing.delta, arena->sticky);
arena->picked = picked;
@@ -291,70 +247,20 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_
}
static void
-sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area)
+sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area)
{
SPCanvasArena *arena = SP_CANVAS_ARENA(item);
-
- cairo_surface_t *new_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- new_area.width(), new_area.height());
- cairo_t *ct = cairo_create(new_cache);
- cairo_set_source_surface(ct, arena->cache, old_area.left() - new_area.left(), old_area.top() - new_area.top());
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
- cairo_destroy(ct);
- cairo_surface_destroy(arena->cache);
- arena->cache = new_cache;
- arena->cache_area = new_area;
-
- cairo_rectangle_int_t crect;
- crect.x = new_area.left();
- crect.y = new_area.top();
- crect.width = new_area.width();
- crect.height = new_area.height();
- cairo_region_intersect_rectangle(arena->dirty, &crect);
-
- // invalidate newly exposed areas
- /*
- * +----------------------+
- * | top strip |
- * +-------+------+-------+
- * | | | |
- * | left | old | right |
- * | strip | area | strip |
- * | | | |
- * +-------+------+-------+
- * | bottom strip |
- * +----------------------+
- */
-
- // top strip
- if (new_area.top() < old_area.top()) {
- NRRectL top_strip(new_area.left(), new_area.top(), new_area.right(), old_area.top());
- sp_canvas_arena_dirty_cache(arena, &top_strip);
- }
- // left strip
- if (new_area.left() < old_area.left()) {
- NRRectL left_strip(new_area.left(), std::max(new_area.top(), old_area.top()),
- old_area.left(), std::min(new_area.bottom(), old_area.bottom()));
- sp_canvas_arena_dirty_cache(arena, &left_strip);
- }
- // right strip
- if (new_area.right() > old_area.right()) {
- NRRectL right_strip(old_area.right(), std::max(new_area.top(), old_area.top()),
- new_area.right(), std::min(new_area.bottom(), old_area.bottom()));
- sp_canvas_arena_dirty_cache(arena, &right_strip);
- }
- // bottom strip
- if (new_area.bottom() > old_area.bottom()) {
- NRRectL bottom_strip(new_area.left(), old_area.bottom(), new_area.right(), new_area.bottom());
- sp_canvas_arena_dirty_cache(arena, &bottom_strip);
- }
+ // make the cache limit larger than screen to facilitate smooth scrolling
+ Geom::IntRect expanded = new_area;
+ Geom::IntPoint expansion(new_area.width()/2, new_area.height()/2);
+ expanded.expandBy(expansion);
+ arena->drawing.setCacheLimit(expanded);
}
static gint
sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
{
- NRArenaItem *new_arena;
+ Inkscape::DrawingItem *new_arena;
/* fixme: This sucks, we have to handle enter/leave notifiers */
SPCanvasArena *arena = SP_CANVAS_ARENA (item);
@@ -366,7 +272,6 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
if (!arena->cursor) {
if (arena->active) {
//g_warning ("Cursor entered to arena with already active item");
- nr_object_unref ((NRObject *) arena->active);
}
arena->cursor = TRUE;
@@ -374,9 +279,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
arena->c = Geom::Point(event->crossing.x, event->crossing.y);
/* fixme: Not sure abut this, but seems the right thing (Lauris) */
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE);
- arena->active = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky);
- if (arena->active) nr_object_ref ((NRObject *) arena->active);
+ arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0);
+ arena->active = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky);
ret = sp_canvas_arena_send_event (arena, event);
}
break;
@@ -384,7 +288,6 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
case GDK_LEAVE_NOTIFY:
if (arena->cursor) {
ret = sp_canvas_arena_send_event (arena, event);
- if (arena->active) nr_object_unref ((NRObject *) arena->active);
arena->active = NULL;
arena->cursor = FALSE;
}
@@ -395,8 +298,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
arena->c = Geom::Point(event->motion.x, event->motion.y);
/* fixme: Not sure abut this, but seems the right thing (Lauris) */
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE);
- new_arena = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky);
+ arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK);
+ new_arena = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky);
if (new_arena != arena->active) {
GdkEventCrossing ec;
ec.window = event->motion.window;
@@ -410,9 +313,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
ec.type = GDK_LEAVE_NOTIFY;
ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec);
}
- if (arena->active) nr_object_unref ((NRObject *) arena->active);
arena->active = new_arena;
- if (arena->active) nr_object_ref ((NRObject *) arena->active);
if (arena->active) {
ec.type = GDK_ENTER_NOTIFY;
ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec);
@@ -442,17 +343,16 @@ sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event)
}
static void
-sp_canvas_arena_request_update (NRArena */*arena*/, NRArenaItem */*item*/, void *data)
+sp_canvas_arena_request_update (SPCanvasArena *ca, DrawingItem */*item*/)
{
- sp_canvas_item_request_update (SP_CANVAS_ITEM (data));
+ sp_canvas_item_request_update (SP_CANVAS_ITEM (ca));
}
static void
-sp_canvas_arena_request_render (NRArena */*arena*/, NRRectL *area, void *data)
+sp_canvas_arena_request_render (SPCanvasArena *ca, Geom::IntRect const &area)
{
- if (!area) return;
- sp_canvas_arena_dirty_cache (SP_CANVAS_ARENA(data), area);
- sp_canvas_request_redraw (SP_CANVAS_ITEM (data)->canvas, area->x0, area->y0, area->x1, area->y1);
+ SPCanvas *canvas = SP_CANVAS_ITEM (ca)->canvas;
+ sp_canvas_request_redraw (canvas, area.left(), area.top(), area.right(), area.bottom());
}
void
@@ -481,13 +381,13 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR
g_return_if_fail (ca != NULL);
g_return_if_fail (SP_IS_CANVAS_ARENA (ca));
- cairo_t *ct = cairo_create(surface);
- cairo_translate(ct, -r.x0, -r.y0);
- nr_arena_item_invoke_render (ct, ca->root, &r, NULL, 0);
- cairo_destroy(ct);
+ Geom::OptIntRect area = r.upgrade_2geom();
+ if (!area) return;
+ Inkscape::DrawingContext ct(surface, area->min());
+ ca->drawing.update(Geom::IntRect::infinite(), ca->ctx);
+ ca->drawing.render(ct, *area);
}
-
/*
Local Variables:
mode:c++
diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h
index 220976da0..f145a9c70 100644
--- a/src/display/canvas-arena.h
+++ b/src/display/canvas-arena.h
@@ -15,9 +15,11 @@
#include <cairo.h>
#include <2geom/rect.h>
+#include "display/display-forward.h"
+#include "display/drawing.h"
+#include "display/drawing-item.h"
#include "display/sp-canvas.h"
#include "display/sp-canvas-item.h"
-#include "display/nr-arena-item.h"
G_BEGIN_DECLS
@@ -29,6 +31,7 @@ G_BEGIN_DECLS
typedef struct _SPCanvasArena SPCanvasArena;
typedef struct _SPCanvasArenaClass SPCanvasArenaClass;
+struct CachePrefObserver;
struct _SPCanvasArena {
SPCanvasItem item;
@@ -37,24 +40,20 @@ struct _SPCanvasArena {
guint sticky : 1;
Geom::Point c; // what is this?
- NRArena *arena;
- NRArenaItem *root;
- NRGC gc;
+ Inkscape::Drawing drawing;
+ Inkscape::UpdateContext ctx;
- NRArenaItem *active;
+ Inkscape::DrawingItem *active;
/* fixme: */
- NRArenaItem *picked;
- gdouble delta;
-
- Geom::IntRect cache_area;
- cairo_surface_t *cache;
- cairo_region_t *dirty;
+ Inkscape::DrawingItem *picked;
+ CachePrefObserver *observer;
+ double delta;
};
struct _SPCanvasArenaClass {
SPCanvasItemClass parent_class;
- gint (* arena_event) (SPCanvasArena *carena, NRArenaItem *item, GdkEvent *event);
+ gint (* arena_event) (SPCanvasArena *carena, Inkscape::DrawingItem *item, GdkEvent *event);
};
GType sp_canvas_arena_get_type (void);
diff --git a/src/display/display-forward.h b/src/display/display-forward.h
index bc7013214..7dccb76ef 100644
--- a/src/display/display-forward.h
+++ b/src/display/display-forward.h
@@ -10,12 +10,30 @@ typedef struct _SPCanvasItemClass SPCanvasItemClass;
struct SPCanvasGroup;
struct SPCanvasGroupClass;
class SPCurve;
+typedef struct _SPCanvasArena SPCanvasArena;
namespace Inkscape {
+class Drawing;
+class DrawingItem;
+class DrawingGroup;
+class DrawingImage;
+class DrawingShape;
+class DrawingGlyphs;
+class DrawingText;
+class UpdateContext;
+
+class DrawingContext;
+class DrawingSurface;
+class DrawingCache;
+
namespace Display {
class TemporaryItem;
class TemporaryItemList;
}
+
+namespace Filters {
+ class Filter;
+}
}
#endif /* !SEEN_DISPLAY_DISPLAY_FORWARD_H */
diff --git a/src/display/drawing-context.cpp b/src/display/drawing-context.cpp
new file mode 100644
index 000000000..3c0c2163b
--- /dev/null
+++ b/src/display/drawing-context.cpp
@@ -0,0 +1,152 @@
+/**
+ * @file
+ * @brief Cairo drawing context with Inkscape extensions
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/drawing-context.h"
+#include "display/drawing-surface.h"
+#include "display/cairo-utils.h"
+#include "helper/geom.h"
+
+namespace Inkscape {
+
+using Geom::X;
+using Geom::Y;
+
+/** @class DrawingContext::Save
+ * @brief RAII idiom for saving the state of DrawingContext. */
+
+DrawingContext::Save::Save()
+ : _ct(NULL)
+{}
+DrawingContext::Save::Save(DrawingContext &ct)
+ : _ct(&ct)
+{
+ _ct->save();
+}
+DrawingContext::Save::~Save()
+{
+ if (_ct) {
+ _ct->restore();
+ }
+}
+void DrawingContext::Save::save(DrawingContext &ct)
+{
+ if (_ct) {
+ // TODO: it might be better to treat this occurence as a bug
+ _ct->restore();
+ }
+ _ct = &ct;
+ _ct->save();
+}
+
+/** @class DrawingContext
+ * @brief Minimal wrapper over Cairo.
+ *
+ * This is a wrapper over cairo_t, extended with operations that work
+ * with 2Geom geometrical primitives. Some of this is probably duplicated
+ * in cairo-render-context.cpp, which provides higher level operations
+ * for drawing entire SPObjects when exporting.
+ */
+
+DrawingContext::DrawingContext(cairo_t *ct, Geom::Point const &origin)
+ : _ct(ct)
+ , _surface(new DrawingSurface(cairo_get_group_target(ct), origin))
+ , _delete_surface(true)
+ , _restore_context(true)
+{
+ _surface->_has_context = true;
+ cairo_reference(_ct);
+ cairo_save(_ct);
+ cairo_translate(_ct, -origin[Geom::X], -origin[Geom::Y]);
+}
+
+DrawingContext::DrawingContext(cairo_surface_t *surface, Geom::Point const &origin)
+ : _ct(NULL)
+ , _surface(new DrawingSurface(surface, origin))
+ , _delete_surface(true)
+ , _restore_context(false)
+{
+ _surface->_has_context = true;
+ _ct = _surface->createRawContext();
+}
+
+DrawingContext::DrawingContext(DrawingSurface &s)
+ : _ct(s.createRawContext())
+ , _surface(&s)
+ , _delete_surface(false)
+ , _restore_context(false)
+{}
+
+DrawingContext::~DrawingContext()
+{
+ if (_restore_context) {
+ cairo_restore(_ct);
+ }
+ cairo_destroy(_ct);
+ _surface->_has_context = false;
+ if (_delete_surface) {
+ delete _surface;
+ }
+}
+
+void DrawingContext::arc(Geom::Point const &center, double radius, Geom::AngleInterval const &angle)
+{
+ double from = angle.initialAngle();
+ double to = angle.finalAngle();
+ if (to > from) {
+ cairo_arc(_ct, center[X], center[Y], radius, from, to);
+ } else {
+ cairo_arc_negative(_ct, center[X], center[Y], radius, to, from);
+ }
+}
+
+void DrawingContext::transform(Geom::Affine const &trans) {
+ ink_cairo_transform(_ct, trans);
+}
+
+void DrawingContext::path(Geom::PathVector const &pv) {
+ feed_pathvector_to_cairo(_ct, pv);
+}
+
+void DrawingContext::paint(double alpha) {
+ if (alpha == 1.0) cairo_paint(_ct);
+ else cairo_paint_with_alpha(_ct, alpha);
+}
+void DrawingContext::setSource(guint32 rgba) {
+ ink_cairo_set_source_rgba32(_ct, rgba);
+}
+void DrawingContext::setSource(DrawingSurface *s) {
+ Geom::Point origin = s->origin();
+ cairo_set_source_surface(_ct, s->raw(), origin[X], origin[Y]);
+}
+void DrawingContext::setSourceCheckerboard() {
+ cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard();
+ cairo_set_source(_ct, check);
+ cairo_pattern_destroy(check);
+}
+
+Geom::Rect DrawingContext::targetLogicalBounds() const
+{
+ Geom::Rect ret(_surface->area());
+ return ret;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h
new file mode 100644
index 000000000..4ada79057
--- /dev/null
+++ b/src/display/drawing-context.h
@@ -0,0 +1,128 @@
+/**
+ * @file
+ * @brief Cairo drawing context with Inkscape extensions
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H
+
+#include <boost/utility.hpp>
+#include <glib.h>
+#include <cairo.h>
+#include <2geom/affine.h>
+#include <2geom/angle.h>
+#include <2geom/rect.h>
+#include <2geom/transforms.h>
+
+namespace Inkscape {
+
+class DrawingSurface;
+
+class DrawingContext
+ : boost::noncopyable
+{
+public:
+ class Save {
+ public:
+ Save();
+ Save(DrawingContext &ct);
+ ~Save();
+ void save(DrawingContext &ct);
+ private:
+ DrawingContext *_ct;
+ };
+
+ DrawingContext(cairo_t *ct, Geom::Point const &origin);
+ DrawingContext(cairo_surface_t *surface, Geom::Point const &origin);
+ DrawingContext(DrawingSurface &s);
+ ~DrawingContext();
+
+ void save() { cairo_save(_ct); }
+ void restore() { cairo_restore(_ct); }
+ void pushGroup() { cairo_push_group(_ct); }
+ void pushAlphaGroup() { cairo_push_group_with_content(_ct, CAIRO_CONTENT_ALPHA); }
+ void popGroupToSource() { cairo_pop_group_to_source(_ct); }
+
+ void transform(Geom::Affine const &trans);
+ void translate(Geom::Point const &t) { cairo_translate(_ct, t[Geom::X], t[Geom::Y]); } // todo: take Translate
+ void translate(double dx, double dy) { cairo_translate(_ct, dx, dy); }
+ void scale(Geom::Scale const &s) { cairo_scale(_ct, s[Geom::X], s[Geom::Y]); }
+ void scale(double sx, double sy) { cairo_scale(_ct, sx, sy); }
+
+ void moveTo(Geom::Point const &p) { cairo_move_to(_ct, p[Geom::X], p[Geom::Y]); }
+ void lineTo(Geom::Point const &p) { cairo_line_to(_ct, p[Geom::X], p[Geom::Y]); }
+ void curveTo(Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) {
+ cairo_curve_to(_ct, p1[Geom::X], p1[Geom::Y], p2[Geom::X], p2[Geom::Y], p3[Geom::X], p3[Geom::Y]);
+ }
+ void arc(Geom::Point const &center, double radius, Geom::AngleInterval const &angle);
+ void rectangle(Geom::Rect const &r) {
+ cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height());
+ }
+ void rectangle(Geom::IntRect const &r) {
+ cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height());
+ }
+ void newPath() { cairo_new_path(_ct); }
+ void newSubpath() { cairo_new_sub_path(_ct); }
+ void path(Geom::PathVector const &pv);
+
+ void paint(double alpha = 1.0);
+ void fill() { cairo_fill(_ct); }
+ void fillPreserve() { cairo_fill_preserve(_ct); }
+ void stroke() { cairo_stroke(_ct); }
+ void strokePreserve() { cairo_stroke_preserve(_ct); }
+ void clip() { cairo_clip(_ct); }
+
+ void setLineWidth(double w) { cairo_set_line_width(_ct, w); }
+ void setLineCap(cairo_line_cap_t cap) { cairo_set_line_cap(_ct, cap); }
+ void setLineJoin(cairo_line_join_t join) { cairo_set_line_join(_ct, join); }
+ void setMiterLimit(double miter) { cairo_set_miter_limit(_ct, miter); }
+ void setFillRule(cairo_fill_rule_t rule) { cairo_set_fill_rule(_ct, rule); }
+ void setOperator(cairo_operator_t op) { cairo_set_operator(_ct, op); }
+ void setTolerance(double tol) { cairo_set_tolerance(_ct, tol); }
+ void setSource(cairo_pattern_t *source) { cairo_set_source(_ct, source); }
+ void setSource(cairo_surface_t *surface, double x, double y) {
+ cairo_set_source_surface(_ct, surface, x, y);
+ }
+ void setSource(double r, double g, double b, double a = 1.0) {
+ cairo_set_source_rgba(_ct, r, g, b, a);
+ }
+ void setSource(guint32 rgba);
+ void setSource(DrawingSurface *s);
+ void setSourceCheckerboard();
+
+ Geom::Rect targetLogicalBounds() const;
+
+ cairo_t *raw() { return _ct; }
+ cairo_surface_t *rawTarget() { return cairo_get_group_target(_ct); }
+
+private:
+ DrawingContext(cairo_t *ct, DrawingSurface *surface, bool destroy);
+
+ cairo_t *_ct;
+ DrawingSurface *_surface;
+ bool _delete_surface;
+ bool _restore_context;
+
+ friend class DrawingSurface;
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp
new file mode 100644
index 000000000..a678c3feb
--- /dev/null
+++ b/src/display/drawing-group.cpp
@@ -0,0 +1,165 @@
+/**
+ * @file
+ * @brief Group belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/cairo-utils.h"
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/drawing-item.h"
+#include "display/drawing-group.h"
+#include "libnr/nr-values.h"
+#include "style.h"
+
+namespace Inkscape {
+
+DrawingGroup::DrawingGroup(Drawing &drawing)
+ : DrawingItem(drawing)
+ , _style(NULL)
+ , _child_transform(NULL)
+{}
+
+DrawingGroup::~DrawingGroup()
+{
+ if (_style)
+ sp_style_unref(_style);
+}
+
+/** @brief Set whether the group returns children from pick calls.
+ * Previously this feature was called "transparent groups".
+ */
+void
+DrawingGroup::setPickChildren(bool p)
+{
+ _pick_children = p;
+}
+
+void
+DrawingGroup::setStyle(SPStyle *style)
+{
+ _setStyleCommon(_style, style);
+}
+
+/** @brief Set additional transform for the group.
+ * This is applied after the normal transform and mainly useful for
+ * markers, clipping paths, etc.
+ */
+void
+DrawingGroup::setChildTransform(Geom::Affine const &new_trans)
+{
+ Geom::Affine current;
+ if (_child_transform) {
+ current = *_child_transform;
+ }
+
+ if (!Geom::are_near(current, new_trans, NR_EPSILON)) {
+ // mark the area where the object was for redraw.
+ _markForRendering();
+ if (new_trans.isIdentity()) {
+ delete _child_transform; // delete NULL; is safe
+ _child_transform = NULL;
+ } else {
+ _child_transform = new Geom::Affine(new_trans);
+ }
+ _markForUpdate(STATE_ALL, true);
+ }
+}
+
+unsigned
+DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ unsigned beststate = STATE_ALL;
+ bool outline = _drawing.outline();
+
+ UpdateContext child_ctx(ctx);
+ if (_child_transform) {
+ child_ctx.ctm = *_child_transform * ctx.ctm;
+ }
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->update(area, child_ctx, flags, reset);
+ }
+ if (beststate & STATE_BBOX) {
+ _bbox = Geom::OptIntRect();
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ if (i->visible()) {
+ _bbox.unionWith(outline ? i->geometricBounds() : i->visualBounds());
+ }
+ }
+ }
+ return beststate;
+}
+
+unsigned
+DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
+{
+ if (stop_at == NULL) {
+ // normal rendering
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->render(ct, area, flags, stop_at);
+ }
+ } else {
+ // background rendering
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ if (&*i == stop_at) return RENDER_OK; // do not render the stop_at item at all
+ if (i->isAncestorOf(stop_at)) {
+ // render its ancestors without masks, opacity or filters
+ i->render(ct, area, flags | RENDER_FILTER_BACKGROUND, stop_at);
+ // stop further rendering
+ return RENDER_OK;
+ } else {
+ i->render(ct, area, flags, stop_at);
+ }
+ }
+ }
+ return RENDER_OK;
+}
+
+void
+DrawingGroup::_clipItem(DrawingContext &ct, Geom::IntRect const &area)
+{
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->clip(ct, area);
+ }
+}
+
+DrawingItem *
+DrawingGroup::_pickItem(Geom::Point const &p, double delta, unsigned flags)
+{
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ DrawingItem *picked = i->pick(p, delta, flags);
+ if (picked) {
+ return _pick_children ? picked : this;
+ }
+ }
+ return NULL;
+}
+
+bool
+DrawingGroup::_canClip()
+{
+ return true;
+}
+
+bool is_drawing_group(DrawingItem *item)
+{
+ return dynamic_cast<DrawingGroup *>(item) != NULL;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h
new file mode 100644
index 000000000..961e5b9a3
--- /dev/null
+++ b/src/display/drawing-group.h
@@ -0,0 +1,62 @@
+/**
+ * @file
+ * @brief Group belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_GROUP_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_GROUP_H
+
+#include "display/drawing-item.h"
+
+class SPStyle;
+
+namespace Inkscape {
+
+class DrawingGroup
+ : public DrawingItem
+{
+public:
+ DrawingGroup(Drawing &drawing);
+ ~DrawingGroup();
+
+ bool pickChildren() { return _pick_children; }
+ void setPickChildren(bool p);
+
+ void setStyle(SPStyle *style);
+ void setChildTransform(Geom::Affine const &new_trans);
+
+protected:
+ virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset);
+ virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags,
+ DrawingItem *stop_at);
+ virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area);
+ virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags);
+ virtual bool _canClip();
+
+ SPStyle *_style;
+ Geom::Affine *_child_transform;
+};
+
+bool is_drawing_group(DrawingItem *item);
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp
new file mode 100644
index 000000000..fa0402699
--- /dev/null
+++ b/src/display/drawing-image.cpp
@@ -0,0 +1,264 @@
+/**
+ * @file
+ * @brief Bitmap image belonging to an SVG drawing
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/cairo-utils.h"
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/drawing-image.h"
+#include "preferences.h"
+#include "style.h"
+
+namespace Inkscape {
+
+DrawingImage::DrawingImage(Drawing &drawing)
+ : DrawingItem(drawing)
+ , _pixbuf(NULL)
+ , _surface(NULL)
+ , _style(NULL)
+{}
+
+DrawingImage::~DrawingImage()
+{
+ if (_style)
+ sp_style_unref(_style);
+ if (_pixbuf) {
+ cairo_surface_destroy(_surface);
+ g_object_unref(_pixbuf);
+ }
+}
+
+void
+DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb)
+{
+ // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1
+ if (pb != NULL) {
+ g_object_ref (pb);
+ }
+ if (_pixbuf != NULL) {
+ g_object_unref(_pixbuf);
+ cairo_surface_destroy(_surface);
+ }
+ _pixbuf = pb;
+ _surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL;
+
+ _markForUpdate(STATE_ALL, false);
+}
+
+void
+DrawingImage::setStyle(SPStyle *style)
+{
+ _setStyleCommon(_style, style);
+}
+
+void
+DrawingImage::setScale(double sx, double sy)
+{
+ _scale = Geom::Scale(sx, sy);
+ _markForUpdate(STATE_ALL, false);
+}
+
+void
+DrawingImage::setOrigin(Geom::Point const &o)
+{
+ _origin = o;
+ _markForUpdate(STATE_ALL, false);
+}
+
+void
+DrawingImage::setClipbox(Geom::Rect const &box)
+{
+ _clipbox = box;
+ _markForUpdate(STATE_ALL, false);
+}
+
+Geom::Rect
+DrawingImage::bounds() const
+{
+ if (!_pixbuf) return _clipbox;
+
+ double pw = gdk_pixbuf_get_width(_pixbuf);
+ double ph = gdk_pixbuf_get_height(_pixbuf);
+ double vw = pw * _scale[Geom::X];
+ double vh = ph * _scale[Geom::Y];
+ Geom::Point wh(vw, vh);
+ Geom::Rect view(_origin, _origin+wh);
+ Geom::OptRect res = _clipbox & view;
+ Geom::Rect ret = res ? *res : _clipbox;
+
+ return ret;
+}
+
+unsigned
+DrawingImage::_updateItem(Geom::IntRect const &, UpdateContext const &, unsigned, unsigned)
+{
+ _markForRendering();
+
+ // Calculate bbox
+ if (_pixbuf) {
+ Geom::Rect r = bounds() * _ctm;
+ _bbox = r.roundOutwards();
+ } else {
+ _bbox = Geom::OptIntRect();
+ }
+
+ return STATE_ALL;
+}
+
+unsigned
+DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
+{
+ bool outline = _drawing.outline();
+
+ if (!outline) {
+ if (!_pixbuf) return RENDER_OK;
+
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(_ctm);
+ ct.newPath();
+ ct.rectangle(_clipbox);
+ ct.clip();
+
+ ct.translate(_origin);
+ ct.scale(_scale);
+ ct.setSource(_surface, 0, 0);
+
+ cairo_matrix_t tt;
+ Geom::Affine total;
+ cairo_get_matrix(ct.raw(), &tt);
+ ink_matrix_to_2geom(total, tt);
+
+ if (total.expansionX() > 1.0 || total.expansionY() > 1.0) {
+ cairo_pattern_t *p = cairo_get_source(ct.raw());
+ cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST);
+ }
+ //ct.paint(_opacity);
+ ct.paint();
+
+ } else { // outline; draw a rect instead
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff);
+
+ { Inkscape::DrawingContext::Save save(ct);
+ ct.transform(_ctm);
+ ct.newPath();
+
+ Geom::Rect r = bounds();
+ Geom::Point c00 = r.corner(0);
+ Geom::Point c01 = r.corner(3);
+ Geom::Point c11 = r.corner(2);
+ Geom::Point c10 = r.corner(1);
+
+ ct.moveTo(c00);
+ // the box
+ ct.lineTo(c10);
+ ct.lineTo(c11);
+ ct.lineTo(c01);
+ ct.lineTo(c00);
+ // the diagonals
+ ct.lineTo(c11);
+ ct.moveTo(c10);
+ ct.lineTo(c01);
+ }
+
+ ct.setLineWidth(0.5);
+ ct.setSource(rgba);
+ ct.stroke();
+ }
+ return RENDER_OK;
+}
+
+/** Calculates the closest distance from p to the segment a1-a2*/
+static double
+distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2)
+{
+ // calculate sides of the triangle and their squares
+ double d1 = Geom::L2(p - a1);
+ double d1_2 = d1 * d1;
+ double d2 = Geom::L2(p - a2);
+ double d2_2 = d2 * d2;
+ double a = Geom::L2(a1 - a2);
+ double a_2 = a * a;
+
+ // if one of the angles at the base is > 90, return the corresponding side
+ if (d1_2 + a_2 <= d2_2) return d1;
+ if (d2_2 + a_2 <= d1_2) return d2;
+
+ // otherwise calculate the height to the base
+ double peri = (a + d1 + d2)/2;
+ return (2*sqrt(peri * (peri - a) * (peri - d1) * (peri - d2))/a);
+}
+
+DrawingItem *
+DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/)
+{
+ if (!_pixbuf) return NULL;
+
+ bool outline = _drawing.outline();
+
+ if (outline) {
+ Geom::Rect r = bounds();
+
+ Geom::Point c00 = r.corner(0);
+ Geom::Point c01 = r.corner(3);
+ Geom::Point c11 = r.corner(2);
+ Geom::Point c10 = r.corner(1);
+
+ // frame
+ if (distance_to_segment (p, c00, c10) < delta) return this;
+ if (distance_to_segment (p, c10, c11) < delta) return this;
+ if (distance_to_segment (p, c11, c01) < delta) return this;
+ if (distance_to_segment (p, c01, c00) < delta) return this;
+
+ // diagonals
+ if (distance_to_segment (p, c00, c11) < delta) return this;
+ if (distance_to_segment (p, c10, c01) < delta) return this;
+
+ return NULL;
+
+ } else {
+ unsigned char *const pixels = gdk_pixbuf_get_pixels(_pixbuf);
+ int width = gdk_pixbuf_get_width(_pixbuf);
+ int height = gdk_pixbuf_get_height(_pixbuf);
+ int rowstride = gdk_pixbuf_get_rowstride(_pixbuf);
+
+ Geom::Point tp = p * _ctm.inverse();
+ Geom::Rect r = bounds();
+
+ if (!r.contains(tp))
+ return NULL;
+
+ double vw = width * _scale[Geom::X];
+ double vh = height * _scale[Geom::Y];
+ int ix = floor((tp[Geom::X] - _origin[Geom::X]) / vw * width);
+ int iy = floor((tp[Geom::Y] - _origin[Geom::Y]) / vh * height);
+
+ if ((ix < 0) || (iy < 0) || (ix >= width) || (iy >= height))
+ return NULL;
+
+ unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4;
+ // pick if the image is less than 99% transparent
+ float alpha = (pix_ptr[3] / 255.0f) * _opacity;
+ return alpha > 0.01 ? this : NULL;
+ }
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h
new file mode 100644
index 000000000..300d6f0b5
--- /dev/null
+++ b/src/display/drawing-image.h
@@ -0,0 +1,67 @@
+/**
+ * @file
+ * @brief Bitmap image belonging to an SVG drawing
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_IMAGE_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_IMAGE_H
+
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <2geom/transforms.h>
+
+#include "display/drawing-item.h"
+
+namespace Inkscape {
+
+class DrawingImage
+ : public DrawingItem
+{
+public:
+ DrawingImage(Drawing &drawing);
+ ~DrawingImage();
+
+ void setARGB32Pixbuf(GdkPixbuf *pb);
+ void setStyle(SPStyle *style);
+ void setScale(double sx, double sy);
+ void setOrigin(Geom::Point const &o);
+ void setClipbox(Geom::Rect const &box);
+ Geom::Rect bounds() const;
+
+protected:
+ virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset);
+ virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags,
+ DrawingItem *stop_at);
+ virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags);
+
+ GdkPixbuf *_pixbuf;
+ cairo_surface_t *_surface;
+ SPStyle *_style;
+
+ // TODO: the following three should probably be merged into a new Geom::Viewbox object
+ Geom::Rect _clipbox; ///< for preserveAspectRatio
+ Geom::Point _origin;
+ Geom::Scale _scale;
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
new file mode 100644
index 000000000..a5496e999
--- /dev/null
+++ b/src/display/drawing-item.cpp
@@ -0,0 +1,900 @@
+/**
+ * @file
+ * @brief Canvas item belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <climits>
+#include "display/cairo-utils.h"
+#include "display/cairo-templates.h"
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/drawing-item.h"
+#include "display/drawing-group.h"
+#include "display/drawing-surface.h"
+#include "nr-filter.h"
+#include "preferences.h"
+#include "style.h"
+
+namespace Inkscape {
+
+/** @class DrawingItem
+ * @brief SVG drawing item for display.
+ *
+ * This was previously known as NRArenaItem. It represents the renderable
+ * portion of the SVG document. Typically this is created by the SP tree,
+ * in particular the show() virtual function.
+ *
+ * @section ObjectLifetime Object lifetime
+ * Deleting a DrawingItem will cause all of its children to be deleted as well.
+ * This can lead to nasty surprises if you hold references to things
+ * which are children of what is being deleted. Therefore, in the SP tree,
+ * you always need to delete the item views of children before deleting
+ * the view of the parent. Do not call delete on things returned from show()
+ * - this will cause dangling pointers inside the SPItem and lead to a crash.
+ * Use the corresponing hide() method.
+ *
+ * Outside of the SP tree, you should not use any references after the root node
+ * has been deleted.
+ */
+
+DrawingItem::DrawingItem(Drawing &drawing)
+ : _drawing(drawing)
+ , _parent(NULL)
+ , _key(0)
+ , _opacity(1.0)
+ , _transform(NULL)
+ , _clip(NULL)
+ , _mask(NULL)
+ , _filter(NULL)
+ , _user_data(NULL)
+ , _cache(NULL)
+ , _state(0)
+ , _child_type(CHILD_ORPHAN)
+ , _background_new(0)
+ , _background_accumulate(0)
+ , _visible(true)
+ , _sensitive(true)
+ , _cached(0)
+ , _cached_persistent(0)
+ , _has_cache_iterator(0)
+ , _propagate(0)
+// , _renders_opacity(0)
+ , _pick_children(0)
+{}
+
+DrawingItem::~DrawingItem()
+{
+ _drawing.signal_item_deleted.emit(this);
+ //if (!_children.empty()) {
+ // g_warning("Removing item with children");
+ //}
+
+ // remove from the set of cached items and delete cache
+ setCached(false, true);
+ if (_has_cache_iterator) {
+ _drawing._candidate_items.erase(_cache_iterator);
+ }
+ // remove this item from parent's children list
+ // due to the effect of clearChildren(), this only happens for the top-level deleted item
+ if (_parent) {
+ _markForRendering();
+ }
+
+ switch (_child_type) {
+ case CHILD_NORMAL: {
+ ChildrenList::iterator ithis = _parent->_children.iterator_to(*this);
+ _parent->_children.erase(ithis);
+ } break;
+ case CHILD_CLIP:
+ // we cannot call setClip(NULL) or setMask(NULL),
+ // because that would be an endless loop
+ _parent->_clip = NULL;
+ break;
+ case CHILD_MASK:
+ _parent->_mask = NULL;
+ break;
+ case CHILD_ROOT:
+ _drawing._root = NULL;
+ break;
+ default: ;
+ }
+
+ if (_parent) {
+ _parent->_markForUpdate(STATE_ALL, false);
+ }
+ clearChildren();
+ delete _transform;
+ delete _clip;
+ delete _mask;
+ delete _filter;
+}
+
+DrawingItem *
+DrawingItem::parent() const
+{
+ // initially I wanted to return NULL if we are a clip or mask child,
+ // but the previous behavior was just to return the parent regardless of child type
+ return _parent;
+}
+
+/// Returns true if item is among the descendants. Will return false if item == this.
+bool
+DrawingItem::isAncestorOf(DrawingItem *item) const
+{
+ for (DrawingItem *i = item->_parent; i; i = i->_parent) {
+ if (i == this) return true;
+ }
+ return false;
+}
+
+void
+DrawingItem::appendChild(DrawingItem *item)
+{
+ item->_parent = this;
+ assert(item->_child_type == CHILD_ORPHAN);
+ item->_child_type = CHILD_NORMAL;
+ _children.push_back(*item);
+ _markForUpdate(STATE_ALL, false);
+}
+
+void
+DrawingItem::prependChild(DrawingItem *item)
+{
+ item->_parent = this;
+ assert(item->_child_type == CHILD_ORPHAN);
+ item->_child_type = CHILD_NORMAL;
+ _children.push_front(*item);
+ _markForUpdate(STATE_ALL, false);
+}
+
+/// Delete all regular children of this item (not mask or clip).
+void
+DrawingItem::clearChildren()
+{
+ // prevent children from referencing the parent during deletion
+ // this way, children won't try to remove themselves from a list
+ // from which they have already been removed by clear_and_dispose
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->_parent = NULL;
+ i->_child_type = CHILD_ORPHAN;
+ }
+ _children.clear_and_dispose(DeleteDisposer());
+}
+
+/// Set the incremental transform for this item
+void
+DrawingItem::setTransform(Geom::Affine const &new_trans)
+{
+ Geom::Affine current;
+ if (_transform) {
+ current = *_transform;
+ }
+
+ if (!Geom::are_near(current, new_trans, NR_EPSILON)) {
+ // mark the area where the object was for redraw.
+ _markForRendering();
+ if (new_trans.isIdentity()) {
+ delete _transform; // delete NULL; is safe
+ _transform = NULL;
+ } else {
+ _transform = new Geom::Affine(new_trans);
+ }
+ _markForUpdate(STATE_ALL, true);
+ }
+}
+
+void
+DrawingItem::setOpacity(float opacity)
+{
+ _opacity = opacity;
+ _markForRendering();
+}
+
+void
+DrawingItem::setVisible(bool v)
+{
+ _visible = v;
+ _markForRendering();
+}
+
+/// This is currently unused
+void
+DrawingItem::setSensitive(bool s)
+{
+ _sensitive = s;
+}
+
+/** @brief Enable / disable storing the rendering in memory.
+ * Calling setCached(false, true) will also remove the persistent status
+ */
+void
+DrawingItem::setCached(bool cached, bool persistent)
+{
+ static const char *cache_env = getenv("_INKSCAPE_DISABLE_CACHE");
+ if (cache_env) return;
+
+ if (_cached_persistent && !persistent)
+ return;
+
+ _cached = cached;
+ _cached_persistent = persistent ? cached : false;
+ if (cached) {
+ _drawing._cached_items.insert(this);
+ } else {
+ _drawing._cached_items.erase(this);
+ delete _cache;
+ _cache = NULL;
+ }
+}
+
+void
+DrawingItem::setClip(DrawingItem *item)
+{
+ _markForRendering();
+ delete _clip;
+ _clip = item;
+ if (item) {
+ item->_parent = this;
+ assert(item->_child_type == CHILD_ORPHAN);
+ item->_child_type = CHILD_CLIP;
+ }
+ _markForUpdate(STATE_ALL, true);
+}
+
+void
+DrawingItem::setMask(DrawingItem *item)
+{
+ _markForRendering();
+ delete _mask;
+ _mask = item;
+ if (item) {
+ item->_parent = this;
+ assert(item->_child_type == CHILD_ORPHAN);
+ item->_child_type = CHILD_MASK;
+ }
+ _markForUpdate(STATE_ALL, true);
+}
+
+/// Move this item to the given place in the Z order of siblings.
+/// Does nothing if the item has no parent.
+void
+DrawingItem::setZOrder(unsigned z)
+{
+ if (!_parent) return;
+
+ ChildrenList::iterator it = _parent->_children.iterator_to(*this);
+ _parent->_children.erase(it);
+
+ ChildrenList::iterator i = _parent->_children.begin();
+ std::advance(i, std::min(z, unsigned(_parent->_children.size())));
+ _parent->_children.insert(i, *this);
+ _markForRendering();
+}
+
+void
+DrawingItem::setItemBounds(Geom::OptRect const &bounds)
+{
+ _item_bbox = bounds;
+}
+
+/** @brief Update derived data before operations.
+ * The purpose of this call is to recompute internal data which depends
+ * on the attributes of the object, but is not directly settable by the user.
+ * Precomputing this data speeds up later rendering, because some items
+ * can be omitted.
+ *
+ * Currently this method handles updating the visual and geometric bounding boxes
+ * in pixels, storing the total transformation from item space to the screen
+ * and cache invalidation.
+ *
+ * @param area Area to which the update should be restricted. Only takes effect
+ * if the bounding box is known.
+ * @param ctx A structure to store cascading state.
+ * @param flags Which internal data should be recomputed. This can be any combination
+ * of StateFlags.
+ * @param reset State fields that should be reset before processing them. This is
+ * a means to force a recomputation of internal data even if the item
+ * considers it up to date. Mainly for internal use, such as
+ * propagating bunding box recomputation to children when the item's
+ * transform changes.
+ */
+void
+DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ bool render_filters = _drawing.renderFilters();
+ bool outline = _drawing.outline();
+
+ // Set reset flags according to propagation status
+ reset |= _propagate_state;
+ _propagate_state = 0;
+
+ _state &= ~reset; // reset state of this item
+
+ if ((~_state & flags) == 0) return; // nothing to do
+
+ // TODO this might be wrong
+ if (_state & STATE_BBOX) {
+ // we have up-to-date bbox
+ if (!area.intersects(outline ? _bbox : _drawbox)) return;
+ }
+
+ // compute which elements need an update
+ unsigned to_update = _state ^ flags;
+
+ // this needs to be called before we recurse into children
+ if (to_update & STATE_BACKGROUND) {
+ _background_accumulate = _background_new;
+ if (_child_type == CHILD_NORMAL && _parent->_background_accumulate)
+ _background_accumulate = true;
+ }
+
+ UpdateContext child_ctx(ctx);
+ if (_transform) {
+ child_ctx.ctm = *_transform * ctx.ctm;
+ }
+ /* Remember the transformation matrix */
+ Geom::Affine ctm_change = _ctm.inverse() * child_ctx.ctm;
+ _ctm = child_ctx.ctm;
+
+ // update _bbox and call this function for children
+ _state = _updateItem(area, child_ctx, flags, reset);
+
+ if (to_update & STATE_BBOX) {
+ // compute drawbox
+ if (_filter && render_filters) {
+ _drawbox = _filter->compute_drawbox(this, _item_bbox);
+ } else {
+ _drawbox = _bbox;
+ }
+
+ // Clipping
+ if (_clip) {
+ _clip->update(area, child_ctx, flags, reset);
+ if (outline) {
+ _bbox.unionWith(_clip->_bbox);
+ } else {
+ _drawbox.intersectWith(_clip->_bbox);
+ }
+ }
+ // Masking
+ if (_mask) {
+ _mask->update(area, child_ctx, flags, reset);
+ if (outline) {
+ _bbox.unionWith(_mask->_bbox);
+ } else {
+ // for masking, we need full drawbox of mask
+ _drawbox.intersectWith(_mask->_drawbox);
+ }
+ }
+ }
+
+ if (to_update & STATE_CACHE) {
+ // Update cache score for this item
+ if (_has_cache_iterator) {
+ // remove old score information
+ _drawing._candidate_items.erase(_cache_iterator);
+ _has_cache_iterator = false;
+ }
+ double score = _cacheScore();
+ if (score >= _drawing._cache_score_threshold) {
+ CacheRecord cr;
+ cr.score = score;
+ // if _cacheRect() is empty, a negative score will be returned from _cacheScore(),
+ // so this will not execute (cache score threshold must be positive)
+ cr.cache_size = _cacheRect()->area() * 4;
+ cr.item = this;
+ _drawing._candidate_items.push_front(cr);
+ _cache_iterator = _drawing._candidate_items.begin();
+ _has_cache_iterator = true;
+ }
+
+ /* Update cache if enabled.
+ * General note: here we only tell the cache how it has to transform
+ * during the render phase. The transformation is deferred because
+ * after the update the item can have its caching turned off,
+ * e.g. because its filter was removed. This way we avoid tempoerarily
+ * using more memory than the cache budget */
+ if (_cache) {
+ Geom::OptIntRect cl = _cacheRect();
+ if (_visible && cl) { // never create cache for invisible items
+ // this takes care of invalidation on transform
+ _cache->scheduleTransform(*cl, ctm_change);
+ } else {
+ // Destroy cache for this item - outside of canvas or invisible.
+ // The opposite transition (invisible -> visible or object
+ // entering the canvas) is handled during the render phase
+ delete _cache;
+ _cache = NULL;
+ }
+ }
+ }
+
+ if (to_update & STATE_RENDER) {
+ // now that we know drawbox, dirty the corresponding rect on canvas
+ // unless filtered, groups do not need to render by themselves, only their members
+ if (!is_drawing_group(this) || (_filter && render_filters)) {
+ _markForRendering();
+ }
+ }
+}
+
+struct MaskLuminanceToAlpha {
+ guint32 operator()(guint32 in) {
+ EXTRACT_ARGB32(in, a, r, g, b)
+ // the operation of unpremul -> luminance-to-alpha -> multiply by alpha
+ // is equivalent to luminance-to-alpha on premultiplied color values
+ // original computation in double: r*0.2125 + g*0.7154 + b*0.0721
+ guint32 ao = r*109 + g*366 + b*37; // coeffs add up to 512
+ return ((ao + 256) << 15) & 0xff000000; // equivalent to ((ao + 256) / 512) << 24
+ }
+};
+
+/** @brief Rasterize items.
+ * This method submits the drawing opeartions required to draw this item
+ * to the supplied DrawingContext, restricting drawing the the specified area.
+ *
+ * This method does some common tasks and calls the item-specific rendering
+ * function, _renderItem(), to render e.g. paths or bitmaps.
+ *
+ * @param flags Rendering options. This deals mainly with cache control.
+ */
+unsigned
+DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
+{
+ bool outline = _drawing.outline();
+ bool render_filters = _drawing.renderFilters();
+
+ // stop_at is handled in DrawingGroup, but this check is required to handle the case
+ // where a filtered item with background-accessing filter has enable-background: new
+ if (this == stop_at) return RENDER_STOP;
+
+ // If we are invisible, return immediately
+ if (!_visible) return RENDER_OK;
+ if (_ctm.isSingular(NR_EPSILON)) return RENDER_OK;
+
+ // TODO convert outline rendering to a separate virtual function
+ if (outline) {
+ _renderOutline(ct, area, flags);
+ return RENDER_OK;
+ }
+
+ // carea is the area to paint
+ Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
+ if (!carea) return RENDER_OK;
+
+ // render from cache if possible
+ if (_cached) {
+ if (_cache) {
+ _cache->prepare();
+ _cache->paintFromCache(ct, carea);
+ if (!carea) return RENDER_OK;
+ } else {
+ // There is no cache. This could be because caching of this item
+ // was just turned on after the last update phase, or because
+ // we were previously outside of the canvas.
+ Geom::OptIntRect cl = _drawing.cacheLimit();
+ cl.intersectWith(_drawbox);
+ if (cl) {
+ _cache = new DrawingCache(*cl);
+ }
+ }
+ } else {
+ // if our caching was turned off after the last update, it was already
+ // deleted in setCached()
+ }
+
+ // determine whether this shape needs intermediate rendering.
+ bool needs_intermediate_rendering = false;
+ bool &nir = needs_intermediate_rendering;
+ bool needs_opacity = (_opacity < 0.995);
+
+ // this item needs an intermediate rendering if:
+ nir |= (_clip != NULL); // 1. it has a clipping path
+ nir |= (_mask != NULL); // 2. it has a mask
+ nir |= (_filter != NULL && render_filters); // 3. it has a filter
+ nir |= needs_opacity; // 4. it is non-opaque
+ nir |= (_cache != NULL); // 5. it is cached
+
+ /* How the rendering is done.
+ *
+ * Clipping, masking and opacity are done by rendering them to a surface
+ * and then compositing the object's rendering onto it with the IN operator.
+ * The object itself is rendered to a group.
+ *
+ * Opacity is done by rendering the clipping path with an alpha
+ * value corresponding to the opacity. If there is no clipping path,
+ * the entire intermediate surface is painted with alpha corresponding
+ * to the opacity value.
+ */
+
+ // Short-circuit the simple case.
+ // We also use this path for filter background rendering, because masking, clipping,
+ // filters and opacity do not apply when rendering the ancestors of the filtered
+ // element
+ if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) {
+ return _renderItem(ct, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at);
+ }
+
+ // iarea is the bounding box for intermediate rendering
+ // Note 1: Pixels inside iarea but outside carea are invalid
+ // (incomplete filter dependence region).
+ // Note 2: We only need to render carea of clip and mask, but
+ // iarea of the object.
+ Geom::OptIntRect iarea = carea;
+ // expand carea to contain the dependent area of filters.
+ if (_filter && render_filters) {
+ _filter->area_enlarge(*iarea, this);
+ iarea.intersectWith(_drawbox);
+ }
+
+ DrawingSurface intermediate(*iarea);
+ DrawingContext ict(intermediate);
+ unsigned render_result = RENDER_OK;
+
+ // 1. Render clipping path with alpha = opacity.
+ ict.setSource(0,0,0,_opacity);
+ // Since clip can be combined with opacity, the result could be incorrect
+ // for overlapping clip children. To fix this we use the SOURCE operator
+ // instead of the default OVER.
+ ict.setOperator(CAIRO_OPERATOR_SOURCE);
+ if (_clip) {
+ _clip->clip(ict, *carea); // fixme: carea or area?
+ } else {
+ // if there is no clipping path, fill the entire surface with alpha = opacity.
+ ict.paint();
+ }
+ ict.setOperator(CAIRO_OPERATOR_OVER); // reset back to default
+
+ // 2. Render the mask if present and compose it with the clipping path + opacity.
+ if (_mask) {
+ ict.pushGroup();
+ _mask->render(ict, *carea, flags);
+
+ cairo_surface_t *mask_s = ict.rawTarget();
+ // Convert mask's luminance to alpha
+ ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha());
+ ict.popGroupToSource();
+ ict.setOperator(CAIRO_OPERATOR_IN);
+ ict.paint();
+ ict.setOperator(CAIRO_OPERATOR_OVER);
+ }
+
+ // 3. Render object itself
+ ict.pushGroup();
+ render_result = _renderItem(ict, *iarea, flags, stop_at);
+
+ // 4. Apply filter.
+ if (_filter && render_filters) {
+ bool rendered = false;
+ if (_filter->uses_background() && _background_accumulate) {
+ DrawingItem *bg_root = this;
+ for (; bg_root; bg_root = bg_root->_parent) {
+ if (bg_root->_background_new) break;
+ }
+ if (bg_root) {
+ DrawingSurface bg(*iarea);
+ DrawingContext bgct(bg);
+ bg_root->render(bgct, *iarea, flags | RENDER_FILTER_BACKGROUND, this);
+ _filter->render(this, ict, &bgct);
+ rendered = true;
+ }
+ }
+ if (!rendered) {
+ _filter->render(this, ict, NULL);
+ }
+ // Note that because the object was rendered to a group,
+ // the internals of the filter need to use cairo_get_group_target()
+ // instead of cairo_get_target().
+ }
+
+ // 5. Render object inside the composited mask + clip
+ ict.popGroupToSource();
+ ict.setOperator(CAIRO_OPERATOR_IN);
+ ict.paint();
+
+ // 6. Paint the completed rendering onto the base context (or into cache)
+ if (_cached && _cache) {
+ DrawingContext cachect(*_cache);
+ cachect.rectangle(*carea);
+ cachect.setOperator(CAIRO_OPERATOR_SOURCE);
+ cachect.setSource(&intermediate);
+ cachect.fill();
+ _cache->markClean(*carea);
+ }
+ ct.rectangle(*carea);
+ ct.setSource(&intermediate);
+ ct.fill();
+ ct.setSource(0,0,0,0);
+ // the call above is to clear a ref on the intermediate surface held by ct
+
+ return render_result;
+}
+
+void
+DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags)
+{
+ // intersect with bbox rather than drawbox, as we want to render things outside
+ // of the clipping path as well
+ Geom::OptIntRect carea = Geom::intersect(area, _bbox);
+ if (!carea) return;
+
+ // just render everything: item, clip, mask
+ // First, render the object itself
+ _renderItem(ct, *carea, flags, NULL);
+
+ // render clip and mask, if any
+ guint32 saved_rgba = _drawing.outlinecolor; // save current outline color
+ // render clippath as an object, using a different color
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (_clip) {
+ _drawing.outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips
+ _clip->render(ct, *carea, flags);
+ }
+ // render mask as an object, using a different color
+ if (_mask) {
+ _drawing.outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks
+ _mask->render(ct, *carea, flags);
+ }
+ _drawing.outlinecolor = saved_rgba; // restore outline color
+}
+
+/** @brief Rasterize the clipping path.
+ * This method submits drawing operations required to draw a basic filled shape
+ * of the item to the supplied drawing context. Rendering is limited to the
+ * given area. The rendering of the clipped object is composited into
+ * the result of this call using the IN operator. See the implementation
+ * of render() for details.
+ */
+void
+DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area)
+{
+ // don't bother if the object does not implement clipping (e.g. DrawingImage)
+ if (!_canClip()) return;
+ if (!_visible) return;
+ if (!area.intersects(_bbox)) return;
+
+ // The item used as the clipping path itself has a clipping path.
+ // Render this item's clipping path onto a temporary surface, then composite it
+ // with the item using the IN operator
+ if (_clip) {
+ ct.pushAlphaGroup();
+ { Inkscape::DrawingContext::Save save(ct);
+ ct.setSource(0,0,0,1);
+ _clip->clip(ct, area);
+ }
+ ct.pushAlphaGroup();
+ }
+
+ // rasterize the clipping path
+ _clipItem(ct, area);
+
+ if (_clip) {
+ ct.popGroupToSource();
+ ct.setOperator(CAIRO_OPERATOR_IN);
+ ct.paint();
+ ct.popGroupToSource();
+ ct.setOperator(CAIRO_OPERATOR_SOURCE);
+ ct.paint();
+ }
+}
+
+/** @brief Get the item under the specified point.
+ * Searches the tree for the first item in the Z-order which is closer than
+ * @a delta to the given point. The pick should be visual - for example
+ * an object with a thick stroke should pick on the entire area of the stroke.
+ * @param p Search point
+ * @param delta Maximum allowed distance from the point
+ * @param sticky Whether the pick should ignore visibility and sensitivity.
+ * When false, only visible and sensitive objects are considered.
+ * When true, invisible and insensitive objects can also be picked.
+ */
+DrawingItem *
+DrawingItem::pick(Geom::Point const &p, double delta, unsigned flags)
+{
+ // Sometimes there's no BBOX in state, reason unknown (bug 992817)
+ // I made this not an assert to remove the warning
+ if (!(_state & STATE_BBOX) || !(_state & STATE_PICK))
+ return NULL;
+ // ignore invisible and insensitive items unless sticky
+ if (!(flags & PICK_STICKY) && !(_visible && _sensitive))
+ return NULL;
+
+ bool outline = _drawing.outline();
+
+ if (!_drawing.outline()) {
+ // pick inside clipping path; if NULL, it means the object is clipped away there
+ if (_clip) {
+ DrawingItem *cpick = _clip->pick(p, delta, flags | PICK_AS_CLIP);
+ if (!cpick) return NULL;
+ }
+ // same for mask
+ if (_mask) {
+ DrawingItem *mpick = _mask->pick(p, delta, flags);
+ if (!mpick) return NULL;
+ }
+ }
+
+ Geom::OptIntRect box = (outline || (flags & PICK_AS_CLIP)) ? _bbox : _drawbox;
+ if (!box) return NULL;
+
+ Geom::Rect expanded = *box;
+ expanded.expandBy(delta);
+
+ if (expanded.contains(p)) {
+ return _pickItem(p, delta, flags);
+ }
+ return NULL;
+}
+
+/** Marks the current visual bounding box of the item for redrawing.
+ * This is called whenever the object changes its visible appearance.
+ * For some cases (such as setting opacity) this is enough, but for others
+ * _markForUpdate() also needs to be called.
+ */
+void
+DrawingItem::_markForRendering()
+{
+ bool outline = _drawing.outline();
+ Geom::OptIntRect dirty = outline ? _bbox : _drawbox;
+ if (!dirty) return;
+
+ // dirty the caches of all parents
+ DrawingItem *bkg_root = NULL;
+
+ for (DrawingItem *i = this; i; i = i->_parent) {
+ if (i != this && i->_filter) {
+ i->_filter->area_enlarge(*dirty, i);
+ }
+ if (i->_cache) {
+ i->_cache->markDirty(*dirty);
+ }
+ if (i->_background_accumulate) {
+ bkg_root = i;
+ }
+ }
+
+ if (bkg_root) {
+ bkg_root->_invalidateFilterBackground(*dirty);
+ }
+ _drawing.signal_request_render.emit(*dirty);
+}
+
+void
+DrawingItem::_invalidateFilterBackground(Geom::IntRect const &area)
+{
+ if (!_drawbox.intersects(area)) return;
+
+ if (_cache && _filter && _filter->uses_background()) {
+ _cache->markDirty(area);
+ }
+
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->_invalidateFilterBackground(area);
+ }
+}
+
+/** @brief Marks the item as needing a recomputation of internal data.
+ *
+ * This mechanism avoids traversing the entire rendering tree (which could be vast)
+ * on every trivial state changed in any item. Only items marked as needing
+ * an update (having some bits in their _state unset) will be traversed
+ * during the update call.
+ *
+ * The _propagate variable is another optimization. We use it to specify that
+ * all children should also have the corresponding flags unset before checking
+ * whether they need to be traversed. This way there is one less traversal
+ * of the tree. Without this we would need to unset state bits in all children.
+ * With _propagate we do this during the update call, when we have to traverse
+ * the tree anyway.
+ */
+void
+DrawingItem::_markForUpdate(unsigned flags, bool propagate)
+{
+ if (propagate) {
+ _propagate_state |= flags;
+ }
+
+ if (_state & flags) {
+ _state &= ~flags;
+ if (_parent) {
+ _parent->_markForUpdate(flags, false);
+ } else {
+ _drawing.signal_request_update.emit(this);
+ }
+ }
+}
+
+void
+DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style)
+{
+ if (style) sp_style_ref(style);
+ if (_style) sp_style_unref(_style);
+ _style = style;
+
+ // if group has a filter
+ if (style->filter.set && style->getFilter()) {
+ if (!_filter) {
+ int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter()));
+ _filter = new Inkscape::Filters::Filter(primitives);
+ }
+ sp_filter_build_renderer(SP_FILTER(style->getFilter()), _filter);
+ } else {
+ // no filter set for this group
+ delete _filter;
+ _filter = NULL;
+ }
+
+ if (style && style->enable_background.set) {
+ if (style->enable_background.value == SP_CSS_BACKGROUND_NEW && !_background_new) {
+ _background_new = true;
+ _markForUpdate(STATE_BACKGROUND, true);
+ } else if (style->enable_background.value == SP_CSS_BACKGROUND_ACCUMULATE && _background_new) {
+ _background_new = false;
+ _markForUpdate(STATE_BACKGROUND, true);
+ }
+ }
+
+ _markForUpdate(STATE_ALL, false);
+}
+
+/** @brief Compute the caching score.
+ *
+ * Higher scores mean the item is more aggresively prioritized for automatic
+ * caching by Inkscape::Drawing. */
+double
+DrawingItem::_cacheScore()
+{
+ Geom::OptIntRect cache_rect = _cacheRect();
+ if (!cache_rect) return -1.0;
+
+ // a crude first approximation:
+ // the basic score is the number of pixels in the drawbox
+ double score = cache_rect->area();
+ // this is multiplied by the filter complexity and its expansion
+ if (_filter &&_drawing.renderFilters()) {
+ score *= _filter->complexity(_ctm);
+ Geom::IntRect ref_area = Geom::IntRect::from_xywh(0, 0, 16, 16);
+ Geom::IntRect test_area = ref_area;
+ Geom::IntRect limit_area(0, INT_MIN, 16, INT_MAX);
+ _filter->area_enlarge(test_area, this);
+ // area_enlarge never shrinks the rect, so the result of intersection below
+ // must be non-empty
+ score *= double((test_area & limit_area)->area()) / ref_area.area();
+ }
+ // if the object is clipped, add 1/2 of its bbox pixels
+ if (_clip && _clip->_bbox) {
+ score += _clip->_bbox->area() * 0.5;
+ }
+ // if masked, add mask score
+ if (_mask) {
+ score += _mask->_cacheScore();
+ }
+ //g_message("caching score: %f", score);
+ return score;
+}
+
+Geom::OptIntRect
+DrawingItem::_cacheRect()
+{
+ Geom::OptIntRect r = _drawbox & _drawing.cacheLimit();
+ return r;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
new file mode 100644
index 000000000..424616427
--- /dev/null
+++ b/src/display/drawing-item.h
@@ -0,0 +1,212 @@
+/**
+ * @file
+ * @brief Canvas item belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+#include <list>
+#include <exception>
+#include <boost/operators.hpp>
+#include <boost/utility.hpp>
+#include <boost/intrusive/list.hpp>
+#include <2geom/rect.h>
+#include <2geom/affine.h>
+#include "display/display-forward.h"
+
+class SPStyle;
+
+namespace Inkscape {
+
+struct UpdateContext {
+ Geom::Affine ctm;
+};
+
+struct CacheRecord
+ : boost::totally_ordered<CacheRecord>
+{
+ bool operator<(CacheRecord const &other) const { return score < other.score; }
+ bool operator==(CacheRecord const &other) const { return score == other.score; }
+ operator DrawingItem *() const { return item; }
+ double score;
+ size_t cache_size;
+ DrawingItem *item;
+};
+typedef std::list<CacheRecord> CacheList;
+
+class InvalidItemException : public std::exception {
+ virtual const char *what() const throw() {
+ return "Invalid item in drawing";
+ }
+};
+
+class DrawingItem
+ : boost::noncopyable
+{
+public:
+ enum RenderFlags {
+ RENDER_DEFAULT = 0,
+ RENDER_CACHE_ONLY = 1,
+ RENDER_BYPASS_CACHE = 2,
+ RENDER_FILTER_BACKGROUND = 4
+ };
+ enum StateFlags {
+ STATE_NONE = 0,
+ STATE_BBOX = (1<<0), // bounding boxes are up-to-date
+ STATE_CACHE = (1<<1), // cache extents and clean area are up-to-date
+ STATE_PICK = (1<<2), // can process pick requests
+ STATE_RENDER = (1<<3), // can be rendered
+ STATE_BACKGROUND = (1<<4), // filter background data is up to date
+ STATE_ALL = (1<<5)-1
+ };
+ enum PickFlags {
+ PICK_NORMAL = 0, // normal pick
+ PICK_STICKY = (1<<0), // sticky pick - ignore visibility and sensitivity
+ PICK_AS_CLIP = (1<<2) // pick with no stroke and opaque fill regardless of item style
+ };
+
+ DrawingItem(Drawing &drawing);
+ virtual ~DrawingItem();
+
+ Geom::OptIntRect geometricBounds() const { return _bbox; }
+ Geom::OptIntRect visualBounds() const { return _drawbox; }
+ Geom::OptRect itemBounds() const { return _item_bbox; }
+ Geom::Affine ctm() const { return _ctm; }
+ Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); }
+ Drawing &drawing() const { return _drawing; }
+ DrawingItem *parent() const;
+ bool isAncestorOf(DrawingItem *item) const;
+
+ void appendChild(DrawingItem *item);
+ void prependChild(DrawingItem *item);
+ void clearChildren();
+
+ bool visible() const { return _visible; }
+ void setVisible(bool v);
+ bool sensitive() const { return _sensitive; }
+ void setSensitive(bool v);
+ bool cached() const { return _cached; }
+ void setCached(bool c, bool persistent = false);
+
+ void setOpacity(float opacity);
+ void setTransform(Geom::Affine const &trans);
+ void setClip(DrawingItem *item);
+ void setMask(DrawingItem *item);
+ void setZOrder(unsigned z);
+ void setItemBounds(Geom::OptRect const &bounds);
+
+ void setKey(unsigned key) { _key = key; }
+ unsigned key() const { return _key; }
+ void setData(void *data) { _user_data = data; }
+ void *data() const { return _user_data; }
+
+ void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = STATE_ALL, unsigned reset = 0);
+ unsigned render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0, DrawingItem *stop_at = NULL);
+ void clip(DrawingContext &ct, Geom::IntRect const &area);
+ DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags = 0);
+
+protected:
+ enum ChildType {
+ CHILD_ORPHAN = 0, // no parent - implies _parent == NULL
+ CHILD_NORMAL = 1, // contained in _children of parent
+ CHILD_CLIP = 2, // referenced by _clip member of parent
+ CHILD_MASK = 3, // referenced by _mask member of parent
+ CHILD_ROOT = 4, // root item of _drawing
+ CHILD_FILL_PATTERN = 5, // not yet implemented: referenced by fill pattern of parent
+ CHILD_STROKE_PATTERN = 6 // not yet implemented: referenced by stroke pattern of parent
+ };
+ enum RenderResult {
+ RENDER_OK = 0,
+ RENDER_STOP = 1
+ };
+ void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags);
+ void _markForUpdate(unsigned state, bool propagate);
+ void _markForRendering();
+ void _invalidateFilterBackground(Geom::IntRect const &area);
+ void _setStyleCommon(SPStyle *&_style, SPStyle *style);
+ double _cacheScore();
+ Geom::OptIntRect _cacheRect();
+ virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset) { return 0; }
+ virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags,
+ DrawingItem *stop_at) { return RENDER_OK; }
+ virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {}
+ virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags) { return NULL; }
+ virtual bool _canClip() { return false; }
+
+ // member variables start here
+
+ Drawing &_drawing;
+ DrawingItem *_parent;
+
+ typedef boost::intrusive::list_member_hook<> ListHook;
+ ListHook _child_hook;
+
+ typedef boost::intrusive::list<
+ DrawingItem,
+ boost::intrusive::member_hook<DrawingItem, ListHook, &DrawingItem::_child_hook>
+ > ChildrenList;
+ ChildrenList _children;
+
+ unsigned _key; ///< Some SPItems can have more than one DrawingItem;
+ /// this value is a hack used to distinguish between them
+ float _opacity;
+
+ Geom::Affine *_transform; ///< Incremental transform from parent to this item's coords
+ Geom::Affine _ctm; ///< Total transform from item coords to display coords
+ Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords including stroke
+ Geom::OptIntRect _drawbox; ///< Full visual bounding box - enlarged by filters, shrunk by clips and masks
+ Geom::OptRect _item_bbox; ///< Geometric bounding box in item coordinates
+
+ DrawingItem *_clip;
+ DrawingItem *_mask;
+ Inkscape::Filters::Filter *_filter;
+ void *_user_data; ///< Used to associate DrawingItems with SPItems that created them
+ DrawingCache *_cache;
+
+ CacheList::iterator _cache_iterator;
+
+ unsigned _state : 8;
+ unsigned _propagate_state : 8;
+ unsigned _child_type : 3; // see ChildType enum
+ unsigned _background_new : 1; ///< Whether enable-background: new is set for this element
+ unsigned _background_accumulate : 1; ///< Whether this element accumulates background
+ /// (has any ancestor with enable-background: new)
+ unsigned _visible : 1;
+ unsigned _sensitive : 1; ///< Whether this item responds to events
+ unsigned _cached : 1; ///< Whether the rendering is stored for reuse
+ unsigned _cached_persistent : 1; ///< If set, will always be cached regardless of score
+ unsigned _has_cache_iterator : 1; ///< If set, _cache_iterator is valid
+ unsigned _propagate : 1; ///< Whether to call update for all children on next update
+ //unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity
+ unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(),
+ /// otherwise the group is returned
+
+ friend class Drawing;
+};
+
+struct DeleteDisposer {
+ void operator()(DrawingItem *item) { delete item; }
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp
new file mode 100644
index 000000000..ac0ff2ccb
--- /dev/null
+++ b/src/display/drawing-shape.cpp
@@ -0,0 +1,343 @@
+/**
+ * @file
+ * @brief Shape (styled path) belonging to an SVG drawing
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <2geom/curves.h>
+#include <2geom/pathvector.h>
+#include <2geom/svg-path.h>
+#include <2geom/svg-path-parser.h>
+
+#include "display/cairo-utils.h"
+#include "display/canvas-arena.h"
+#include "display/canvas-bpath.h"
+#include "display/curve.h"
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/drawing-group.h"
+#include "display/drawing-shape.h"
+#include "helper/geom-curves.h"
+#include "helper/geom.h"
+#include "libnr/nr-convert2geom.h"
+#include "preferences.h"
+#include "style.h"
+#include "svg/svg.h"
+
+namespace Inkscape {
+
+DrawingShape::DrawingShape(Drawing &drawing)
+ : DrawingItem(drawing)
+ , _curve(NULL)
+ , _style(NULL)
+ , _last_pick(NULL)
+ , _repick_after(0)
+{}
+
+DrawingShape::~DrawingShape()
+{
+ if (_style)
+ sp_style_unref(_style);
+ if (_curve)
+ _curve->unref();
+}
+
+void
+DrawingShape::setPath(SPCurve *curve)
+{
+ _markForRendering();
+
+ if (_curve) {
+ _curve->unref();
+ _curve = NULL;
+ }
+ if (curve) {
+ _curve = curve;
+ curve->ref();
+ }
+
+ _markForUpdate(STATE_ALL, false);
+}
+
+void
+DrawingShape::setStyle(SPStyle *style)
+{
+ _setStyleCommon(_style, style);
+ _nrstyle.set(style);
+}
+
+unsigned
+DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ Geom::OptRect boundingbox;
+
+ unsigned beststate = STATE_ALL;
+
+ // update markers
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->update(area, ctx, flags, reset);
+ }
+
+ if (!(flags & STATE_RENDER)) {
+ /* We do not have to create rendering structures */
+ if (flags & STATE_BBOX) {
+ if (_curve) {
+ boundingbox = bounds_exact_transformed(_curve->get_pathvector(), ctx.ctm);
+ if (boundingbox) {
+ _bbox = boundingbox->roundOutwards();
+ } else {
+ _bbox = Geom::OptIntRect();
+ }
+ }
+ if (beststate & STATE_BBOX) {
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ _bbox.unionWith(i->geometricBounds());
+ }
+ }
+ }
+ return (flags | _state);
+ }
+
+ boundingbox = Geom::OptRect();
+ bool outline = _drawing.outline();
+
+ // clear Cairo data to force update
+ _nrstyle.update();
+
+ if (_curve) {
+ boundingbox = bounds_exact_transformed(_curve->get_pathvector(), ctx.ctm);
+
+ if (boundingbox && (_nrstyle.stroke.type != NRStyle::PAINT_NONE || outline)) {
+ float width, scale;
+ scale = ctx.ctm.descrim();
+ width = std::max(0.125f, _nrstyle.stroke_width * scale);
+ if ( fabs(_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true
+ boundingbox->expandBy(width);
+ }
+ // those pesky miters, now
+ float miterMax = width * _nrstyle.miter_limit;
+ if ( miterMax > 0.01 ) {
+ // grunt mode. we should compute the various miters instead
+ // (one for each point on the curve)
+ boundingbox->expandBy(miterMax);
+ }
+ }
+ }
+
+ _bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect();
+
+ if (!_curve ||
+ !_style ||
+ _curve->is_empty() ||
+ (( _nrstyle.fill.type != NRStyle::PAINT_NONE ) &&
+ ( _nrstyle.stroke.type != NRStyle::PAINT_NONE && !outline) ))
+ {
+ return STATE_ALL;
+ }
+
+ if (beststate & STATE_BBOX) {
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ _bbox.unionWith(i->geometricBounds());
+ }
+ }
+
+ return STATE_ALL;
+}
+
+unsigned
+DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
+{
+ if (!_curve || !_style) return RENDER_OK;
+ if (!area.intersects(_bbox)) return RENDER_OK; // skip if not within bounding box
+
+ bool outline = _drawing.outline();
+
+ if (outline) {
+ guint32 rgba = _drawing.outlinecolor;
+
+ { Inkscape::DrawingContext::Save save(ct);
+ ct.transform(_ctm);
+ ct.path(_curve->get_pathvector());
+ }
+ { Inkscape::DrawingContext::Save save(ct);
+ ct.setSource(rgba);
+ ct.setLineWidth(0.5);
+ ct.setTolerance(1.25);
+ ct.stroke();
+ }
+ } else {
+ bool has_stroke, has_fill;
+ // we assume the context has no path
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(_ctm);
+
+ // update fill and stroke paints.
+ // this cannot be done during nr_arena_shape_update, because we need a Cairo context
+ // to render svg:pattern
+ has_fill = _nrstyle.prepareFill(ct, _item_bbox);
+ has_stroke = _nrstyle.prepareStroke(ct, _item_bbox);
+ has_stroke &= (_nrstyle.stroke_width != 0);
+
+ if (has_fill || has_stroke) {
+ // TODO: remove segments outside of bbox when no dashes present
+ ct.path(_curve->get_pathvector());
+ if (has_fill) {
+ _nrstyle.applyFill(ct);
+ ct.fillPreserve();
+ }
+ if (has_stroke) {
+ _nrstyle.applyStroke(ct);
+ ct.strokePreserve();
+ }
+ ct.newPath(); // clear path
+ } // has fill or stroke pattern
+ }
+
+ // marker rendering
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->render(ct, area, flags, stop_at);
+ }
+ return RENDER_OK;
+}
+
+void
+DrawingShape::_clipItem(DrawingContext &ct, Geom::IntRect const &area)
+{
+ if (!_curve) return;
+
+ Inkscape::DrawingContext::Save save(ct);
+ // handle clip-rule
+ if (_style) {
+ if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
+ ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD);
+ } else {
+ ct.setFillRule(CAIRO_FILL_RULE_WINDING);
+ }
+ }
+ ct.transform(_ctm);
+ ct.path(_curve->get_pathvector());
+ ct.fill();
+}
+
+DrawingItem *
+DrawingShape::_pickItem(Geom::Point const &p, double delta, unsigned flags)
+{
+ if (_repick_after > 0)
+ --_repick_after;
+
+ if (_repick_after > 0) // we are a slow, huge path
+ return _last_pick; // skip this pick, returning what was returned last time
+
+ if (!_curve) return NULL;
+ if (!_style) return NULL;
+
+ bool outline = _drawing.outline();
+ bool pick_as_clip = flags & PICK_AS_CLIP;
+
+ if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline && !pick_as_clip)
+ // fully transparent, no pick unless outline mode
+ return NULL;
+
+ GTimeVal tstart, tfinish;
+ g_get_current_time (&tstart);
+
+ double width;
+ if (pick_as_clip) {
+ width = 0; // no width should be applied to clip picking
+ // this overrides display mode and stroke style considerations
+ } else if (outline) {
+ width = 0.5; // in outline mode, everything is stroked with the same 0.5px line width
+ } else if (_nrstyle.stroke.type != NRStyle::PAINT_NONE && _nrstyle.stroke.opacity > 1e-3) {
+ // for normal picking calculate the distance corresponding top the stroke width
+ // FIXME BUG: this is incorrect for transformed strokes
+ float const scale = _ctm.descrim();
+ width = std::max(0.125f, _nrstyle.stroke_width * scale) / 2;
+ } else {
+ width = 0;
+ }
+
+ double dist = Geom::infinity();
+ int wind = 0;
+ bool needfill = pick_as_clip || (_nrstyle.fill.type != NRStyle::PAINT_NONE &&
+ _nrstyle.fill.opacity > 1e-3 && !outline);
+ bool wind_evenodd = pick_as_clip ? (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) :
+ (_style->fill_rule.computed == SP_WIND_RULE_EVENODD);
+
+ // actual shape picking
+ if (_drawing.arena()) {
+ Geom::Rect viewbox = _drawing.arena()->item.canvas->getViewbox();
+ viewbox.expandBy (width);
+ pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox);
+ } else {
+ pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL);
+ }
+
+ g_get_current_time (&tfinish);
+ glong this_pick = (tfinish.tv_sec - tstart.tv_sec) * 1000000 + (tfinish.tv_usec - tstart.tv_usec);
+ //g_print ("pick time %lu\n", this_pick);
+
+ if (this_pick > 10000) { // slow picking, remember to skip several new picks
+ _repick_after = this_pick / 5000;
+ }
+
+ // covered by fill?
+ if (needfill) {
+ if (wind_evenodd) {
+ if (wind & 0x1) {
+ _last_pick = this;
+ return this;
+ }
+ } else {
+ if (wind != 0) {
+ _last_pick = this;
+ return this;
+ }
+ }
+ }
+
+ // close to the edge, as defined by strokewidth and delta?
+ // this ignores dashing (as if the stroke is solid) and always works as if caps are round
+ if (needfill || width > 0) { // if either fill or stroke visible,
+ if ((dist - width) < delta) {
+ _last_pick = this;
+ return this;
+ }
+ }
+
+ // if not picked on the shape itself, try its markers
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ DrawingItem *ret = i->pick(p, delta, flags & ~PICK_STICKY);
+ if (ret) {
+ _last_pick = this;
+ return this;
+ }
+ }
+
+ _last_pick = NULL;
+ return NULL;
+}
+
+bool
+DrawingShape::_canClip()
+{
+ return true;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h
new file mode 100644
index 000000000..27bd7fbba
--- /dev/null
+++ b/src/display/drawing-shape.h
@@ -0,0 +1,63 @@
+/**
+ * @file
+ * @brief Group belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SHAPE_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_SHAPE_H
+
+#include "display/drawing-item.h"
+#include "display/nr-style.h"
+
+class SPStyle;
+class SPCurve;
+
+namespace Inkscape {
+
+class DrawingShape
+ : public DrawingItem
+{
+public:
+ DrawingShape(Drawing &drawing);
+ ~DrawingShape();
+
+ void setPath(SPCurve *curve);
+ void setStyle(SPStyle *style);
+
+protected:
+ virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset);
+ virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags,
+ DrawingItem *stop_at);
+ virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area);
+ virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags);
+ virtual bool _canClip();
+
+ SPCurve *_curve;
+ SPStyle *_style;
+ NRStyle _nrstyle;
+
+ DrawingItem *_last_pick;
+ unsigned _repick_after;
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp
new file mode 100644
index 000000000..5cbfaa3fe
--- /dev/null
+++ b/src/display/drawing-surface.cpp
@@ -0,0 +1,354 @@
+/**
+ * @file
+ * @brief Cairo surface that remembers its origin
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+//#include <iostream>
+#include "display/drawing-surface.h"
+#include "display/drawing-context.h"
+#include "display/cairo-utils.h"
+
+namespace Inkscape {
+
+using Geom::X;
+using Geom::Y;
+
+
+/** @class DrawingSurface
+ * @brief Drawing surface that remembers its origin.
+ *
+ * This is a very minimalistic wrapper over cairo_surface_t. The main
+ * extra functionality provided by this class is that it automates
+ * the mapping from "logical space" (coordinates in the rendering)
+ * and the "physical space" (surface pixels). For example, patterns
+ * have to be rendered on tiles which have possibly non-integer
+ * widths and heights.
+ *
+ * This class has delayed allocation functionality - it creates
+ * the Cairo surface it wraps on the first call to createRawContext()
+ * of when a DrawingContext is constructed.
+ */
+
+/** @brief Creates a surface with the given physical extents.
+ * When a drawing context is created for this surface, its pixels
+ * will cover the area under the given rectangle. */
+DrawingSurface::DrawingSurface(Geom::IntRect const &area)
+ : _surface(NULL)
+ , _origin(area.min())
+ , _scale(1, 1)
+ , _pixels(area.dimensions())
+{}
+
+/** @brief Creates a surface with the given logical and physical extents.
+ * When a drawing context is created for this surface, its pixels
+ * will cover the area under the given rectangle. IT will contain
+ * the number of pixels specified by the second argument.
+ * @param logbox Logical extents of the surface
+ * @param pixdims Pixel dimensions of the surface. */
+DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims)
+ : _surface(NULL)
+ , _origin(logbox.min())
+ , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height())
+ , _pixels(pixdims)
+{}
+
+/** @brief Wrap a cairo_surface_t.
+ * This constructor will take an extra reference on @a surface, which will
+ * be released on destruction. */
+DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin)
+ : _surface(surface)
+ , _origin(origin)
+ , _scale(1, 1)
+{
+ cairo_surface_reference(surface);
+ _pixels[X] = cairo_image_surface_get_width(surface);
+ _pixels[Y] = cairo_image_surface_get_height(surface);
+}
+
+DrawingSurface::~DrawingSurface()
+{
+ if (_surface)
+ cairo_surface_destroy(_surface);
+}
+
+/// Get the logical extents of the surface.
+Geom::Rect
+DrawingSurface::area() const
+{
+ Geom::Rect r = Geom::Rect::from_xywh(_origin, dimensions());
+ return r;
+}
+
+/// Get the pixel dimensions of the surface
+Geom::IntPoint
+DrawingSurface::pixels() const
+{
+ return _pixels;
+}
+
+/// Get the logical width and weight of the surface as a point.
+Geom::Point
+DrawingSurface::dimensions() const
+{
+ Geom::Point logical_dims(_pixels[X] / _scale[X], _pixels[Y] / _scale[Y]);
+ return logical_dims;
+}
+
+Geom::Point
+DrawingSurface::origin() const
+{
+ return _origin;
+}
+
+Geom::Scale
+DrawingSurface::scale() const
+{
+ return _scale;
+}
+
+/// Get the transformation applied to the drawing context on construction.
+Geom::Affine
+DrawingSurface::drawingTransform() const
+{
+ Geom::Affine ret = _scale * Geom::Translate(-_origin);
+ return ret;
+}
+
+cairo_surface_type_t
+DrawingSurface::type() const
+{
+ // currently hardcoded
+ return CAIRO_SURFACE_TYPE_IMAGE;
+}
+
+/// Drop contents of the surface and release the underlying Cairo object.
+void
+DrawingSurface::dropContents()
+{
+ if (_surface) {
+ cairo_surface_destroy(_surface);
+ _surface = NULL;
+ }
+}
+
+/** @brief Create a drawing context for this surface.
+ * It's better to use the surface constructor of DrawingContext. */
+cairo_t *
+DrawingSurface::createRawContext()
+{
+ // deferred allocation
+ if (!_surface) {
+ _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _pixels[X], _pixels[Y]);
+ }
+ cairo_t *ct = cairo_create(_surface);
+ if (_scale != Geom::Scale::identity()) {
+ cairo_scale(ct, _scale[X], _scale[Y]);
+ }
+ cairo_translate(ct, -_origin[X], -_origin[Y]);
+ return ct;
+}
+
+Geom::IntRect
+DrawingSurface::pixelArea() const
+{
+ Geom::IntRect ret = Geom::IntRect::from_xywh(_origin.round(), _pixels);
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DrawingCache::DrawingCache(Geom::IntRect const &area)
+ : DrawingSurface(area)
+ , _clean_region(cairo_region_create())
+ , _pending_area(area)
+{}
+
+DrawingCache::~DrawingCache()
+{
+ cairo_region_destroy(_clean_region);
+}
+
+void
+DrawingCache::markDirty(Geom::IntRect const &area)
+{
+ cairo_rectangle_int_t dirty = _convertRect(area);
+ cairo_region_subtract_rectangle(_clean_region, &dirty);
+}
+void
+DrawingCache::markClean(Geom::IntRect const &area)
+{
+ Geom::OptIntRect r = Geom::intersect(area, pixelArea());
+ if (!r) return;
+ cairo_rectangle_int_t clean = _convertRect(*r);
+ cairo_region_union_rectangle(_clean_region, &clean);
+}
+
+/// Call this during the update phase to schedule a transformation of the cache.
+void
+DrawingCache::scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans)
+{
+ _pending_area = new_area;
+ _pending_transform *= trans;
+}
+
+/// Transforms the cache according to the transform specified during the update phase.
+/// Call this during render phase, before painting.
+void
+DrawingCache::prepare()
+{
+ Geom::IntRect old_area = pixelArea();
+ bool is_identity = _pending_transform.isIdentity();
+ if (is_identity && _pending_area == old_area) return; // no change
+
+ bool is_integer_translation = false;
+ if (!is_identity && _pending_transform.isTranslation()) {
+ Geom::IntPoint t = _pending_transform.translation().round();
+ if (Geom::are_near(Geom::Point(t), _pending_transform.translation())) {
+ is_integer_translation = true;
+ cairo_region_translate(_clean_region, t[X], t[Y]);
+ if (old_area + t == _pending_area) {
+ // if the areas match, the only thing to do
+ // is to ensure that the clean area is not too large
+ cairo_rectangle_int_t limit = _convertRect(_pending_area);
+ cairo_region_intersect_rectangle(_clean_region, &limit);
+ _origin += t;
+ _pending_transform.setIdentity();
+ return;
+ }
+ }
+ }
+ // otherwise, we need to transform the cache
+ Geom::IntPoint old_origin = old_area.min();
+ cairo_surface_t *old_surface = _surface;
+ _surface = NULL;
+ _pixels = _pending_area.dimensions();
+ _origin = _pending_area.min();
+
+ cairo_t *ct = createRawContext();
+ if (!is_identity) {
+ ink_cairo_transform(ct, _pending_transform);
+ }
+ cairo_set_source_surface(ct, old_surface, old_origin[X], old_origin[Y]);
+ cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ct);
+
+ cairo_surface_destroy(old_surface);
+ cairo_destroy(ct);
+
+ if (!is_identity && !is_integer_translation) {
+ // dirty everything
+ cairo_region_destroy(_clean_region);
+ _clean_region = cairo_region_create();
+ } else {
+ cairo_rectangle_int_t limit = _convertRect(_pending_area);
+ cairo_region_intersect_rectangle(_clean_region, &limit);
+ }
+ //std::cout << _pending_transform << old_area << _pending_area << std::endl;
+ _pending_transform.setIdentity();
+}
+
+/** @brief Paints the clean area from cache and modifies the @a area
+ * parameter to the bounds of the region that must be repainted. */
+void
+DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area)
+{
+ if (!area) return;
+
+ // We subtract the clean region from the area, then get the bounds
+ // of the resulting region. This is the area that needs to be repainted
+ // by the item.
+ // Then we subtract the area that needs to be repainted from the
+ // original area and paint the resulting region from cache.
+ cairo_rectangle_int_t area_c = _convertRect(*area);
+ cairo_region_t *dirty_region = cairo_region_create_rectangle(&area_c);
+ cairo_region_t *cache_region = cairo_region_copy(dirty_region);
+ cairo_region_subtract(dirty_region, _clean_region);
+
+ if (cairo_region_is_empty(dirty_region)) {
+ area = Geom::OptIntRect();
+ } else {
+ cairo_rectangle_int_t to_repaint;
+ cairo_region_get_extents(dirty_region, &to_repaint);
+ area = _convertRect(to_repaint);
+ cairo_region_subtract_rectangle(cache_region, &to_repaint);
+ }
+ cairo_region_destroy(dirty_region);
+
+ if (!cairo_region_is_empty(cache_region)) {
+ int nr = cairo_region_num_rectangles(cache_region);
+ cairo_rectangle_int_t tmp;
+ for (int i = 0; i < nr; ++i) {
+ cairo_region_get_rectangle(cache_region, i, &tmp);
+ ct.rectangle(_convertRect(tmp));
+ }
+ ct.setSource(this);
+ ct.fill();
+ }
+ cairo_region_destroy(cache_region);
+}
+
+// debugging utility
+void
+DrawingCache::_dumpCache(Geom::OptIntRect const &area)
+{
+ static int dumpnr = 0;
+ cairo_surface_t *surface = ink_cairo_surface_copy(_surface);
+ DrawingContext ct(surface, _origin);
+ if (!cairo_region_is_empty(_clean_region)) {
+ Inkscape::DrawingContext::Save save(ct);
+ int nr = cairo_region_num_rectangles(_clean_region);
+ cairo_rectangle_int_t tmp;
+ for (int i = 0; i < nr; ++i) {
+ cairo_region_get_rectangle(_clean_region, i, &tmp);
+ ct.rectangle(_convertRect(tmp));
+ }
+ ct.setSource(0,1,0,0.1);
+ ct.fill();
+ }
+ ct.rectangle(*area);
+ ct.setSource(1,0,0,0.1);
+ ct.fill();
+ char *fn = g_strdup_printf("dump%d.png", dumpnr++);
+ cairo_surface_write_to_png(surface, fn);
+ cairo_surface_destroy(surface);
+ g_free(fn);
+}
+
+cairo_rectangle_int_t
+DrawingCache::_convertRect(Geom::IntRect const &area)
+{
+ cairo_rectangle_int_t ret;
+ ret.x = area.left();
+ ret.y = area.top();
+ ret.width = area.width();
+ ret.height = area.height();
+ return ret;
+}
+
+Geom::IntRect
+DrawingCache::_convertRect(cairo_rectangle_int_t const &r)
+{
+ Geom::IntRect ret = Geom::IntRect::from_xywh(
+ r.x, r.y,
+ r.width, r.height);
+ return ret;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h
new file mode 100644
index 000000000..e3637d402
--- /dev/null
+++ b/src/display/drawing-surface.h
@@ -0,0 +1,93 @@
+/**
+ * @file
+ * @brief Cairo surface that remembers its origin
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H
+
+#include <boost/shared_ptr.hpp>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <2geom/affine.h>
+#include <2geom/rect.h>
+#include <2geom/transforms.h>
+
+namespace Inkscape {
+class DrawingContext;
+
+class DrawingSurface
+{
+public:
+ explicit DrawingSurface(Geom::IntRect const &area);
+ DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims);
+ DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin);
+ virtual ~DrawingSurface();
+
+ Geom::Rect area() const;
+ Geom::IntPoint pixels() const;
+ Geom::Point dimensions() const;
+ Geom::Point origin() const;
+ Geom::Scale scale() const;
+ Geom::Affine drawingTransform() const;
+ cairo_surface_type_t type() const;
+ void dropContents();
+
+ cairo_surface_t *raw() { return _surface; }
+ cairo_t *createRawContext();
+
+protected:
+ Geom::IntRect pixelArea() const;
+
+ cairo_surface_t *_surface;
+ Geom::Point _origin;
+ Geom::Scale _scale;
+ Geom::IntPoint _pixels;
+ bool _has_context;
+
+ friend class DrawingContext;
+};
+
+class DrawingCache
+ : public DrawingSurface
+{
+public:
+ explicit DrawingCache(Geom::IntRect const &area);
+ ~DrawingCache();
+
+ void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite());
+ void markClean(Geom::IntRect const &area = Geom::IntRect::infinite());
+ void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans);
+ void prepare();
+ void paintFromCache(DrawingContext &ct, Geom::OptIntRect &area);
+
+protected:
+ cairo_region_t *_clean_region;
+ Geom::IntRect _pending_area;
+ Geom::Affine _pending_transform;
+private:
+ void _dumpCache(Geom::OptIntRect const &area);
+ static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r);
+ static Geom::IntRect _convertRect(cairo_rectangle_int_t const &r);
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp
new file mode 100644
index 000000000..1134771bc
--- /dev/null
+++ b/src/display/drawing-text.cpp
@@ -0,0 +1,255 @@
+/**
+ * @file
+ * @brief Group belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/cairo-utils.h"
+#include "display/canvas-bpath.h" // for SPWindRule (WTF!)
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/drawing-surface.h"
+#include "display/drawing-text.h"
+#include "helper/geom.h"
+#include "libnrtype/font-instance.h"
+#include "style.h"
+
+namespace Inkscape {
+
+DrawingGlyphs::DrawingGlyphs(Drawing &drawing)
+ : DrawingItem(drawing)
+ , _font(NULL)
+ , _glyph(0)
+{}
+
+DrawingGlyphs::~DrawingGlyphs()
+{
+ if (_font) {
+ _font->Unref();
+ _font = NULL;
+ }
+}
+
+void
+DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &trans)
+{
+ _markForRendering();
+
+ setTransform(trans);
+
+ if (font) font->Ref();
+ if (_font) _font->Unref();
+ _font = font;
+ _glyph = glyph;
+
+ _markForUpdate(STATE_ALL, false);
+}
+
+unsigned
+DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ DrawingText *ggroup = dynamic_cast<DrawingText *>(_parent);
+ if (!ggroup) throw InvalidItemException();
+
+ if (!_font || !ggroup->_style) return STATE_ALL;
+ if (ggroup->_nrstyle.fill.type == NRStyle::PAINT_NONE &&
+ ggroup->_nrstyle.stroke.type == NRStyle::PAINT_NONE)
+ {
+ return STATE_ALL;
+ }
+
+ Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm);
+ if (b && ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) {
+ float width, scale;
+ scale = ctx.ctm.descrim();
+ width = MAX(0.125, ggroup->_nrstyle.stroke_width * scale);
+ if ( fabs(ggroup->_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true
+ b->expandBy(width);
+ }
+ // those pesky miters, now
+ float miterMax = width * ggroup->_nrstyle.miter_limit;
+ if ( miterMax > 0.01 ) {
+ // grunt mode. we should compute the various miters instead
+ // (one for each point on the curve)
+ b->expandBy(miterMax);
+ }
+ }
+
+ if (b) {
+ _bbox = b->roundOutwards();
+ } else {
+ _bbox = Geom::OptIntRect();
+ }
+
+ return STATE_ALL;
+}
+
+DrawingItem *
+DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, unsigned /*flags*/)
+{
+ if (!_font || !_bbox) return NULL;
+
+ // With text we take a simple approach: pick if the point is in a characher bbox
+ Geom::Rect expanded(*_bbox);
+ expanded.expandBy(delta);
+ if (expanded.contains(p)) return this;
+ return NULL;
+}
+
+
+
+DrawingText::DrawingText(Drawing &drawing)
+ : DrawingGroup(drawing)
+{}
+
+DrawingText::~DrawingText()
+{}
+
+void
+DrawingText::clear()
+{
+ _markForRendering();
+ _children.clear_and_dispose(DeleteDisposer());
+}
+
+void
+DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &trans)
+{
+ if (!font || !font->PathVector(glyph)) return;
+
+ _markForRendering();
+ DrawingGlyphs *ng = new DrawingGlyphs(_drawing);
+ ng->setGlyph(font, glyph, trans);
+ appendChild(ng);
+}
+
+void
+DrawingText::setStyle(SPStyle *style)
+{
+ _nrstyle.set(style);
+ DrawingGroup::setStyle(style);
+}
+
+void
+DrawingText::setPaintBox(Geom::OptRect const &box)
+{
+ _paintbox = box;
+ _markForUpdate(STATE_ALL, false);
+}
+
+unsigned
+DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ _nrstyle.update();
+ return DrawingGroup::_updateItem(area, ctx, flags, reset);
+}
+
+unsigned
+DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
+{
+ if (_drawing.outline()) {
+ guint32 rgba = _drawing.outlinecolor;
+ Inkscape::DrawingContext::Save save(ct);
+ ct.setSource(rgba);
+ ct.setTolerance(1.25); // low quality, but good enough for outline mode
+
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i);
+ if (!g) throw InvalidItemException();
+
+ Inkscape::DrawingContext::Save save(ct);
+ // skip glpyhs with singular transforms
+ if (g->_ctm.isSingular()) continue;
+ ct.transform(g->_ctm);
+ ct.path(*g->_font->PathVector(g->_glyph));
+ ct.fill();
+ }
+ return RENDER_OK;
+ }
+
+ // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding
+ bool has_stroke, has_fill;
+
+ has_fill = _nrstyle.prepareFill(ct, _paintbox);
+ has_stroke = _nrstyle.prepareStroke(ct, _paintbox);
+
+ if (has_fill || has_stroke) {
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i);
+ if (!g) throw InvalidItemException();
+
+ Inkscape::DrawingContext::Save save(ct);
+ if (g->_ctm.isSingular()) continue;
+ ct.transform(g->_ctm);
+ ct.path(*g->_font->PathVector(g->_glyph));
+ }
+
+ if (has_fill) {
+ _nrstyle.applyFill(ct);
+ ct.fillPreserve();
+ }
+ if (has_stroke) {
+ _nrstyle.applyStroke(ct);
+ ct.strokePreserve();
+ }
+ ct.newPath(); // clear path
+ }
+ return RENDER_OK;
+}
+
+void
+DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area)
+{
+ Inkscape::DrawingContext::Save save(ct);
+
+ // handle clip-rule
+ if (_style) {
+ if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
+ ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD);
+ } else {
+ ct.setFillRule(CAIRO_FILL_RULE_WINDING);
+ }
+ }
+
+ for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i);
+ if (!g) throw InvalidItemException();
+
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(g->_ctm);
+ ct.path(*g->_font->PathVector(g->_glyph));
+ }
+ ct.fill();
+}
+
+DrawingItem *
+DrawingText::_pickItem(Geom::Point const &p, double delta, unsigned flags)
+{
+ DrawingItem *picked = DrawingGroup::_pickItem(p, delta, flags);
+ if (picked) return this;
+ return NULL;
+}
+
+bool
+DrawingText::_canClip()
+{
+ return true;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h
new file mode 100644
index 000000000..4f3940dde
--- /dev/null
+++ b/src/display/drawing-text.h
@@ -0,0 +1,83 @@
+/**
+ * @file
+ * @brief Group belonging to an SVG drawing element
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_TEXT_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_TEXT_H
+
+#include "display/drawing-group.h"
+#include "display/nr-style.h"
+
+class SPStyle;
+class font_instance;
+
+namespace Inkscape {
+
+class DrawingGlyphs
+ : public DrawingItem
+{
+public:
+ DrawingGlyphs(Drawing &drawing);
+ ~DrawingGlyphs();
+
+ void setGlyph(font_instance *font, int glyph, Geom::Affine const &trans);
+
+protected:
+ unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset);
+ virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags);
+
+ font_instance *_font;
+ int _glyph;
+
+ friend class DrawingText;
+};
+
+class DrawingText
+ : public DrawingGroup
+{
+public:
+ DrawingText(Drawing &drawing);
+ ~DrawingText();
+
+ void clear();
+ void addComponent(font_instance *font, int glyph, Geom::Affine const &trans);
+ void setStyle(SPStyle *style);
+ void setPaintBox(Geom::OptRect const &box);
+
+protected:
+ virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset);
+ virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags,
+ DrawingItem *stop_at);
+ virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area);
+ virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags);
+ virtual bool _canClip();
+
+ Geom::OptRect _paintbox;
+ NRStyle _nrstyle;
+
+ friend class DrawingGlyphs;
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
new file mode 100644
index 000000000..06183fed2
--- /dev/null
+++ b/src/display/drawing.cpp
@@ -0,0 +1,205 @@
+/**
+ * @file
+ * @brief SVG drawing for display
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <algorithm>
+#include "display/drawing.h"
+#include "nr-filter-gaussian.h"
+#include "nr-filter-types.h"
+
+namespace Inkscape {
+
+Drawing::Drawing(SPCanvasArena *arena)
+ : _root(NULL)
+ , outlinecolor(0x000000ff)
+ , delta(0)
+ , _exact(false)
+ , _rendermode(RENDERMODE_NORMAL)
+ , _colormode(COLORMODE_NORMAL)
+ , _blur_quality(BLUR_QUALITY_BEST)
+ , _filter_quality(Filters::FILTER_QUALITY_BEST)
+ , _cache_score_threshold(50000.0)
+ , _cache_budget(0)
+ , _canvasarena(arena)
+{
+
+}
+
+Drawing::~Drawing()
+{
+ delete _root;
+}
+
+void
+Drawing::setRoot(DrawingItem *item)
+{
+ delete _root;
+ _root = item;
+ if (item) {
+ assert(item->_child_type == DrawingItem::CHILD_ORPHAN);
+ item->_child_type = DrawingItem::CHILD_ROOT;
+ }
+}
+
+RenderMode
+Drawing::renderMode() const
+{
+ return _exact ? RENDERMODE_NORMAL : _rendermode;
+}
+ColorMode
+Drawing::colorMode() const
+{
+ return (outline() || _exact) ? COLORMODE_NORMAL : _colormode;
+}
+bool
+Drawing::outline() const
+{
+ return renderMode() == RENDERMODE_OUTLINE;
+}
+bool
+Drawing::renderFilters() const
+{
+ return renderMode() == RENDERMODE_NORMAL;
+}
+int
+Drawing::blurQuality() const
+{
+ if (renderMode() == RENDERMODE_NORMAL) {
+ return _exact ? BLUR_QUALITY_BEST : _blur_quality;
+ } else {
+ return BLUR_QUALITY_WORST;
+ }
+}
+int
+Drawing::filterQuality() const
+{
+ if (renderMode() == RENDERMODE_NORMAL) {
+ return _exact ? Filters::FILTER_QUALITY_BEST : _filter_quality;
+ } else {
+ return Filters::FILTER_QUALITY_WORST;
+ }
+}
+
+void
+Drawing::setRenderMode(RenderMode mode)
+{
+ _rendermode = mode;
+}
+void
+Drawing::setColorMode(ColorMode mode)
+{
+ _colormode = mode;
+}
+void
+Drawing::setBlurQuality(int q)
+{
+ _blur_quality = q;
+}
+void
+Drawing::setFilterQuality(int q)
+{
+ _filter_quality = q;
+}
+void
+Drawing::setExact(bool e)
+{
+ _exact = e;
+}
+
+Geom::OptIntRect const &
+Drawing::cacheLimit() const
+{
+ return _cache_limit;
+}
+void
+Drawing::setCacheLimit(Geom::OptIntRect const &r)
+{
+ _cache_limit = r;
+ for (std::set<DrawingItem *>::iterator i = _cached_items.begin();
+ i != _cached_items.end(); ++i)
+ {
+ (*i)->_markForUpdate(DrawingItem::STATE_CACHE, false);
+ }
+}
+void
+Drawing::setCacheBudget(size_t bytes)
+{
+ _cache_budget = bytes;
+ _pickItemsForCaching();
+}
+
+void
+Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ if (_root) {
+ _root->update(area, ctx, flags, reset);
+ }
+ // process the updated cache scores
+ _pickItemsForCaching();
+}
+
+void
+Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags)
+{
+ if (_root) {
+ _root->render(ct, area, flags);
+ }
+}
+
+DrawingItem *
+Drawing::pick(Geom::Point const &p, double delta, unsigned flags)
+{
+ if (_root) {
+ return _root->pick(p, delta, flags);
+ }
+ return NULL;
+}
+
+void
+Drawing::_pickItemsForCaching()
+{
+ // we cache the objects with the highest score until the budget is exhausted
+ _candidate_items.sort(std::greater<CacheRecord>());
+ size_t used = 0;
+ CandidateList::iterator i;
+ for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) {
+ if (used + i->cache_size > _cache_budget) break;
+ used += i->cache_size;
+ }
+
+ std::set<DrawingItem*> to_cache;
+ for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) {
+ i->item->setCached(true);
+ to_cache.insert(i->item);
+ }
+ // Everything which is now in _cached_items but not in to_cache must be uncached
+ // Note that calling setCached on an item modifies _cached_items
+ // TODO: find a way to avoid the set copy
+ std::set<DrawingItem*> to_uncache;
+ std::set_difference(_cached_items.begin(), _cached_items.end(),
+ to_cache.begin(), to_cache.end(),
+ std::inserter(to_uncache, to_uncache.end()));
+ for (std::set<DrawingItem*>::iterator j = to_uncache.begin(); j != to_uncache.end(); ++j) {
+ (*j)->setCached(false);
+ }
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing.h b/src/display/drawing.h
new file mode 100644
index 000000000..cfba4ebe6
--- /dev/null
+++ b/src/display/drawing.h
@@ -0,0 +1,113 @@
+/**
+ * @file
+ * @brief SVG drawing for display
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_H
+
+#include <set>
+#include <boost/operators.hpp>
+#include <boost/utility.hpp>
+#include <sigc++/sigc++.h>
+#include <2geom/rect.h>
+#include "display/display-forward.h"
+#include "display/drawing-item.h"
+#include "display/rendermode.h"
+
+namespace Inkscape {
+
+class Drawing
+ : boost::noncopyable
+{
+public:
+ struct OutlineColors {
+ guint32 paths;
+ guint32 clippaths;
+ guint32 masks;
+ guint32 images;
+ };
+
+ Drawing(SPCanvasArena *arena = NULL);
+ ~Drawing();
+
+ DrawingItem *root() { return _root; }
+ SPCanvasArena *arena() { return _canvasarena; }
+ void setRoot(DrawingItem *item);
+
+ RenderMode renderMode() const;
+ ColorMode colorMode() const;
+ bool outline() const;
+ bool renderFilters() const;
+ int blurQuality() const;
+ int filterQuality() const;
+ void setRenderMode(RenderMode mode);
+ void setColorMode(ColorMode mode);
+ void setBlurQuality(int q);
+ void setFilterQuality(int q);
+ void setExact(bool e);
+
+ Geom::OptIntRect const &cacheLimit() const;
+ void setCacheLimit(Geom::OptIntRect const &r);
+ void setCacheBudget(size_t bytes);
+
+ OutlineColors const &colors() const { return _colors; }
+
+ void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0);
+ void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0);
+ DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags);
+
+ sigc::signal<void, DrawingItem *> signal_request_update;
+ sigc::signal<void, Geom::IntRect const &> signal_request_render;
+ sigc::signal<void, DrawingItem *> signal_item_deleted;
+
+private:
+ void _pickItemsForCaching();
+
+ typedef std::list<CacheRecord> CandidateList;
+
+ DrawingItem *_root;
+ std::set<DrawingItem *> _cached_items; // modified by DrawingItem::setCached()
+ CacheList _candidate_items;
+public:
+ // TODO: remove these temporarily public members
+ guint32 outlinecolor;
+ double delta;
+private:
+ bool _exact; // if true then rendering must be exact
+ RenderMode _rendermode;
+ ColorMode _colormode;
+ int _blur_quality;
+ int _filter_quality;
+ Geom::OptIntRect _cache_limit;
+
+ double _cache_score_threshold; ///< do not consider objects for caching below this score
+ size_t _cache_budget; ///< maximum allowed size of cache
+
+ OutlineColors _colors;
+ SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen
+ // but used for export etc.
+
+ friend class DrawingItem;
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DRAWING_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/grayscale.cpp b/src/display/grayscale.cpp
index 745a08c1e..e468044d3 100644
--- a/src/display/grayscale.cpp
+++ b/src/display/grayscale.cpp
@@ -82,7 +82,7 @@ guchar luminance(guchar r, guchar g, guchar b) {
*/
bool activeDesktopIsGrayscale() {
if (SP_ACTIVE_DESKTOP) {
- return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORRENDERMODE_GRAYSCALE);
+ return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORMODE_GRAYSCALE);
} else {
return false;
}
diff --git a/src/display/nr-arena-forward.h b/src/display/nr-arena-forward.h
deleted file mode 100644
index 5a5cf228a..000000000
--- a/src/display/nr-arena-forward.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef __NR_ARENA_FORWARD_H__
-#define __NR_ARENA_FORWARD_H__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-struct NRArena;
-struct NRArenaClass;
-
-struct NRArenaItem;
-struct NRArenaItemClass;
-
-struct NRArenaGroup;
-struct NRArenaGroupClass;
-
-struct NRArenaShape;
-struct NRArenaShapeClass;
-
-struct NRArenaShapeGroup;
-struct NRArenaShapeGroupClass;
-
-struct NRArenaImage;
-struct NRArenaImageClass;
-
-struct NRArenaGlyphs;
-struct NRArenaGlyphsClass;
-
-struct NRArenaGlyphsGroup;
-struct NRArenaGlyphsGroupClass;
-
-#endif
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp
deleted file mode 100644
index d09f66a2f..000000000
--- a/src/display/nr-arena-glyphs.cpp
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2002 Lauris Kaplinski
- *
- * Released under GNU GPL
- *
- */
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include "libnr/nr-convert2geom.h"
-#include <2geom/affine.h>
-#include "style.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-glyphs.h"
-#include <cairo.h>
-#include "display/cairo-utils.h"
-#include "helper/geom.h"
-
-#ifdef test_glyph_liv
-#include "../display/canvas-bpath.h"
-#include "libnrtype/font-instance.h"
-
-// defined in nr-arena-shape.cpp
-void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS);
-#endif
-
-#ifdef ENABLE_SVG_FONTS
-#include "nr-svgfonts.h"
-#endif //#ifdef ENABLE_SVG_FONTS
-
-static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
-static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
-static void nr_arena_glyphs_finalize(NRObject *object);
-
-static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
-static guint nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
-
-static NRArenaItemClass *glyphs_parent_class;
-
-NRType
-nr_arena_glyphs_get_type(void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
- "NRArenaGlyphs",
- sizeof(NRArenaGlyphsClass),
- sizeof(NRArenaGlyphs),
- (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init,
- (void (*)(NRObject *)) nr_arena_glyphs_init);
- }
- return type;
-}
-
-static void
-nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
-{
- NRObjectClass *object_class;
- NRArenaItemClass *item_class;
-
- object_class = (NRObjectClass *) klass;
- item_class = (NRArenaItemClass *) klass;
-
- glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
-
- object_class->finalize = nr_arena_glyphs_finalize;
- object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
-
- item_class->update = nr_arena_glyphs_update;
- item_class->clip = nr_arena_glyphs_clip;
- item_class->pick = nr_arena_glyphs_pick;
-}
-
-static void
-nr_arena_glyphs_init(NRArenaGlyphs *glyphs)
-{
- glyphs->g_transform.setIdentity();
- glyphs->font = NULL;
- glyphs->glyph = 0;
- glyphs->x = glyphs->y = 0.0;
-}
-
-static void
-nr_arena_glyphs_finalize(NRObject *object)
-{
- NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object);
-
- if (glyphs->font) {
- glyphs->font->Unref();
- glyphs->font=NULL;
- }
-
- ((NRObjectClass *) glyphs_parent_class)->finalize(object);
-}
-
-static guint
-nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/)
-{
- NRArenaGlyphs *glyphs = NR_ARENA_GLYPHS(item);
- NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item->parent);
-
- if (!glyphs->font || !ggroup->style)
- return NR_ARENA_ITEM_STATE_ALL;
- if (ggroup->nrstyle.fill.type == NRStyle::PAINT_NONE && ggroup->nrstyle.stroke.type == NRStyle::PAINT_NONE)
- return NR_ARENA_ITEM_STATE_ALL;
-
- Geom::OptRect b;
- Geom::Affine t = glyphs->g_transform * gc->transform;
- glyphs->x = t[4];
- glyphs->y = t[5];
-
- b = bounds_exact_transformed(*glyphs->font->PathVector(glyphs->glyph), t);
- if (b && ggroup->nrstyle.stroke.type != NRStyle::PAINT_NONE) {
- float width, scale;
- scale = gc->transform.descrim();
- width = MAX(0.125, ggroup->nrstyle.stroke_width * scale);
- if ( fabs(ggroup->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true
- b->expandBy(width);
- }
- // those pesky miters, now
- float miterMax = width * ggroup->nrstyle.miter_limit;
- if ( miterMax > 0.01 ) {
- // grunt mode. we should compute the various miters instead
- // (one for each point on the curve)
- b->expandBy(miterMax);
- }
- }
-
- if (b) {
- item->bbox.x0 = floor(b->left());
- item->bbox.y0 = floor(b->top());
- item->bbox.x1 = ceil (b->right());
- item->bbox.y1 = ceil (b->bottom());
- } else {
- item->bbox.x0 = 0;
- item->bbox.y0 = 0;
- item->bbox.x1 = -1;
- item->bbox.y1 = -1;
- }
-
- return NR_ARENA_ITEM_STATE_ALL;
-}
-
-static guint nr_arena_glyphs_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/)
-{
- NRArenaGlyphs *glyphs;
-
- glyphs = NR_ARENA_GLYPHS(item);
-
- if (!glyphs->font) return item->state;
-
- // TODO : render to greyscale pixblock provided for clipping
-
- return item->state;
-}
-
-static NRArenaItem *
-nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int /*sticky*/)
-{
- NRArenaGlyphs *glyphs;
-
- glyphs = NR_ARENA_GLYPHS(item);
-
- if (!glyphs->font ) return NULL;
-
- double const x = p[Geom::X];
- double const y = p[Geom::Y];
- /* With text we take a simple approach: pick if the point is in a characher bbox */
- if ((x + delta >= item->bbox.x0) && (y + delta >= item->bbox.y0) && (x - delta <= item->bbox.x1) && (y - delta <= item->bbox.y1)) return item;
-
- return NULL;
-}
-
-void
-nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, Geom::Affine const *transform)
-{
- nr_return_if_fail(glyphs != NULL);
- nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
-
- nr_arena_item_request_render(NR_ARENA_ITEM(glyphs));
-
- if (transform) {
- glyphs->g_transform = *transform;
- } else {
- glyphs->g_transform.setIdentity();
- }
-
- if (font) font->Ref();
- if (glyphs->font) glyphs->font->Unref();
- glyphs->font=font;
- glyphs->glyph = glyph;
-
- nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
-static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
-static void nr_arena_glyphs_group_finalize(NRObject *object);
-
-static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
-static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky);
-
-static NRArenaGroupClass *group_parent_class;
-
-NRType
-nr_arena_glyphs_group_get_type(void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
- "NRArenaGlyphsGroup",
- sizeof(NRArenaGlyphsGroupClass),
- sizeof(NRArenaGlyphsGroup),
- (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
- (void (*)(NRObject *)) nr_arena_glyphs_group_init);
- }
- return type;
-}
-
-static void
-nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
-{
- NRObjectClass *object_class;
- NRArenaItemClass *item_class;
-
- object_class = (NRObjectClass *) klass;
- item_class = (NRArenaItemClass *) klass;
-
- group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
-
- object_class->finalize = nr_arena_glyphs_group_finalize;
- object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
-
- item_class->update = nr_arena_glyphs_group_update;
- item_class->render = nr_arena_glyphs_group_render;
- item_class->clip = nr_arena_glyphs_group_clip;
- item_class->pick = nr_arena_glyphs_group_pick;
-}
-
-static void
-nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
-{
- group->style = NULL;
- group->paintbox.x0 = group->paintbox.y0 = 0.0F;
- group->paintbox.x1 = group->paintbox.y1 = -1.0F;
-}
-
-static void
-nr_arena_glyphs_group_finalize(NRObject *object)
-{
- NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
-
- if (group->style) {
- sp_style_unref(group->style);
- group->style = NULL;
- }
-
- ((NRObjectClass *) group_parent_class)->finalize(object);
-}
-
-static guint
-nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
-{
- NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
-
- group->nrstyle.update();
-
- if (((NRArenaItemClass *) group_parent_class)->update)
- return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);
-
- return NR_ARENA_ITEM_STATE_ALL;
-}
-
-
-static unsigned int
-nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/)
-{
- NRArenaItem *child = 0;
-
- NRArenaGroup *group = NR_ARENA_GROUP(item);
- NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
-
- if (!ct) {
- return item->state;
- }
-
- if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
- cairo_save(ct);
- guint32 rgba = item->arena->outlinecolor;
- ink_cairo_set_source_rgba32(ct, rgba);
- cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
- cairo_new_path(ct);
- ink_cairo_transform(ct, ggroup->ctm);
-
- for (child = group->children; child != NULL; child = child->next) {
- NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
-
- Geom::PathVector const * pathv = g->font->PathVector(g->glyph);
- Geom::Affine transform = g->g_transform;
-
- cairo_save(ct);
- ink_cairo_transform(ct, transform);
- feed_pathvector_to_cairo (ct, *pathv);
- cairo_fill(ct);
- cairo_restore(ct);
- }
- cairo_restore(ct);
- return item->state;
- }
-
- // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding
- bool has_stroke, has_fill;
-
- cairo_save(ct);
- ink_cairo_transform(ct, ggroup->ctm);
-
- has_fill = ggroup->nrstyle.prepareFill(ct, &ggroup->paintbox);
- has_stroke = ggroup->nrstyle.prepareStroke(ct, &ggroup->paintbox);
-
- if (has_fill || has_stroke) {
- for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) {
- NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
- Geom::PathVector const &pathv = *g->font->PathVector(g->glyph);
-
- cairo_save(ct);
- ink_cairo_transform(ct, g->g_transform);
- feed_pathvector_to_cairo(ct, pathv);
- cairo_restore(ct);
- }
-
- if (has_fill) {
- ggroup->nrstyle.applyFill(ct);
- cairo_fill_preserve(ct);
- }
- if (has_stroke) {
- ggroup->nrstyle.applyStroke(ct);
- cairo_stroke_preserve(ct);
- }
- cairo_new_path(ct); // clear path
- } // has fill or stroke pattern
- cairo_restore(ct);
-
- return item->state;
-}
-
-static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/)
-{
- NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
-
- cairo_save(ct);
- // handle clip-rule
- if (ggroup->style) {
- if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD);
- } else {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING);
- }
- }
- ink_cairo_transform(ct, ggroup->ctm);
-
- for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) {
- NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
- Geom::PathVector const &pathv = *g->font->PathVector(g->glyph);
-
- cairo_save(ct);
- ink_cairo_transform(ct, g->g_transform);
- feed_pathvector_to_cairo(ct, pathv);
- cairo_restore(ct);
- }
- cairo_fill(ct);
- cairo_restore(ct);
-
- return item->state;
-}
-
-static NRArenaItem *
-nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky)
-{
- NRArenaItem *picked = NULL;
-
- if (((NRArenaItemClass *) group_parent_class)->pick)
- picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky);
-
- if (picked) picked = item;
-
- return picked;
-}
-
-void
-nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
-{
- NRArenaGroup *group = NR_ARENA_GROUP(sg);
-
- nr_arena_item_request_render(NR_ARENA_ITEM(group));
-
- while (group->children) {
- nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children);
- }
-}
-
-void
-nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, Geom::Affine const &transform)
-{
- NRArenaGroup *group;
-
- group = NR_ARENA_GROUP(sg);
-
- Geom::PathVector const * pathv = ( font
- ? font->PathVector(glyph)
- : NULL );
- if ( pathv ) {
- nr_arena_item_request_render(NR_ARENA_ITEM(group));
-
- NRArenaItem *new_arena = NRArenaGlyphs::create(group->arena);
- nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena);
- nr_arena_item_unref(new_arena);
- nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, &transform);
- }
-}
-
-void
-nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
-{
- nr_return_if_fail(sg != NULL);
- nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg));
-
- if (style) sp_style_ref(style);
- if (sg->style) sp_style_unref(sg->style);
- sg->style = style;
-
- sg->nrstyle.set(style);
-
- nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void
-nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
-{
- nr_return_if_fail(gg != NULL);
- nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
- nr_return_if_fail(pbox != NULL);
-
- if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
- gg->paintbox.x0 = pbox->x0;
- gg->paintbox.y0 = pbox->y0;
- gg->paintbox.x1 = pbox->x1;
- gg->paintbox.y1 = pbox->y1;
- } else {
- gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
- gg->paintbox.x1 = gg->paintbox.y1 = -1.0F;
- }
-
- nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h
deleted file mode 100644
index c43095cb2..000000000
--- a/src/display/nr-arena-glyphs.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef SEEN_NR_ARENA_GLYPHS_H
-#define SEEN_NR_ARENA_GLYPHS_H
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2002 Lauris Kaplinski
- *
- * Released under GNU GPL
- *
- */
-
-#define NR_TYPE_ARENA_GLYPHS (nr_arena_glyphs_get_type ())
-#define NR_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_GLYPHS, NRArenaGlyphs))
-#define NR_IS_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS))
-
-#include "libnrtype/nrtype-forward.h"
-#include "display/display-forward.h"
-#include "forward.h"
-#include "display/nr-arena-item.h"
-#include "display/nr-style.h"
-
-#define test_glyph_liv
-
-struct SPCurve;
-class Shape;
-class SPPainter;
-
-NRType nr_arena_glyphs_get_type (void);
-
-struct NRArenaGlyphs : public NRArenaItem {
- /* Glyphs data */
- Geom::Affine g_transform;
-
- font_instance *font;
- gint glyph;
- float x, y;
-
- static NRArenaGlyphs *create(NRArena *arena) {
- NRArenaGlyphs *obj=reinterpret_cast<NRArenaGlyphs *>(nr_object_new(NR_TYPE_ARENA_GLYPHS));
- obj->init(arena);
- return obj;
- }
-};
-
-struct NRArenaGlyphsClass {
- NRArenaItemClass parent_class;
-};
-
-void nr_arena_glyphs_set_path ( NRArenaGlyphs *glyphs,
- SPCurve *curve, unsigned int lieutenant,
- font_instance *font, int glyph,
- Geom::Affine const *transform );
-void nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style);
-
-/* Integrated group of component glyphss */
-
-typedef struct NRArenaGlyphsGroup NRArenaGlyphsGroup;
-typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass;
-
-#include "nr-arena-group.h"
-
-#define NR_TYPE_ARENA_GLYPHS_GROUP (nr_arena_glyphs_group_get_type ())
-#define NR_ARENA_GLYPHS_GROUP(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_GLYPHS_GROUP, NRArenaGlyphsGroup))
-#define NR_IS_ARENA_GLYPHS_GROUP(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS_GROUP))
-
-NRType nr_arena_glyphs_group_get_type (void);
-
-struct NRArenaGlyphsGroup : public NRArenaGroup {
- NRRect paintbox;
- NRStyle nrstyle;
-
- static NRArenaGlyphsGroup *create(NRArena *arena) {
- NRArenaGlyphsGroup *obj=reinterpret_cast<NRArenaGlyphsGroup *>(nr_object_new(NR_TYPE_ARENA_GLYPHS_GROUP));
- obj->init(arena);
- return obj;
- }
-};
-
-struct NRArenaGlyphsGroupClass {
- NRArenaGroupClass parent_class;
-};
-
-/* Utility functions */
-
-void nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *group);
-
-void nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *group, font_instance *font, int glyph, Geom::Affine const &transform);
-
-void nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *group, SPStyle *style);
-
-void nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *group, const NRRect *pbox);
-
-#endif // SEEN_NR_ARENA_GLYPHS_H
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp
deleted file mode 100644
index 1d552fbc2..000000000
--- a/src/display/nr-arena-group.cpp
+++ /dev/null
@@ -1,299 +0,0 @@
-#define __NR_ARENA_GROUP_C__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include "display/canvas-bpath.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-group.h"
-#include "display/nr-filter.h"
-#include "display/nr-filter-types.h"
-#include "display/rendermode.h"
-#include "style.h"
-#include "sp-filter.h"
-#include "sp-filter-reference.h"
-#include "filters/blend.h"
-#include "display/nr-filter-blend.h"
-#include "helper/geom.h"
-
-static void nr_arena_group_class_init (NRArenaGroupClass *klass);
-static void nr_arena_group_init (NRArenaGroup *group);
-
-static NRArenaItem *nr_arena_group_children (NRArenaItem *item);
-static NRArenaItem *nr_arena_group_last_child (NRArenaItem *item);
-static void nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-static void nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child);
-static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-
-static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
-static unsigned int nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
-
-static NRArenaItemClass *parent_class;
-
-NRType
-nr_arena_group_get_type (void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type (NR_TYPE_ARENA_ITEM,
- "NRArenaGroup",
- sizeof (NRArenaGroupClass),
- sizeof (NRArenaGroup),
- (void (*) (NRObjectClass *)) nr_arena_group_class_init,
- (void (*) (NRObject *)) nr_arena_group_init);
- }
- return type;
-}
-
-static void
-nr_arena_group_class_init (NRArenaGroupClass *klass)
-{
- NRObjectClass *object_class;
- NRArenaItemClass *item_class;
-
- object_class = (NRObjectClass *) klass;
- item_class = (NRArenaItemClass *) klass;
-
- parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
-
- object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGroup>;
-
- item_class->children = nr_arena_group_children;
- item_class->last_child = nr_arena_group_last_child;
- item_class->add_child = nr_arena_group_add_child;
- item_class->set_child_position = nr_arena_group_set_child_position;
- item_class->remove_child = nr_arena_group_remove_child;
- item_class->update = nr_arena_group_update;
- item_class->render = nr_arena_group_render;
- item_class->clip = nr_arena_group_clip;
- item_class->pick = nr_arena_group_pick;
-}
-
-static void
-nr_arena_group_init (NRArenaGroup *group)
-{
- group->transparent = FALSE;
- group->children = NULL;
- group->last = NULL;
- group->style = NULL;
- group->child_transform.setIdentity();
-}
-
-static NRArenaItem *
-nr_arena_group_children (NRArenaItem *item)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- return group->children;
-}
-
-static NRArenaItem *
-nr_arena_group_last_child (NRArenaItem *item)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- return group->last;
-}
-
-static void
-nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- if (!ref) {
- group->children = nr_arena_item_attach (item, child, NULL, group->children);
- } else {
- ref->next = nr_arena_item_attach (item, child, ref, ref->next);
- }
-
- if (ref == group->last) group->last = child;
-
- nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-static void
-nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- if (child == group->last) group->last = child->prev;
-
- if (child->prev) {
- nr_arena_item_detach (item, child);
- } else {
- group->children = nr_arena_item_detach (item, child);
- }
-
- nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-static void
-nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- if (child == group->last) group->last = child->prev;
-
- if (child->prev) {
- nr_arena_item_detach (item, child);
- } else {
- group->children = nr_arena_item_detach (item, child);
- }
-
- if (!ref) {
- group->children = nr_arena_item_attach (item, child, NULL, group->children);
- } else {
- ref->next = nr_arena_item_attach (item, child, ref, ref->next);
- }
-
- if (ref == group->last) group->last = child;
-
- nr_arena_item_request_render (child);
-}
-
-static unsigned int
-nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset)
-{
- unsigned int newstate;
- NRArenaGroup *group = NR_ARENA_GROUP (item);
- unsigned int beststate = NR_ARENA_ITEM_STATE_ALL;
- bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
- NRGC cgc(gc);
- cgc.transform = group->child_transform * gc->transform;
- newstate = nr_arena_item_invoke_update (child, area, &cgc, state, reset);
- beststate = beststate & newstate;
- }
-
- if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
- item->bbox = NR_RECT_L_EMPTY;
- for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
- if (child->visible)
- nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox);
- }
- }
-
- return beststate;
-}
-
-void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style)
-{
- g_return_if_fail(group != NULL);
- g_return_if_fail(NR_IS_ARENA_GROUP(group));
-
- if (style) sp_style_ref(style);
- if (group->style) sp_style_unref(group->style);
- group->style = style;
-
- //if group has a filter
- if (style->filter.set && style->getFilter()) {
- if (!group->filter) {
- int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter()));
- group->filter = new Inkscape::Filters::Filter(primitives);
- }
- sp_filter_build_renderer(SP_FILTER(style->getFilter()), group->filter);
- } else {
- //no filter set for this group
- delete group->filter;
- group->filter = NULL;
- }
-
- if (style && style->enable_background.set
- && style->enable_background.value == SP_CSS_BACKGROUND_NEW) {
- group->background_new = true;
- }
-}
-
-static unsigned int
-nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- unsigned int ret = item->state;
-
- /* Just compose children into parent buffer */
- for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
- ret = nr_arena_item_invoke_render (ct, child, area, pb, flags);
- if (ret & NR_ARENA_ITEM_STATE_INVALID) break;
- }
-
- return ret;
-}
-
-static unsigned int
-nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
- unsigned int ret = item->state;
-
- for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
- ret = nr_arena_item_invoke_clip (ct, child, area);
- if (ret & NR_ARENA_ITEM_STATE_INVALID) break;
- }
-
- return ret;
-}
-
-static NRArenaItem *
-nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky)
-{
- NRArenaGroup *group = NR_ARENA_GROUP (item);
-
- for (NRArenaItem *child = group->last; child != NULL; child = child->prev) {
- NRArenaItem *picked = nr_arena_item_invoke_pick (child, p, delta, sticky);
- if (picked)
- return (group->transparent) ? picked : item;
- }
-
- return NULL;
-}
-
-void
-nr_arena_group_set_transparent (NRArenaGroup *group, unsigned int transparent)
-{
- nr_return_if_fail (group != NULL);
- nr_return_if_fail (NR_IS_ARENA_GROUP (group));
-
- group->transparent = transparent;
-}
-
-void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t)
-{
- Geom::Affine nt(t);
- nr_arena_group_set_child_transform(group, &nt);
-}
-
-void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t)
-{
- if (!t) t = &GEOM_MATRIX_IDENTITY;
-
- if (!Geom::matrix_equalp(*t, group->child_transform, NR_EPSILON)) {
- nr_arena_item_request_render (NR_ARENA_ITEM (group));
- group->child_transform = *t;
- nr_arena_item_request_update (NR_ARENA_ITEM (group), NR_ARENA_ITEM_STATE_ALL, TRUE);
- }
-}
-
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-group.h b/src/display/nr-arena-group.h
deleted file mode 100644
index 58394643c..000000000
--- a/src/display/nr-arena-group.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __NR_ARENA_GROUP_H__
-#define __NR_ARENA_GROUP_H__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@ximian.com>
- *
- * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc.
- *
- * Released under GNU GPL
- *
- */
-
-#define NR_TYPE_ARENA_GROUP (nr_arena_group_get_type ())
-#define NR_ARENA_GROUP(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_GROUP, NRArenaGroup))
-#define NR_IS_ARENA_GROUP(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_GROUP))
-
-#include "nr-arena-item.h"
-#include "style.h"
-
-NRType nr_arena_group_get_type (void);
-
-struct NRArenaGroup : public NRArenaItem{
- unsigned int transparent : 1;
- NRArenaItem *children;
- NRArenaItem *last;
- Geom::Affine child_transform;
- SPStyle *style;
-
- static NRArenaGroup *create(NRArena *arena) {
- NRArenaGroup *obj = reinterpret_cast<NRArenaGroup *>(nr_object_new(NR_TYPE_ARENA_GROUP));
- obj->init(arena);
- return obj;
- }
-};
-
-struct NRArenaGroupClass {
- NRArenaItemClass parent_class;
-};
-
-void nr_arena_group_set_transparent(NRArenaGroup *group, unsigned int transparent);
-
-void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t);
-void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t);
-void nr_arena_group_set_style(NRArenaGroup *group, SPStyle *style);
-
-#endif
-
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp
deleted file mode 100644
index a943a6214..000000000
--- a/src/display/nr-arena-image.cpp
+++ /dev/null
@@ -1,408 +0,0 @@
-#define __NR_ARENA_IMAGE_C__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <2geom/transforms.h>
-#include "../preferences.h"
-#include "nr-arena-image.h"
-#include "style.h"
-#include "display/cairo-utils.h"
-#include "display/nr-arena.h"
-#include "display/nr-filter.h"
-#include "sp-filter.h"
-#include "sp-filter-reference.h"
-
-int nr_arena_image_x_sample = 1;
-int nr_arena_image_y_sample = 1;
-
-/*
- * NRArenaCanvasImage
- *
- */
-
-static void nr_arena_image_class_init (NRArenaImageClass *klass);
-static void nr_arena_image_init (NRArenaImage *image);
-static void nr_arena_image_finalize (NRObject *object);
-
-static unsigned int nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
-static unsigned int nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
-static Geom::Rect nr_arena_image_rect (NRArenaImage *image);
-
-static NRArenaItemClass *parent_class;
-
-NRType
-nr_arena_image_get_type (void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type (NR_TYPE_ARENA_ITEM,
- "NRArenaImage",
- sizeof (NRArenaImageClass),
- sizeof (NRArenaImage),
- (void (*) (NRObjectClass *)) nr_arena_image_class_init,
- (void (*) (NRObject *)) nr_arena_image_init);
- }
- return type;
-}
-
-static void
-nr_arena_image_class_init (NRArenaImageClass *klass)
-{
- NRObjectClass *object_class;
- NRArenaItemClass *item_class;
-
- object_class = (NRObjectClass *) klass;
- item_class = (NRArenaItemClass *) klass;
-
- parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
-
- object_class->finalize = nr_arena_image_finalize;
- object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaImage>;
-
- item_class->update = nr_arena_image_update;
- item_class->render = nr_arena_image_render;
- item_class->pick = nr_arena_image_pick;
-}
-
-static void
-nr_arena_image_init (NRArenaImage *image)
-{
- image->pixbuf = NULL;
- image->ctm.setIdentity();
- image->clipbox = Geom::Rect();
- image->ox = image->oy = 0.0;
- image->sx = image->sy = 1.0;
-
- image->style = 0;
- image->render_opacity = TRUE;
-}
-
-static void
-nr_arena_image_finalize (NRObject *object)
-{
- NRArenaImage *image = NR_ARENA_IMAGE (object);
-
- if (image->pixbuf != NULL) {
- g_object_unref(image->pixbuf);
- cairo_surface_destroy(image->surface);
- }
- if (image->style)
- sp_style_unref(image->style);
-
- ((NRObjectClass *) parent_class)->finalize (object);
-}
-
-static unsigned int
-nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ )
-{
- // clear old bbox
- nr_arena_item_request_render(item);
-
- NRArenaImage *image = NR_ARENA_IMAGE (item);
-
- /* Copy affine */
- image->ctm = gc->transform;
-
- /* Calculate bbox */
- if (image->pixbuf) {
- NRRect bbox;
-
- Geom::Rect r = nr_arena_image_rect(image) * gc->transform;
-
- item->bbox.x0 = floor(r.left()); // Floor gives the coordinate in which the point resides
- item->bbox.y0 = floor(r.top());
- item->bbox.x1 = ceil(r.right()); // Ceil gives the first coordinate beyond the point
- item->bbox.y1 = ceil(r.bottom());
- } else {
- item->bbox.x0 = (int) gc->transform[4];
- item->bbox.y0 = (int) gc->transform[5];
- item->bbox.x1 = item->bbox.x0 - 1;
- item->bbox.y1 = item->bbox.y0 - 1;
- }
-
- return NR_ARENA_ITEM_STATE_ALL;
-}
-
-static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/, NRPixBlock * /*pb*/, unsigned int /*flags*/ )
-{
- if (!ct) {
- return item->state;
- }
-
- bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- NRArenaImage *image = NR_ARENA_IMAGE (item);
-
- if (!outline) {
- if (!image->pixbuf) {
- return item->state;
- }
-
- // FIXME: at the moment gdk_cairo_set_source_pixbuf creates an ARGB copy
- // of the pixbuf. Fix this in Cairo and/or GDK.
- cairo_save(ct);
- ink_cairo_transform(ct, image->ctm);
-
- cairo_new_path(ct);
- cairo_rectangle(ct, image->clipbox.left(), image->clipbox.top(),
- image->clipbox.width(), image->clipbox.height());
- cairo_clip(ct);
-
- cairo_translate(ct, image->ox, image->oy);
- cairo_scale(ct, image->sx, image->sy);
-
- cairo_set_source_surface(ct, image->surface, 0, 0);
-
- cairo_matrix_t tt;
- Geom::Affine total;
- cairo_get_matrix(ct, &tt);
- ink_matrix_to_2geom(total, tt);
-
- if (total.expansionX() > 1.0 || total.expansionY() > 1.0) {
- cairo_pattern_t *p = cairo_get_source(ct);
- cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST);
- }
-
- cairo_paint_with_alpha(ct, ((double) item->opacity) / 255.0);
- cairo_restore(ct);
-
- } else { // outline; draw a rect instead
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff);
-
- cairo_save(ct);
- ink_cairo_transform(ct, image->ctm);
-
- cairo_new_path(ct);
-
- Geom::Rect r = nr_arena_image_rect (image);
- Geom::Point c00 = r.corner(0);
- Geom::Point c01 = r.corner(3);
- Geom::Point c11 = r.corner(2);
- Geom::Point c10 = r.corner(1);
-
- cairo_move_to (ct, c00[Geom::X], c00[Geom::Y]);
- // the box
- cairo_line_to (ct, c10[Geom::X], c10[Geom::Y]);
- cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]);
- cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]);
- cairo_line_to (ct, c00[Geom::X], c00[Geom::Y]);
- // the diagonals
- cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]);
- cairo_move_to (ct, c10[Geom::X], c10[Geom::Y]);
- cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]);
- cairo_restore(ct);
-
- cairo_set_line_width(ct, 0.5);
- ink_cairo_set_source_rgba32(ct, rgba);
- cairo_stroke(ct);
- }
- return item->state;
-}
-
-/** Calculates the closest distance from p to the segment a1-a2*/
-double
-distance_to_segment (Geom::Point p, Geom::Point a1, Geom::Point a2)
-{
- // calculate sides of the triangle and their squares
- double d1 = Geom::L2(p - a1);
- double d1_2 = d1 * d1;
- double d2 = Geom::L2(p - a2);
- double d2_2 = d2 * d2;
- double a = Geom::L2(a1 - a2);
- double a_2 = a * a;
-
- // if one of the angles at the base is > 90, return the corresponding side
- if (d1_2 + a_2 <= d2_2) return d1;
- if (d2_2 + a_2 <= d1_2) return d2;
-
- // otherwise calculate the height to the base
- double peri = (a + d1 + d2)/2;
- return (2*sqrt(peri * (peri - a) * (peri - d1) * (peri - d2))/a);
-}
-
-static NRArenaItem *
-nr_arena_image_pick( NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/ )
-{
- NRArenaImage *image = NR_ARENA_IMAGE (item);
-
- if (!image->pixbuf) return NULL;
-
- bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- if (outline) {
- Geom::Rect r = nr_arena_image_rect (image);
-
- Geom::Point c00 = r.corner(0);
- Geom::Point c01 = r.corner(3);
- Geom::Point c11 = r.corner(2);
- Geom::Point c10 = r.corner(1);
-
- // frame
- if (distance_to_segment (p, c00, c10) < delta) return item;
- if (distance_to_segment (p, c10, c11) < delta) return item;
- if (distance_to_segment (p, c11, c01) < delta) return item;
- if (distance_to_segment (p, c01, c00) < delta) return item;
-
- // diagonals
- if (distance_to_segment (p, c00, c11) < delta) return item;
- if (distance_to_segment (p, c10, c01) < delta) return item;
-
- return NULL;
-
- } else {
-
- unsigned char *const pixels = gdk_pixbuf_get_pixels(image->pixbuf);
- int const width = gdk_pixbuf_get_width(image->pixbuf);
- int const height = gdk_pixbuf_get_height(image->pixbuf);
- int const rowstride = gdk_pixbuf_get_rowstride(image->pixbuf);
-
- Geom::Point tp = p * image->ctm.inverse();
- Geom::Rect r = nr_arena_image_rect(image);
-
- if (!r.contains(tp))
- return NULL;
-
- double vw = width * image->sx;
- double vh = height * image->sy;
- int ix = floor((tp[Geom::X] - image->ox) / vw * width);
- int iy = floor((tp[Geom::Y] - image->oy) / vh * height);
-
- if ((ix < 0) || (iy < 0) || (ix >= width) || (iy >= height))
- return NULL;
-
- unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4;
- // is the alpha not transparent?
- return (pix_ptr[3] > 0) ? item : NULL;
- }
-}
-
-Geom::Rect
-nr_arena_image_rect (NRArenaImage *image)
-{
- Geom::Rect r = image->clipbox;
-
- if (image->pixbuf) {
- double pw = gdk_pixbuf_get_width(image->pixbuf);
- double ph = gdk_pixbuf_get_height(image->pixbuf);
- double vw = pw * image->sx;
- double vh = ph * image->sy;
- Geom::Point p(image->ox, image->oy);
- Geom::Point wh(vw, vh);
- Geom::Rect view(p, p+wh);
- Geom::OptRect res = r & view;
- r = res ? *res : r;
- }
-
- return r;
-}
-
-/* Utility */
-
-void
-nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb)
-{
- nr_return_if_fail (image != NULL);
- nr_return_if_fail (NR_IS_ARENA_IMAGE (image));
-
- // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1
- if (pb != NULL) {
- g_object_ref (pb);
- }
- if (image->pixbuf != NULL) {
- g_object_unref(image->pixbuf);
- cairo_surface_destroy(image->surface);
- }
- image->pixbuf = pb;
- image->surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL;
-
- nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void
-nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip)
-{
- nr_return_if_fail (image != NULL);
- nr_return_if_fail (NR_IS_ARENA_IMAGE (image));
-
- image->clipbox = clip;
-
- nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void
-nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin)
-{
- nr_return_if_fail (image != NULL);
- nr_return_if_fail (NR_IS_ARENA_IMAGE (image));
-
- image->ox = origin[Geom::X];
- image->oy = origin[Geom::Y];
-
- nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void
-nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy)
-{
- nr_return_if_fail (image != NULL);
- nr_return_if_fail (NR_IS_ARENA_IMAGE (image));
-
- image->sx = sx;
- image->sy = sy;
-
- nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style)
-{
- g_return_if_fail(image != NULL);
- g_return_if_fail(NR_IS_ARENA_IMAGE(image));
-
- if (style) sp_style_ref(style);
- if (image->style) sp_style_unref(image->style);
- image->style = style;
-
- //if image has a filter
- if (style->filter.set && style->getFilter()) {
- if (!image->filter) {
- int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter()));
- image->filter = new Inkscape::Filters::Filter(primitives);
- }
- sp_filter_build_renderer(SP_FILTER(style->getFilter()), image->filter);
- } else {
- //no filter set for this image
- delete image->filter;
- image->filter = NULL;
- }
-
- if (style && style->enable_background.set
- && style->enable_background.value == SP_CSS_BACKGROUND_NEW) {
- image->background_new = true;
- }
-
- nr_arena_item_request_update(image, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-image.h b/src/display/nr-arena-image.h
deleted file mode 100644
index 6fa9223dd..000000000
--- a/src/display/nr-arena-image.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef __NR_ARENA_IMAGE_H__
-#define __NR_ARENA_IMAGE_H__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <2geom/rect.h>
-#include "nr-arena-item.h"
-#include "style.h"
-
-#define NR_TYPE_ARENA_IMAGE (nr_arena_image_get_type ())
-#define NR_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_IMAGE, NRArenaImage))
-#define NR_IS_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_IMAGE))
-
-NRType nr_arena_image_get_type (void);
-
-struct NRArenaImage : public NRArenaItem {
- GdkPixbuf *pixbuf;
- cairo_surface_t *surface;
-
- Geom::Affine ctm;
- Geom::Rect clipbox;
- double ox, oy;
- double sx, sy;
-
- SPStyle *style;
-
- static NRArenaImage *create(NRArena *arena) {
- NRArenaImage *obj=reinterpret_cast<NRArenaImage *>(nr_object_new(NR_TYPE_ARENA_IMAGE));
- obj->init(arena);
- return obj;
- }
-};
-
-struct NRArenaImageClass {
- NRArenaItemClass parent_class;
-};
-
-void nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb);
-void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style);
-void nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip);
-void nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin);
-void nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy);
-
-#endif
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp
deleted file mode 100644
index 9ca5a7463..000000000
--- a/src/display/nr-arena-item.cpp
+++ /dev/null
@@ -1,882 +0,0 @@
-#define __NR_ARENA_ITEM_C__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#define noNR_ARENA_ITEM_VERBOSE
-#define noNR_ARENA_ITEM_DEBUG_CASCADE
-
-#include <cstring>
-#include <string>
-#include <cairomm/cairomm.h>
-
-#include "display/cairo-utils.h"
-#include "display/cairo-templates.h"
-#include "display/canvas-arena.h"
-#include "nr-arena.h"
-#include "nr-arena-item.h"
-#include "gc-core.h"
-#include "helper/geom.h"
-
-#include "nr-filter.h"
-#include "nr-arena-group.h"
-#include "preferences.h"
-
-namespace GC = Inkscape::GC;
-
-static void nr_arena_item_class_init (NRArenaItemClass *klass);
-static void nr_arena_item_init (NRArenaItem *item);
-static void nr_arena_item_private_finalize (NRObject *object);
-
-static NRObjectClass *parent_class;
-
-NRType
-nr_arena_item_get_type (void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type (NR_TYPE_OBJECT,
- "NRArenaItem",
- sizeof (NRArenaItemClass),
- sizeof (NRArenaItem),
- (void (*)(NRObjectClass *))
- nr_arena_item_class_init,
- (void (*)(NRObject *))
- nr_arena_item_init);
- }
- return type;
-}
-
-static void
-nr_arena_item_class_init (NRArenaItemClass *klass)
-{
- NRObjectClass *object_class;
-
- object_class = (NRObjectClass *) klass;
-
- parent_class = ((NRObjectClass *) klass)->parent;
-
- object_class->finalize = nr_arena_item_private_finalize;
- object_class->cpp_ctor = NRObject::invoke_ctor < NRArenaItem >;
-}
-
-static void
-nr_arena_item_init (NRArenaItem *item)
-{
- item->arena = NULL;
- item->parent = NULL;
- item->next = item->prev = NULL;
-
- item->key = 0;
-
- item->state = 0;
- item->sensitive = TRUE;
- item->visible = TRUE;
-
- memset (&item->bbox, 0, sizeof (item->bbox));
- memset (&item->drawbox, 0, sizeof (item->drawbox));
- item->transform = NULL;
- item->ctm.setIdentity();
- item->opacity = 255;
- item->render_opacity = FALSE;
-
- item->transform = NULL;
- item->clip = NULL;
- item->mask = NULL;
- item->px = NULL;
- item->data = NULL;
- item->filter = NULL;
- item->background_pb = NULL;
- item->background_new = false;
-}
-
-static void
-nr_arena_item_private_finalize (NRObject *object)
-{
- NRArenaItem *item = static_cast < NRArenaItem * >(object);
-
- item->px = NULL;
- item->transform = NULL;
-
- if (item->clip)
- nr_arena_item_detach(item, item->clip);
- if (item->mask)
- nr_arena_item_detach(item, item->mask);
-
- ((NRObjectClass *) (parent_class))->finalize (object);
-}
-
-NRArenaItem *
-nr_arena_item_children (NRArenaItem *item)
-{
- nr_return_val_if_fail (item != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
-
- if (NR_ARENA_ITEM_VIRTUAL (item, children))
- return NR_ARENA_ITEM_VIRTUAL (item, children) (item);
-
- return NULL;
-}
-
-NRArenaItem *
-nr_arena_item_last_child (NRArenaItem *item)
-{
- nr_return_val_if_fail (item != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
-
- if (NR_ARENA_ITEM_VIRTUAL (item, last_child)) {
- return NR_ARENA_ITEM_VIRTUAL (item, last_child) (item);
- } else {
- NRArenaItem *ref = nr_arena_item_children (item);
- if (ref)
- while (ref->next)
- ref = ref->next;
- return ref;
- }
-}
-
-void
-nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child,
- NRArenaItem *ref)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_return_if_fail (child != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (child));
- nr_return_if_fail (child->parent == NULL);
- nr_return_if_fail (child->prev == NULL);
- nr_return_if_fail (child->next == NULL);
- nr_return_if_fail (child->arena == item->arena);
- nr_return_if_fail (child != ref);
- nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
- nr_return_if_fail (!ref || (ref->parent == item));
-
- if (NR_ARENA_ITEM_VIRTUAL (item, add_child))
- NR_ARENA_ITEM_VIRTUAL (item, add_child) (item, child, ref);
-}
-
-void
-nr_arena_item_remove_child (NRArenaItem *item, NRArenaItem *child)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_return_if_fail (child != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (child));
- nr_return_if_fail (child->parent == item);
-
- if (NR_ARENA_ITEM_VIRTUAL (item, remove_child))
- NR_ARENA_ITEM_VIRTUAL (item, remove_child) (item, child);
-}
-
-void
-nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child,
- NRArenaItem *ref)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_return_if_fail (child != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (child));
- nr_return_if_fail (child->parent == item);
- nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
- nr_return_if_fail (!ref || (ref->parent == item));
-
- if (NR_ARENA_ITEM_VIRTUAL (item, set_child_position))
- NR_ARENA_ITEM_VIRTUAL (item, set_child_position) (item, child, ref);
-}
-
-NRArenaItem *
-nr_arena_item_ref (NRArenaItem *item)
-{
- nr_object_ref ((NRObject *) item);
-
- return item;
-}
-
-NRArenaItem *
-nr_arena_item_unref (NRArenaItem *item)
-{
- nr_object_unref ((NRObject *) item);
-
- return NULL;
-}
-
-unsigned int
-nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
- unsigned int state, unsigned int reset)
-{
- NRGC childgc (gc);
- bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL);
- bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
- NR_ARENA_ITEM_STATE_INVALID);
- nr_return_val_if_fail (!(state & NR_ARENA_ITEM_STATE_INVALID),
- NR_ARENA_ITEM_STATE_INVALID);
-
-#ifdef NR_ARENA_ITEM_DEBUG_CASCADE
- printf ("Update %s:%p %x %x %x\n",
- nr_type_name_from_instance ((GTypeInstance *) item), item, state,
- item->state, reset);
-#endif
-
- /* return if in error */
- if (item->state & NR_ARENA_ITEM_STATE_INVALID)
- return item->state;
- /* Set reset flags according to propagation status */
- if (item->propagate) {
- reset |= ~item->state;
- item->propagate = FALSE;
- }
- /* Reset our state */
- item->state &= ~reset;
- /* Return if NOP */
- if (!(~item->state & state))
- return item->state;
- /* Test whether to return immediately */
- if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) {
- if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox))
- return item->state;
- }
-
- /* Reset image cache, if not to be kept */
- if (!(item->state & NR_ARENA_ITEM_STATE_IMAGE) && (item->px)) {
- item->px = NULL;
- }
-
- /* Set up local gc */
- childgc = *gc;
- if (item->transform) {
- childgc.transform = (*item->transform) * childgc.transform;
- }
- /* Remember the transformation matrix */
- item->ctm = childgc.transform;
-
- /* Invoke the real method */
- // that will update bbox
- item->state = NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state, reset);
- if (item->state & NR_ARENA_ITEM_STATE_INVALID)
- return item->state;
-
- /* Enlarge the drawbox to contain filter effects */
- if (item->filter && filter && item->item_bbox) {
- item->drawbox.x0 = item->item_bbox->min()[Geom::X];
- item->drawbox.y0 = item->item_bbox->min()[Geom::Y];
- item->drawbox.x1 = item->item_bbox->max()[Geom::X];
- item->drawbox.y1 = item->item_bbox->max()[Geom::Y];
- item->filter->compute_drawbox (item, item->drawbox);
- } else {
- memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox));
- }
-
- /* Clipping */
- if (item->clip) {
- // FIXME: since here we only need bbox, consider passing
- // ((state & !(NR_ARENA_ITEM_STATE_RENDER)) | NR_ARENA_ITEM_STATE_BBOX)
- // instead of state, so it does not have to create rendering structures in nr_arena_shape_update
- unsigned int newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset);
- if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
- }
- if (outline) {
- nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox);
- } else {
- // for clipping, we need geometric bbox
- nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox);
- }
- }
- /* Masking */
- if (item->mask) {
- unsigned int newstate = nr_arena_item_invoke_update (item->mask, area, &childgc, state, reset);
- if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
- }
- if (outline) {
- nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox);
- } else {
- // for masking, we need full drawbox of mask
- nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox);
- }
- }
-
- // now that we know drawbox, dirty the corresponding rect on canvas:
- if (!NR_IS_ARENA_GROUP(item) || (item->filter && filter)) {
- // unless filtered, groups do not need to render by themselves, only their members
- nr_arena_item_request_render (item);
- }
-
- return item->state;
-}
-
-struct MaskLuminanceToAlpha {
- guint32 operator()(guint32 in) {
- EXTRACT_ARGB32(in, a, r, g, b)
- // the operation of unpremul -> luminance-to-alpha -> multiply by alpha
- // is equivalent to luminance-to-alpha on premultiplied color values
- // original computation in double: r*0.2125 + g*0.7154 + b*0.0721
- guint32 ao = r*109 + g*366 + b*37; // coeffs add up to 512
- return ((ao + 256) << 15) & 0xff000000; // equivalent to ((ao + 256) / 512) << 24
- }
-};
-
-unsigned int
-nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area,
- NRPixBlock *pb, unsigned int flags)
-{
- bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
- bool filter = (item->arena->rendermode != Inkscape::RENDERMODE_OUTLINE &&
- item->arena->rendermode != Inkscape::RENDERMODE_NO_FILTERS);
-
- nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
- NR_ARENA_ITEM_STATE_INVALID);
- nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX,
- item->state);
- if (!ct) return item->state;
-
-#ifdef NR_ARENA_ITEM_VERBOSE
- g_message ("Invoke render %p on %p: %d %d - %d %d, %d %d - %d %d", item, pb,
- area->x0, area->y0,
- area->x1, area->y1,
- item->drawbox.x0, item->drawbox.y0,
- item->drawbox.x1, item->drawbox.y1);
-#endif
-
- /* If we are invisible, just return successfully */
- if (!item->visible)
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
-
- if (outline) {
- // intersect with bbox rather than drawbox, as we want to render things outside
- // of the clipping path as well
- NRRectL carea;
- nr_rect_l_intersect (&carea, area, &item->bbox);
- if (nr_rect_l_test_empty(carea))
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
-
- // No caching in outline mode for now; investigate if it really gives any advantage with cairo.
- // Also no attempts to clip anything; just render everything: item, clip, mask
- // First, render the object itself
- unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags);
- if (state & NR_ARENA_ITEM_STATE_INVALID) {
- /* Clean up and return error */
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
- }
-
- // render clip and mask, if any
- guint32 saved_rgba = item->arena->outlinecolor; // save current outline color
- // render clippath as an object, using a different color
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (item->clip) {
- item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips
- NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags);
- }
- // render mask as an object, using a different color
- if (item->mask) {
- item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks
- NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags);
- }
- item->arena->outlinecolor = saved_rgba; // restore outline color
-
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
- }
-
- // carea is the bounding box for intermediate rendering.
- // NOTE: carea might be larger than area, because of filter effects.
- NRRectL carea;
- nr_rect_l_intersect (&carea, area, &item->drawbox);
- if (nr_rect_l_test_empty(carea))
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
- if (item->filter && filter) {
- item->filter->area_enlarge (carea, item);
- nr_rect_l_intersect (&carea, &carea, &item->drawbox);
- }
-
- using namespace Inkscape;
-
- unsigned state;
- unsigned retstate;
-
- // determine whether this shape needs intermediate rendering.
- bool needs_intermediate_rendering = false;
- bool &nir = needs_intermediate_rendering;
- bool needs_opacity = (item->opacity != 255 && !item->render_opacity);
-
- // this item needs an intermediate rendering if:
- nir |= (item->clip != NULL); // 1. it has a clipping path
- nir |= (item->mask != NULL); // 2. it has a mask
- nir |= (item->filter != NULL && filter); // 3. it has a filter
- nir |= needs_opacity; // 4. it is non-opaque
-
- double opacity = static_cast<double>(item->opacity) / 255.0;
-
- /* How the rendering is done.
- *
- * Clipping, masking and opacity are done by rendering them to a surface
- * and then compositing the object's rendering onto it with the IN operator.
- * The object itself is rendered to a group.
- *
- * Opacity is done by rendering the clipping path with an alpha
- * value corresponding to the opacity. If there is no clipping path,
- * the entire intermediate surface is painted with alpha corresponding
- * to the opacity value.
- */
-
- // short-circuit the simple case.
- if (!needs_intermediate_rendering) {
- state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags);
- if (state & NR_ARENA_ITEM_STATE_INVALID) {
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
- }
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
- }
-
- cairo_surface_t *intermediate = cairo_surface_create_similar(
- cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA,
- carea.x1 - carea.x0, carea.y1 - carea.y0);
- cairo_t *ict = cairo_create(intermediate);
- cairo_translate(ict, -carea.x0, -carea.y0);
-
- // 1. Render clipping path with alpha = opacity.
- cairo_set_source_rgba(ict, 0,0,0,opacity);
- // Since clip can be combined with opacity, the result could be incorrect
- // for overlapping clip children. To fix this we use the SOURCE operator
- // instead of the default OVER.
- cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE);
- if (item->clip) {
- state = nr_arena_item_invoke_clip(ict, item->clip, const_cast<NRRectL*>(area));
- if (state & NR_ARENA_ITEM_STATE_INVALID) {
- retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID);
- goto cleanup;
- }
- } else {
- // if there is no clipping path, fill the entire surface with alpha = opacity.
- cairo_paint(ict);
- }
- // reset back to default
- cairo_set_operator(ict, CAIRO_OPERATOR_OVER);
-
- // 2. Render the mask if present and compose it with the clipping path + opacity.
- if (item->mask) {
- cairo_push_group(ict);
- state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags);
- if (state & NR_ARENA_ITEM_STATE_INVALID) {
- retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID);
- goto cleanup;
- }
- cairo_surface_t *mask_s = cairo_get_group_target(ict);
- // Convert mask's luminance to alpha
- ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha());
- cairo_pop_group_to_source(ict);
- cairo_set_operator(ict, CAIRO_OPERATOR_IN);
- cairo_paint(ict);
- cairo_set_operator(ict, CAIRO_OPERATOR_OVER);
- }
-
- // 3. Render object itself.
- cairo_push_group(ict);
- state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags);
- if (state & NR_ARENA_ITEM_STATE_INVALID) {
- retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID);
- goto cleanup;
- }
-
- // 4. Apply filter.
- if (item->filter && filter) {
- // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering
- // Proper fix: call this function with a drawing context class
- // that contains information about the surface's bounds
- NRRectL bgarea;
- if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) {
- bgarea = carea;
- } else {
- bgarea = NRRectL(item->arena->canvasarena->cache_area);
- }
- item->filter->render(item, ct, &bgarea, ict, &carea);
- // Note that because the object was rendered to a group,
- // the internals of the filter need to use cairo_get_group_target()
- // instead of cairo_get_target().
- }
-
- // 5. Render object inside the composited mask + clip
- cairo_pop_group_to_source(ict);
- cairo_set_operator(ict, CAIRO_OPERATOR_IN);
- cairo_paint(ict);
-
- // 6. Paint the completed rendering onto the base context
- cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0);
- cairo_paint(ct);
- cairo_set_source_rgba(ct, 0,0,0,0);
- // the call above is to clear a ref on the intermediate surface held by ct
-
- retstate = item->state | NR_ARENA_ITEM_STATE_RENDER;
-
- cleanup:
- cairo_destroy(ict);
- cairo_surface_destroy(intermediate);
-
- return retstate;
-}
-
-unsigned int
-nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
-{
- nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
- NR_ARENA_ITEM_STATE_INVALID);
-
-#ifdef NR_ARENA_ITEM_VERBOSE
- printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n",
- item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0,
- (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1);
-#endif
-
- unsigned retstate = 0;
-
- // don't bother if the object does not implement clipping (e.g. NRArenaImage)
- if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip)
- return retstate;
-
- if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
- // The item used as the clipping path itself has a clipping path.
- // Render this item's clipping path onto a temporary surface, then composite it with the item
- // using the IN operator
- if (item->clip) {
- cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA);
- cairo_save(ct);
- cairo_set_source_rgba(ct, 0,0,0,1);
- nr_arena_item_invoke_clip(ct, item->clip, area);
- cairo_restore(ct);
- cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA);
- }
-
- // rasterize the clipping path
- retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
- clip (ct, item, area);
-
- if (item->clip) {
- cairo_pop_group_to_source(ct);
- cairo_set_operator(ct, CAIRO_OPERATOR_IN);
- cairo_paint(ct);
- cairo_pop_group_to_source(ct);
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
- }
- }
-
- return retstate;
-}
-
-NRArenaItem *
-nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta,
- unsigned int sticky)
-{
- nr_return_val_if_fail (item != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
-
- // Sometimes there's no BBOX in item->state, reason unknown (bug 992817); I made this not an assert to remove the warning
- if (!(item->state & NR_ARENA_ITEM_STATE_BBOX)
- || !(item->state & NR_ARENA_ITEM_STATE_PICK))
- return NULL;
-
- if (!sticky && !(item->visible && item->sensitive))
- return NULL;
-
- // TODO: rewrite using Geom::Rect
- const double x = p[Geom::X];
- const double y = p[Geom::Y];
-
- if (((x + delta) >= item->bbox.x0) &&
- ((x - delta) < item->bbox.x1) &&
- ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1))
- {
- if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick)
- return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
- pick (item, p, delta, sticky);
- }
-
- return NULL;
-}
-
-void
-nr_arena_item_request_update (NRArenaItem *item, unsigned int reset,
- unsigned int propagate)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_return_if_fail (!(reset & NR_ARENA_ITEM_STATE_INVALID));
-
- if (propagate && !item->propagate)
- item->propagate = TRUE;
-
- if (item->state & reset) {
- item->state &= ~reset;
- if (item->parent) {
- nr_arena_item_request_update (item->parent, reset, FALSE);
- } else {
- nr_arena_request_update (item->arena, item);
- }
- }
-}
-
-void
-nr_arena_item_request_render (NRArenaItem *item)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
-
- bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
- nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox);
-}
-
-/* Public */
-
-NRArenaItem *
-nr_arena_item_unparent (NRArenaItem *item)
-{
- nr_return_val_if_fail (item != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
-
- nr_arena_item_request_render (item);
-
- if (item->parent) {
- nr_arena_item_remove_child (item->parent, item);
- }
-
- return NULL;
-}
-
-void
-nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child)
-{
- nr_return_if_fail (parent != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (parent));
- nr_return_if_fail (child != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (child));
- nr_return_if_fail (parent->arena == child->arena);
- nr_return_if_fail (child->parent == NULL);
- nr_return_if_fail (child->prev == NULL);
- nr_return_if_fail (child->next == NULL);
-
- nr_arena_item_add_child (parent, child, nr_arena_item_last_child (parent));
-}
-
-void
-nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const &transform)
-{
- Geom::Affine const t (transform);
- nr_arena_item_set_transform (item, &t);
-}
-
-void
-nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
-
- if (!transform && !item->transform)
- return;
-
- const Geom::Affine *md = (item->transform) ? item->transform : &GEOM_MATRIX_IDENTITY;
- const Geom::Affine *ms = (transform) ? transform : &GEOM_MATRIX_IDENTITY;
-
- if (!Geom::matrix_equalp(*md, *ms, NR_EPSILON)) {
- nr_arena_item_request_render (item);
- if (!transform || transform->isIdentity()) {
- /* Set to identity affine */
- item->transform = NULL;
- } else {
- if (!item->transform)
- item->transform = new (GC::ATOMIC) Geom::Affine ();
- *item->transform = *transform;
- }
- nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
- }
-}
-
-void
-nr_arena_item_set_opacity (NRArenaItem *item, double opacity)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
-
- nr_arena_item_request_render (item);
-
- item->opacity = (unsigned int) (opacity * 255.9999);
-}
-
-void
-nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
-
- /* fixme: mess with pick/repick... */
-
- item->sensitive = sensitive;
-}
-
-void
-nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
-
- item->visible = visible;
-
- nr_arena_item_request_render (item);
-}
-
-void
-nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_return_if_fail (!clip || NR_IS_ARENA_ITEM (clip));
-
- if (clip != item->clip) {
- nr_arena_item_request_render (item);
- if (item->clip)
- item->clip = nr_arena_item_detach (item, item->clip);
- if (clip)
- item->clip = nr_arena_item_attach (item, clip, NULL, NULL);
- nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
- }
-}
-
-void
-nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_return_if_fail (!mask || NR_IS_ARENA_ITEM (mask));
-
- if (mask != item->mask) {
- nr_arena_item_request_render (item);
- if (item->mask)
- item->mask = nr_arena_item_detach (item, item->mask);
- if (mask)
- item->mask = nr_arena_item_attach (item, mask, NULL, NULL);
- nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
- }
-}
-
-void
-nr_arena_item_set_order (NRArenaItem *item, int order)
-{
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
-
- if (!item->parent)
- return;
-
- NRArenaItem *children = nr_arena_item_children (item->parent);
-
- NRArenaItem *ref = NULL;
- int pos = 0;
- for (NRArenaItem *child = children; child != NULL; child = child->next) {
- if (pos >= order)
- break;
- if (child != item) {
- ref = child;
- pos += 1;
- }
- }
-
- nr_arena_item_set_child_position (item->parent, item, ref);
-}
-
-void
-nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox)
-{
- nr_return_if_fail(item != NULL);
- nr_return_if_fail(NR_IS_ARENA_ITEM(item));
-
- item->item_bbox = bbox;
-}
-
-/** Returns a background image for use with filter effects. */
-NRPixBlock *nr_arena_item_get_background(NRArenaItem const * /*item*/)
-{
- return NULL;
-}
-
-/* Helpers */
-
-NRArenaItem *
-nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child,
- NRArenaItem *prev, NRArenaItem *next)
-{
- nr_return_val_if_fail (parent != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
- nr_return_val_if_fail (child != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
- nr_return_val_if_fail (child->parent == NULL, NULL);
- nr_return_val_if_fail (child->prev == NULL, NULL);
- nr_return_val_if_fail (child->next == NULL, NULL);
- nr_return_val_if_fail (!prev || NR_IS_ARENA_ITEM (prev), NULL);
- nr_return_val_if_fail (!prev || (prev->parent == parent), NULL);
- nr_return_val_if_fail (!prev || (prev->next == next), NULL);
- nr_return_val_if_fail (!next || NR_IS_ARENA_ITEM (next), NULL);
- nr_return_val_if_fail (!next || (next->parent == parent), NULL);
- nr_return_val_if_fail (!next || (next->prev == prev), NULL);
-
- child->parent = parent;
- child->prev = prev;
- child->next = next;
-
- if (prev)
- prev->next = child;
- if (next)
- next->prev = child;
-
- return child;
-}
-
-NRArenaItem *
-nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child)
-{
- nr_return_val_if_fail (parent != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
- nr_return_val_if_fail (child != NULL, NULL);
- nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
- nr_return_val_if_fail (child->parent == parent, NULL);
-
- NRArenaItem *prev = child->prev;
- NRArenaItem *next = child->next;
-
- child->parent = NULL;
- child->prev = NULL;
- child->next = NULL;
-
- if (prev)
- prev->next = next;
- if (next)
- next->prev = prev;
-
- return next;
-}
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h
deleted file mode 100644
index d65a75ed8..000000000
--- a/src/display/nr-arena-item.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#ifndef SEEN_DISPLAY_NR_ARENA_ITEM_H
-#define SEEN_DISPLAY_NR_ARENA_ITEM_H
-
-#include <cairo.h>
-#include <2geom/affine.h>
-#include <2geom/rect.h>
-#include "libnr/nr-forward.h"
-#include "libnr/nr-rect-l.h"
-#include "libnr/nr-object.h"
-#include "gc-soft-ptr.h"
-#include "nr-arena-forward.h"
-
-namespace Inkscape {
-namespace Filters {
-class Filter;
-} }
-
-#define NR_TYPE_ARENA_ITEM (nr_arena_item_get_type ())
-#define NR_ARENA_ITEM(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_ITEM, NRArenaItem))
-#define NR_IS_ARENA_ITEM(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_ITEM))
-
-#define NR_ARENA_ITEM_VIRTUAL(i,m) (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (i))->m)
-
-/*
- * NRArenaItem state flags
- */
-
-/*
- * NR_ARENA_ITEM_STATE_INVALID
- *
- * If set or retuned indicates, that given object is in error.
- * Calling method has to return immediately, with appropriate
- * error flag.
- */
-
-#define NR_ARENA_ITEM_STATE_INVALID (1 << 0)
-
-
-#define NR_ARENA_ITEM_STATE_BBOX (1 << 1)
-#define NR_ARENA_ITEM_STATE_COVERAGE (1 << 2)
-#define NR_ARENA_ITEM_STATE_DRAFT (1 << 3)
-#define NR_ARENA_ITEM_STATE_RENDER (1 << 4)
-#define NR_ARENA_ITEM_STATE_CLIP (1 << 5)
-#define NR_ARENA_ITEM_STATE_MASK (1 << 6)
-#define NR_ARENA_ITEM_STATE_PICK (1 << 7)
-#define NR_ARENA_ITEM_STATE_IMAGE (1 << 8)
-
-#define NR_ARENA_ITEM_STATE_NONE 0x0000
-#define NR_ARENA_ITEM_STATE_ALL 0x01fe
-
-#define NR_ARENA_ITEM_STATE(i,s) (NR_ARENA_ITEM (i)->state & (s))
-#define NR_ARENA_ITEM_SET_STATE(i,s) (NR_ARENA_ITEM (i)->state |= (s))
-#define NR_ARENA_ITEM_UNSET_STATE(i,s) (NR_ARENA_ITEM (i)->state &= ~(s))
-
-#define NR_ARENA_ITEM_RENDER_NO_CACHE (1 << 0)
-
-struct NRGC {
- NRGC(NRGC const *p) : parent(p) {}
- NRGC const *parent;
- Geom::Affine transform;
-};
-
-struct NRArenaItem : public NRObject {
-
- NRArena *arena;
- Inkscape::GC::soft_ptr<NRArenaItem> parent;
- NRArenaItem *next;
- Inkscape::GC::soft_ptr<NRArenaItem> prev;
-
- /* Item state */
- unsigned int state : 16;
- unsigned int propagate : 1;
- unsigned int sensitive : 1;
- unsigned int visible : 1;
- /* Whether items renders opacity itself */
- unsigned int render_opacity : 1;
- /* Opacity itself */
- unsigned int opacity : 8;
-
- unsigned int key; ///< Some SPItems can have more than one NRArenaItem,
- ///this value is a hack used to distinguish between them
-
- NRRectL bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin
- NRRectL drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks
- Geom::OptRect item_bbox; ///< Bounding box in item coordinates, required by filters
- Geom::Affine *transform; ///< Incremental transform of this item, as given by the transform= attribute
- Geom::Affine ctm; ///< Total transform from pixel grid to item coords
- NRArenaItem *clip; ///< Clipping path
- NRArenaItem *mask; ///< Mask
- Inkscape::Filters::Filter *filter; ///< Filter
- unsigned char *px; ///< Render cache; unused
-
- void *data; ///< Anonymous data member - this is used to associate SPItems with arena items
-
- NRPixBlock *background_pb; ///< Background for filters; unused
- bool background_new;
-
- void init(NRArena *arena) {
- this->arena = arena;
- }
-};
-
-struct NRArenaItemClass : public NRObjectClass {
- NRArenaItem * (* children) (NRArenaItem *item);
- NRArenaItem * (* last_child) (NRArenaItem *item);
- void (* add_child) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
- void (* remove_child) (NRArenaItem *item, NRArenaItem *child);
- void (* set_child_position) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-
- unsigned int (* update) (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
- unsigned int (* render) (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
- unsigned int (* clip) (cairo_t *ct, NRArenaItem *item, NRRectL *area);
- NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
-};
-
-#define NR_ARENA_ITEM_ARENA(ai) (((NRArenaItem *) (ai))->arena)
-
-NRType nr_arena_item_get_type (void);
-
-NRArenaItem *nr_arena_item_ref (NRArenaItem *item);
-NRArenaItem *nr_arena_item_unref (NRArenaItem *item);
-
-NRArenaItem *nr_arena_item_children (NRArenaItem *item);
-NRArenaItem *nr_arena_item_last_child (NRArenaItem *item);
-void nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-void nr_arena_item_remove_child (NRArenaItem *item, NRArenaItem *child);
-void nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-
-/*
- * Invoke update to given state, if item is inside area
- *
- * area == NULL is infinite
- * gc is PARENT gc for invoke, CHILD gc in corresponding virtual method
- * state - requested to state (bitwise or of requested flags)
- * reset - reset to state (bitwise or of flags to reset)
- */
-
-unsigned int nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
-
-unsigned int nr_arena_item_invoke_render(cairo_t *ct, NRArenaItem *item, NRRectL const *area, NRPixBlock *pb, unsigned int flags);
-
-unsigned int nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area);
-NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
-
-void nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, unsigned int propagate);
-void nr_arena_item_request_render (NRArenaItem *item);
-
-/* Public */
-
-NRArenaItem *nr_arena_item_unparent (NRArenaItem *item);
-
-void nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child);
-
-void nr_arena_item_set_transform(NRArenaItem *item, Geom::Affine const &transform);
-void nr_arena_item_set_transform(NRArenaItem *item, Geom::Affine const *transform);
-void nr_arena_item_set_opacity (NRArenaItem *item, double opacity);
-void nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive);
-void nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible);
-void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip);
-void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask);
-void nr_arena_item_set_order (NRArenaItem *item, int order);
-void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox);
-
-NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item);
-
-/* Helpers */
-
-NRArenaItem *nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child, NRArenaItem *prev, NRArenaItem *next);
-NRArenaItem *nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child);
-
-#define NR_ARENA_ITEM_SET_DATA(i,v) (((NRArenaItem *) (i))->data = (v))
-#define NR_ARENA_ITEM_GET_DATA(i) (((NRArenaItem *) (i))->data)
-
-#define NR_ARENA_ITEM_SET_KEY(i,k) (((NRArenaItem *) (i))->key = (k))
-#define NR_ARENA_ITEM_GET_KEY(i) (((NRArenaItem *) (i))->key)
-
-#endif /* !SEEN_DISPLAY_NR_ARENA_ITEM_H */
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp
deleted file mode 100644
index 6d65611bf..000000000
--- a/src/display/nr-arena-shape.cpp
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <cairo.h>
-#include <glib.h>
-#include <fenv.h>
-#include <typeinfo>
-
-#include <2geom/curves.h>
-#include <2geom/pathvector.h>
-#include <2geom/svg-path.h>
-#include <2geom/svg-path-parser.h>
-#include "display/cairo-utils.h"
-#include "display/canvas-arena.h"
-#include "display/canvas-bpath.h"
-#include "display/curve.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-shape.h"
-#include "display/nr-filter.h"
-#include "helper/geom-curves.h"
-#include "helper/geom.h"
-#include "libnr/nr-convert2geom.h"
-#include "preferences.h"
-#include "sp-filter.h"
-#include "sp-filter-reference.h"
-#include "style.h"
-#include "svg/svg.h"
-
-static void nr_arena_shape_class_init(NRArenaShapeClass *klass);
-static void nr_arena_shape_init(NRArenaShape *shape);
-static void nr_arena_shape_finalize(NRObject *object);
-
-static NRArenaItem *nr_arena_shape_children(NRArenaItem *item);
-static void nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-static void nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child);
-static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-
-static guint nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
-static unsigned int nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
-
-static NRArenaItemClass *shape_parent_class;
-
-NRType
-nr_arena_shape_get_type(void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
- "NRArenaShape",
- sizeof(NRArenaShapeClass),
- sizeof(NRArenaShape),
- (void (*)(NRObjectClass *)) nr_arena_shape_class_init,
- (void (*)(NRObject *)) nr_arena_shape_init);
- }
- return type;
-}
-
-static void
-nr_arena_shape_class_init(NRArenaShapeClass *klass)
-{
- NRObjectClass *object_class;
- NRArenaItemClass *item_class;
-
- object_class = (NRObjectClass *) klass;
- item_class = (NRArenaItemClass *) klass;
-
- shape_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
-
- object_class->finalize = nr_arena_shape_finalize;
- object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaShape>;
-
- item_class->children = nr_arena_shape_children;
- item_class->add_child = nr_arena_shape_add_child;
- item_class->set_child_position = nr_arena_shape_set_child_position;
- item_class->remove_child = nr_arena_shape_remove_child;
- item_class->update = nr_arena_shape_update;
- item_class->render = nr_arena_shape_render;
- item_class->clip = nr_arena_shape_clip;
- item_class->pick = nr_arena_shape_pick;
-}
-
-/**
- * Initializes the arena shape, setting all parameters to null, 0, false,
- * or other defaults
- */
-static void
-nr_arena_shape_init(NRArenaShape *shape)
-{
- shape->curve = NULL;
- shape->style = NULL;
- shape->paintbox.x0 = shape->paintbox.y0 = 0.0F;
- shape->paintbox.x1 = shape->paintbox.y1 = 256.0F;
- shape->delayed_shp = false;
- shape->path = NULL;
-
- shape->approx_bbox.x0 = shape->approx_bbox.y0 = 0;
- shape->approx_bbox.x1 = shape->approx_bbox.y1 = 0;
-
- shape->markers = NULL;
- shape->last_pick = NULL;
- shape->repick_after = 0;
-}
-
-static void
-nr_arena_shape_finalize(NRObject *object)
-{
- NRArenaShape *shape = (NRArenaShape *) object;
-
- if (shape->path) cairo_path_destroy(shape->path);
- if (shape->style) sp_style_unref(shape->style);
- if (shape->curve) shape->curve->unref();
- shape->last_pick = NULL;
-
- ((NRObjectClass *) shape_parent_class)->finalize(object);
-}
-
-/**
- * Retrieves the markers from the item
- */
-static NRArenaItem *
-nr_arena_shape_children(NRArenaItem *item)
-{
- NRArenaShape *shape = (NRArenaShape *) item;
-
- return shape->markers;
-}
-
-/**
- * Attaches child to item, and if ref is not NULL, sets it and ref->next as
- * the prev and next items. If ref is NULL, then it sets the item's markers
- * as the next items.
- */
-static void
-nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
-{
- NRArenaShape *shape = (NRArenaShape *) item;
-
- if (!ref) {
- shape->markers = nr_arena_item_attach(item, child, NULL, shape->markers);
- } else {
- ref->next = nr_arena_item_attach(item, child, ref, ref->next);
- }
-
- nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-/**
- * Removes child from the shape. If there are no prev items in
- * the child, it sets items' markers to the next item in the child.
- */
-static void
-nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child)
-{
- NRArenaShape *shape = (NRArenaShape *) item;
-
- if (child->prev) {
- nr_arena_item_detach(item, child);
- } else {
- shape->markers = nr_arena_item_detach(item, child);
- }
-
- nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-/**
- * Detaches child from item, and if there are no previous items in child, it
- * sets item's markers to the child. It then attaches the child back onto the item.
- * If ref is null, it sets the markers to be the next item, otherwise it uses
- * the next/prev items in ref.
- */
-static void
-nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
-{
- NRArenaShape *shape = (NRArenaShape *) item;
-
- if (child->prev) {
- nr_arena_item_detach(item, child);
- } else {
- shape->markers = nr_arena_item_detach(item, child);
- }
-
- if (!ref) {
- shape->markers = nr_arena_item_attach(item, child, NULL, shape->markers);
- } else {
- ref->next = nr_arena_item_attach(item, child, ref, ref->next);
- }
-
- nr_arena_item_request_render(child);
-}
-
-/**
- * Updates the arena shape 'item' and all of its children, including the markers.
- */
-static guint
-nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
-{
- Geom::OptRect boundingbox;
-
- NRArenaShape *shape = NR_ARENA_SHAPE(item);
-
- unsigned int beststate = NR_ARENA_ITEM_STATE_ALL;
-
- // update markers
- unsigned int newstate;
- for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- newstate = nr_arena_item_invoke_update(child, area, gc, state, reset);
- beststate = beststate & newstate;
- }
-
- if (!(state & NR_ARENA_ITEM_STATE_RENDER)) {
- /* We do not have to create rendering structures */
- if (state & NR_ARENA_ITEM_STATE_BBOX) {
- if (shape->curve) {
- boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform);
- if (boundingbox) {
- item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides
- item->bbox.y0 = floor((*boundingbox)[1][0]);
- item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point
- item->bbox.y1 = ceil ((*boundingbox)[1][1]);
- } else {
- item->bbox = NR_RECT_L_EMPTY;
- }
- }
- if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
- for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox);
- }
- }
- }
- return (state | item->state);
- }
-
- shape->delayed_shp=true;
- boundingbox = Geom::OptRect();
-
- bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- // clear Cairo data to force update
- shape->nrstyle.update();
- if (shape->path) {
- cairo_path_destroy(shape->path);
- shape->path = NULL;
- }
-
- if (shape->curve) {
- boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform);
-
- if (boundingbox && (shape->nrstyle.stroke.type != NRStyle::PAINT_NONE || outline)) {
- float width, scale;
- scale = gc->transform.descrim();
- width = MAX(0.125, shape->nrstyle.stroke_width * scale);
- if ( fabs(shape->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true
- boundingbox->expandBy(width);
- }
- // those pesky miters, now
- float miterMax = width * shape->nrstyle.miter_limit;
- if ( miterMax > 0.01 ) {
- // grunt mode. we should compute the various miters instead
- // (one for each point on the curve)
- boundingbox->expandBy(miterMax);
- }
- }
- }
-
- /// \todo just write item->bbox = boundingbox
- if (boundingbox) {
- shape->approx_bbox.x0 = floor(boundingbox->left());
- shape->approx_bbox.y0 = floor(boundingbox->top());
- shape->approx_bbox.x1 = ceil (boundingbox->right());
- shape->approx_bbox.y1 = ceil (boundingbox->bottom());
- } else {
- shape->approx_bbox = NR_RECT_L_EMPTY;
- }
- if ( area && nr_rect_l_test_intersect_ptr(area, &shape->approx_bbox) ) shape->delayed_shp=false;
-
- // TODO: compute a better bounding box that respects miters
- item->bbox = shape->approx_bbox;
-
- if (!shape->curve ||
- !shape->style ||
- shape->curve->is_empty() ||
- (( shape->nrstyle.fill.type != NRStyle::PAINT_NONE ) &&
- ( shape->nrstyle.stroke.type != NRStyle::PAINT_NONE && !outline) ))
- {
- //item->bbox = shape->approx_bbox;
- return NR_ARENA_ITEM_STATE_ALL;
- }
-
- if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
- for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox);
- }
- }
-
- return NR_ARENA_ITEM_STATE_ALL;
-}
-
-// cairo outline rendering:
-static unsigned int
-cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /*area*/)
-{
- NRArenaShape *shape = NR_ARENA_SHAPE(item);
-
- if (!ct)
- return item->state;
-
- guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor;
-
- cairo_save(ct);
- ink_cairo_transform(ct, shape->ctm);
- feed_pathvector_to_cairo (ct, shape->curve->get_pathvector());
- cairo_restore(ct);
- cairo_save(ct);
- ink_cairo_set_source_rgba32(ct, rgba);
- cairo_set_line_width(ct, 0.5);
- cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
- cairo_stroke(ct);
- cairo_restore(ct);
-
- return item->state;
-}
-
-/**
- * Renders the item. Markers are just composed into the parent buffer.
- */
-static unsigned int
-nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
-{
- NRArenaShape *shape = NR_ARENA_SHAPE(item);
-
- if (!shape->curve) return item->state;
- if (!shape->style) return item->state;
- if (!ct) return item->state;
-
- // skip if not within bounding box
- if (!nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
- return item->state;
- }
-
- bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- if (outline) { // cairo outline rendering
-
- NRRect temp(area->x0, area->y0, area->x1, area->y1);
- unsigned int ret = cairo_arena_shape_render_outline (ct, item, temp.upgrade_2geom());
- if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret;
-
- } else {
- bool has_stroke, has_fill;
- // we assume the context has no path
- cairo_save(ct);
- ink_cairo_transform(ct, shape->ctm);
-
- // update fill and stroke paints.
- // this cannot be done during nr_arena_shape_update, because we need a Cairo context
- // to render svg:pattern
- has_fill = shape->nrstyle.prepareFill(ct, &shape->paintbox);
- has_stroke = shape->nrstyle.prepareStroke(ct, &shape->paintbox);
- has_stroke &= (shape->nrstyle.stroke_width != 0);
-
- if (has_fill || has_stroke) {
- // TODO: remove segments outside of bbox when no dashes present
- feed_pathvector_to_cairo(ct, shape->curve->get_pathvector());
- if (has_fill) {
- shape->nrstyle.applyFill(ct);
- cairo_fill_preserve(ct);
- }
- if (has_stroke) {
- shape->nrstyle.applyStroke(ct);
- cairo_stroke_preserve(ct);
- }
- cairo_new_path(ct); // clear path
- } // has fill or stroke pattern
- cairo_restore(ct);
- }
-
- // marker rendering
- for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- unsigned int ret = nr_arena_item_invoke_render(ct, child, area, pb, flags);
- if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret;
- }
-
- return item->state;
-}
-
-
-static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/)
-{
- NRArenaShape *shape = NR_ARENA_SHAPE(item);
- if (!shape->curve) {
- return item->state;
- }
-
- cairo_save(ct);
- // handle clip-rule
- if (shape->style) {
- if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD);
- } else {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING);
- }
- }
- ink_cairo_transform(ct, shape->ctm);
- feed_pathvector_to_cairo(ct, shape->curve->get_pathvector());
- cairo_fill(ct);
- cairo_restore(ct);
-
- return item->state;
-}
-
-static NRArenaItem *
-nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/)
-{
- NRArenaShape *shape = NR_ARENA_SHAPE(item);
-
- if (shape->repick_after > 0)
- shape->repick_after--;
-
- if (shape->repick_after > 0) // we are a slow, huge path. skip this pick, returning what was returned last time
- return shape->last_pick;
-
- if (!shape->curve) return NULL;
- if (!shape->style) return NULL;
-
- bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
-
- if (SP_SCALE24_TO_FLOAT(shape->style->opacity.value) == 0 && !outline)
- // fully transparent, no pick unless outline mode
- return NULL;
-
- GTimeVal tstart, tfinish;
- g_get_current_time (&tstart);
-
- double width;
- if (outline) {
- width = 0.5;
- } else if (shape->nrstyle.stroke.type != NRStyle::PAINT_NONE && shape->nrstyle.stroke.opacity > 1e-3) {
- float const scale = shape->ctm.descrim();
- width = MAX(0.125, shape->nrstyle.stroke_width * scale) / 2;
- } else {
- width = 0;
- }
-
- double dist = Geom::infinity();
- int wind = 0;
- bool needfill = (shape->nrstyle.fill.type != NRStyle::PAINT_NONE
- && shape->nrstyle.fill.opacity > 1e-3 && !outline);
-
- if (item->arena->canvasarena) {
- Geom::Rect viewbox = item->arena->canvasarena->item.canvas->getViewbox();
- viewbox.expandBy (width);
- pathv_matrix_point_bbox_wind_distance(shape->curve->get_pathvector(), shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox);
- } else {
- pathv_matrix_point_bbox_wind_distance(shape->curve->get_pathvector(), shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL);
- }
-
- g_get_current_time (&tfinish);
- glong this_pick = (tfinish.tv_sec - tstart.tv_sec) * 1000000 + (tfinish.tv_usec - tstart.tv_usec);
- //g_print ("pick time %lu\n", this_pick);
-
- if (this_pick > 10000) { // slow picking, remember to skip several new picks
- shape->repick_after = this_pick / 5000;
- }
-
- // covered by fill?
- if (needfill) {
- if (!shape->style->fill_rule.computed) {
- if (wind != 0) {
- shape->last_pick = item;
- return item;
- }
- } else {
- if (wind & 0x1) {
- shape->last_pick = item;
- return item;
- }
- }
- }
-
- // close to the edge, as defined by strokewidth and delta?
- // this ignores dashing (as if the stroke is solid) and always works as if caps are round
- if (needfill || width > 0) { // if either fill or stroke visible,
- if ((dist - width) < delta) {
- shape->last_pick = item;
- return item;
- }
- }
-
- // if not picked on the shape itself, try its markers
- for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- NRArenaItem *ret = nr_arena_item_invoke_pick(child, p, delta, 0);
- if (ret) {
- shape->last_pick = item;
- return item;
- }
- }
-
- shape->last_pick = NULL;
- return NULL;
-}
-
-/**
- *
- * Requests a render of the shape, then if the shape is already a curve it
- * unrefs the old curve; if the new curve is valid it creates a copy of the
- * curve and adds it to the shape. Finally, it requests an update of the
- * arena for the shape.
- */
-void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve, bool /*justTrans*/)
-{
- g_return_if_fail(shape != NULL);
- g_return_if_fail(NR_IS_ARENA_SHAPE(shape));
-
- nr_arena_item_request_render(NR_ARENA_ITEM(shape));
-
- if (shape->curve) {
- shape->curve->unref();
- shape->curve = NULL;
- }
-
- if (curve) {
- shape->curve = curve;
- curve->ref();
- }
-
- nr_arena_item_request_update(NR_ARENA_ITEM(shape), NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-/** nr_arena_shape_set_style
- *
- * Unrefs any existing style and ref's to the given one, then requests an update of the arena
- */
-void
-nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style)
-{
- g_return_if_fail(shape != NULL);
- g_return_if_fail(NR_IS_ARENA_SHAPE(shape));
- g_return_if_fail(style != NULL);
-
- sp_style_ref(style);
- if (shape->style) sp_style_unref(shape->style);
- shape->style = style;
-
- shape->nrstyle.set(style);
-
- //if shape has a filter
- if (style->filter.set && style->getFilter()) {
- if (!shape->filter) {
- int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter()));
- shape->filter = new Inkscape::Filters::Filter(primitives);
- }
- sp_filter_build_renderer(SP_FILTER(style->getFilter()), shape->filter);
- } else {
- //no filter set for this shape
- delete shape->filter;
- shape->filter = NULL;
- }
-
- nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void
-nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox)
-{
- g_return_if_fail(shape != NULL);
- g_return_if_fail(NR_IS_ARENA_SHAPE(shape));
- g_return_if_fail(pbox != NULL);
-
- if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
- shape->paintbox = *pbox;
- } else {
- /* fixme: We kill warning, although not sure what to do here (Lauris) */
- shape->paintbox.x0 = shape->paintbox.y0 = 0.0F;
- shape->paintbox.x1 = shape->paintbox.y1 = 256.0F;
- }
-
- nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-void NRArenaShape::setPaintBox(Geom::Rect const &pbox)
-{
- paintbox.x0 = pbox.min()[Geom::X];
- paintbox.y0 = pbox.min()[Geom::Y];
- paintbox.x1 = pbox.max()[Geom::X];
- paintbox.y1 = pbox.max()[Geom::Y];
-
- nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE);
-}
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h
deleted file mode 100644
index 7b86f7f59..000000000
--- a/src/display/nr-arena-shape.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef __NR_ARENA_SHAPE_H__
-#define __NR_ARENA_SHAPE_H__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#define NR_TYPE_ARENA_SHAPE (nr_arena_shape_get_type ())
-#define NR_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_SHAPE, NRArenaShape))
-#define NR_IS_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_SHAPE))
-
-#include <cairo.h>
-#include "display/display-forward.h"
-#include "forward.h"
-#include "nr-arena-item.h"
-#include "nr-style.h"
-#include "libnr/nr-rect.h"
-
-NRType nr_arena_shape_get_type (void);
-
-struct NRArenaShape : public NRArenaItem {
- /* Shape data */
- SPCurve *curve;
- SPStyle *style;
- NRStyle nrstyle;
- NRRect paintbox;
-
- cairo_path_t *path;
-
- // delayed_shp=true means the *_shp polygons are not computed yet
- // they'll be computed on demand in *_render(), *_pick() or *_clip()
- // the goal is to not uncross polygons that are outside the viewing region
- bool delayed_shp;
- // approximate bounding box, for the case when the polygons have been delayed
- NRRectL approx_bbox;
-
- /* Markers */
- NRArenaItem *markers;
-
- NRArenaItem *last_pick;
- guint repick_after;
-
- static NRArenaShape *create(NRArena *arena) {
- NRArenaShape *obj=reinterpret_cast<NRArenaShape *>(nr_object_new(NR_TYPE_ARENA_SHAPE));
- obj->init(arena);
- obj->key = 0;
- return obj;
- }
-
- void setPaintBox(Geom::Rect const &pbox);
-};
-
-struct NRArenaShapeClass {
- NRArenaItemClass parent_class;
-};
-
-void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve, bool justTrans);
-void nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style);
-void nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox);
-
-
-#endif /* !__NR_ARENA_SHAPE_H__ */
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp
deleted file mode 100644
index ce62a81dc..000000000
--- a/src/display/nr-arena.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-#define __NR_ARENA_C__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include "nr-arena-item.h"
-#include "nr-arena.h"
-#include "nr-filter-gaussian.h"
-#include "nr-filter-types.h"
-#include "preferences.h"
-#include "color.h"
-#include "libnr/nr-rect.h"
-
-static void nr_arena_class_init (NRArenaClass *klass);
-static void nr_arena_init (NRArena *arena);
-static void nr_arena_finalize (NRObject *object);
-
-static NRActiveObjectClass *parent_class;
-
-NRType
-nr_arena_get_type (void)
-{
- static NRType type = 0;
- if (!type) {
- type = nr_object_register_type (NR_TYPE_ACTIVE_OBJECT,
- "NRArena",
- sizeof (NRArenaClass),
- sizeof (NRArena),
- (void (*) (NRObjectClass *)) nr_arena_class_init,
- (void (*) (NRObject *)) nr_arena_init);
- }
- return type;
-}
-
-static void
-nr_arena_class_init (NRArenaClass *klass)
-{
- NRObjectClass *object_class = (NRObjectClass *) klass;
-
- parent_class = (NRActiveObjectClass *) (((NRObjectClass *) klass)->parent);
-
- object_class->finalize = nr_arena_finalize;
- object_class->cpp_ctor = NRObject::invoke_ctor<NRArena>;
-}
-
-static void
-nr_arena_init (NRArena *arena)
-{
- arena->delta = 0; // to be set by desktop from prefs
- arena->renderoffscreen = false; // use render values from preferences otherwise render exact
- arena->rendermode = Inkscape::RENDERMODE_NORMAL; // default is normal render
- arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; // default is normal color
- arena->blurquality = BLUR_QUALITY_NORMAL;
- arena->filterquality = Inkscape::Filters::FILTER_QUALITY_NORMAL;
- arena->outlinecolor = 0xff; // black; to be set by desktop from bg color
- arena->canvasarena = NULL;
-}
-
-static void
-nr_arena_finalize (NRObject *object)
-{
- ((NRObjectClass *) (parent_class))->finalize (object);
-}
-
-void
-nr_arena_request_update (NRArena *arena, NRArenaItem *item)
-{
- NRActiveObject *aobject = (NRActiveObject *) arena;
-
- nr_return_if_fail (arena != NULL);
- nr_return_if_fail (NR_IS_ARENA (arena));
- nr_return_if_fail (item != NULL);
- nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- // setup render parameter
- if (arena->renderoffscreen == false) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- arena->blurquality = prefs->getInt("/options/blurquality/value", 0);
- arena->filterquality = prefs->getInt("/options/filterquality/value", 0);
- } else {
- arena->blurquality = BLUR_QUALITY_BEST;
- arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST;
- arena->rendermode = Inkscape::RENDERMODE_NORMAL;
- arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL;
- }
-
- if (aobject->callbacks) {
- for (unsigned int i = 0; i < aobject->callbacks->length; i++) {
- NRObjectListener *listener = aobject->callbacks->listeners + i;
- NRArenaEventVector *avector = (NRArenaEventVector *) listener->vector;
- if ((listener->size >= sizeof (NRArenaEventVector)) && avector->request_update) {
- avector->request_update (arena, item, listener->data);
- }
- }
- }
-}
-
-void
-nr_arena_request_render_rect (NRArena *arena, NRRectL *area)
-{
- NRActiveObject *aobject = (NRActiveObject *) arena;
-
- nr_return_if_fail (arena != NULL);
- nr_return_if_fail (NR_IS_ARENA (arena));
- nr_return_if_fail (area != NULL);
-
- // setup render parameter
- if (arena->renderoffscreen == false) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- arena->blurquality = prefs->getInt("/options/blurquality/value", 0);
- arena->filterquality = prefs->getInt("/options/filterquality/value", 0);
- } else {
- arena->blurquality = BLUR_QUALITY_BEST;
- arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST;
- arena->rendermode = Inkscape::RENDERMODE_NORMAL;
- arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL;
- }
- if (aobject->callbacks && area && !nr_rect_l_test_empty_ptr(area)) {
- for (unsigned int i = 0; i < aobject->callbacks->length; i++) {
- NRObjectListener *listener = aobject->callbacks->listeners + i;
- NRArenaEventVector *avector = (NRArenaEventVector *) listener->vector;
- if ((listener->size >= sizeof (NRArenaEventVector)) && avector->request_render) {
- avector->request_render (arena, area, listener->data);
- }
- }
- }
-}
-
-/**
- set arena to offscreen mode
- rendering will be exact
- @param arena NRArena object
-*/
-void
-nr_arena_set_renderoffscreen (NRArena *arena)
-{
- nr_return_if_fail (arena != NULL);
- nr_return_if_fail (NR_IS_ARENA (arena));
-
- // the real assignment to the quality indicators is in the update function
- arena->renderoffscreen = true;
-
-}
-
-#define FLOAT_TO_UINT8(f) (int(f*255))
-#define RGBA_R(v) ((v) >> 24)
-#define RGBA_G(v) (((v) >> 16) & 0xff)
-#define RGBA_B(v) (((v) >> 8) & 0xff)
-#define RGBA_A(v) ((v) & 0xff)
-
-void nr_arena_separate_color_plates(guint32* rgba){
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- bool render_cyan = prefs->getBool("/options/printcolorspreview/cyan", true);
- bool render_magenta = prefs->getBool("/options/printcolorspreview/magenta", true);
- bool render_yellow = prefs->getBool("/options/printcolorspreview/yellow", true);
- bool render_black = prefs->getBool("/options/printcolorspreview/black", true);
-
- float rgb_v[3];
- float cmyk_v[4];
- sp_color_rgb_to_cmyk_floatv (cmyk_v, RGBA_R(*rgba)/256.0, RGBA_G(*rgba)/256.0, RGBA_B(*rgba)/256.0);
- sp_color_cmyk_to_rgb_floatv (rgb_v, render_cyan ? cmyk_v[0] : 0,
- render_magenta ? cmyk_v[1] : 0,
- render_yellow ? cmyk_v[2] : 0,
- render_black ? cmyk_v[3] : 0);
- *rgba = (FLOAT_TO_UINT8(rgb_v[0])<<24) + (FLOAT_TO_UINT8(rgb_v[1])<<16) + (FLOAT_TO_UINT8(rgb_v[2])<<8) + 0xff;
-}
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h
deleted file mode 100644
index 1c8216434..000000000
--- a/src/display/nr-arena.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef __NR_ARENA_H__
-#define __NR_ARENA_H__
-
-/*
- * RGBA display list system for inkscape
- *
- * Author:
- * Lauris Kaplinski <lauris@kaplinski.com>
- *
- * Copyright (C) 2001-2002 Lauris Kaplinski
- * Copyright (C) 2001 Ximian, Inc.
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <glib/gmacros.h>
-
-#include "display/rendermode.h"
-
-G_BEGIN_DECLS
-
-typedef struct _SPCanvasArena SPCanvasArena;
-
-G_END_DECLS
-
-#define NR_TYPE_ARENA (nr_arena_get_type ())
-#define NR_ARENA(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA, NRArena))
-#define NR_IS_ARENA(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA))
-
-#include <libnr/nr-forward.h>
-#include <libnr/nr-object.h>
-#include "nr-arena-forward.h"
-
-class SPPainter;
-
-NRType nr_arena_get_type (void);
-
-struct NRArenaEventVector {
- NRObjectEventVector parent;
- void (* request_update) (NRArena *arena, NRArenaItem *item, void *data);
- void (* request_render) (NRArena *arena, NRRectL *area, void *data);
-};
-
-struct NRArena : public NRActiveObject {
- static NRArena *create() {
- return reinterpret_cast<NRArena *>(nr_object_new(NR_TYPE_ARENA));
- }
-
- double delta;
- bool renderoffscreen; // if true then rendering must be exact
- Inkscape::RenderMode rendermode;
- Inkscape::ColorRenderMode colorrendermode;
- int blurquality; // will be updated during update from preferences
- int filterquality; // will be updated during update from preferences
-
- guint32 outlinecolor;
- SPCanvasArena *canvasarena; // may be NULL is this arena is not the screen but used for export etc.
-};
-
-struct NRArenaClass : public NRActiveObjectClass {
-};
-
-void nr_arena_request_update (NRArena *arena, NRArenaItem *item);
-void nr_arena_request_render_rect (NRArena *arena, NRRectL *area);
-void nr_arena_set_renderoffscreen (NRArena *arena);
-
-void nr_arena_separate_color_plates(guint32* rgba);
-
-#endif
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
index 3cec479fa..267883b4b 100644
--- a/src/display/nr-filter-blend.cpp
+++ b/src/display/nr-filter-blend.cpp
@@ -196,6 +196,22 @@ bool FilterBlend::can_handle_affine(Geom::Affine const &)
return true;
}
+double FilterBlend::complexity(Geom::Affine const &)
+{
+ return 1.1;
+}
+
+bool FilterBlend::uses_background()
+{
+ if (_input == NR_FILTER_BACKGROUNDIMAGE || _input == NR_FILTER_BACKGROUNDALPHA ||
+ _input2 == NR_FILTER_BACKGROUNDIMAGE || _input2 == NR_FILTER_BACKGROUNDALPHA)
+ {
+ return true;
+ } else {
+ return false;
+ }
+}
+
void FilterBlend::set_input(int slot) {
_input = slot;
}
diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h
index 64b3c9284..957d3cfc8 100644
--- a/src/display/nr-filter-blend.h
+++ b/src/display/nr-filter-blend.h
@@ -39,6 +39,8 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
+ virtual bool uses_background();
virtual void set_input(int slot);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp
index 7eb2fa2e9..6fa34bf0b 100644
--- a/src/display/nr-filter-colormatrix.cpp
+++ b/src/display/nr-filter-colormatrix.cpp
@@ -192,6 +192,11 @@ void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*tr
{
}
+double FilterColorMatrix::complexity(Geom::Affine const &)
+{
+ return 2.0;
+}
+
void FilterColorMatrix::set_type(FilterColorMatrixType t){
type = t;
}
diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h
index df851e0aa..5864a010e 100644
--- a/src/display/nr-filter-colormatrix.h
+++ b/src/display/nr-filter-colormatrix.h
@@ -38,6 +38,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
virtual void set_type(FilterColorMatrixType type);
virtual void set_value(gdouble value);
diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp
index 80bc07df8..887352f62 100644
--- a/src/display/nr-filter-component-transfer.cpp
+++ b/src/display/nr-filter-component-transfer.cpp
@@ -308,6 +308,11 @@ void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Affine const
{
}
+double FilterComponentTransfer::complexity(Geom::Affine const &)
+{
+ return 2.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-component-transfer.h b/src/display/nr-filter-component-transfer.h
index 89bc61403..6d65ae6d1 100644
--- a/src/display/nr-filter-component-transfer.h
+++ b/src/display/nr-filter-component-transfer.h
@@ -38,6 +38,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
FilterComponentTransferType type[4];
std::vector<gdouble> tableValues[4];
diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp
index 694ccaec5..b25ecdf2c 100644
--- a/src/display/nr-filter-composite.cpp
+++ b/src/display/nr-filter-composite.cpp
@@ -139,6 +139,11 @@ void FilterComposite::set_arithmetic(double k1, double k2, double k3, double k4)
this->k4 = k4;
}
+double FilterComposite::complexity(Geom::Affine const &)
+{
+ return 1.1;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-composite.h b/src/display/nr-filter-composite.h
index 930898830..95579cc0e 100644
--- a/src/display/nr-filter-composite.h
+++ b/src/display/nr-filter-composite.h
@@ -28,6 +28,7 @@ public:
virtual void render_cairo(FilterSlot &);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
virtual void set_input(int input);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp
index 06e28b074..469baf346 100644
--- a/src/display/nr-filter-convolve-matrix.cpp
+++ b/src/display/nr-filter-convolve-matrix.cpp
@@ -212,6 +212,11 @@ void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Affine const &/*tra
area.y1 += orderY - targetY - 1;
}
+double FilterConvolveMatrix::complexity(Geom::Affine const &)
+{
+ return kernelMatrix.size();
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-convolve-matrix.h b/src/display/nr-filter-convolve-matrix.h
index d13738260..8b7fc35d1 100644
--- a/src/display/nr-filter-convolve-matrix.h
+++ b/src/display/nr-filter-convolve-matrix.h
@@ -36,6 +36,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
void set_targetY(int coord);
void set_targetX(int coord);
diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp
index eaed2a8bd..14144ace5 100644
--- a/src/display/nr-filter-diffuselighting.cpp
+++ b/src/display/nr-filter-diffuselighting.cpp
@@ -16,7 +16,6 @@
#include "display/cairo-templates.h"
#include "display/cairo-utils.h"
#include "display/nr-3dutils.h"
-#include "display/nr-arena-item.h"
#include "display/nr-filter-diffuselighting.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-units.h"
@@ -172,6 +171,11 @@ void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*t
area.y1 += 1;
}
+double FilterDiffuseLighting::complexity(Geom::Affine const &)
+{
+ return 9.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h
index 6e39242f6..bb3ceccb3 100644
--- a/src/display/nr-filter-diffuselighting.h
+++ b/src/display/nr-filter-diffuselighting.h
@@ -33,6 +33,7 @@ public:
virtual ~FilterDiffuseLighting();
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
union {
SPFeDistantLight *distant;
diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp
index 15200223b..75e310339 100644
--- a/src/display/nr-filter-displacement-map.cpp
+++ b/src/display/nr-filter-displacement-map.cpp
@@ -140,6 +140,11 @@ void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Affine const &tran
area.y1 += (int)(scaley)+2;
}
+double FilterDisplacementMap::complexity(Geom::Affine const &)
+{
+ return 3.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-displacement-map.h b/src/display/nr-filter-displacement-map.h
index aec4b7eb6..393a904c1 100644
--- a/src/display/nr-filter-displacement-map.h
+++ b/src/display/nr-filter-displacement-map.h
@@ -27,12 +27,14 @@ public:
static FilterPrimitive *create();
virtual ~FilterDisplacementMap();
+ virtual void render_cairo(FilterSlot &slot);
+ virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
+
virtual void set_input(int slot);
virtual void set_input(int input, int slot);
virtual void set_scale(double s);
virtual void set_channel_selector(int s, FilterDisplacementMapChannelSelector channel);
- virtual void render_cairo(FilterSlot &slot);
- virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
private:
double scale;
diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp
index a015d3f1f..5716c1bc5 100644
--- a/src/display/nr-filter-flood.cpp
+++ b/src/display/nr-filter-flood.cpp
@@ -86,6 +86,13 @@ void FilterFlood::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/)
{
}
+double FilterFlood::complexity(Geom::Affine const &)
+{
+ // flood is actually less expensive than normal rendering,
+ // but when flood is processed, the object has already been rendered
+ return 1.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h
index 6db90d439..f744e9f48 100644
--- a/src/display/nr-filter-flood.h
+++ b/src/display/nr-filter-flood.h
@@ -27,10 +27,14 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
+ virtual bool uses_background() { return false; }
+
virtual void set_opacity(double o);
virtual void set_color(guint32 c);
virtual void set_icc(SVGICCColor *icc_color);
- virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+
private:
double opacity;
guint32 color;
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp
index d240c1a43..8a7244e02 100644
--- a/src/display/nr-filter-gaussian.cpp
+++ b/src/display/nr-filter-gaussian.cpp
@@ -509,7 +509,7 @@ gaussian_pass_IIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_su
w, h, b, M, tmpdata, num_threads);
break;
default:
- assert(false);
+ g_warning("gaussian_pass_IIR: unsupported image format");
};
}
@@ -542,7 +542,7 @@ gaussian_pass_FIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_su
w, h, &kernel[0], scr_len, num_threads);
break;
default:
- assert(false);
+ g_warning("gaussian_pass_FIR: unsupported image format");
};
}
@@ -641,6 +641,13 @@ void FilterGaussian::render_cairo(FilterSlot &slot)
}
}
+ // free the temporary data
+ if ( use_IIR_x || use_IIR_y ) {
+ for(int i = 0; i < threads; ++i) {
+ delete[] tmpdata[i];
+ }
+ }
+
cairo_surface_mark_dirty(downsampled);
if (resampling) {
cairo_surface_t *upsampled = cairo_surface_create_similar(downsampled, cairo_surface_get_content(downsampled),
@@ -682,6 +689,13 @@ bool FilterGaussian::can_handle_affine(Geom::Affine const &)
return false;
}
+double FilterGaussian::complexity(Geom::Affine const &trans)
+{
+ int area_x = _effect_area_scr(_deviation_x * trans.expansionX());
+ int area_y = _effect_area_scr(_deviation_y * trans.expansionY());
+ return 2.0 * area_x * area_y;
+}
+
void FilterGaussian::set_deviation(double deviation)
{
if(IS_FINITE(deviation) && deviation >= 0) {
diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h
index 811502016..f52bea01e 100644
--- a/src/display/nr-filter-gaussian.h
+++ b/src/display/nr-filter-gaussian.h
@@ -37,6 +37,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &m);
virtual bool can_handle_affine(Geom::Affine const &m);
+ virtual double complexity(Geom::Affine const &ctm);
/**
* Set the standard deviation value for gaussian blur. Deviation along
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index 0cb7901b3..a22d23548 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -13,8 +13,9 @@
#include "document.h"
#include "sp-item.h"
#include "display/cairo-utils.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-item.h"
+#include "display/drawing-context.h"
+#include "display/drawing.h"
+#include "display/drawing-item.h"
#include "display/nr-filter.h"
#include "display/nr-filter-image.h"
#include "display/nr-filter-units.h"
@@ -69,21 +70,20 @@ void FilterImage::render_cairo(FilterSlot &slot)
// TODO: do not recreate the rendering tree every time
// TODO: the entire thing is a hack, we should give filter primitives an "update" method
- // like the one for NRArenaItems
+ // like the one for DrawingItems
document->ensureUpToDate();
- NRArena* arena = NRArena::create();
+ Drawing drawing;
Geom::OptRect optarea = SVGElem->getBounds(Geom::identity());
if (!optarea) return;
unsigned const key = SPItem::display_key_new(1);
- NRArenaItem* ai = SVGElem->invoke_show(arena, key, SP_ITEM_SHOW_DISPLAY);
-
+ DrawingItem *ai = SVGElem->invoke_show(drawing, key, SP_ITEM_SHOW_DISPLAY);
if (!ai) {
- g_warning("feImage renderer: error creating NRArenaItem for SVG Element");
- nr_object_unref((NRObject *) arena);
+ g_warning("feImage renderer: error creating DrawingItem for SVG Element");
return;
}
+ drawing.setRoot(ai);
Geom::Rect area = *optarea;
Geom::Affine pu2pb = slot.get_units().get_matrix_primitiveunits2pb();
@@ -94,30 +94,18 @@ void FilterImage::render_cairo(FilterSlot &slot)
Geom::Rect sa = slot.get_slot_area();
cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
sa.width(), sa.height());
- cairo_t *ct = cairo_create(out);
- cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]);
- ink_cairo_transform(ct, pu2pb); // we are now in primitive units
- cairo_translate(ct, feImageX, feImageY);
- cairo_scale(ct, scaleX, scaleY);
-
- NRRectL render_rect;
- render_rect.x0 = floor(area.left());
- render_rect.y0 = floor(area.top());
- render_rect.x1 = ceil(area.right());
- render_rect.y1 = ceil(area.bottom());
- cairo_translate(ct, render_rect.x0, render_rect.y0);
+ Inkscape::DrawingContext ct(out, sa.min());
+ ct.transform(pu2pb); // we are now in primitive units
+ ct.translate(feImageX, feImageY);
+ ct.scale(scaleX, scaleY);
+
+ Geom::IntRect render_rect = area.roundOutwards();
+ ct.translate(render_rect.min());
// Update to renderable state
- NRGC gc(NULL);
- Geom::Affine t = Geom::identity();
- nr_arena_item_set_transform(ai, &t);
- gc.transform.setIdentity();
- nr_arena_item_invoke_update(ai, NULL, &gc,
- NR_ARENA_ITEM_STATE_ALL,
- NR_ARENA_ITEM_STATE_NONE);
- nr_arena_item_invoke_render(ct, ai, &render_rect, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE);
+ drawing.update(render_rect);
+ drawing.render(ct, render_rect);
SVGElem->invoke_hide(key);
- nr_object_unref((NRObject*) arena);
slot.set(_output, out);
cairo_surface_destroy(out);
@@ -208,6 +196,12 @@ bool FilterImage::can_handle_affine(Geom::Affine const &)
return true;
}
+double FilterImage::complexity(Geom::Affine const &)
+{
+ // TODO: right now we cannot actually measure this in any meaningful way.
+ return 1.1;
+}
+
void FilterImage::set_href(const gchar *href){
if (feImageHref) g_free (feImageHref);
feImageHref = (href) ? g_strdup (href) : NULL;
diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h
index 0651109ec..5af0b3338 100644
--- a/src/display/nr-filter-image.h
+++ b/src/display/nr-filter-image.h
@@ -29,6 +29,8 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
+
void set_document( SPDocument *document );
void set_href(const gchar *href);
void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height);
diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp
index 51d3975cb..28ac19a19 100644
--- a/src/display/nr-filter-merge.cpp
+++ b/src/display/nr-filter-merge.cpp
@@ -67,6 +67,22 @@ bool FilterMerge::can_handle_affine(Geom::Affine const &)
return true;
}
+double FilterMerge::complexity(Geom::Affine const &)
+{
+ return 1.02;
+}
+
+bool FilterMerge::uses_background()
+{
+ for (int i = 0; i < _input_image.size(); ++i) {
+ int input = _input_image[i];
+ if (input == NR_FILTER_BACKGROUNDIMAGE || input == NR_FILTER_BACKGROUNDALPHA) {
+ return true;
+ }
+ }
+ return false;
+}
+
void FilterMerge::set_input(int slot) {
_input_image[0] = slot;
}
diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h
index 263fc8026..238f9a3e7 100644
--- a/src/display/nr-filter-merge.h
+++ b/src/display/nr-filter-merge.h
@@ -26,6 +26,8 @@ public:
virtual void render_cairo(FilterSlot &);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
+ virtual bool uses_background();
virtual void set_input(int input);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp
index c79667d3e..9e43d01f3 100644
--- a/src/display/nr-filter-morphology.cpp
+++ b/src/display/nr-filter-morphology.cpp
@@ -158,6 +158,13 @@ void FilterMorphology::area_enlarge(NRRectL &area, Geom::Affine const &trans)
area.y1 += enlarge_y;
}
+double FilterMorphology::complexity(Geom::Affine const &trans)
+{
+ int enlarge_x = ceil(xradius * trans.expansionX());
+ int enlarge_y = ceil(yradius * trans.expansionY());
+ return enlarge_x * enlarge_y;
+}
+
void FilterMorphology::set_operator(FilterMorphologyOperator &o){
Operator = o;
}
diff --git a/src/display/nr-filter-morphology.h b/src/display/nr-filter-morphology.h
index 5924085d9..512eca83c 100644
--- a/src/display/nr-filter-morphology.h
+++ b/src/display/nr-filter-morphology.h
@@ -33,6 +33,8 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
+
void set_operator(FilterMorphologyOperator &o);
void set_xradius(double x);
void set_yradius(double y);
diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp
index 3b0f83841..db8b6d92a 100644
--- a/src/display/nr-filter-offset.cpp
+++ b/src/display/nr-filter-offset.cpp
@@ -85,6 +85,11 @@ void FilterOffset::area_enlarge(NRRectL &area, Geom::Affine const &trans)
}
}
+double FilterOffset::complexity(Geom::Affine const &)
+{
+ return 1.02;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-offset.h b/src/display/nr-filter-offset.h
index 09c57f803..841be6008 100644
--- a/src/display/nr-filter-offset.h
+++ b/src/display/nr-filter-offset.h
@@ -29,6 +29,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
void set_dx(double amount);
void set_dy(double amount);
diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp
index 539e3e952..0a445b9e6 100644
--- a/src/display/nr-filter-primitive.cpp
+++ b/src/display/nr-filter-primitive.cpp
@@ -161,10 +161,6 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
return area;
}
-FilterTraits FilterPrimitive::get_input_traits() {
- return TRAIT_ANYTHING;
-}
-
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h
index ebecb91ec..501d76447 100644
--- a/src/display/nr-filter-primitive.h
+++ b/src/display/nr-filter-primitive.h
@@ -12,6 +12,7 @@
#define SEEN_NR_FILTER_PRIMITIVE_H
#include <2geom/forward.h>
+#include "display/nr-filter-types.h"
#include "svg/svg-length.h"
struct NRRectL;
@@ -22,24 +23,6 @@ namespace Filters {
class FilterSlot;
class FilterUnits;
-/*
- * Different filter effects need different types of inputs. This is what
- * traits are used for: one can specify, what special restrictions
- * there are for inputs.
- *
- * Example: gaussian blur requires that x- and y-axis of input image
- * are paraller to blurred object's x- and y-axis, respectively.
- * Otherwise blur wouldn't rotate with the object.
- *
- * Values here should be powers of two, so these can be used as bitfield.
- * That is: any combination ef existing traits can be specified. (excluding
- * TRAIT_ANYTHING, which is alias for no traits defined)
- */
-enum FilterTraits {
- TRAIT_ANYTHING = 0,
- TRAIT_PARALLER = 1
-};
-
class FilterPrimitive {
public:
FilterPrimitive();
@@ -81,6 +64,18 @@ public:
*/
virtual void set_output(int slot);
+ // returns cache score factor, reflecting the cost of rendering this filter
+ // this should return how many times slower this primitive is that normal rendering
+ virtual double complexity(Geom::Affine const &/*ctm*/) { return 1.0; }
+
+ virtual bool uses_background() {
+ if (_input == NR_FILTER_BACKGROUNDIMAGE || _input == NR_FILTER_BACKGROUNDALPHA) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
/**
* Sets the filter primitive subregion. Passing an unset length
* (length._set == false) WILL change the parameter as it is
@@ -103,14 +98,6 @@ public:
*/
Geom::Rect filter_primitive_area(FilterUnits const &units);
- /**
- * Queries the filter, which traits it needs from its input buffers.
- * At the time of writing this, only one trait was needed, having
- * user coordinate system and input pixelblock coordinates paraller to
- * each other.
- */
- virtual FilterTraits get_input_traits();
-
/** @brief Indicate whether the filter primitive can handle the given affine.
*
* Results of some filter primitives depend on the coordinate system used when rendering.
@@ -121,7 +108,7 @@ public:
* When any filter returns false, filter rendering is performed on an intermediate surface
* with edges parallel to the axes of the user coordinate system. This means
* the matrices from FilterUnits will contain at most a (possibly non-uniform) scale
- * and a translation. When all primitives of the filter return false, the rendering is
+ * and a translation. When all primitives of the filter return true, the rendering is
* performed in display coordinate space and no intermediate surface is used. */
virtual bool can_handle_affine(Geom::Affine const &) { return false; }
diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp
index 3464fda66..4f7a8849e 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -16,7 +16,7 @@
#include <2geom/transforms.h>
#include "display/cairo-utils.h"
-#include "display/nr-arena-item.h"
+#include "display/drawing-context.h"
#include "display/nr-filter-types.h"
#include "display/nr-filter-gaussian.h"
#include "display/nr-filter-slot.h"
@@ -25,13 +25,13 @@
namespace Inkscape {
namespace Filters {
-FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea,
- cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u)
+FilterSlot::FilterSlot(DrawingItem *item, DrawingContext *bgct,
+ DrawingContext &graphic, FilterUnits const &u)
: _item(item)
- , _source_graphic(graphic)
- , _background_ct(bgct)
- , _source_graphic_area(graphicarea)
- , _background_area(bgarea)
+ , _source_graphic(graphic.rawTarget())
+ , _background_ct(bgct ? bgct->raw() : NULL)
+ , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme
+ , _background_area(bgct ? bgct->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme
, _units(u)
, _last_out(NR_FILTER_SOURCEGRAPHIC)
, filterquality(FILTER_QUALITY_BEST)
@@ -41,19 +41,15 @@ FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea,
using Geom::Y;
// compute slot bbox
- Geom::Rect bbox(
- Geom::Point(_source_graphic_area->x0, _source_graphic_area->y0),
- Geom::Point(_source_graphic_area->x1, _source_graphic_area->y1));
-
Geom::Affine trans = _units.get_matrix_display2pb();
- Geom::Rect bbox_trans = bbox * trans;
+ Geom::Rect bbox_trans = graphic.targetLogicalBounds() * trans;
Geom::Point min = bbox_trans.min();
_slot_x = min[X];
_slot_y = min[Y];
if (trans.isTranslation()) {
- _slot_w = _source_graphic_area->x1 - _source_graphic_area->x0;
- _slot_h = _source_graphic_area->y1 - _source_graphic_area->y0;
+ _slot_w = _source_graphic_area.width();
+ _slot_h = _source_graphic_area.height();
} else {
_slot_w = ceil(bbox_trans.width());
_slot_h = ceil(bbox_trans.height());
@@ -143,7 +139,7 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic()
cairo_translate(tsg_ct, -_slot_x, -_slot_y);
ink_cairo_transform(tsg_ct, trans);
- cairo_translate(tsg_ct, _source_graphic_area->x0, _source_graphic_area->y0);
+ cairo_translate(tsg_ct, _source_graphic_area.left(), _source_graphic_area.top());
cairo_set_source_surface(tsg_ct, _source_graphic, 0, 0);
cairo_set_operator(tsg_ct, CAIRO_OPERATOR_SOURCE);
cairo_paint(tsg_ct);
@@ -156,19 +152,25 @@ cairo_surface_t *FilterSlot::_get_transformed_background()
{
Geom::Affine trans = _units.get_matrix_display2pb();
- cairo_surface_t *bg = cairo_get_group_target(_background_ct);
- cairo_surface_t *tbg = cairo_surface_create_similar(
- bg, cairo_surface_get_content(bg),
- _slot_w, _slot_h);
- cairo_t *tbg_ct = cairo_create(tbg);
+ cairo_surface_t *tbg;
- cairo_translate(tbg_ct, -_slot_x, -_slot_y);
- ink_cairo_transform(tbg_ct, trans);
- cairo_translate(tbg_ct, _background_area->x0, _background_area->y0);
- cairo_set_source_surface(tbg_ct, bg, 0, 0);
- cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(tbg_ct);
- cairo_destroy(tbg_ct);
+ if (_background_ct) {
+ cairo_surface_t *bg = cairo_get_group_target(_background_ct);
+ tbg = cairo_surface_create_similar(
+ bg, cairo_surface_get_content(bg),
+ _slot_w, _slot_h);
+ cairo_t *tbg_ct = cairo_create(tbg);
+
+ cairo_translate(tbg_ct, -_slot_x, -_slot_y);
+ ink_cairo_transform(tbg_ct, trans);
+ cairo_translate(tbg_ct, _background_area.left(), _background_area.top());
+ cairo_set_source_surface(tbg_ct, bg, 0, 0);
+ cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(tbg_ct);
+ cairo_destroy(tbg_ct);
+ } else {
+ tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w, _slot_h);
+ }
return tbg;
}
@@ -184,11 +186,11 @@ cairo_surface_t *FilterSlot::get_result(int res)
cairo_surface_t *r = cairo_surface_create_similar(_source_graphic,
cairo_surface_get_content(_source_graphic),
- _source_graphic_area->x1 - _source_graphic_area->x0,
- _source_graphic_area->y1 - _source_graphic_area->y0);
+ _source_graphic_area.width(),
+ _source_graphic_area.height());
cairo_t *r_ct = cairo_create(r);
- cairo_translate(r_ct, -_source_graphic_area->x0, -_source_graphic_area->y0);
+ cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top());
ink_cairo_transform(r_ct, trans);
cairo_translate(r_ct, _slot_x, _slot_y);
cairo_set_source_surface(r_ct, getcairo(res), 0, 0);
diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h
index 3b08743ed..d41b5180b 100644
--- a/src/display/nr-filter-slot.h
+++ b/src/display/nr-filter-slot.h
@@ -19,16 +19,17 @@
#include "display/nr-filter-types.h"
#include "display/nr-filter-units.h"
-struct NRArenaItem;
-
namespace Inkscape {
+class DrawingContext;
+class DrawingItem;
+
namespace Filters {
class FilterSlot {
public:
/** Creates a new FilterSlot object. */
- FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea,
- cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u);
+ FilterSlot(DrawingItem *item, DrawingContext *bgct,
+ DrawingContext &graphic, FilterUnits const &u);
/** Destroys the FilterSlot object and all its contents */
virtual ~FilterSlot();
@@ -66,12 +67,12 @@ public:
FilterUnits const &get_units() const { return _units; }
Geom::Rect get_slot_area() const;
- NRRectL const &get_sg_area() const { return *_source_graphic_area; }
+ NRRectL get_sg_area() const { NRRectL ret(_source_graphic_area); return ret; }
private:
typedef std::map<int, cairo_surface_t *> SlotMap;
SlotMap _slots;
- NRArenaItem *_item;
+ DrawingItem *_item;
//Geom::Rect _source_bbox; ///< bounding box of source graphic surface
//Geom::Rect _intermediate_bbox; ///< bounding box of intermediate surfaces
@@ -81,8 +82,8 @@ private:
double _slot_x, _slot_y;
cairo_surface_t *_source_graphic;
cairo_t *_background_ct;
- NRRectL const *_source_graphic_area;
- NRRectL const *_background_area; ///< needed to extract background
+ Geom::IntRect _source_graphic_area;
+ Geom::IntRect _background_area; ///< needed to extract background
FilterUnits const &_units;
int _last_out;
FilterQuality filterquality;
diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp
index 2e5f69d65..c28fd485a 100644
--- a/src/display/nr-filter-specularlighting.cpp
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -174,136 +174,6 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
-/*
-int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) {
- NRPixBlock *in = slot.get(_input);
- if (!in) {
- g_warning("Missing source image for feSpecularLighting (in=%d)", _input);
- return 1;
- }
-
- NRPixBlock *out = new NRPixBlock;
-
- //Fvector *L = NULL; //vector to the light
-
- int w = in->area.x1 - in->area.x0;
- int h = in->area.y1 - in->area.y0;
- int x0 = in->area.x0;
- int y0 = in->area.y0;
- int i, j;
- //As long as FilterRes and kernel unit is not supported we hardcode the
- //default value
- int dx = 1; //TODO setup
- int dy = 1; //TODO setup
- //surface scale
- Geom::Affine trans = units.get_matrix_primitiveunits2pb();
- gdouble ss = surfaceScale * trans[0];
- gdouble ks = specularConstant; //diffuse lighting constant
- NR::Fvector L, N, LC, H;
- gdouble inter;
-
- nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N,
- in->area.x0, in->area.y0, in->area.x1, in->area.y1,
- true);
- unsigned char *data_i = NR_PIXBLOCK_PX (in);
- unsigned char *data_o = NR_PIXBLOCK_PX (out);
- //No light, nothing to do
- switch (light_type) {
- case DISTANT_LIGHT:
- //the light vector is constant
- {
- DistantLight *dl = new DistantLight(light.distant, lighting_color);
- dl->light_vector(L);
- dl->light_components(LC);
- NR::normalized_sum(H, L, NR::EYE_VECTOR);
- //finish the work
- for (i = 0, j = 0; i < w*h; i++) {
- NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
- COMPUTE_INTER(inter, N, H, ks, specularExponent);
-
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); // CLAMP includes rounding!
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
- data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
- ++j;
- }
- out->empty = FALSE;
- delete dl;
- }
- break;
- case POINT_LIGHT:
- {
- PointLight *pl = new PointLight(light.point, lighting_color, trans);
- pl->light_components(LC);
- //TODO we need a reference to the filter to determine primitiveUnits
- //if objectBoundingBox is used, use a different matrix for light_vector
- // UPDATE: trans is now correct matrix from primitiveUnits to
- // pixblock coordinates
- //finish the work
- for (i = 0, j = 0; i < w*h; i++) {
- NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
- pl->light_vector(L,
- i % w + x0,
- i / w + y0,
- ss * (double) data_i[4*i+3]/ 255);
- NR::normalized_sum(H, L, NR::EYE_VECTOR);
- COMPUTE_INTER(inter, N, H, ks, specularExponent);
-
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
- data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
- ++j;
- }
- out->empty = FALSE;
- delete pl;
- }
- break;
- case SPOT_LIGHT:
- {
- SpotLight *sl = new SpotLight(light.spot, lighting_color, trans);
- //TODO we need a reference to the filter to determine primitiveUnits
- //if objectBoundingBox is used, use a different matrix for light_vector
- // UPDATE: trans is now correct matrix from primitiveUnits to
- // pixblock coordinates
- //finish the work
- for (i = 0, j = 0; i < w*h; i++) {
- NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
- sl->light_vector(L,
- i % w + x0,
- i / w + y0,
- ss * (double) data_i[4*i+3]/ 255);
- sl->light_components(LC, L);
- NR::normalized_sum(H, L, NR::EYE_VECTOR);
- COMPUTE_INTER(inter, N, H, ks, specularExponent);
-
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
- data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
- ++j;
- }
- out->empty = FALSE;
- delete sl;
- }
- break;
- //else unknown light source, doing nothing
- case NO_LIGHT:
- default:
- {
- if (light_type != NO_LIGHT)
- g_warning("unknown light source %d", light_type);
- out->empty = false;
- }
- }
-
- //finishing
- slot.set(_output, out);
- //nr_pixblock_release(in);
- //delete in;
- return 0;
-}*/
-
void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*trans*/)
{
// TODO: support kernelUnitLength
@@ -314,6 +184,11 @@ void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*
area.y1 += 1;
}
+double FilterSpecularLighting::complexity(Geom::Affine const &)
+{
+ return 9.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h
index 2fcb02588..8471b70b0 100644
--- a/src/display/nr-filter-specularlighting.h
+++ b/src/display/nr-filter-specularlighting.h
@@ -31,8 +31,10 @@ public:
FilterSpecularLighting();
static FilterPrimitive *create();
virtual ~FilterSpecularLighting();
+
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
union {
SPFeDistantLight *distant;
diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp
index b88386638..4aadde2aa 100644
--- a/src/display/nr-filter-tile.cpp
+++ b/src/display/nr-filter-tile.cpp
@@ -45,6 +45,11 @@ void FilterTile::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/)
{
}
+double FilterTile::complexity(Geom::Affine const &)
+{
+ return 1.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h
index 5c0a3e553..37e257f79 100644
--- a/src/display/nr-filter-tile.h
+++ b/src/display/nr-filter-tile.h
@@ -27,6 +27,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
};
} /* namespace Filters */
diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp
index 60d5ce872..f065ded11 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -388,6 +388,11 @@ void FilterTurbulence::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
+double FilterTurbulence::complexity(Geom::Affine const &)
+{
+ return 5.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h
index 8d3639543..0b451d355 100644
--- a/src/display/nr-filter-turbulence.h
+++ b/src/display/nr-filter-turbulence.h
@@ -45,6 +45,8 @@ public:
virtual ~FilterTurbulence();
virtual void render_cairo(FilterSlot &slot);
+ virtual double complexity(Geom::Affine const &ctm);
+ virtual bool uses_background() { return false; }
void set_baseFrequency(int axis, double freq);
void set_numOctaves(int num);
diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp
index a8686545a..baf4af45d 100644
--- a/src/display/nr-filter-units.cpp
+++ b/src/display/nr-filter-units.cpp
@@ -71,10 +71,10 @@ Geom::Affine FilterUnits::get_matrix_user2pb() const {
Geom::Affine u2pb = ctm;
if (paraller_axis || !automatic_resolution) {
- u2pb[0] = resolution_x / (filter_area->max()[X] - filter_area->min()[X]);
+ u2pb[0] = resolution_x / filter_area->width();
u2pb[1] = 0;
u2pb[2] = 0;
- u2pb[3] = resolution_y / (filter_area->max()[Y] - filter_area->min()[Y]);
+ u2pb[3] = resolution_y / filter_area->height();
u2pb[4] = ctm[4];
u2pb[5] = ctm[5];
}
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index 963d98654..450ce689d 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -38,8 +38,9 @@
#include "display/nr-filter-tile.h"
#include "display/nr-filter-turbulence.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-item.h"
+#include "display/drawing.h"
+#include "display/drawing-item.h"
+#include "display/drawing-context.h"
#include <2geom/affine.h>
#include <2geom/rect.h>
#include "svg/svg-length.h"
@@ -96,50 +97,38 @@ Filter::~Filter()
}
-int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area)
+int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct)
{
if (_primitive.empty()) {
// when no primitives are defined, clear source graphic
- cairo_set_source_rgba(graphic, 0,0,0,0);
- cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE);
- cairo_paint(graphic);
- cairo_set_operator(graphic, CAIRO_OPERATOR_OVER);
+ graphic.setSource(0,0,0,0);
+ graphic.setOperator(CAIRO_OPERATOR_SOURCE);
+ graphic.paint();
+ graphic.setOperator(CAIRO_OPERATOR_OVER);
return 1;
}
- FilterQuality const filterquality = (FilterQuality)item->arena->filterquality;
- int const blurquality = item->arena->blurquality;
+ FilterQuality const filterquality = (FilterQuality)item->drawing().filterQuality();
+ int const blurquality = item->drawing().blurQuality();
- Geom::Affine trans = item->ctm;
+ Geom::Affine trans = item->ctm();
- Geom::Rect item_bbox;
- {
- Geom::OptRect maybe_bbox = item->item_bbox;
- if (maybe_bbox.isEmpty()) {
- // Code below needs a bounding box
- return 1;
- }
- item_bbox = *maybe_bbox;
- }
- if (item_bbox.hasZeroArea()) {
- // It's no use to try and filter an empty object.
- return 1;
- }
- Geom::Rect filter_area = filter_effect_area(item_bbox);
+ Geom::OptRect filter_area = filter_effect_area(item->itemBounds());
+ if (!filter_area) return 1;
FilterUnits units(_filter_units, _primitive_units);
units.set_ctm(trans);
- units.set_item_bbox(item_bbox);
- units.set_filter_area(filter_area);
+ units.set_item_bbox(item->itemBounds());
+ units.set_filter_area(*filter_area);
std::pair<double,double> resolution
- = _filter_resolution(filter_area, trans, filterquality);
+ = _filter_resolution(*filter_area, trans, filterquality);
if (!(resolution.first > 0 && resolution.second > 0)) {
// zero resolution - clear source graphic and return
- cairo_set_source_rgba(graphic, 0,0,0,0);
- cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE);
- cairo_paint(graphic);
- cairo_set_operator(graphic, CAIRO_OPERATOR_OVER);
+ graphic.setSource(0,0,0,0);
+ graphic.setOperator(CAIRO_OPERATOR_SOURCE);
+ graphic.paint();
+ graphic.setOperator(CAIRO_OPERATOR_OVER);
return 1;
}
@@ -160,7 +149,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea
}
}
- FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_group_target(graphic), area, units);
+ FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgct, graphic, units);
slot.set_quality(filterquality);
slot.set_blurquality(blurquality);
@@ -168,11 +157,12 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea
_primitive[i]->render_cairo(slot);
}
+ Geom::Point origin = graphic.targetLogicalBounds().min();
cairo_surface_t *result = slot.get_result(_output_slot);
- cairo_set_source_surface(graphic, result, area->x0, area->y0);
- cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE);
- cairo_paint(graphic);
- cairo_set_operator(graphic, CAIRO_OPERATOR_OVER);
+ graphic.setSource(result, origin[Geom::X], origin[Geom::Y]);
+ graphic.setOperator(CAIRO_OPERATOR_SOURCE);
+ graphic.paint();
+ graphic.setOperator(CAIRO_OPERATOR_OVER);
cairo_surface_destroy(result);
return 0;
@@ -186,10 +176,12 @@ void Filter::set_primitive_units(SPFilterUnits unit) {
_primitive_units = unit;
}
-void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
+void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item) const {
+ NRRectL b(bbox);
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
- if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm);
+ if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm());
}
+ bbox = *b.upgrade_2geom();
/*
TODO: something. See images at the bottom of filters.svg with medium-low
@@ -204,7 +196,7 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
}
Geom::Rect item_bbox;
- Geom::OptRect maybe_bbox = item->item_bbox;
+ Geom::OptRect maybe_bbox = item->itemBounds();
if (maybe_bbox.isEmpty()) {
// Code below needs a bounding box
return;
@@ -212,9 +204,9 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
item_bbox = *maybe_bbox;
std::pair<double,double> res_low
- = _filter_resolution(item_bbox, item->ctm, filterquality);
+ = _filter_resolution(item_bbox, item->ctm(), filterquality);
//std::pair<double,double> res_full
- // = _filter_resolution(item_bbox, item->ctm, FILTER_QUALITY_BEST);
+ // = _filter_resolution(item_bbox, item->ctm(), FILTER_QUALITY_BEST);
double pixels_per_block = fmax(item_bbox.width() / res_low.first,
item_bbox.height() / res_low.second);
bbox.x0 -= (int)pixels_per_block;
@@ -224,39 +216,36 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
*/
}
-void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) {
- // Modifying empty bounding boxes confuses rest of the renderer, so
- // let's not do that.
- if (item_bbox.x0 > item_bbox.x1 || item_bbox.y0 > item_bbox.y1) return;
-
- Geom::Point min(item_bbox.x0, item_bbox.y0);
- Geom::Point max(item_bbox.x1, item_bbox.y1);
- Geom::Rect tmp_bbox(min, max);
+Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) {
- Geom::Rect enlarged = filter_effect_area(tmp_bbox);
- enlarged = enlarged * item->ctm;
+ Geom::OptRect enlarged = filter_effect_area(item_bbox);
+ if (enlarged) {
+ *enlarged *= item->ctm();
- item_bbox.x0 = floor(enlarged.min()[X]);
- item_bbox.y0 = floor(enlarged.min()[Y]);
- item_bbox.x1 = ceil(enlarged.max()[X]);
- item_bbox.y1 = ceil(enlarged.max()[Y]);
+ Geom::OptIntRect ret(enlarged->roundOutwards());
+ return ret;
+ } else {
+ return Geom::OptIntRect();
+ }
}
-Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
+Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox)
{
Geom::Point minp, maxp;
- double len_x = bbox.width();
- double len_y = bbox.height();
+ double len_x = bbox ? bbox->width() : 0;
+ double len_y = bbox ? bbox->height() : 0;
/* TODO: fetch somehow the object ex and em lengths */
_region_x.update(12, 6, len_x);
_region_y.update(12, 6, len_y);
_region_width.update(12, 6, len_x);
_region_height.update(12, 6, len_y);
if (_filter_units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) {
+ if (!bbox) return Geom::OptRect();
+
if (_region_x.unit == SVGLength::PERCENT) {
- minp[X] = bbox.min()[X] + _region_x.computed;
+ minp[X] = bbox->left() + _region_x.computed;
} else {
- minp[X] = bbox.min()[X] + _region_x.computed * len_x;
+ minp[X] = bbox->left() + _region_x.computed * len_x;
}
if (_region_width.unit == SVGLength::PERCENT) {
maxp[X] = minp[X] + _region_width.computed;
@@ -265,9 +254,9 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
}
if (_region_y.unit == SVGLength::PERCENT) {
- minp[Y] = bbox.min()[Y] + _region_y.computed;
+ minp[Y] = bbox->top() + _region_y.computed;
} else {
- minp[Y] = bbox.min()[Y] + _region_y.computed * len_y;
+ minp[Y] = bbox->top() + _region_y.computed * len_y;
}
if (_region_height.unit == SVGLength::PERCENT) {
maxp[Y] = minp[Y] + _region_height.computed;
@@ -283,10 +272,32 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
} else {
g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units");
}
- Geom::Rect area(minp, maxp);
+ Geom::OptRect area(minp, maxp);
return area;
}
+double Filter::complexity(Geom::Affine const &ctm)
+{
+ double factor = 1.0;
+ for (unsigned i = 0 ; i < _primitive.size() ; i++) {
+ if (_primitive[i]) {
+ double f = _primitive[i]->complexity(ctm);
+ factor += (f - 1.0);
+ }
+ }
+ return factor;
+}
+
+bool Filter::uses_background()
+{
+ for (unsigned i = 0 ; i < _primitive.size() ; i++) {
+ if (_primitive[i] && _primitive[i]->uses_background()) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* Constructor table holds pointers to static methods returning filter
* primitives. This table is indexed with FilterPrimitiveType, so that
* for example method in _constructor[NR_FILTER_GAUSSIANBLUR]
diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h
index e1d4c10e5..32e1df60b 100644
--- a/src/display/nr-filter.h
+++ b/src/display/nr-filter.h
@@ -21,19 +21,20 @@
#include "sp-filter-units.h"
#include "gc-managed.h"
-struct NRArenaItem;
-
namespace Inkscape {
+class DrawingContext;
+class DrawingItem;
+
namespace Filters {
-class Filter : public Inkscape::GC::Managed<> {
+class Filter {
public:
/** Given background state from @a bgct and an intermediate rendering from the surface
* backing @a graphic, modify the contents of the surface backing @a graphic to represent
* the results of filter rendering. @a bgarea and @a area specify bounding boxes
* of both surfaces in world coordinates; Cairo contexts are assumed to be in default state
* (0,0 = surface origin, no path, OVER operator) */
- int render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area);
+ int render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct);
/**
* Creates a new filter primitive under this filter object.
@@ -149,19 +150,25 @@ public:
* to be rendered so that after filtering, the original area is
* drawn correctly.
*/
- void area_enlarge(NRRectL &area, NRArenaItem const *item) const;
+ void area_enlarge(Geom::IntRect &area, Inkscape::DrawingItem const *item) const;
/**
* Given an item bounding box (in user coords), this function enlarges it
* to contain the filter effects region and transforms it to screen
* coordinates
*/
- void compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox);
+ Geom::OptIntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox);
/**
* Returns the filter effects area in user coordinate system.
* The given bounding box should be a bounding box as specified in
* SVG standard and in user coordinate system.
*/
- Geom::Rect filter_effect_area(Geom::Rect const &bbox);
+ Geom::OptRect filter_effect_area(Geom::OptRect const &bbox);
+
+ // returns cache score factor
+ double complexity(Geom::Affine const &ctm);
+
+ // says whether the filter accesses any of the background images
+ bool uses_background();
/** Creates a new filter with space for one filter element */
Filter();
diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp
index 72fa0c444..fa5dd0d98 100644
--- a/src/display/nr-style.cpp
+++ b/src/display/nr-style.cpp
@@ -13,6 +13,8 @@
#include "style.h"
#include "sp-paint-server.h"
#include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!)
+#include "display/drawing-context.h"
+#include "libnr/nr-rect.h"
void NRStyle::Paint::clear()
{
@@ -142,14 +144,15 @@ void NRStyle::set(SPStyle *style)
update();
}
-bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox)
+bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox)
{
// update fill pattern
if (!fill_pattern) {
switch (fill.type) {
- case PAINT_SERVER:
- fill_pattern = sp_paint_server_create_pattern(fill.server, ct, paintbox, fill.opacity);
- break;
+ case PAINT_SERVER: {
+ NRRect pb(paintbox);
+ fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), &pb, fill.opacity);
+ } break;
case PAINT_COLOR: {
SPColor const &c = fill.color;
fill_pattern = cairo_pattern_create_rgba(
@@ -162,19 +165,20 @@ bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox)
return true;
}
-void NRStyle::applyFill(cairo_t *ct)
+void NRStyle::applyFill(Inkscape::DrawingContext &ct)
{
- cairo_set_source(ct, fill_pattern);
- cairo_set_fill_rule(ct, fill_rule);
+ ct.setSource(fill_pattern);
+ ct.setFillRule(fill_rule);
}
-bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox)
+bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox)
{
if (!stroke_pattern) {
switch (stroke.type) {
- case PAINT_SERVER:
- stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct, paintbox, stroke.opacity);
- break;
+ case PAINT_SERVER: {
+ NRRect pb(paintbox);
+ stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), &pb, stroke.opacity);
+ } break;
case PAINT_COLOR: {
SPColor const &c = stroke.color;
stroke_pattern = cairo_pattern_create_rgba(
@@ -187,14 +191,14 @@ bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox)
return true;
}
-void NRStyle::applyStroke(cairo_t *ct)
+void NRStyle::applyStroke(Inkscape::DrawingContext &ct)
{
- cairo_set_source(ct, stroke_pattern);
- cairo_set_line_width(ct, stroke_width);
- cairo_set_line_cap(ct, line_cap);
- cairo_set_line_join(ct, line_join);
- cairo_set_miter_limit(ct, miter_limit);
- cairo_set_dash(ct, dash, n_dash, dash_offset);
+ ct.setSource(stroke_pattern);
+ ct.setLineWidth(stroke_width);
+ ct.setLineCap(line_cap);
+ ct.setLineJoin(line_join);
+ ct.setMiterLimit(miter_limit);
+ cairo_set_dash(ct.raw(), dash, n_dash, dash_offset); // fixme
}
void NRStyle::update()
diff --git a/src/display/nr-style.h b/src/display/nr-style.h
index e741e46b4..0ba6ce2c6 100644
--- a/src/display/nr-style.h
+++ b/src/display/nr-style.h
@@ -13,22 +13,25 @@
#define SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H
#include <cairo.h>
+#include <2geom/rect.h>
#include "color.h"
class SPColor;
class SPPaintServer;
class SPStyle;
-struct NRRect;
+namespace Inkscape {
+class DrawingContext;
+}
struct NRStyle {
NRStyle();
~NRStyle();
void set(SPStyle *);
- bool prepareFill(cairo_t *ct, NRRect *paintbox);
- bool prepareStroke(cairo_t *ct, NRRect *paintbox);
- void applyFill(cairo_t *ct);
- void applyStroke(cairo_t *ct);
+ bool prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox);
+ bool prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox);
+ void applyFill(Inkscape::DrawingContext &ct);
+ void applyStroke(Inkscape::DrawingContext &ct);
void update();
enum PaintType {
diff --git a/src/display/rendermode.h b/src/display/rendermode.h
index 8fc022bfb..cbd35de73 100644
--- a/src/display/rendermode.h
+++ b/src/display/rendermode.h
@@ -15,10 +15,10 @@ enum RenderMode {
RENDERMODE_OUTLINE
};
-enum ColorRenderMode {
- COLORRENDERMODE_NORMAL,
- COLORRENDERMODE_GRAYSCALE,
- COLORRENDERMODE_PRINT_COLORS_PREVIEW
+enum ColorMode {
+ COLORMODE_NORMAL,
+ COLORMODE_GRAYSCALE,
+ COLORMODE_PRINT_COLORS_PREVIEW
};
}
diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h
index 4c731e56b..415c36566 100644
--- a/src/display/sp-canvas-item.h
+++ b/src/display/sp-canvas-item.h
@@ -64,7 +64,7 @@ struct _SPCanvasItemClass : public GtkObjectClass {
double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
int (* event) (SPCanvasItem *item, GdkEvent *event);
- void (* visible_area_changed) (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area);
+ void (* viewbox_changed) (SPCanvasItem *item, Geom::IntRect const &new_area);
};
SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GType type, const gchar *first_arg_name, ...);
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 71f608118..7d6727ff3 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -689,7 +689,7 @@ static void sp_canvas_group_destroy (GtkObject *object);
static void sp_canvas_group_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
static double sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
static void sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf);
-static void sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area);
+static void sp_canvas_group_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area);
static SPCanvasItemClass *group_parent_class;
@@ -733,7 +733,7 @@ sp_canvas_group_class_init (SPCanvasGroupClass *klass)
item_class->update = sp_canvas_group_update;
item_class->render = sp_canvas_group_render;
item_class->point = sp_canvas_group_point;
- item_class->visible_area_changed = sp_canvas_group_visible_area_changed;
+ item_class->viewbox_changed = sp_canvas_group_viewbox_changed;
}
/**
@@ -878,15 +878,15 @@ sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf)
}
static void
-sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area)
+sp_canvas_group_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area)
{
SPCanvasGroup *group = SP_CANVAS_GROUP (item);
for (GList *list = group->items; list; list = list->next) {
SPCanvasItem *child = (SPCanvasItem *)list->data;
if (child->flags & SP_CANVAS_ITEM_VISIBLE) {
- if (SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed)
- SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed (child, old_area, new_area);
+ if (SP_CANVAS_ITEM_GET_CLASS (child)->viewbox_changed)
+ SP_CANVAS_ITEM_GET_CLASS (child)->viewbox_changed (child, new_area);
}
}
}
@@ -1234,8 +1234,8 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
/* Schedule redraw of new region */
sp_canvas_resize_tiles(canvas,canvas->x0,canvas->y0,canvas->x0+allocation->width,canvas->y0+allocation->height);
- if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed)
- SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area);
+ if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed)
+ SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed (canvas->root, new_area);
if (allocation->width > widget->allocation.width) {
sp_canvas_request_redraw (canvas,
@@ -1655,6 +1655,15 @@ static void sp_canvas_paint_single_buffer(SPCanvas *canvas, int x0, int y0, int
buf.is_empty = true;
//buf.ct = gdk_cairo_create(widget->window);
+ /*
+ cairo_t *xctt = gdk_cairo_create(widget->window);
+ cairo_translate(xctt, x0 - canvas->x0, y0 - canvas->y0);
+ cairo_set_source_rgb(xctt, 1,0,0);
+ cairo_rectangle(xctt, 0, 0, x1-x0, y1-y0);
+ cairo_fill(xctt);
+ cairo_destroy(xctt);
+ //*/
+
// create temporary surface
int w = x1 - x0;
int h = y1 - y0;
@@ -2168,8 +2177,8 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear,
canvas->y0 = iy;
sp_canvas_resize_tiles (canvas, canvas->x0, canvas->y0, canvas->x0+canvas->widget.allocation.width, canvas->y0+canvas->widget.allocation.height);
- if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed)
- SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area);
+ if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed)
+ SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed (canvas->root, new_area);
if (!clear) {
// scrolling without zoom; redraw only the newly exposed areas