summaryrefslogtreecommitdiffstats
path: root/src/display/canvas-arena.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/canvas-arena.cpp')
-rw-r--r--src/display/canvas-arena.cpp302
1 files changed, 101 insertions, 201 deletions
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++