summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-07-22 02:09:27 +0000
committerKrzysztof Kosiński <tweenk.pl@gmail.com>2011-07-22 02:09:27 +0000
commit328fad57dbfb65e3bd31062021d5cc3081e68515 (patch)
tree55b02cfb325a87d994fefb0e4ea88311812e9444 /src/display
parentClean up some commented-out code (diff)
downloadinkscape-328fad57dbfb65e3bd31062021d5cc3081e68515.tar.gz
inkscape-328fad57dbfb65e3bd31062021d5cc3081e68515.zip
Replace direct use of Cairo contexts and surfaces in the rendering tree
with wrappers which keep some extra information about the surface, amd NRRect and NRRectL use with Geom::Rect and Geom::IntRect. Should simplify implementing filter primitive subregions. (bzr r10347.1.17)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/Makefile_insert4
-rw-r--r--src/display/cairo-templates.h4
-rw-r--r--src/display/canvas-arena.cpp61
-rw-r--r--src/display/display-forward.h3
-rw-r--r--src/display/drawing-context.cpp135
-rw-r--r--src/display/drawing-context.h123
-rw-r--r--src/display/drawing-surface.cpp149
-rw-r--r--src/display/drawing-surface.h78
-rw-r--r--src/display/nr-arena-glyphs.cpp147
-rw-r--r--src/display/nr-arena-glyphs.h2
-rw-r--r--src/display/nr-arena-group.cpp23
-rw-r--r--src/display/nr-arena-image.cpp108
-rw-r--r--src/display/nr-arena-item.cpp183
-rw-r--r--src/display/nr-arena-item.h23
-rw-r--r--src/display/nr-arena-shape.cpp137
-rw-r--r--src/display/nr-arena-shape.h11
-rw-r--r--src/display/nr-arena.cpp9
-rw-r--r--src/display/nr-arena.h3
-rw-r--r--src/display/nr-filter-image.cpp24
-rw-r--r--src/display/nr-filter-slot.cpp33
-rw-r--r--src/display/nr-filter-slot.h12
-rw-r--r--src/display/nr-filter.cpp55
-rw-r--r--src/display/nr-filter.h8
-rw-r--r--src/display/nr-style.cpp40
-rw-r--r--src/display/nr-style.h13
25 files changed, 872 insertions, 516 deletions
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index fc7c8e9ab..53f87efb1 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -23,6 +23,10 @@ ink_common_sources += \
display/canvas-text.h \
display/curve.cpp \
display/curve.h \
+ display/drawing-context.cpp \
+ display/drawing-context.h \
+ display/drawing-surface.cpp \
+ display/drawing-surface.h \
display/gnome-canvas-acetate.cpp \
display/gnome-canvas-acetate.h \
display/grayscale.cpp \
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index a79f58548..d4c8e1493 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -12,6 +12,10 @@
#ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H
#define SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#ifdef HAVE_OPENMP
#include <omp.h>
#include "preferences.h"
diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp
index 4c105cd09..1d5cfe826 100644
--- a/src/display/canvas-arena.cpp
+++ b/src/display/canvas-arena.cpp
@@ -19,6 +19,8 @@
#include "display/nr-arena-group.h"
#include "display/canvas-arena.h"
#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
+#include "display/drawing-surface.h"
enum {
ARENA_EVENT,
@@ -161,12 +163,15 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
guint reset;
reset = (flags & SP_CANVAS_UPDATE_AFFINE)? NR_ARENA_ITEM_STATE_ALL : NR_ARENA_ITEM_STATE_NONE;
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset);
+ nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset);
- item->x1 = arena->root->bbox.x0 - 1;
- item->y1 = arena->root->bbox.y0 - 1;
- item->x2 = arena->root->bbox.x1 + 1;
- item->y2 = arena->root->bbox.y1 + 1;
+ Geom::OptIntRect b = arena->root->bbox;
+ if (b) {
+ item->x1 = b->left() - 1;
+ item->y1 = b->top() - 1;
+ item->x2 = b->right() + 1;
+ item->y2 = b->bottom() + 1;
+ }
if (arena->cursor) {
/* Mess with enter/leave notifiers */
@@ -228,27 +233,23 @@ static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect cons
Geom::OptIntRect r = Geom::intersect(arena->cache_area, area);
if (!r || r->hasZeroArea()) return; // nothing to do
-
- cairo_t *ct = cairo_create(arena->cache);
- cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top());
-
- // clear area to paint
- cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height());
- cairo_clip(ct);
- cairo_save(ct);
- cairo_set_source_rgba(ct, 0,0,0,0);
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
- cairo_restore(ct);
-
- NRRectL nr_area(r);
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
+ Inkscape::DrawingSurface cache(arena->cache, arena->cache_area.min());
+ Inkscape::DrawingContext ct(cache);
+
+ ct.rectangle(area);
+ ct.clip();
+
+ { Inkscape::DrawingContext::Save save(ct);
+ ct.setSource(0,0,0,0);
+ ct.setOperator(CAIRO_OPERATOR_SOURCE);
+ ct.paint();
+ }
+
+ 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, &nr_area, NULL, 0);
-
- cairo_destroy(ct);
+ nr_arena_item_invoke_render (ct, arena->root, *r, 0);
}
static void
@@ -267,7 +268,7 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_
{
SPCanvasArena *arena = SP_CANVAS_ARENA (item);
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
+ nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc,
NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK,
NR_ARENA_ITEM_STATE_NONE);
@@ -367,7 +368,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
arena->c = Geom::Point(event->crossing.x, event->crossing.y);
/* fixme: Not sure abut this, but seems the right thing (Lauris) */
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE);
+ 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);
ret = sp_canvas_arena_send_event (arena, event);
@@ -388,7 +389,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
arena->c = Geom::Point(event->motion.x, event->motion.y);
/* fixme: Not sure abut this, but seems the right thing (Lauris) */
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE);
+ 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);
if (new_arena != arena->active) {
GdkEventCrossing ec;
@@ -474,10 +475,10 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR
g_return_if_fail (ca != NULL);
g_return_if_fail (SP_IS_CANVAS_ARENA (ca));
- cairo_t *ct = cairo_create(surface);
- cairo_translate(ct, -r.x0, -r.y0);
- nr_arena_item_invoke_render (ct, ca->root, &r, NULL, 0);
- cairo_destroy(ct);
+ Geom::OptIntRect area = r.upgrade_2geom();
+ if (!area) return;
+ Inkscape::DrawingContext ct(surface, area->min());
+ nr_arena_item_invoke_render (ct, ca->root, *area, 0);
}
diff --git a/src/display/display-forward.h b/src/display/display-forward.h
index bc7013214..288da829a 100644
--- a/src/display/display-forward.h
+++ b/src/display/display-forward.h
@@ -12,6 +12,9 @@ struct SPCanvasGroupClass;
class SPCurve;
namespace Inkscape {
+class DrawingContext;
+class DrawingSurface;
+
namespace Display {
class TemporaryItem;
class TemporaryItemList;
diff --git a/src/display/drawing-context.cpp b/src/display/drawing-context.cpp
new file mode 100644
index 000000000..8f37bb693
--- /dev/null
+++ b/src/display/drawing-context.cpp
@@ -0,0 +1,135 @@
+/**
+ * @file
+ * @brief Cairo drawing context with Inkscape extensions
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/drawing-context.h"
+#include "display/drawing-surface.h"
+#include "display/cairo-utils.h"
+#include "helper/geom.h"
+
+namespace Inkscape {
+
+using Geom::X;
+using Geom::Y;
+
+/** @class DrawingContext::Save
+ * @brief RAII idiom for saving the state of DrawingContext. */
+
+DrawingContext::Save::Save()
+ : _ct(NULL)
+{}
+DrawingContext::Save::Save(DrawingContext &ct)
+ : _ct(&ct)
+{
+ _ct->save();
+}
+DrawingContext::Save::~Save()
+{
+ if (_ct) {
+ _ct->restore();
+ }
+}
+void DrawingContext::Save::save(DrawingContext &ct)
+{
+ if (_ct) {
+ // TODO: it might be better to treat this occurence as a bug
+ _ct->restore();
+ }
+ _ct = &ct;
+ _ct->save();
+}
+
+/** @class DrawingContext
+ * @brief Minimal wrapper over Cairo.
+ *
+ * This is a wrapper over cairo_t, extended with operations that work
+ * with 2Geom geometrical primitives. Some of this is probably duplicated
+ * in cairo-render-context.cpp, which provides higher level operations
+ * for drawing entire SPObjects when exporting.
+ */
+
+DrawingContext::DrawingContext(cairo_surface_t *surface, Geom::Point const &origin)
+ : _ct(NULL)
+ , _surface(new DrawingSurface(surface, origin))
+ , _delete_surface(true)
+{
+ _surface->_has_context = true;
+ _ct = _surface->createRawContext();
+}
+
+DrawingContext::DrawingContext(DrawingSurface &s)
+ : _ct(s.createRawContext())
+ , _surface(&s)
+ , _delete_surface(false)
+{}
+
+DrawingContext::~DrawingContext()
+{
+ cairo_destroy(_ct);
+ _surface->_has_context = false;
+ if (_delete_surface) {
+ delete _surface;
+ }
+}
+
+void DrawingContext::arc(Geom::Point const &center, double radius, Geom::AngleInterval const &angle)
+{
+ double from = angle.initialAngle();
+ double to = angle.finalAngle();
+ if (to > from) {
+ cairo_arc(_ct, center[X], center[Y], radius, from, to);
+ } else {
+ cairo_arc_negative(_ct, center[X], center[Y], radius, to, from);
+ }
+}
+
+void DrawingContext::transform(Geom::Affine const &trans) {
+ ink_cairo_transform(_ct, trans);
+}
+
+void DrawingContext::path(Geom::PathVector const &pv) {
+ feed_pathvector_to_cairo(_ct, pv);
+}
+
+void DrawingContext::paint(double alpha) {
+ if (alpha == 1.0) cairo_paint(_ct);
+ else cairo_paint_with_alpha(_ct, alpha);
+}
+void DrawingContext::setSource(guint32 rgba) {
+ ink_cairo_set_source_rgba32(_ct, rgba);
+}
+void DrawingContext::setSource(DrawingSurface *s) {
+ Geom::Point origin = s->origin();
+ cairo_set_source_surface(_ct, s->raw(), origin[X], origin[Y]);
+}
+void DrawingContext::setSourceCheckerboard() {
+ cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard();
+ cairo_set_source(_ct, check);
+ cairo_pattern_destroy(check);
+}
+
+Geom::Rect DrawingContext::targetLogicalBounds() const
+{
+ Geom::Rect ret(_surface->area());
+ return ret;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h
new file mode 100644
index 000000000..c0ea81874
--- /dev/null
+++ b/src/display/drawing-context.h
@@ -0,0 +1,123 @@
+/**
+ * @file
+ * @brief Cairo drawing context with Inkscape extensions
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H
+
+#include <boost/utility.hpp>
+#include <glib.h>
+#include <cairo.h>
+#include <2geom/affine.h>
+#include <2geom/angle.h>
+#include <2geom/rect.h>
+#include <2geom/transforms.h>
+
+namespace Inkscape {
+
+class DrawingSurface;
+
+class DrawingContext
+ : boost::noncopyable
+{
+public:
+ class Save {
+ public:
+ Save();
+ Save(DrawingContext &ct);
+ ~Save();
+ void save(DrawingContext &ct);
+ private:
+ DrawingContext *_ct;
+ };
+
+ DrawingContext(cairo_surface_t *surface, Geom::Point const &origin);
+ DrawingContext(DrawingSurface &s);
+ ~DrawingContext();
+
+ void save() { cairo_save(_ct); }
+ void restore() { cairo_restore(_ct); }
+ void pushGroup() { cairo_push_group(_ct); }
+ void pushAlphaGroup() { cairo_push_group_with_content(_ct, CAIRO_CONTENT_ALPHA); }
+ void popGroupToSource() { cairo_pop_group_to_source(_ct); }
+
+ void transform(Geom::Affine const &trans);
+ void translate(Geom::Point const &t) { cairo_translate(_ct, t[Geom::X], t[Geom::Y]); } // todo: take Translate
+ void translate(double dx, double dy) { cairo_translate(_ct, dx, dy); }
+ void scale(Geom::Scale const &s) { cairo_scale(_ct, s[Geom::X], s[Geom::Y]); }
+ void scale(double sx, double sy) { cairo_scale(_ct, sx, sy); }
+
+ void moveTo(Geom::Point const &p) { cairo_move_to(_ct, p[Geom::X], p[Geom::Y]); }
+ void lineTo(Geom::Point const &p) { cairo_line_to(_ct, p[Geom::X], p[Geom::Y]); }
+ void curveTo(Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) {
+ cairo_curve_to(_ct, p1[Geom::X], p1[Geom::Y], p2[Geom::X], p2[Geom::Y], p3[Geom::X], p3[Geom::Y]);
+ }
+ void arc(Geom::Point const &center, double radius, Geom::AngleInterval const &angle);
+ void rectangle(Geom::Rect const &r) {
+ cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height());
+ }
+ void newPath() { cairo_new_path(_ct); }
+ void newSubpath() { cairo_new_sub_path(_ct); }
+ void path(Geom::PathVector const &pv);
+
+ void paint(double alpha = 1.0);
+ void fill() { cairo_fill(_ct); }
+ void fillPreserve() { cairo_fill_preserve(_ct); }
+ void stroke() { cairo_stroke(_ct); }
+ void strokePreserve() { cairo_stroke_preserve(_ct); }
+ void clip() { cairo_clip(_ct); }
+
+ void setLineWidth(double w) { cairo_set_line_width(_ct, w); }
+ void setLineCap(cairo_line_cap_t cap) { cairo_set_line_cap(_ct, cap); }
+ void setLineJoin(cairo_line_join_t join) { cairo_set_line_join(_ct, join); }
+ void setMiterLimit(double miter) { cairo_set_miter_limit(_ct, miter); }
+ void setFillRule(cairo_fill_rule_t rule) { cairo_set_fill_rule(_ct, rule); }
+ void setOperator(cairo_operator_t op) { cairo_set_operator(_ct, op); }
+ void setTolerance(double tol) { cairo_set_tolerance(_ct, tol); }
+ void setSource(cairo_pattern_t *source) { cairo_set_source(_ct, source); }
+ void setSource(cairo_surface_t *surface, double x, double y) {
+ cairo_set_source_surface(_ct, surface, x, y);
+ }
+ void setSource(double r, double g, double b, double a = 1.0) {
+ cairo_set_source_rgba(_ct, r, g, b, a);
+ }
+ void setSource(guint32 rgba);
+ void setSource(DrawingSurface *s);
+ void setSourceCheckerboard();
+
+ Geom::Rect targetLogicalBounds() const;
+
+ cairo_t *raw() { return _ct; }
+ cairo_surface_t *rawTarget() { return cairo_get_group_target(_ct); }
+
+private:
+ DrawingContext(cairo_t *ct, DrawingSurface *surface, bool destroy);
+
+ cairo_t *_ct;
+ DrawingSurface *_surface;
+ bool _delete_surface;
+
+ friend class DrawingSurface;
+};
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp
new file mode 100644
index 000000000..e50a732c6
--- /dev/null
+++ b/src/display/drawing-surface.cpp
@@ -0,0 +1,149 @@
+/**
+ * @file
+ * @brief Cairo surface that remembers its origin
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/drawing-surface.h"
+#include "display/cairo-utils.h"
+
+namespace Inkscape {
+
+using Geom::X;
+using Geom::Y;
+
+
+/** @class DrawingSurface
+ * @brief Drawing surface that remembers its origin.
+ *
+ * This is a very minimalistic wrapper over cairo_surface_t. The main
+ * extra functionality provided by this class is that it automates
+ * the mapping from "logical space" (coordinates in the rendering)
+ * and the "physical space" (surface pixels). For example, patterns
+ * have to be rendered on surfaces which have possibly non-integer
+ * widths and heights.
+ */
+
+/** @brief Creates a surface with the given physical extents.
+ * When a drawing context is created for this surface, its pixels
+ * will cover the area under the given rectangle. */
+DrawingSurface::DrawingSurface(Geom::IntRect const &area)
+ : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, area.width(), area.height()))
+ , _origin(area.min())
+ , _scale(1, 1)
+{}
+
+/** @brief Creates a surface with the given logical extents.
+ * When a drawing context is created for this surface, its pixels
+ * will cover the area under the given rectangle. If the rectangle
+ * has non-integer width, there will be slightly more than 1 pixel
+ * per logical unit. */
+DrawingSurface::DrawingSurface(Geom::Rect const &area)
+ : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil(area.width()), ceil(area.height())))
+ , _origin(area.min())
+ , _scale(ceil(area.width()) / area.width(), ceil(area.height()) / area.height())
+{}
+
+/** @brief Creates a surface with the given logical and physical extents.
+ * When a drawing context is created for this surface, its pixels
+ * will cover the area under the given rectangle. IT will contain
+ * the number of pixels specified by the second argument.
+ * @param logbox Logical extents of the surface
+ * @param pixdims Pixel dimensions of the surface. */
+DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims)
+ : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pixdims[X], pixdims[Y]))
+ , _origin(logbox.min())
+ , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height())
+{}
+
+/** @brief Wrap a cairo_surface_t.
+ * This constructor will take an extra reference on @a surface, which will
+ * be released on destruction. */
+DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin)
+ : _surface(surface)
+ , _origin(origin)
+ , _scale(1, 1)
+{
+ cairo_surface_reference(surface);
+}
+
+DrawingSurface::~DrawingSurface()
+{
+ cairo_surface_destroy(_surface);
+}
+
+/// Get the logical extents of the surface.
+Geom::Rect
+DrawingSurface::area() const
+{
+ Geom::Rect r = Geom::Rect::from_xywh(_origin, dimensions());
+ return r;
+}
+
+/// Get the logical width and weight of the surface as a point.
+Geom::Point
+DrawingSurface::dimensions() const
+{
+ double w = cairo_image_surface_get_width(_surface);
+ double h = cairo_image_surface_get_height(_surface);
+ Geom::Point logical_dims(w / _scale[X], h / _scale[Y]);
+ return logical_dims;
+}
+
+Geom::Point
+DrawingSurface::origin() const
+{
+ return _origin;
+}
+
+Geom::Scale
+DrawingSurface::scale() const
+{
+ return _scale;
+}
+
+/// Get the transformation applied to the drawing context on construction.
+Geom::Affine
+DrawingSurface::drawingTransform() const
+{
+ Geom::Affine ret = _scale * Geom::Translate(-_origin);
+ return ret;
+}
+
+cairo_surface_type_t
+DrawingSurface::type() const
+{
+ // currently hardcoded
+ return CAIRO_SURFACE_TYPE_IMAGE;
+}
+
+/** @brief Create a drawing context for this surface.
+ * It's better to use the surface constructor of DrawingContext. */
+cairo_t *
+DrawingSurface::createRawContext()
+{
+ cairo_t *ct = cairo_create(_surface);
+ if (_scale != Geom::Scale::identity()) {
+ cairo_scale(ct, _scale[X], _scale[Y]);
+ }
+ cairo_translate(ct, -_origin[X], -_origin[Y]);
+ return ct;
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h
new file mode 100644
index 000000000..2d0e147e2
--- /dev/null
+++ b/src/display/drawing-surface.h
@@ -0,0 +1,78 @@
+/**
+ * @file
+ * @brief Cairo surface that remembers its origin
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2011 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H
+
+#include <boost/shared_ptr.hpp>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <2geom/affine.h>
+#include <2geom/rect.h>
+#include <2geom/transforms.h>
+
+namespace Inkscape {
+class DrawingContext;
+
+class DrawingSurface
+{
+public:
+ explicit DrawingSurface(Geom::IntRect const &area);
+ explicit DrawingSurface(Geom::Rect const &area);
+ DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims);
+ DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin);
+ virtual ~DrawingSurface();
+
+ Geom::Rect area() const;
+ Geom::Point dimensions() const;
+ Geom::Point origin() const;
+ Geom::Scale scale() const;
+ Geom::Affine drawingTransform() const;
+ cairo_surface_type_t type() const;
+
+ cairo_surface_t *raw() { return _surface; }
+ cairo_t *createRawContext();
+
+protected:
+ cairo_surface_t *_surface;
+ Geom::Point _origin;
+ Geom::Scale _scale;
+ bool _has_context;
+
+ friend class DrawingContext;
+};
+
+class PixbufSurface
+ : public DrawingSurface
+{
+public:
+ explicit PixbufSurface(GdkPixbuf *pb, Geom::Point const &origin = Geom::Point(0,0));
+ ~PixbufSurface();
+protected:
+ GdkPixbuf *pb;
+
+ friend class DrawingContext;
+};
+
+} // 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/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp
index d09f66a2f..99b0a004e 100644
--- a/src/display/nr-arena-glyphs.cpp
+++ b/src/display/nr-arena-glyphs.cpp
@@ -14,13 +14,15 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#include "libnr/nr-convert2geom.h"
+#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 <cairo.h>
#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
#include "helper/geom.h"
#ifdef test_glyph_liv
@@ -39,9 +41,8 @@ static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
static void nr_arena_glyphs_finalize(NRObject *object);
-static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
-static guint nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
+static 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;
@@ -75,7 +76,6 @@ nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
item_class->update = nr_arena_glyphs_update;
- item_class->clip = nr_arena_glyphs_clip;
item_class->pick = nr_arena_glyphs_pick;
}
@@ -102,7 +102,7 @@ nr_arena_glyphs_finalize(NRObject *object)
}
static guint
-nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/)
+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);
@@ -132,50 +132,32 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s
// (one for each point on the curve)
b->expandBy(miterMax);
}
- }
+ }
if (b) {
- item->bbox.x0 = floor(b->left());
- item->bbox.y0 = floor(b->top());
- item->bbox.x1 = ceil (b->right());
- item->bbox.y1 = ceil (b->bottom());
+ item->bbox = b->roundOutwards();
} else {
- item->bbox.x0 = 0;
- item->bbox.y0 = 0;
- item->bbox.x1 = -1;
- item->bbox.y1 = -1;
+ item->bbox = Geom::OptIntRect();
}
return NR_ARENA_ITEM_STATE_ALL;
}
-static guint nr_arena_glyphs_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/)
-{
- NRArenaGlyphs *glyphs;
-
- glyphs = NR_ARENA_GLYPHS(item);
-
- if (!glyphs->font) return item->state;
-
- // TODO : render to greyscale pixblock provided for clipping
-
- return item->state;
-}
-
static NRArenaItem *
-nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int /*sticky*/)
+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;
- double const x = p[Geom::X];
- double const y = p[Geom::Y];
- /* With text we take a simple approach: pick if the point is in a characher bbox */
- if ((x + delta >= item->bbox.x0) && (y + delta >= item->bbox.y0) && (x - delta <= item->bbox.x1) && (y - delta <= item->bbox.y1)) return item;
-
+ // 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;
}
@@ -205,10 +187,10 @@ static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
static void nr_arena_glyphs_group_finalize(NRObject *object);
-static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
-static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky);
+static 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;
@@ -251,14 +233,12 @@ static void
nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
{
group->style = NULL;
- group->paintbox.x0 = group->paintbox.y0 = 0.0F;
- group->paintbox.x1 = group->paintbox.y1 = -1.0F;
}
static void
nr_arena_glyphs_group_finalize(NRObject *object)
{
- NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
+ NRArenaGlyphsGroup *group = static_cast<NRArenaGlyphsGroup *>(object);
if (group->style) {
sp_style_unref(group->style);
@@ -269,7 +249,7 @@ nr_arena_glyphs_group_finalize(NRObject *object)
}
static guint
-nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
+nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset)
{
NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
@@ -283,24 +263,20 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s
static unsigned int
-nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/)
+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 (!ct) {
- return item->state;
- }
-
if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
- cairo_save(ct);
+ Inkscape::DrawingContext::Save save(ct);
guint32 rgba = item->arena->outlinecolor;
- ink_cairo_set_source_rgba32(ct, rgba);
- cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
- cairo_new_path(ct);
- ink_cairo_transform(ct, ggroup->ctm);
+ 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);
@@ -308,83 +284,78 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi
Geom::PathVector const * pathv = g->font->PathVector(g->glyph);
Geom::Affine transform = g->g_transform;
- cairo_save(ct);
- ink_cairo_transform(ct, transform);
- feed_pathvector_to_cairo (ct, *pathv);
- cairo_fill(ct);
- cairo_restore(ct);
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(transform);
+ ct.path(*pathv);
+ ct.fill();
}
- cairo_restore(ct);
return item->state;
}
// NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding
bool has_stroke, has_fill;
- cairo_save(ct);
- ink_cairo_transform(ct, ggroup->ctm);
+ 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);
+ has_fill = ggroup->nrstyle.prepareFill(ct, ggroup->paintbox);
+ has_stroke = ggroup->nrstyle.prepareStroke(ct, ggroup->paintbox);
if (has_fill || has_stroke) {
for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) {
NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
Geom::PathVector const &pathv = *g->font->PathVector(g->glyph);
- cairo_save(ct);
- ink_cairo_transform(ct, g->g_transform);
- feed_pathvector_to_cairo(ct, pathv);
- cairo_restore(ct);
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(g->g_transform);
+ ct.path(pathv);
}
if (has_fill) {
ggroup->nrstyle.applyFill(ct);
- cairo_fill_preserve(ct);
+ ct.fillPreserve();
}
if (has_stroke) {
ggroup->nrstyle.applyStroke(ct);
- cairo_stroke_preserve(ct);
+ ct.strokePreserve();
}
- cairo_new_path(ct); // clear path
+ ct.newPath(); // clear path
} // has fill or stroke pattern
- cairo_restore(ct);
return item->state;
}
-static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/)
+static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/)
{
NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
- cairo_save(ct);
+ Inkscape::DrawingContext::Save save(ct);
+
// handle clip-rule
if (ggroup->style) {
if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD);
+ ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD);
} else {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING);
+ ct.setFillRule(CAIRO_FILL_RULE_WINDING);
}
}
- ink_cairo_transform(ct, ggroup->ctm);
+ 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);
- cairo_save(ct);
- ink_cairo_transform(ct, g->g_transform);
- feed_pathvector_to_cairo(ct, pathv);
- cairo_restore(ct);
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(g->g_transform);
+ ct.path(pathv);
}
- cairo_fill(ct);
- cairo_restore(ct);
+ ct.fill();
return item->state;
}
static NRArenaItem *
-nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky)
+nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky)
{
NRArenaItem *picked = NULL;
@@ -450,15 +421,7 @@ nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
nr_return_if_fail(pbox != NULL);
- if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
- gg->paintbox.x0 = pbox->x0;
- gg->paintbox.y0 = pbox->y0;
- gg->paintbox.x1 = pbox->x1;
- gg->paintbox.y1 = pbox->y1;
- } else {
- gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
- gg->paintbox.x1 = gg->paintbox.y1 = -1.0F;
- }
+ gg->paintbox = pbox->upgrade_2geom();
nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
}
diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h
index c43095cb2..4b2aed7b9 100644
--- a/src/display/nr-arena-glyphs.h
+++ b/src/display/nr-arena-glyphs.h
@@ -70,7 +70,7 @@ typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass;
NRType nr_arena_glyphs_group_get_type (void);
struct NRArenaGlyphsGroup : public NRArenaGroup {
- NRRect paintbox;
+ Geom::OptRect paintbox;
NRStyle nrstyle;
static NRArenaGlyphsGroup *create(NRArena *arena) {
diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp
index 1d552fbc2..1f7c421d0 100644
--- a/src/display/nr-arena-group.cpp
+++ b/src/display/nr-arena-group.cpp
@@ -24,6 +24,7 @@
#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);
@@ -34,10 +35,10 @@ static void nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRA
static void nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child);
static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
-static unsigned int nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
+static 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;
@@ -163,7 +164,7 @@ nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRAren
}
static unsigned int
-nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset)
+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);
@@ -178,10 +179,10 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int
}
if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
- item->bbox = NR_RECT_L_EMPTY;
+ item->bbox = Geom::OptIntRect();
for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
if (child->visible)
- nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox);
+ item->bbox.unionWith(outline ? child->bbox : child->drawbox);
}
}
@@ -217,7 +218,7 @@ void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style)
}
static unsigned int
-nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
+nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags)
{
NRArenaGroup *group = NR_ARENA_GROUP (item);
@@ -225,7 +226,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock
/* Just compose children into parent buffer */
for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
- ret = nr_arena_item_invoke_render (ct, child, area, pb, flags);
+ ret = nr_arena_item_invoke_render (ct, child, area, flags);
if (ret & NR_ARENA_ITEM_STATE_INVALID) break;
}
@@ -233,7 +234,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock
}
static unsigned int
-nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
+nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area)
{
NRArenaGroup *group = NR_ARENA_GROUP (item);
unsigned int ret = item->state;
@@ -247,7 +248,7 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
}
static NRArenaItem *
-nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky)
+nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky)
{
NRArenaGroup *group = NR_ARENA_GROUP (item);
diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp
index a943a6214..5336fcda9 100644
--- a/src/display/nr-arena-image.cpp
+++ b/src/display/nr-arena-image.cpp
@@ -17,6 +17,7 @@
#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"
@@ -34,9 +35,9 @@ static void nr_arena_image_class_init (NRArenaImageClass *klass);
static void nr_arena_image_init (NRArenaImage *image);
static void nr_arena_image_finalize (NRObject *object);
-static unsigned int nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
-static unsigned int nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
+static 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;
@@ -104,7 +105,7 @@ nr_arena_image_finalize (NRObject *object)
}
static unsigned int
-nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ )
+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);
@@ -116,30 +117,17 @@ nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned
/* Calculate bbox */
if (image->pixbuf) {
- NRRect bbox;
-
Geom::Rect r = nr_arena_image_rect(image) * gc->transform;
-
- item->bbox.x0 = floor(r.left()); // Floor gives the coordinate in which the point resides
- item->bbox.y0 = floor(r.top());
- item->bbox.x1 = ceil(r.right()); // Ceil gives the first coordinate beyond the point
- item->bbox.y1 = ceil(r.bottom());
+ item->bbox = r.roundOutwards();
} else {
- item->bbox.x0 = (int) gc->transform[4];
- item->bbox.y0 = (int) gc->transform[5];
- item->bbox.x1 = item->bbox.x0 - 1;
- item->bbox.y1 = item->bbox.y0 - 1;
+ item->bbox = Geom::OptIntRect();
}
return NR_ARENA_ITEM_STATE_ALL;
}
-static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/, NRPixBlock * /*pb*/, unsigned int /*flags*/ )
+static unsigned int nr_arena_image_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/, unsigned int /*flags*/ )
{
- if (!ct) {
- return item->state;
- }
-
bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
NRArenaImage *image = NR_ARENA_IMAGE (item);
@@ -151,69 +139,63 @@ static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRec
// FIXME: at the moment gdk_cairo_set_source_pixbuf creates an ARGB copy
// of the pixbuf. Fix this in Cairo and/or GDK.
- cairo_save(ct);
- ink_cairo_transform(ct, image->ctm);
+ Inkscape::DrawingContext::Save save(ct);
+ ct.transform(image->ctm);
+ ct.newPath();
+ ct.rectangle(image->clipbox);
+ ct.clip();
- cairo_new_path(ct);
- cairo_rectangle(ct, image->clipbox.left(), image->clipbox.top(),
- image->clipbox.width(), image->clipbox.height());
- cairo_clip(ct);
-
- cairo_translate(ct, image->ox, image->oy);
- cairo_scale(ct, image->sx, image->sy);
-
- cairo_set_source_surface(ct, image->surface, 0, 0);
+ 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, &tt);
+ 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);
+ cairo_pattern_t *p = cairo_get_source(ct.raw());
cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST);
}
-
- cairo_paint_with_alpha(ct, ((double) item->opacity) / 255.0);
- cairo_restore(ct);
+ 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);
- cairo_save(ct);
- ink_cairo_transform(ct, image->ctm);
-
- cairo_new_path(ct);
-
- Geom::Rect r = nr_arena_image_rect (image);
- Geom::Point c00 = r.corner(0);
- Geom::Point c01 = r.corner(3);
- Geom::Point c11 = r.corner(2);
- Geom::Point c10 = r.corner(1);
+ { 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);
+ }
- cairo_move_to (ct, c00[Geom::X], c00[Geom::Y]);
- // the box
- cairo_line_to (ct, c10[Geom::X], c10[Geom::Y]);
- cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]);
- cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]);
- cairo_line_to (ct, c00[Geom::X], c00[Geom::Y]);
- // the diagonals
- cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]);
- cairo_move_to (ct, c10[Geom::X], c10[Geom::Y]);
- cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]);
- cairo_restore(ct);
-
- cairo_set_line_width(ct, 0.5);
- ink_cairo_set_source_rgba32(ct, rgba);
- cairo_stroke(ct);
+ 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 p, Geom::Point a1, Geom::Point a2)
+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);
@@ -233,7 +215,7 @@ distance_to_segment (Geom::Point p, Geom::Point a1, Geom::Point a2)
}
static NRArenaItem *
-nr_arena_image_pick( NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/ )
+nr_arena_image_pick( NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/ )
{
NRArenaImage *image = NR_ARENA_IMAGE (item);
diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp
index 9ca5a7463..c1ffefa1d 100644
--- a/src/display/nr-arena-item.cpp
+++ b/src/display/nr-arena-item.cpp
@@ -21,6 +21,8 @@
#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"
@@ -210,7 +212,7 @@ nr_arena_item_unref (NRArenaItem *item)
}
unsigned int
-nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
+nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc,
unsigned int state, unsigned int reset)
{
NRGC childgc (gc);
@@ -243,8 +245,8 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
if (!(~item->state & state))
return item->state;
/* Test whether to return immediately */
- if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) {
- if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox))
+ if (item->state & NR_ARENA_ITEM_STATE_BBOX) {
+ if (!area.intersects(outline ? item->bbox : item->drawbox))
return item->state;
}
@@ -269,13 +271,9 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
/* Enlarge the drawbox to contain filter effects */
if (item->filter && filter && item->item_bbox) {
- item->drawbox.x0 = item->item_bbox->min()[Geom::X];
- item->drawbox.y0 = item->item_bbox->min()[Geom::Y];
- item->drawbox.x1 = item->item_bbox->max()[Geom::X];
- item->drawbox.y1 = item->item_bbox->max()[Geom::Y];
- item->filter->compute_drawbox (item, item->drawbox);
+ item->drawbox = item->filter->compute_drawbox(item, *item->item_bbox);
} else {
- memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox));
+ item->drawbox = item->bbox;
}
/* Clipping */
@@ -289,10 +287,9 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
return item->state;
}
if (outline) {
- nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox);
+ item->bbox.unionWith(item->clip->bbox);
} else {
- // for clipping, we need geometric bbox
- nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox);
+ item->drawbox.intersectWith(item->clip->bbox);
}
}
/* Masking */
@@ -303,10 +300,10 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
return item->state;
}
if (outline) {
- nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox);
+ item->bbox.unionWith(item->mask->bbox);
} else {
// for masking, we need full drawbox of mask
- nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox);
+ item->drawbox.intersectWith(item->mask->drawbox);
}
}
@@ -331,8 +328,8 @@ struct MaskLuminanceToAlpha {
};
unsigned int
-nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area,
- NRPixBlock *pb, unsigned int flags)
+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 &&
@@ -343,15 +340,6 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
NR_ARENA_ITEM_STATE_INVALID);
nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX,
item->state);
- if (!ct) return item->state;
-
-#ifdef NR_ARENA_ITEM_VERBOSE
- g_message ("Invoke render %p on %p: %d %d - %d %d, %d %d - %d %d", item, pb,
- area->x0, area->y0,
- area->x1, area->y1,
- item->drawbox.x0, item->drawbox.y0,
- item->drawbox.x1, item->drawbox.y1);
-#endif
/* If we are invisible, just return successfully */
if (!item->visible)
@@ -360,15 +348,14 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
if (outline) {
// intersect with bbox rather than drawbox, as we want to render things outside
// of the clipping path as well
- NRRectL carea;
- nr_rect_l_intersect (&carea, area, &item->bbox);
- if (nr_rect_l_test_empty(carea))
+ 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, pb, flags);
+ 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;
@@ -381,12 +368,12 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (item->clip) {
item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips
- NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags);
- }
+ 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, pb, flags);
+ NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, *carea, flags);
}
item->arena->outlinecolor = saved_rgba; // restore outline color
@@ -395,13 +382,12 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
// carea is the bounding box for intermediate rendering.
// NOTE: carea might be larger than area, because of filter effects.
- NRRectL carea;
- nr_rect_l_intersect (&carea, area, &item->drawbox);
- if (nr_rect_l_test_empty(carea))
+ Geom::OptIntRect carea = Geom::intersect(area, item->drawbox);
+ if (!carea)
return item->state | NR_ARENA_ITEM_STATE_RENDER;
if (item->filter && filter) {
- item->filter->area_enlarge (carea, item);
- nr_rect_l_intersect (&carea, &carea, &item->drawbox);
+ item->filter->area_enlarge(*carea, item);
+ carea.intersectWith(item->drawbox);
}
using namespace Inkscape;
@@ -436,7 +422,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
// short-circuit the simple case.
if (!needs_intermediate_rendering) {
- state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags);
+ 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;
@@ -444,51 +430,48 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
return item->state | NR_ARENA_ITEM_STATE_RENDER;
}
- cairo_surface_t *intermediate = cairo_surface_create_similar(
- cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA,
- carea.x1 - carea.x0, carea.y1 - carea.y0);
- cairo_t *ict = cairo_create(intermediate);
- cairo_translate(ict, -carea.x0, -carea.y0);
+ DrawingSurface intermediate(*carea);
+ DrawingContext ict(intermediate);
// 1. Render clipping path with alpha = opacity.
- cairo_set_source_rgba(ict, 0,0,0,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.
- cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE);
+ ict.setOperator(CAIRO_OPERATOR_SOURCE);
if (item->clip) {
- state = nr_arena_item_invoke_clip(ict, item->clip, const_cast<NRRectL*>(area));
+ 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.
- cairo_paint(ict);
+ ict.paint();
}
// reset back to default
- cairo_set_operator(ict, CAIRO_OPERATOR_OVER);
+ ict.setOperator(CAIRO_OPERATOR_OVER);
// 2. Render the mask if present and compose it with the clipping path + opacity.
if (item->mask) {
- cairo_push_group(ict);
- state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags);
+ 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 = cairo_get_group_target(ict);
+ cairo_surface_t *mask_s = ict.rawTarget();
// Convert mask's luminance to alpha
ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha());
- cairo_pop_group_to_source(ict);
- cairo_set_operator(ict, CAIRO_OPERATOR_IN);
- cairo_paint(ict);
- cairo_set_operator(ict, CAIRO_OPERATOR_OVER);
+ ict.popGroupToSource();
+ ict.setOperator(CAIRO_OPERATOR_IN);
+ ict.paint();
+ ict.setOperator(CAIRO_OPERATOR_OVER);
}
// 3. Render object itself.
- cairo_push_group(ict);
- state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags);
+ 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;
@@ -496,71 +479,53 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
// 4. Apply filter.
if (item->filter && filter) {
- // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering
- // Proper fix: call this function with a drawing context class
- // that contains information about the surface's bounds
- NRRectL bgarea;
- if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) {
- bgarea = carea;
- } else {
- bgarea = NRRectL(item->arena->canvasarena->cache_area);
- }
- item->filter->render(item, ct, &bgarea, ict, &carea);
+ 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
- cairo_pop_group_to_source(ict);
- cairo_set_operator(ict, CAIRO_OPERATOR_IN);
- cairo_paint(ict);
+ ict.popGroupToSource();
+ ict.setOperator(CAIRO_OPERATOR_IN);
+ ict.paint();
// 6. Paint the completed rendering onto the base context
- cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0);
- cairo_paint(ct);
- cairo_set_source_rgba(ct, 0,0,0,0);
+ 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:
- cairo_destroy(ict);
- cairo_surface_destroy(intermediate);
-
return retstate;
}
unsigned int
-nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
+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);
-#ifdef NR_ARENA_ITEM_VERBOSE
- printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n",
- item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0,
- (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1);
-#endif
-
unsigned retstate = 0;
-
+
// don't bother if the object does not implement clipping (e.g. NRArenaImage)
if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip)
return retstate;
- if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
+ 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
+ // Render this item's clipping path onto a temporary surface, then composite it
+ // with the item using the IN operator
if (item->clip) {
- cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA);
- cairo_save(ct);
- cairo_set_source_rgba(ct, 0,0,0,1);
- nr_arena_item_invoke_clip(ct, item->clip, area);
- cairo_restore(ct);
- cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA);
+ 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
@@ -568,12 +533,12 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
clip (ct, item, area);
if (item->clip) {
- cairo_pop_group_to_source(ct);
- cairo_set_operator(ct, CAIRO_OPERATOR_IN);
- cairo_paint(ct);
- cairo_pop_group_to_source(ct);
- cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ct);
+ ct.popGroupToSource();
+ ct.setOperator(CAIRO_OPERATOR_IN);
+ ct.paint();
+ ct.popGroupToSource();
+ ct.setOperator(CAIRO_OPERATOR_SOURCE);
+ ct.paint();
}
}
@@ -581,7 +546,7 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
}
NRArenaItem *
-nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta,
+nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta,
unsigned int sticky)
{
nr_return_val_if_fail (item != NULL, NULL);
@@ -595,14 +560,11 @@ nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta,
if (!sticky && !(item->visible && item->sensitive))
return NULL;
- // TODO: rewrite using Geom::Rect
- const double x = p[Geom::X];
- const double y = p[Geom::Y];
+ if (!item->bbox) return NULL;
+ Geom::Rect expanded(*item->bbox);
+ expanded.expandBy(delta);
- if (((x + delta) >= item->bbox.x0) &&
- ((x - delta) < item->bbox.x1) &&
- ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1))
- {
+ if (expanded.contains(p)) {
if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick)
return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
pick (item, p, delta, sticky);
@@ -639,7 +601,7 @@ nr_arena_item_request_render (NRArenaItem *item)
nr_return_if_fail (NR_IS_ARENA_ITEM (item));
bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
- nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox);
+ nr_arena_request_render_rect (item->arena, outline ? item->bbox : item->drawbox);
}
/* Public */
@@ -694,6 +656,7 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform)
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 */
@@ -703,6 +666,8 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *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);
}
}
@@ -800,7 +765,7 @@ nr_arena_item_set_order (NRArenaItem *item, int order)
}
void
-nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox)
+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));
diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h
index d65a75ed8..4b43e4da8 100644
--- a/src/display/nr-arena-item.h
+++ b/src/display/nr-arena-item.h
@@ -23,6 +23,7 @@
#include "nr-arena-forward.h"
namespace Inkscape {
+class DrawingContext;
namespace Filters {
class Filter;
} }
@@ -92,8 +93,8 @@ struct NRArenaItem : public NRObject {
unsigned int key; ///< Some SPItems can have more than one NRArenaItem,
///this value is a hack used to distinguish between them
- NRRectL bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin
- NRRectL drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks
+ Geom::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
@@ -119,10 +120,10 @@ struct NRArenaItemClass : public NRObjectClass {
void (* remove_child) (NRArenaItem *item, NRArenaItem *child);
void (* set_child_position) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
- unsigned int (* update) (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
- unsigned int (* render) (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
- unsigned int (* clip) (cairo_t *ct, NRArenaItem *item, NRRectL *area);
- NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
+ 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)
@@ -147,12 +148,12 @@ void nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, NR
* reset - reset to state (bitwise or of flags to reset)
*/
-unsigned int nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
+unsigned int nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset);
-unsigned int nr_arena_item_invoke_render(cairo_t *ct, NRArenaItem *item, NRRectL const *area, NRPixBlock *pb, unsigned int flags);
+unsigned int nr_arena_item_invoke_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags);
-unsigned int nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area);
-NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
+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);
@@ -171,7 +172,7 @@ void nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible);
void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip);
void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask);
void nr_arena_item_set_order (NRArenaItem *item, int order);
-void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox);
+void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox);
NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item);
diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp
index 6d65611bf..ff985550c 100644
--- a/src/display/nr-arena-shape.cpp
+++ b/src/display/nr-arena-shape.cpp
@@ -23,6 +23,7 @@
#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"
@@ -44,10 +45,10 @@ static void nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRAr
static void nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child);
static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
-static guint nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
-static unsigned int nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
-static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area);
-static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);
+static 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;
@@ -99,14 +100,6 @@ nr_arena_shape_init(NRArenaShape *shape)
{
shape->curve = NULL;
shape->style = NULL;
- shape->paintbox.x0 = shape->paintbox.y0 = 0.0F;
- shape->paintbox.x1 = shape->paintbox.y1 = 256.0F;
- shape->delayed_shp = false;
- shape->path = NULL;
-
- shape->approx_bbox.x0 = shape->approx_bbox.y0 = 0;
- shape->approx_bbox.x1 = shape->approx_bbox.y1 = 0;
-
shape->markers = NULL;
shape->last_pick = NULL;
shape->repick_after = 0;
@@ -117,7 +110,6 @@ nr_arena_shape_finalize(NRObject *object)
{
NRArenaShape *shape = (NRArenaShape *) object;
- if (shape->path) cairo_path_destroy(shape->path);
if (shape->style) sp_style_unref(shape->style);
if (shape->curve) shape->curve->unref();
shape->last_pick = NULL;
@@ -203,7 +195,7 @@ nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArena
* Updates the arena shape 'item' and all of its children, including the markers.
*/
static guint
-nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
+nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset)
{
Geom::OptRect boundingbox;
@@ -224,34 +216,26 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g
if (shape->curve) {
boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform);
if (boundingbox) {
- item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides
- item->bbox.y0 = floor((*boundingbox)[1][0]);
- item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point
- item->bbox.y1 = ceil ((*boundingbox)[1][1]);
+ item->bbox = boundingbox->roundOutwards();
} else {
- item->bbox = NR_RECT_L_EMPTY;
+ item->bbox = Geom::OptIntRect();
}
}
if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox);
+ item->bbox.unionWith(child->bbox);
}
}
}
return (state | item->state);
}
- shape->delayed_shp=true;
boundingbox = Geom::OptRect();
bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
// clear Cairo data to force update
shape->nrstyle.update();
- if (shape->path) {
- cairo_path_destroy(shape->path);
- shape->path = NULL;
- }
if (shape->curve) {
boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform);
@@ -273,19 +257,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g
}
}
- /// \todo just write item->bbox = boundingbox
- if (boundingbox) {
- shape->approx_bbox.x0 = floor(boundingbox->left());
- shape->approx_bbox.y0 = floor(boundingbox->top());
- shape->approx_bbox.x1 = ceil (boundingbox->right());
- shape->approx_bbox.y1 = ceil (boundingbox->bottom());
- } else {
- shape->approx_bbox = NR_RECT_L_EMPTY;
- }
- if ( area && nr_rect_l_test_intersect_ptr(area, &shape->approx_bbox) ) shape->delayed_shp=false;
-
- // TODO: compute a better bounding box that respects miters
- item->bbox = shape->approx_bbox;
+ item->bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect();
if (!shape->curve ||
!shape->style ||
@@ -299,7 +271,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g
if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox);
+ item->bbox.unionWith(child->bbox);
}
}
@@ -308,25 +280,22 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g
// cairo outline rendering:
static unsigned int
-cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /*area*/)
+cairo_arena_shape_render_outline(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/)
{
NRArenaShape *shape = NR_ARENA_SHAPE(item);
- if (!ct)
- return item->state;
-
guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor;
- cairo_save(ct);
- ink_cairo_transform(ct, shape->ctm);
- feed_pathvector_to_cairo (ct, shape->curve->get_pathvector());
- cairo_restore(ct);
- cairo_save(ct);
- ink_cairo_set_source_rgba32(ct, rgba);
- cairo_set_line_width(ct, 0.5);
- cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
- cairo_stroke(ct);
- cairo_restore(ct);
+ { 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;
}
@@ -335,59 +304,55 @@ cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /
* Renders the item. Markers are just composed into the parent buffer.
*/
static unsigned int
-nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
+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;
- if (!ct) return item->state;
// skip if not within bounding box
- if (!nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
+ if (!area.intersects(item->bbox)) {
return item->state;
}
bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
- if (outline) { // cairo outline rendering
-
- NRRect temp(area->x0, area->y0, area->x1, area->y1);
- unsigned int ret = cairo_arena_shape_render_outline (ct, item, temp.upgrade_2geom());
+ if (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
- cairo_save(ct);
- ink_cairo_transform(ct, shape->ctm);
+ 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_fill = shape->nrstyle.prepareFill(ct, shape->paintbox);
+ has_stroke = shape->nrstyle.prepareStroke(ct, shape->paintbox);
has_stroke &= (shape->nrstyle.stroke_width != 0);
if (has_fill || has_stroke) {
// TODO: remove segments outside of bbox when no dashes present
- feed_pathvector_to_cairo(ct, shape->curve->get_pathvector());
+ ct.path(shape->curve->get_pathvector());
if (has_fill) {
shape->nrstyle.applyFill(ct);
- cairo_fill_preserve(ct);
+ ct.fillPreserve();
}
if (has_stroke) {
shape->nrstyle.applyStroke(ct);
- cairo_stroke_preserve(ct);
+ ct.strokePreserve();
}
- cairo_new_path(ct); // clear path
+ ct.newPath(); // clear path
} // has fill or stroke pattern
- cairo_restore(ct);
}
// marker rendering
for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) {
- unsigned int ret = nr_arena_item_invoke_render(ct, child, area, pb, flags);
+ unsigned int ret = nr_arena_item_invoke_render(ct, child, area, flags);
if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret;
}
@@ -395,32 +360,31 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock
}
-static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/)
+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;
}
- cairo_save(ct);
+ Inkscape::DrawingContext::Save save(ct);
// handle clip-rule
if (shape->style) {
if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD);
+ ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD);
} else {
- cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING);
+ ct.setFillRule(CAIRO_FILL_RULE_WINDING);
}
}
- ink_cairo_transform(ct, shape->ctm);
- feed_pathvector_to_cairo(ct, shape->curve->get_pathvector());
- cairo_fill(ct);
- cairo_restore(ct);
+ 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 p, double delta, unsigned int /*sticky*/)
+nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/)
{
NRArenaShape *shape = NR_ARENA_SHAPE(item);
@@ -577,23 +541,14 @@ nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox)
g_return_if_fail(NR_IS_ARENA_SHAPE(shape));
g_return_if_fail(pbox != NULL);
- if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
- shape->paintbox = *pbox;
- } else {
- /* fixme: We kill warning, although not sure what to do here (Lauris) */
- shape->paintbox.x0 = shape->paintbox.y0 = 0.0F;
- shape->paintbox.x1 = shape->paintbox.y1 = 256.0F;
- }
+ 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.x0 = pbox.min()[Geom::X];
- paintbox.y0 = pbox.min()[Geom::Y];
- paintbox.x1 = pbox.max()[Geom::X];
- paintbox.y1 = pbox.max()[Geom::Y];
+ paintbox = pbox;
nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE);
}
diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h
index 7b86f7f59..317cff7fb 100644
--- a/src/display/nr-arena-shape.h
+++ b/src/display/nr-arena-shape.h
@@ -31,16 +31,7 @@ struct NRArenaShape : public NRArenaItem {
SPCurve *curve;
SPStyle *style;
NRStyle nrstyle;
- NRRect paintbox;
-
- cairo_path_t *path;
-
- // delayed_shp=true means the *_shp polygons are not computed yet
- // they'll be computed on demand in *_render(), *_pick() or *_clip()
- // the goal is to not uncross polygons that are outside the viewing region
- bool delayed_shp;
- // approximate bounding box, for the case when the polygons have been delayed
- NRRectL approx_bbox;
+ Geom::OptRect paintbox;
/* Markers */
NRArenaItem *markers;
diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp
index ce62a81dc..5747de26c 100644
--- a/src/display/nr-arena.cpp
+++ b/src/display/nr-arena.cpp
@@ -104,13 +104,13 @@ nr_arena_request_update (NRArena *arena, NRArenaItem *item)
}
void
-nr_arena_request_render_rect (NRArena *arena, NRRectL *area)
+nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area)
{
NRActiveObject *aobject = (NRActiveObject *) arena;
nr_return_if_fail (arena != NULL);
nr_return_if_fail (NR_IS_ARENA (arena));
- nr_return_if_fail (area != NULL);
+ if (!area) return;
// setup render parameter
if (arena->renderoffscreen == false) {
@@ -123,12 +123,13 @@ nr_arena_request_render_rect (NRArena *arena, NRRectL *area)
arena->rendermode = Inkscape::RENDERMODE_NORMAL;
arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL;
}
- if (aobject->callbacks && area && !nr_rect_l_test_empty_ptr(area)) {
+ NRRectL nr_area(*area);
+ if (aobject->callbacks) {
for (unsigned int i = 0; i < aobject->callbacks->length; i++) {
NRObjectListener *listener = aobject->callbacks->listeners + i;
NRArenaEventVector *avector = (NRArenaEventVector *) listener->vector;
if ((listener->size >= sizeof (NRArenaEventVector)) && avector->request_render) {
- avector->request_render (arena, area, listener->data);
+ avector->request_render (arena, &nr_area, listener->data);
}
}
}
diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h
index 1c8216434..49d133f9f 100644
--- a/src/display/nr-arena.h
+++ b/src/display/nr-arena.h
@@ -27,6 +27,7 @@ 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 <2geom/rect.h>
#include <libnr/nr-forward.h>
#include <libnr/nr-object.h>
#include "nr-arena-forward.h"
@@ -61,7 +62,7 @@ struct NRArenaClass : public NRActiveObjectClass {
};
void nr_arena_request_update (NRArena *arena, NRArenaItem *item);
-void nr_arena_request_render_rect (NRArena *arena, NRRectL *area);
+void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area);
void nr_arena_set_renderoffscreen (NRArena *arena);
void nr_arena_separate_color_plates(guint32* rgba);
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index 0cb7901b3..01d2eca64 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -13,6 +13,7 @@
#include "document.h"
#include "sp-item.h"
#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
#include "display/nr-arena.h"
#include "display/nr-arena-item.h"
#include "display/nr-filter.h"
@@ -94,28 +95,23 @@ void FilterImage::render_cairo(FilterSlot &slot)
Geom::Rect sa = slot.get_slot_area();
cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
sa.width(), sa.height());
- cairo_t *ct = cairo_create(out);
- cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]);
- ink_cairo_transform(ct, pu2pb); // we are now in primitive units
- cairo_translate(ct, feImageX, feImageY);
- cairo_scale(ct, scaleX, scaleY);
-
- NRRectL render_rect;
- render_rect.x0 = floor(area.left());
- render_rect.y0 = floor(area.top());
- render_rect.x1 = ceil(area.right());
- render_rect.y1 = ceil(area.bottom());
- cairo_translate(ct, render_rect.x0, render_rect.y0);
+ Inkscape::DrawingContext ct(out, sa.min());
+ ct.transform(pu2pb); // we are now in primitive units
+ ct.translate(feImageX, feImageY);
+ ct.scale(scaleX, scaleY);
+
+ Geom::IntRect render_rect = area.roundOutwards();
+ ct.translate(render_rect.min());
// Update to renderable state
NRGC gc(NULL);
Geom::Affine t = Geom::identity();
nr_arena_item_set_transform(ai, &t);
gc.transform.setIdentity();
- nr_arena_item_invoke_update(ai, NULL, &gc,
+ nr_arena_item_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, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE);
+ nr_arena_item_invoke_render(ct, ai, render_rect, NR_ARENA_ITEM_RENDER_NO_CACHE);
SVGElem->invoke_hide(key);
nr_object_unref((NRObject*) arena);
diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp
index 3464fda66..494d77749 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -16,6 +16,7 @@
#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"
@@ -25,13 +26,13 @@
namespace Inkscape {
namespace Filters {
-FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea,
- cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u)
+FilterSlot::FilterSlot(NRArenaItem *item, DrawingContext &bgct,
+ DrawingContext &graphic, FilterUnits const &u)
: _item(item)
- , _source_graphic(graphic)
- , _background_ct(bgct)
- , _source_graphic_area(graphicarea)
- , _background_area(bgarea)
+ , _source_graphic(graphic.rawTarget())
+ , _background_ct(bgct.raw())
+ , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme
+ , _background_area(bgct.targetLogicalBounds().roundOutwards()) // fixme
, _units(u)
, _last_out(NR_FILTER_SOURCEGRAPHIC)
, filterquality(FILTER_QUALITY_BEST)
@@ -41,19 +42,15 @@ FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea,
using Geom::Y;
// compute slot bbox
- Geom::Rect bbox(
- Geom::Point(_source_graphic_area->x0, _source_graphic_area->y0),
- Geom::Point(_source_graphic_area->x1, _source_graphic_area->y1));
-
Geom::Affine trans = _units.get_matrix_display2pb();
- Geom::Rect bbox_trans = bbox * trans;
+ Geom::Rect bbox_trans = graphic.targetLogicalBounds() * trans;
Geom::Point min = bbox_trans.min();
_slot_x = min[X];
_slot_y = min[Y];
if (trans.isTranslation()) {
- _slot_w = _source_graphic_area->x1 - _source_graphic_area->x0;
- _slot_h = _source_graphic_area->y1 - _source_graphic_area->y0;
+ _slot_w = _source_graphic_area.width();
+ _slot_h = _source_graphic_area.height();
} else {
_slot_w = ceil(bbox_trans.width());
_slot_h = ceil(bbox_trans.height());
@@ -143,7 +140,7 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic()
cairo_translate(tsg_ct, -_slot_x, -_slot_y);
ink_cairo_transform(tsg_ct, trans);
- cairo_translate(tsg_ct, _source_graphic_area->x0, _source_graphic_area->y0);
+ cairo_translate(tsg_ct, _source_graphic_area.left(), _source_graphic_area.top());
cairo_set_source_surface(tsg_ct, _source_graphic, 0, 0);
cairo_set_operator(tsg_ct, CAIRO_OPERATOR_SOURCE);
cairo_paint(tsg_ct);
@@ -164,7 +161,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background()
cairo_translate(tbg_ct, -_slot_x, -_slot_y);
ink_cairo_transform(tbg_ct, trans);
- cairo_translate(tbg_ct, _background_area->x0, _background_area->y0);
+ cairo_translate(tbg_ct, _background_area.left(), _background_area.top());
cairo_set_source_surface(tbg_ct, bg, 0, 0);
cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE);
cairo_paint(tbg_ct);
@@ -184,11 +181,11 @@ cairo_surface_t *FilterSlot::get_result(int res)
cairo_surface_t *r = cairo_surface_create_similar(_source_graphic,
cairo_surface_get_content(_source_graphic),
- _source_graphic_area->x1 - _source_graphic_area->x0,
- _source_graphic_area->y1 - _source_graphic_area->y0);
+ _source_graphic_area.width(),
+ _source_graphic_area.height());
cairo_t *r_ct = cairo_create(r);
- cairo_translate(r_ct, -_source_graphic_area->x0, -_source_graphic_area->y0);
+ cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top());
ink_cairo_transform(r_ct, trans);
cairo_translate(r_ct, _slot_x, _slot_y);
cairo_set_source_surface(r_ct, getcairo(res), 0, 0);
diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h
index 3b08743ed..6a86ded8c 100644
--- a/src/display/nr-filter-slot.h
+++ b/src/display/nr-filter-slot.h
@@ -22,13 +22,15 @@
struct NRArenaItem;
namespace Inkscape {
+class DrawingContext;
+
namespace Filters {
class FilterSlot {
public:
/** Creates a new FilterSlot object. */
- FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea,
- cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u);
+ FilterSlot(NRArenaItem *item, DrawingContext &bgct,
+ DrawingContext &graphic, FilterUnits const &u);
/** Destroys the FilterSlot object and all its contents */
virtual ~FilterSlot();
@@ -66,7 +68,7 @@ public:
FilterUnits const &get_units() const { return _units; }
Geom::Rect get_slot_area() const;
- NRRectL const &get_sg_area() const { return *_source_graphic_area; }
+ NRRectL get_sg_area() const { NRRectL ret(_source_graphic_area); return ret; }
private:
typedef std::map<int, cairo_surface_t *> SlotMap;
@@ -81,8 +83,8 @@ private:
double _slot_x, _slot_y;
cairo_surface_t *_source_graphic;
cairo_t *_background_ct;
- NRRectL const *_source_graphic_area;
- NRRectL const *_background_area; ///< needed to extract background
+ Geom::IntRect _source_graphic_area;
+ Geom::IntRect _background_area; ///< needed to extract background
FilterUnits const &_units;
int _last_out;
FilterQuality filterquality;
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index 963d98654..25ef80c17 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -40,6 +40,7 @@
#include "display/nr-arena.h"
#include "display/nr-arena-item.h"
+#include "display/drawing-context.h"
#include <2geom/affine.h>
#include <2geom/rect.h>
#include "svg/svg-length.h"
@@ -96,14 +97,14 @@ Filter::~Filter()
}
-int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area)
+int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic)
{
if (_primitive.empty()) {
// when no primitives are defined, clear source graphic
- cairo_set_source_rgba(graphic, 0,0,0,0);
- cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE);
- cairo_paint(graphic);
- cairo_set_operator(graphic, CAIRO_OPERATOR_OVER);
+ graphic.setSource(0,0,0,0);
+ graphic.setOperator(CAIRO_OPERATOR_SOURCE);
+ graphic.paint();
+ graphic.setOperator(CAIRO_OPERATOR_OVER);
return 1;
}
@@ -136,10 +137,10 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea
= _filter_resolution(filter_area, trans, filterquality);
if (!(resolution.first > 0 && resolution.second > 0)) {
// zero resolution - clear source graphic and return
- cairo_set_source_rgba(graphic, 0,0,0,0);
- cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE);
- cairo_paint(graphic);
- cairo_set_operator(graphic, CAIRO_OPERATOR_OVER);
+ graphic.setSource(0,0,0,0);
+ graphic.setOperator(CAIRO_OPERATOR_SOURCE);
+ graphic.paint();
+ graphic.setOperator(CAIRO_OPERATOR_OVER);
return 1;
}
@@ -160,7 +161,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea
}
}
- FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_group_target(graphic), area, units);
+ FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, graphic, units);
slot.set_quality(filterquality);
slot.set_blurquality(blurquality);
@@ -168,11 +169,12 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea
_primitive[i]->render_cairo(slot);
}
+ Geom::Point origin = graphic.targetLogicalBounds().min();
cairo_surface_t *result = slot.get_result(_output_slot);
- cairo_set_source_surface(graphic, result, area->x0, area->y0);
- cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE);
- cairo_paint(graphic);
- cairo_set_operator(graphic, CAIRO_OPERATOR_OVER);
+ graphic.setSource(result, origin[Geom::X], origin[Geom::Y]);
+ graphic.setOperator(CAIRO_OPERATOR_SOURCE);
+ graphic.paint();
+ graphic.setOperator(CAIRO_OPERATOR_OVER);
cairo_surface_destroy(result);
return 0;
@@ -186,10 +188,12 @@ void Filter::set_primitive_units(SPFilterUnits unit) {
_primitive_units = unit;
}
-void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
+void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const {
+ NRRectL b(bbox);
for (unsigned i = 0 ; i < _primitive.size() ; i++) {
- if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm);
+ if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm);
}
+ bbox = *b.upgrade_2geom();
/*
TODO: something. See images at the bottom of filters.svg with medium-low
@@ -224,22 +228,13 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const {
*/
}
-void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) {
- // Modifying empty bounding boxes confuses rest of the renderer, so
- // let's not do that.
- if (item_bbox.x0 > item_bbox.x1 || item_bbox.y0 > item_bbox.y1) return;
+Geom::IntRect Filter::compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox) {
- Geom::Point min(item_bbox.x0, item_bbox.y0);
- Geom::Point max(item_bbox.x1, item_bbox.y1);
- Geom::Rect tmp_bbox(min, max);
+ Geom::Rect enlarged = filter_effect_area(item_bbox);
+ enlarged *= item->ctm;
- Geom::Rect enlarged = filter_effect_area(tmp_bbox);
- enlarged = enlarged * item->ctm;
-
- item_bbox.x0 = floor(enlarged.min()[X]);
- item_bbox.y0 = floor(enlarged.min()[Y]);
- item_bbox.x1 = ceil(enlarged.max()[X]);
- item_bbox.y1 = ceil(enlarged.max()[Y]);
+ Geom::IntRect ret(enlarged.roundOutwards());
+ return ret;
}
Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h
index e1d4c10e5..5cebf3ad3 100644
--- a/src/display/nr-filter.h
+++ b/src/display/nr-filter.h
@@ -24,6 +24,8 @@
struct NRArenaItem;
namespace Inkscape {
+class DrawingContext;
+
namespace Filters {
class Filter : public Inkscape::GC::Managed<> {
@@ -33,7 +35,7 @@ public:
* the results of filter rendering. @a bgarea and @a area specify bounding boxes
* of both surfaces in world coordinates; Cairo contexts are assumed to be in default state
* (0,0 = surface origin, no path, OVER operator) */
- int render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area);
+ int render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic);
/**
* Creates a new filter primitive under this filter object.
@@ -149,13 +151,13 @@ public:
* to be rendered so that after filtering, the original area is
* drawn correctly.
*/
- void area_enlarge(NRRectL &area, NRArenaItem const *item) const;
+ void area_enlarge(Geom::IntRect &area, NRArenaItem const *item) const;
/**
* Given an item bounding box (in user coords), this function enlarges it
* to contain the filter effects region and transforms it to screen
* coordinates
*/
- void compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox);
+ Geom::IntRect compute_drawbox(NRArenaItem 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/nr-style.cpp b/src/display/nr-style.cpp
index 72fa0c444..fa5dd0d98 100644
--- a/src/display/nr-style.cpp
+++ b/src/display/nr-style.cpp
@@ -13,6 +13,8 @@
#include "style.h"
#include "sp-paint-server.h"
#include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!)
+#include "display/drawing-context.h"
+#include "libnr/nr-rect.h"
void NRStyle::Paint::clear()
{
@@ -142,14 +144,15 @@ void NRStyle::set(SPStyle *style)
update();
}
-bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox)
+bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox)
{
// update fill pattern
if (!fill_pattern) {
switch (fill.type) {
- case PAINT_SERVER:
- fill_pattern = sp_paint_server_create_pattern(fill.server, ct, paintbox, fill.opacity);
- break;
+ case PAINT_SERVER: {
+ NRRect pb(paintbox);
+ fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), &pb, fill.opacity);
+ } break;
case PAINT_COLOR: {
SPColor const &c = fill.color;
fill_pattern = cairo_pattern_create_rgba(
@@ -162,19 +165,20 @@ bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox)
return true;
}
-void NRStyle::applyFill(cairo_t *ct)
+void NRStyle::applyFill(Inkscape::DrawingContext &ct)
{
- cairo_set_source(ct, fill_pattern);
- cairo_set_fill_rule(ct, fill_rule);
+ ct.setSource(fill_pattern);
+ ct.setFillRule(fill_rule);
}
-bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox)
+bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox)
{
if (!stroke_pattern) {
switch (stroke.type) {
- case PAINT_SERVER:
- stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct, paintbox, stroke.opacity);
- break;
+ case PAINT_SERVER: {
+ NRRect pb(paintbox);
+ stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), &pb, stroke.opacity);
+ } break;
case PAINT_COLOR: {
SPColor const &c = stroke.color;
stroke_pattern = cairo_pattern_create_rgba(
@@ -187,14 +191,14 @@ bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox)
return true;
}
-void NRStyle::applyStroke(cairo_t *ct)
+void NRStyle::applyStroke(Inkscape::DrawingContext &ct)
{
- cairo_set_source(ct, stroke_pattern);
- cairo_set_line_width(ct, stroke_width);
- cairo_set_line_cap(ct, line_cap);
- cairo_set_line_join(ct, line_join);
- cairo_set_miter_limit(ct, miter_limit);
- cairo_set_dash(ct, dash, n_dash, dash_offset);
+ ct.setSource(stroke_pattern);
+ ct.setLineWidth(stroke_width);
+ ct.setLineCap(line_cap);
+ ct.setLineJoin(line_join);
+ ct.setMiterLimit(miter_limit);
+ cairo_set_dash(ct.raw(), dash, n_dash, dash_offset); // fixme
}
void NRStyle::update()
diff --git a/src/display/nr-style.h b/src/display/nr-style.h
index e741e46b4..0ba6ce2c6 100644
--- a/src/display/nr-style.h
+++ b/src/display/nr-style.h
@@ -13,22 +13,25 @@
#define SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H
#include <cairo.h>
+#include <2geom/rect.h>
#include "color.h"
class SPColor;
class SPPaintServer;
class SPStyle;
-struct NRRect;
+namespace Inkscape {
+class DrawingContext;
+}
struct NRStyle {
NRStyle();
~NRStyle();
void set(SPStyle *);
- bool prepareFill(cairo_t *ct, NRRect *paintbox);
- bool prepareStroke(cairo_t *ct, NRRect *paintbox);
- void applyFill(cairo_t *ct);
- void applyStroke(cairo_t *ct);
+ bool prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox);
+ bool prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox);
+ void applyFill(Inkscape::DrawingContext &ct);
+ void applyStroke(Inkscape::DrawingContext &ct);
void update();
enum PaintType {