diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-08-06 12:18:32 +0000 |
|---|---|---|
| committer | Krzysztof Kosiński <tweenk.pl@gmail.com> | 2011-08-06 12:18:32 +0000 |
| commit | 4dd33aa4d5c57706c7f64f63391174954160a308 (patch) | |
| tree | b9d4ea1278348836a718c5e6aaeaff9f82c790bf /src/display | |
| parent | Per-item render cache. (diff) | |
| download | inkscape-4dd33aa4d5c57706c7f64f63391174954160a308.tar.gz inkscape-4dd33aa4d5c57706c7f64f63391174954160a308.zip | |
Rewrite NRArenaItem hierarchy into C++
(bzr r10347.1.21)
Diffstat (limited to 'src/display')
35 files changed, 2213 insertions, 3323 deletions
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index 53f87efb1..1c51f19a0 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -25,8 +25,18 @@ ink_common_sources += \ display/curve.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 \ @@ -35,19 +45,9 @@ ink_common_sources += \ display/guideline.h \ display/nr-3dutils.cpp \ display/nr-3dutils.h \ + display/nr-arena.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/canvas-arena.cpp b/src/display/canvas-arena.cpp index 0f653a258..81416fefb 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -16,12 +16,15 @@ #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" +using namespace Inkscape; + enum { ARENA_EVENT, LAST_SIGNAL @@ -31,6 +34,7 @@ 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 double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); @@ -39,7 +43,7 @@ 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_update (NRArena *arena, DrawingItem *item, void *data); static void sp_canvas_arena_request_render (NRArena *arena, NRRectL *area, void *data); NRArenaEventVector carenaev = { @@ -105,10 +109,16 @@ sp_canvas_arena_init (SPCanvasArena *arena) arena->sticky = FALSE; arena->arena = NRArena::create(); + nr_object_ref(arena->arena); arena->arena->canvasarena = arena; - arena->root = NRArenaGroup::create(arena->arena); - nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE); - nr_arena_item_set_cache(arena->root, true); + arena->arena->item_deleted.connect( + sigc::bind<0>( + sigc::ptr_fun(&sp_canvas_arena_item_deleted), + arena)); + + arena->root = new DrawingGroup(arena->arena); + arena->root->setPickChildren(true); + arena->root->setCached(true); arena->active = NULL; @@ -120,22 +130,11 @@ 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); + delete arena->root; - nr_object_unref ((NRObject *) arena->arena); - arena->arena = NULL; - } + nr_active_object_remove_listener_by_data ((NRActiveObject *) arena->arena, arena); + nr_object_unref ((NRObject *) arena->arena); + arena->arena = NULL; if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -149,14 +148,12 @@ 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->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, reset); - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); - - Geom::OptIntRect b = arena->root->bbox; + Geom::OptIntRect b = arena->root->visualBounds(); if (b) { item->x1 = b->left() - 1; item->y1 = b->top() - 1; @@ -166,7 +163,7 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned 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->root->pick(arena->c, arena->arena->delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = GTK_WIDGET (item->canvas)->window; @@ -180,10 +177,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); @@ -193,6 +187,14 @@ 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 @@ -203,10 +205,8 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) Inkscape::DrawingContext ct(buf->ct, r->min()); - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &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, *r, 0); + arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, 0); + arena->root->render(ct, *r, 0); } static double @@ -214,11 +214,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, Geom::IntRect::infinite(), &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->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + DrawingItem *picked = arena->root->pick(p, arena->arena->delta, arena->sticky); arena->picked = picked; @@ -244,7 +241,7 @@ sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_ar 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); @@ -256,7 +253,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; @@ -264,9 +260,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, Geom::IntRect::infinite(), &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->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + arena->active = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); ret = sp_canvas_arena_send_event (arena, event); } break; @@ -274,7 +269,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; } @@ -285,8 +279,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, Geom::IntRect::infinite(), &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->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + new_arena = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = event->motion.window; @@ -300,9 +294,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); @@ -332,7 +324,7 @@ 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 (NRArena */*arena*/, DrawingItem */*item*/, void *data) { sp_canvas_item_request_update (SP_CANVAS_ITEM (data)); } @@ -373,7 +365,8 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR Geom::OptIntRect area = r.upgrade_2geom(); if (!area) return; Inkscape::DrawingContext ct(surface, area->min()); - nr_arena_item_invoke_render (ct, ca->root, *area, 0); + ca->root->update(Geom::IntRect::infinite(), ca->ctx, DrawingItem::STATE_ALL, 0); + ca->root->render(ct, *area, 0); } diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 4cfeccb5a..e63a524f2 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -15,9 +15,10 @@ #include <cairo.h> #include <2geom/rect.h> +#include "display/display-forward.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 @@ -38,19 +39,19 @@ struct _SPCanvasArena { Geom::Point c; // what is this? NRArena *arena; - NRArenaItem *root; - NRGC gc; + Inkscape::DrawingGroup *root; + Inkscape::UpdateContext ctx; - NRArenaItem *active; + Inkscape::DrawingItem *active; /* fixme: */ - NRArenaItem *picked; - gdouble delta; + Inkscape::DrawingItem *picked; + 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 288da829a..d7e7d72ab 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -11,9 +11,17 @@ struct SPCanvasGroup; struct SPCanvasGroupClass; class SPCurve; +class NRArena; + namespace Inkscape { class DrawingContext; class DrawingSurface; +class DrawingItem; +class DrawingGroup; +class DrawingImage; +class DrawingShape; +class DrawingGlyphs; +class DrawingText; namespace Display { class TemporaryItem; diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp new file mode 100644 index 000000000..2d40f0a83 --- /dev/null +++ b/src/display/drawing-group.cpp @@ -0,0 +1,141 @@ +/** + * @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-context.h" +#include "display/drawing-item.h" +#include "display/drawing-group.h" +#include "libnr/nr-values.h" +#include "nr-arena.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); +} + +void +DrawingGroup::setPickChildren(bool p) +{ + _pick_children = p; +} + +void +DrawingGroup::setStyle(SPStyle *style) +{ + _setStyleCommon(_style, style); +} + +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->rendermode == RENDERMODE_OUTLINE); + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + UpdateContext child_ctx(ctx); + if (_child_transform) { + child_ctx.ctm = *_child_transform * ctx.ctm; + } + 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; +} + +void +DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->render(ct, area, flags); + } +} + +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) +{ + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingItem *picked = i->pick(p, delta, false); + 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..f7d6a2be3 --- /dev/null +++ b/src/display/drawing-group.h @@ -0,0 +1,61 @@ +/** + * @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: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + 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..ea6f6ce3c --- /dev/null +++ b/src/display/drawing-image.cpp @@ -0,0 +1,263 @@ +/** + * @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-context.h" +#include "display/drawing-image.h" +#include "nr-arena.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; +} + +void +DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + if (!outline) { + if (!_pixbuf) return; + + 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(); + } +} + +/** 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) +{ + if (!_pixbuf) return NULL; + + bool outline = (_drawing->rendermode == RENDERMODE_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..570c10360 --- /dev/null +++ b/src/display/drawing-image.h @@ -0,0 +1,66 @@ +/** + * @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 void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + + 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..318ff28e7 --- /dev/null +++ b/src/display/drawing-item.cpp @@ -0,0 +1,620 @@ +/** + * @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 "display/cairo-utils.h" +#include "display/cairo-templates.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing-group.h" +#include "display/drawing-surface.h" +#include "nr-arena.h" +#include "nr-filter.h" +#include "preferences.h" +#include "style.h" + +namespace Inkscape { + +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) + , _visible(true) + , _sensitive(true) + , _cached(0) + , _propagate(0) +// , _renders_opacity(0) + , _clip_child(0) + , _mask_child(0) + , _pick_children(0) +{ + nr_object_ref(_drawing); +} + +DrawingItem::~DrawingItem() +{ + _drawing->item_deleted.emit(this); + //if (!_children.empty()) { + // g_warning("Removing item with children"); + //} + + // remove from the set of cached items + if (_cached) { + _drawing->cached_items.erase(this); + } + // 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(); + // we cannot call setClip(NULL) or setMask(NULL), + // because that would be an endless loop + if (_clip_child) { + _parent->_clip = NULL; + } else if (_mask_child) { + _parent->_mask = NULL; + } else { + ChildrenList::iterator ithis = _parent->_children.iterator_to(*this); + _parent->_children.erase(ithis); + } + _parent->_markForUpdate(STATE_ALL, false); + } + clearChildren(); + delete _transform; + delete _clip; + delete _mask; + delete _filter; + nr_object_unref(_drawing); +} + +DrawingItem * +DrawingItem::parent() const +{ + //if (_clip_child || _mask_child) + // return NULL; + + return _parent; +} + +void +DrawingItem::appendChild(DrawingItem *item) +{ + item->_parent = this; + _children.push_back(*item); + _markForUpdate(STATE_ALL, false); +} + +void +DrawingItem::prependChild(DrawingItem *item) +{ + item->_parent = this; + _children.push_front(*item); + _markForUpdate(STATE_ALL, false); +} + +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; + } + _children.clear_and_dispose(DeleteDisposer()); +} + +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(); +} + +void +DrawingItem::setSensitive(bool s) +{ + _sensitive = s; +} + +void +DrawingItem::setCached(bool c) +{ + _cached = c; + if (c) { + _drawing->cached_items.insert(this); + } else { + _drawing->cached_items.erase(this); + } + _markForUpdate(STATE_CACHE, false); +} + +void +DrawingItem::setClip(DrawingItem *item) +{ + _markForRendering(); + delete _clip; + _clip = item; + if (item) { + item->_parent = this; + item->_clip_child = true; + } + _markForUpdate(STATE_ALL, true); +} + +void +DrawingItem::setMask(DrawingItem *item) +{ + _markForRendering(); + delete _mask; + _mask = item; + if (item) { + item->_parent = this; + item->_mask_child = true; + } + _markForUpdate(STATE_ALL, true); +} + +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; +} + +void +DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + bool render_filters = (_drawing->rendermode == Inkscape::RENDERMODE_NORMAL); + bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + + // Set reset flags according to propagation status + if (_propagate) { + reset |= ~_state; + _propagate = FALSE; + } + _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; + } + + 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 + _state = _updateItem(area, child_ctx, flags, reset); + + // compute drawbox + if (_filter && render_filters && _item_bbox) { + _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); + } + } + + // update cache if enabled + if (_cached) { + Geom::OptIntRect cl = _drawing->cache_limit; + cl.intersectWith(_drawbox); + if (cl) { + if (_cache) { + // this takes care of invalidation on transform + _cache->resizeAndTransform(*cl, ctm_change); + } else { + _cache = new Inkscape::DrawingCache(*cl); + // the cache is initially dirty + } + } else { + // disable cache for this item - not visible + delete _cache; + _cache = NULL; + } + } + + // 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)) { + if (flags & ~STATE_CACHE) { + _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 + } +}; + +void +DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + bool render_filters = (_drawing->rendermode == Inkscape::RENDERMODE_NORMAL); + + /* If we are invisible, just return successfully */ + if (!_visible) return; + + if (outline) { + _renderOutline(ct, area, flags); + return; + } + + // carea is the bounding box for intermediate rendering. + Geom::OptIntRect carea = Geom::intersect(area, _drawbox); + if (!carea) return; + + // render from cache + if (_cached && _cache) { + if (_cache->paintFromCache(ct, *carea)) + return; + } + + // expand carea to contain the dependent area of filters. + if (_filter && render_filters) { + _filter->area_enlarge(*carea, this); + carea.intersectWith(_drawbox); + } + + // 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 + + /* 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) { + if (_cached && _cache) { + Inkscape::DrawingContext cachect(*_cache); + cachect.rectangle(area); + cachect.clip(); + + { // 1. clear the corresponding part of cache + Inkscape::DrawingContext::Save save(cachect); + cachect.setSource(0,0,0,0); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.paint(); + } + // 2. render to cache + _renderItem(cachect, *carea, flags); + // 3. copy from cache to output + Inkscape::DrawingContext::Save save(ct); + ct.rectangle(*carea); + ct.clip(); + ct.setSource(_cache); + ct.paint(); + // 4. mark as clean + _cache->markClean(area); + return; + } else { + _renderItem(ct, *carea, flags); + return; + } + } + + DrawingSurface intermediate(*carea); + DrawingContext ict(intermediate); + + // 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(); + _renderItem(ict, *carea, flags); + + // 4. Apply filter. + if (_filter && render_filters) { + _filter->render(this, ct, ict); + // 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(area); + cachect.clip(); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.setSource(&intermediate); + cachect.paint(); + _cache->markClean(area); + } + ct.setSource(&intermediate); + ct.paint(); + ct.setSource(0,0,0,0); + // the call above is to clear a ref on the intermediate surface held by ct +} + +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); + + // 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 +} + +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(); + } +} + +DrawingItem * +DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) +{ + // 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; + + if (!sticky && !(_visible && _sensitive)) + return NULL; + + if (!_bbox) return NULL; + Geom::Rect expanded(*_bbox); + expanded.expandBy(delta); + + if (expanded.contains(p)) { + return _pickItem(p, delta); + } + return NULL; +} + +void +DrawingItem::_markForRendering() +{ + bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + Geom::OptIntRect dirty = outline ? _bbox : _drawbox; + if (!dirty) return; + + // dirty the caches of all parents + for (DrawingItem *i = this; i; i = i->_parent) { + if (i->_cached && i->_cache) { + i->_cache->markDirty(*dirty); + } + } + + nr_arena_request_render_rect (_drawing, dirty); +} + +void +DrawingItem::_markForUpdate(unsigned flags, bool propagate) +{ + // here we can't simply assign because a previous markForUpdate call + // could have had propagate=true even if this one has propagate=false + if (propagate) + _propagate = true; + + if (_state & flags) { + _state &= ~flags; + if (_parent) { + _parent->_markForUpdate(flags, false); + } else { + nr_arena_request_update (_drawing, 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 + && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { + _background_new = 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-item.h b/src/display/drawing-item.h new file mode 100644 index 000000000..b34ddf0e4 --- /dev/null +++ b/src/display/drawing-item.h @@ -0,0 +1,168 @@ +/** + * @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 <exception> +#include <boost/intrusive/list.hpp> +#include <2geom/rect.h> +#include <2geom/affine.h> + +class NRArena; +class SPStyle; +void nr_arena_set_cache_limit(NRArena *, Geom::OptIntRect const &); + +namespace Inkscape { + +typedef ::NRArena Drawing; +class DrawingContext; +class DrawingCache; +class DrawingItem; +namespace Filters { class Filter; } + +struct UpdateContext { + Geom::Affine ctm; +}; + +class InvalidItemException : public std::exception { + virtual const char *what() const throw() { + return "Invalid item in drawing"; + } +}; + +typedef boost::intrusive::list_base_hook<> ChildrenListHook; + +class DrawingItem + : public ChildrenListHook +{ +public: + enum RenderFlags { + RENDER_DEFAULT = 0, + RENDER_CACHE_ONLY = 1, + RENDER_BYPASS_CACHE = 2 + }; + enum StateFlags { + STATE_NONE = 0, + STATE_BBOX = (1<<0), // geometric bounding box is up-to-date + STATE_DRAWBOX = (1<<1), // visual bounding box is up-to-date + STATE_CACHE = (1<<2), // cache extents and clean area are up-to-date + STATE_PICK = (1<<3), // can process pick requests + STATE_RENDER = (1<<4), // can be rendered + STATE_ALL = (1<<5)-1 + }; + typedef boost::intrusive::list<DrawingItem> ChildrenList; + + 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; + + 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); + + 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); + void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); + void clip(DrawingContext &ct, Geom::IntRect const &area); + DrawingItem *pick(Geom::Point const &p, double delta, bool sticky); + +protected: + void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + void _markForUpdate(unsigned state, bool propagate); + void _markForRendering(); + void _setStyleCommon(SPStyle *&_style, SPStyle *style); + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset) { return 0; } + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta) { return NULL; } + virtual bool _canClip() { return false; } + + Drawing *_drawing; + DrawingItem *_parent; + ChildrenList _children; + + unsigned _key; ///< Some SPItems can have more than one NRArenaItem; + /// 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 + Geom::OptIntRect _drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks + Geom::OptRect _item_bbox; ///< 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; + + unsigned _state : 8; + unsigned _visible : 1; + unsigned _sensitive : 1; ///< Whether this item responds to events + unsigned _cached : 1; ///< Whether the rendering is stored for reuse + 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 _clip_child : 1; ///< If set, this is not a child of _parent, but a clipping path + unsigned _mask_child : 1; ///< If set, this is not a child of _parent, but a mask + unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(), + /// otherwise the group is returned + + // temporary hacks until I rewrite NRArena to Inkscape::Drawing + friend class NRArena; + friend void ::nr_arena_set_cache_limit(NRArena *, Geom::OptIntRect const &); +}; + +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..1a56eea9b --- /dev/null +++ b/src/display/drawing-shape.cpp @@ -0,0 +1,340 @@ +/** + * @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-context.h" +#include "display/drawing-group.h" +#include "display/drawing-shape.h" +#include "display/nr-arena.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); +} + +void +DrawingShape::setPaintBox(Geom::Rect const &box) +{ + _paintbox = box; + _markForUpdate(STATE_ALL, false); +} + +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->rendermode == RENDERMODE_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; +} + +void +DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (!_curve || !_style) return; + if (!area.intersects(_bbox)) return; // skip if not within bounding box + + bool outline = (_drawing->rendermode == RENDERMODE_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, _paintbox); + has_stroke = _nrstyle.prepareStroke(ct, _paintbox); + 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); + } +} + +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) +{ + if (_repick_after > 0) + --_repick_after; + + if (_repick_after > 0) // we are a slow, huge path. skip this pick, returning what was returned last time + return _last_pick; + + if (!_curve) return NULL; + if (!_style) return NULL; + + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + if (SP_SCALE24_TO_FLOAT(_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 (_nrstyle.stroke.type != NRStyle::PAINT_NONE && _nrstyle.stroke.opacity > 1e-3) { + 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 = (_nrstyle.fill.type != NRStyle::PAINT_NONE + && _nrstyle.fill.opacity > 1e-3 && !outline); + + if (_drawing->canvasarena) { + Geom::Rect viewbox = _drawing->canvasarena->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 (!_style->fill_rule.computed) { + if (wind != 0) { + _last_pick = this; + return this; + } + } else { + if (wind & 0x1) { + _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, false); + 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..7fd16374e --- /dev/null +++ b/src/display/drawing-shape.h @@ -0,0 +1,64 @@ +/** + * @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); + void setPaintBox(Geom::Rect const &box); + +protected: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual bool _canClip(); + + SPCurve *_curve; + SPStyle *_style; + NRStyle _nrstyle; + + Geom::OptRect _paintbox; + 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-text.cpp b/src/display/drawing-text.cpp new file mode 100644 index 000000000..784888bd7 --- /dev/null +++ b/src/display/drawing-text.cpp @@ -0,0 +1,275 @@ +/** + * @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-context.h" +#include "display/drawing-surface.h" +#include "display/drawing-text.h" +#include "display/nr-arena.h" +#include "helper/geom.h" +#include "libnrtype/font-instance.h" +#include "style.h" + +namespace Inkscape { + +DrawingGlyphs::DrawingGlyphs(Drawing *drawing) + : DrawingItem(drawing) + , _glyph_transform(NULL) + , _font(NULL) + , _glyph(0) +{} + +DrawingGlyphs::~DrawingGlyphs() +{ + if (_font) { + _font->Unref(); + _font = NULL; + } + delete _glyph_transform; +} + +void +DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &trans) +{ + _markForRendering(); + + if (trans.isIdentity()) { + delete _glyph_transform; // delete NULL; is safe + _glyph_transform = NULL; + } else { + _glyph_transform = new Geom::Affine(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; + Geom::Affine t = _glyph_transform ? *_glyph_transform * ctx.ctm : ctx.ctm; + _x = t[4]; + _y = t[5]; + + b = bounds_exact_transformed(*_font->PathVector(_glyph), t); + 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) +{ + 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); +} + +void +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (_drawing->rendermode == RENDERMODE_OUTLINE) { + DrawingContext::Save save(ct); + guint32 rgba = _drawing->outlinecolor; + ct.setSource(rgba); + ct.setTolerance(1.25); // low quality, but good enough for outline mode + ct.newPath(); + ct.transform(_ctm); + + 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->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + ct.fill(); + } + return; + } + + // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding + bool has_stroke, has_fill; + + Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + + 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->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + 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 + } +} + +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); + } + } + ct.transform(_ctm); + + 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->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + } + ct.fill(); +} + +DrawingItem * +DrawingText::_pickItem(Geom::Point const &p, double delta) +{ + DrawingItem *picked = DrawingGroup::_pickItem(p, delta); + 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..58fecc067 --- /dev/null +++ b/src/display/drawing-text.h @@ -0,0 +1,84 @@ +/** + * @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); + + Geom::Affine *_glyph_transform; + font_instance *_font; + int _glyph; + float _x, _y; + + 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: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + 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/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 99b0a004e..000000000 --- a/src/display/nr-arena-glyphs.cpp +++ /dev/null @@ -1,439 +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 <cairo.h> -#include <2geom/affine.h> -#include <2geom/rect.h> -#include "libnr/nr-convert2geom.h" -#include "style.h" -#include "display/nr-arena.h" -#include "display/nr-arena-glyphs.h" -#include "display/cairo-utils.h" -#include "display/drawing-context.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, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); -static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &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->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, Geom::IntRect const &/*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 = b->roundOutwards(); - } else { - item->bbox = Geom::OptIntRect(); - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -static NRArenaItem * -nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int /*sticky*/) -{ - NRArenaGlyphs *glyphs; - - glyphs = NR_ARENA_GLYPHS(item); - - if (!glyphs->font ) return NULL; - if (!item->bbox) return NULL; - - // With text we take a simple approach: pick if the point is in a characher bbox - Geom::Rect expanded(*item->bbox); - expanded.expandBy(delta); - if (expanded.contains(p)) - 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, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &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; -} - -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, Geom::IntRect const &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(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int /*flags*/) -{ - NRArenaItem *child = 0; - - NRArenaGroup *group = NR_ARENA_GROUP(item); - NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - - if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - Inkscape::DrawingContext::Save save(ct); - guint32 rgba = item->arena->outlinecolor; - ct.setSource(rgba); - ct.setTolerance(1.25); // low quality, but good enough for outline mode - ct.newPath(); - ct.transform(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; - - Inkscape::DrawingContext::Save save(ct); - ct.transform(transform); - ct.path(*pathv); - ct.fill(); - } - return item->state; - } - - // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding - bool has_stroke, has_fill; - - Inkscape::DrawingContext::Save save(ct); - ct.transform(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); - - Inkscape::DrawingContext::Save save(ct); - ct.transform(g->g_transform); - ct.path(pathv); - } - - if (has_fill) { - ggroup->nrstyle.applyFill(ct); - ct.fillPreserve(); - } - if (has_stroke) { - ggroup->nrstyle.applyStroke(ct); - ct.strokePreserve(); - } - ct.newPath(); // clear path - } // has fill or stroke pattern - - return item->state; -} - -static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) -{ - NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - - Inkscape::DrawingContext::Save save(ct); - - // handle clip-rule - if (ggroup->style) { - if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); - } else { - ct.setFillRule(CAIRO_FILL_RULE_WINDING); - } - } - ct.transform(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); - - Inkscape::DrawingContext::Save save(ct); - ct.transform(g->g_transform); - ct.path(pathv); - } - ct.fill(); - - return item->state; -} - -static NRArenaItem * -nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &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); - - gg->paintbox = pbox->upgrade_2geom(); - - 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 4b2aed7b9..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 { - Geom::OptRect 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 1f7c421d0..000000000 --- a/src/display/nr-arena-group.cpp +++ /dev/null @@ -1,300 +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" -#include "display/drawing-context.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, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static unsigned int nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point const &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, Geom::IntRect const &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 = Geom::OptIntRect(); - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - if (child->visible) - item->bbox.unionWith(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 (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, 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, flags); - if (ret & NR_ARENA_ITEM_STATE_INVALID) break; - } - - return ret; -} - -static unsigned int -nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &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 const &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 5336fcda9..000000000 --- a/src/display/nr-arena-image.cpp +++ /dev/null @@ -1,390 +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/drawing-context.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, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_image_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point const &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, Geom::IntRect const &/*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) { - Geom::Rect r = nr_arena_image_rect(image) * gc->transform; - item->bbox = r.roundOutwards(); - } else { - item->bbox = Geom::OptIntRect(); - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -static unsigned int nr_arena_image_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/, unsigned int /*flags*/ ) -{ - 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. - Inkscape::DrawingContext::Save save(ct); - ct.transform(image->ctm); - ct.newPath(); - ct.rectangle(image->clipbox); - ct.clip(); - - ct.translate(image->ox, image->oy); - ct.scale(image->sx, image->sy); - ct.setSource(image->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(((double) item->opacity) / 255.0); - - } 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(image->ctm); - ct.newPath(); - - 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); - - 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 item->state; -} - -/** Calculates the closest distance from p to the segment a1-a2*/ -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); -} - -static NRArenaItem * -nr_arena_image_pick( NRArenaItem *item, Geom::Point const &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 264b8ab10..000000000 --- a/src/display/nr-arena-item.cpp +++ /dev/null @@ -1,932 +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/drawing-context.h" -#include "display/drawing-surface.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->render_cache = FALSE; - - item->transform = NULL; - item->clip = NULL; - item->mask = NULL; - item->cache = NULL; - item->data = NULL; - item->filter = NULL; - item->background_new = false; -} - -static void -nr_arena_item_private_finalize (NRObject *object) -{ - NRArenaItem *item = static_cast < NRArenaItem * >(object); - - item->transform = NULL; - - if (item->clip) - nr_arena_item_detach(item, item->clip); - if (item->mask) - nr_arena_item_detach(item, item->mask); - delete item->cache; - - ((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, Geom::IntRect const &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 (item->state & NR_ARENA_ITEM_STATE_BBOX) { - // we have up-to-date bbox - if (!area.intersects(outline ? item->bbox : item->drawbox)) - return item->state; - } - - /* Set up local gc */ - childgc = *gc; - if (item->transform) { - childgc.transform = (*item->transform) * childgc.transform; - } - /* Remember the transformation matrix */ - Geom::Affine ctm_change = item->ctm.inverse() * childgc.transform; - 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 = item->filter->compute_drawbox(item, *item->item_bbox); - } else { - item->drawbox = 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) { - item->bbox.unionWith(item->clip->bbox); - } else { - item->drawbox.intersectWith(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) { - item->bbox.unionWith(item->mask->bbox); - } else { - // for masking, we need full drawbox of mask - item->drawbox.intersectWith(item->mask->drawbox); - } - } - - // update cache if enabled - if (item->render_cache) { - Geom::OptIntRect cl = item->arena->cache_limit; - cl.intersectWith(item->drawbox); - if (cl) { - if (item->cache) { - // this takes care of invalidation on transform - item->cache->resizeAndTransform(*cl, ctm_change); - } else { - item->cache = new Inkscape::DrawingCache(*cl); - // the cache is initially dirty - } - } else { - // disable cache for this item - not visible - delete item->cache; - item->cache = NULL; - } - } - - // 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 - if (state & ~NR_ARENA_ITEM_STATE_CACHE) { - 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 (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, - 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 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 - Geom::OptIntRect carea = Geom::intersect(area, item->bbox); - if (!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, 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, 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, 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. - Geom::OptIntRect carea = Geom::intersect(area, item->drawbox); - if (!carea) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - - // render from cache - if (item->render_cache && item->cache) { - if(item->cache->paintFromCache(ct, *carea)) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } - - // expand carea to contain the dependent area of filters. - if (item->filter && filter) { - item->filter->area_enlarge(*carea, item); - carea.intersectWith(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) { - if (item->render_cache && item->cache) { - Inkscape::DrawingContext cachect(*item->cache); - cachect.rectangle(area); - cachect.clip(); - - { // 1. clear the corresponding part of cache - Inkscape::DrawingContext::Save save(cachect); - cachect.setSource(0,0,0,0); - cachect.setOperator(CAIRO_OPERATOR_SOURCE); - cachect.paint(); - } - // 2. render to cache - state = NR_ARENA_ITEM_VIRTUAL (item, render) (cachect, item, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - // 3. copy from cache to output - Inkscape::DrawingContext::Save save(ct); - ct.rectangle(*carea); - ct.clip(); - ct.setSource(item->cache); - ct.paint(); - // 4. mark as clean - item->cache->markClean(area); - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } else { - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, 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; - } - } - - DrawingSurface intermediate(*carea); - DrawingContext ict(intermediate); - - // 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 (item->clip) { - state = nr_arena_item_invoke_clip(ict, item->clip, *carea); // fixme: carea or 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. - ict.paint(); - } - // reset back to default - ict.setOperator(CAIRO_OPERATOR_OVER); - - // 2. Render the mask if present and compose it with the clipping path + opacity. - if (item->mask) { - ict.pushGroup(); - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); - goto cleanup; - } - 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(); - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, *carea, 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) { - item->filter->render(item, ct, ict); - // 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 (item->render_cache && item->cache) { - DrawingContext cachect(*item->cache); - cachect.rectangle(area); - cachect.clip(); - cachect.setOperator(CAIRO_OPERATOR_SOURCE); - cachect.setSource(&intermediate); - cachect.paint(); - item->cache->markClean(area); - } - ct.setSource(&intermediate); - ct.paint(); - ct.setSource(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: - return retstate; -} - -unsigned int -nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &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); - - 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 && area.intersects(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) { - ct.pushAlphaGroup(); - { Inkscape::DrawingContext::Save save(ct); - ct.setSource(0,0,0,1); - nr_arena_item_invoke_clip(ct, item->clip, area); - } - ct.pushAlphaGroup(); - } - - // rasterize the clipping path - retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - clip (ct, item, area); - - if (item->clip) { - ct.popGroupToSource(); - ct.setOperator(CAIRO_OPERATOR_IN); - ct.paint(); - ct.popGroupToSource(); - ct.setOperator(CAIRO_OPERATOR_SOURCE); - ct.paint(); - } - } - - return retstate; -} - -NRArenaItem * -nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &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; - - if (!item->bbox) return NULL; - Geom::Rect expanded(*item->bbox); - expanded.expandBy(delta); - - if (expanded.contains(p)) { - 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); - Geom::OptIntRect dirty = outline ? item->bbox : item->drawbox; - if (!dirty) return; - - // dirty the caches of all parents - for (NRArenaItem *i = item; i; i = i->parent) { - if (i->render_cache && i->cache) { - i->cache->markDirty(*dirty); - } - } - - nr_arena_request_render_rect (item->arena, dirty); -} - -/* 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)) { - // mark the area where the object was for redraw. - 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; - } - // when update is called, the area where the object was moved - // will be redrawn as well - 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 const &bbox) -{ - nr_return_if_fail(item != NULL); - nr_return_if_fail(NR_IS_ARENA_ITEM(item)); - - item->item_bbox = bbox; -} - -void -nr_arena_item_set_cache (NRArenaItem *item, bool cache) -{ - if (cache) { - item->render_cache = TRUE; - item->arena->cached_items.insert(item); - } else { - item->render_cache = FALSE; - item->arena->cached_items.erase(item); - } - nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -/** 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 2c00c0bf3..000000000 --- a/src/display/nr-arena-item.h +++ /dev/null @@ -1,205 +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 { -class DrawingContext; -class DrawingCache; -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_CACHE (1 << 9) - -#define NR_ARENA_ITEM_STATE_NONE 0x0000 -#define NR_ARENA_ITEM_STATE_ALL 0x03fe - -#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) -#define NR_ARENA_ITEM_RENDER_CACHE (1 << 1) - -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 state : 16; - /* Opacity itself */ - unsigned opacity : 8; - unsigned propagate : 1; - unsigned sensitive : 1; - unsigned visible : 1; - /* Whether items renders opacity itself */ - unsigned render_opacity : 1; - unsigned render_cache : 1; - - unsigned int key; ///< Some SPItems can have more than one NRArenaItem, - ///this value is a hack used to distinguish between them - - Geom::OptIntRect bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin - Geom::OptIntRect 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 - Inkscape::DrawingCache *cache; ///< Render cache - - void *data; ///< Anonymous data member - this is used to associate SPItems with arena items - - 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, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); - unsigned int (* render) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); - unsigned int (* clip) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); - NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point const &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, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); - -unsigned int nr_arena_item_invoke_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); - -unsigned int nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &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 const &bbox); -void nr_arena_item_set_cache (NRArenaItem *item, bool cache); - -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 ff985550c..000000000 --- a/src/display/nr-arena-shape.cpp +++ /dev/null @@ -1,565 +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/drawing-context.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, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &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->markers = NULL; - shape->last_pick = NULL; - shape->repick_after = 0; -} - -static void -nr_arena_shape_finalize(NRObject *object) -{ - NRArenaShape *shape = (NRArenaShape *) object; - - 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, Geom::IntRect const &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 = boundingbox->roundOutwards(); - } else { - item->bbox = Geom::OptIntRect(); - } - } - if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - item->bbox.unionWith(child->bbox); - } - } - } - return (state | item->state); - } - - 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->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); - } - } - } - - item->bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect(); - - 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) { - item->bbox.unionWith(child->bbox); - } - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -// cairo outline rendering: -static unsigned int -cairo_arena_shape_render_outline(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - - guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor; - - { Inkscape::DrawingContext::Save save(ct); - ct.transform(shape->ctm); - ct.path(shape->curve->get_pathvector()); - } - { Inkscape::DrawingContext::Save save(ct); - ct.setSource(rgba); - ct.setLineWidth(0.5); - ct.setTolerance(1.25); - ct.stroke(); - } - - return item->state; -} - -/** - * Renders the item. Markers are just composed into the parent buffer. - */ -static unsigned int -nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - - if (!shape->curve) return item->state; - if (!shape->style) return item->state; - - // skip if not within bounding box - if (!area.intersects(item->bbox)) { - return item->state; - } - - bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - if (outline) { - // cairo outline rendering - unsigned int ret = cairo_arena_shape_render_outline (ct, item, area); - if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } else { - bool has_stroke, has_fill; - // we assume the context has no path - Inkscape::DrawingContext::Save save(ct); - ct.transform(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 - ct.path(shape->curve->get_pathvector()); - if (has_fill) { - shape->nrstyle.applyFill(ct); - ct.fillPreserve(); - } - if (has_stroke) { - shape->nrstyle.applyStroke(ct); - ct.strokePreserve(); - } - ct.newPath(); // clear path - } // has fill or stroke pattern - } - - // marker rendering - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - unsigned int ret = nr_arena_item_invoke_render(ct, child, area, flags); - if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } - - return item->state; -} - - -static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - if (!shape->curve) { - return item->state; - } - - Inkscape::DrawingContext::Save save(ct); - // handle clip-rule - if (shape->style) { - if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); - } else { - ct.setFillRule(CAIRO_FILL_RULE_WINDING); - } - } - ct.transform(shape->ctm); - ct.path(shape->curve->get_pathvector()); - ct.fill(); - - return item->state; -} - -static NRArenaItem * -nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &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); - - shape->paintbox = pbox->upgrade_2geom(); - - nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void NRArenaShape::setPaintBox(Geom::Rect const &pbox) -{ - paintbox = pbox; - - 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 317cff7fb..000000000 --- a/src/display/nr-arena-shape.h +++ /dev/null @@ -1,72 +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; - Geom::OptRect paintbox; - - /* 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 index 735d44e9e..b3e962201 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -12,13 +12,14 @@ * 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 "display/drawing-item.h" +#include "display/nr-arena.h" +#include "display/nr-filter-gaussian.h" +#include "display/nr-filter-types.h" #include "preferences.h" #include "color.h" #include "libnr/nr-rect.h" +#include "libnr/nr-rect-l.h" static void nr_arena_class_init (NRArenaClass *klass); static void nr_arena_init (NRArena *arena); @@ -58,7 +59,7 @@ 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->colormode = Inkscape::COLORMODE_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 @@ -72,14 +73,14 @@ nr_arena_finalize (NRObject *object) } void -nr_arena_request_update (NRArena *arena, NRArenaItem *item) +nr_arena_request_update (NRArena *arena, Inkscape::DrawingItem *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(); @@ -89,7 +90,7 @@ nr_arena_request_update (NRArena *arena, NRArenaItem *item) arena->blurquality = BLUR_QUALITY_BEST; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; arena->rendermode = Inkscape::RENDERMODE_NORMAL; - arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; + arena->colormode = Inkscape::COLORMODE_NORMAL; } if (aobject->callbacks) { @@ -121,7 +122,7 @@ nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area) arena->blurquality = BLUR_QUALITY_BEST; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; arena->rendermode = Inkscape::RENDERMODE_NORMAL; - arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; + arena->colormode = Inkscape::COLORMODE_NORMAL; } NRRectL nr_area(*area); if (aobject->callbacks) { @@ -155,10 +156,10 @@ void nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit) { arena->cache_limit = cache_limit; - for (std::set<NRArenaItem *>::iterator i = arena->cached_items.begin(); + for (std::set<Inkscape::DrawingItem *>::iterator i = arena->cached_items.begin(); i != arena->cached_items.end(); ++i) { - nr_arena_item_request_update(*i, NR_ARENA_ITEM_STATE_CACHE, FALSE); + (*i)->_markForUpdate(Inkscape::DrawingItem::STATE_CACHE, false); } } diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index 5d078e19d..a444ed505 100644 --- a/src/display/nr-arena.h +++ b/src/display/nr-arena.h @@ -13,9 +13,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <set> #include <glib/gmacros.h> - +#include <sigc++/sigc++.h> +#include <2geom/rect.h> #include "display/rendermode.h" +#include "libnr/nr-forward.h" +#include "libnr/nr-object.h" +#include "display/display-forward.h" G_BEGIN_DECLS @@ -27,19 +32,13 @@ G_END_DECLS #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 <set> -#include <2geom/rect.h> -#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_update) (NRArena *arena, Inkscape::DrawingItem *item, void *data); void (* request_render) (NRArena *arena, NRRectL *area, void *data); }; @@ -51,20 +50,22 @@ struct NRArena : public NRActiveObject { double delta; bool renderoffscreen; // if true then rendering must be exact Inkscape::RenderMode rendermode; - Inkscape::ColorRenderMode colorrendermode; + Inkscape::ColorMode colormode; int blurquality; // will be updated during update from preferences int filterquality; // will be updated during update from preferences Geom::OptIntRect cache_limit; - std::set<NRArenaItem *> cached_items; + std::set<Inkscape::DrawingItem *> cached_items; guint32 outlinecolor; SPCanvasArena *canvasarena; // may be NULL is this arena is not the screen but used for export etc. + + sigc::signal<void, Inkscape::DrawingItem *> item_deleted; }; struct NRArenaClass : public NRActiveObjectClass { }; -void nr_arena_request_update (NRArena *arena, NRArenaItem *item); +void nr_arena_request_update (NRArena *arena, Inkscape::DrawingItem *item); void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area); void nr_arena_set_renderoffscreen (NRArena *arena); void nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index eaed2a8bd..039e56bb0 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" diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 01d2eca64..55cd02697 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -15,7 +15,7 @@ #include "display/cairo-utils.h" #include "display/drawing-context.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "display/nr-filter.h" #include "display/nr-filter-image.h" #include "display/nr-filter-units.h" @@ -70,7 +70,7 @@ 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(); @@ -78,7 +78,7 @@ void FilterImage::render_cairo(FilterSlot &slot) 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(arena, key, SP_ITEM_SHOW_DISPLAY); if (!ai) { g_warning("feImage renderer: error creating NRArenaItem for SVG Element"); @@ -104,15 +104,12 @@ void FilterImage::render_cairo(FilterSlot &slot) 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, render_rect, &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render(ct, ai, render_rect, NR_ARENA_ITEM_RENDER_NO_CACHE); + UpdateContext ctx; + ai->setTransform(Geom::identity()); + ai->update(render_rect, ctx, DrawingItem::STATE_ALL, 0); + ai->render(ct, render_rect, DrawingItem::RENDER_BYPASS_CACHE); SVGElem->invoke_hide(key); + //delete ai; // should be deleted by hide() above nr_object_unref((NRObject*) arena); slot.set(_output, out); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 494d77749..d2f992859 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -17,7 +17,6 @@ #include <2geom/transforms.h> #include "display/cairo-utils.h" #include "display/drawing-context.h" -#include "display/nr-arena-item.h" #include "display/nr-filter-types.h" #include "display/nr-filter-gaussian.h" #include "display/nr-filter-slot.h" @@ -26,7 +25,7 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(NRArenaItem *item, DrawingContext &bgct, +FilterSlot::FilterSlot(DrawingItem *item, DrawingContext &bgct, DrawingContext &graphic, FilterUnits const &u) : _item(item) , _source_graphic(graphic.rawTarget()) diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 6a86ded8c..1e7c3a5a6 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -19,17 +19,16 @@ #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, DrawingContext &bgct, + FilterSlot(DrawingItem *item, DrawingContext &bgct, DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); @@ -73,7 +72,7 @@ public: 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 diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 25ef80c17..abd102452 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -39,7 +39,7 @@ #include "display/nr-filter-turbulence.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "display/drawing-context.h" #include <2geom/affine.h> #include <2geom/rect.h> @@ -97,7 +97,7 @@ Filter::~Filter() } -int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic) +int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic @@ -108,14 +108,14 @@ int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext 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; + Geom::OptRect maybe_bbox = item->itemBounds(); if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return 1; @@ -161,7 +161,7 @@ int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext } } - FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, graphic, units); + FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgct, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -188,10 +188,10 @@ void Filter::set_primitive_units(SPFilterUnits unit) { _primitive_units = unit; } -void Filter::area_enlarge(Geom::IntRect &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(b, item->ctm); + if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm()); } bbox = *b.upgrade_2geom(); @@ -208,7 +208,7 @@ void Filter::area_enlarge(Geom::IntRect &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; @@ -216,9 +216,9 @@ void Filter::area_enlarge(Geom::IntRect &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; @@ -228,10 +228,10 @@ void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { */ } -Geom::IntRect Filter::compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox) { +Geom::IntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox) { Geom::Rect enlarged = filter_effect_area(item_bbox); - enlarged *= item->ctm; + enlarged *= item->ctm(); Geom::IntRect ret(enlarged.roundOutwards()); return ret; diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 5cebf3ad3..31705f53b 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -21,21 +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, DrawingContext &bgct, DrawingContext &graphic); + int render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic); /** * Creates a new filter primitive under this filter object. @@ -151,13 +150,13 @@ public: * to be rendered so that after filtering, the original area is * drawn correctly. */ - void area_enlarge(Geom::IntRect &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 */ - Geom::IntRect compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox); + Geom::IntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in 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 }; } |
