From 328fad57dbfb65e3bd31062021d5cc3081e68515 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 22 Jul 2011 04:09:27 +0200 Subject: 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) --- src/display/Makefile_insert | 4 + src/display/cairo-templates.h | 4 + src/display/canvas-arena.cpp | 61 +++++++------- src/display/display-forward.h | 3 + src/display/drawing-context.cpp | 135 +++++++++++++++++++++++++++++ src/display/drawing-context.h | 123 +++++++++++++++++++++++++++ src/display/drawing-surface.cpp | 149 ++++++++++++++++++++++++++++++++ src/display/drawing-surface.h | 78 +++++++++++++++++ src/display/nr-arena-glyphs.cpp | 147 ++++++++++++-------------------- src/display/nr-arena-glyphs.h | 2 +- src/display/nr-arena-group.cpp | 23 ++--- src/display/nr-arena-image.cpp | 108 ++++++++++-------------- src/display/nr-arena-item.cpp | 183 ++++++++++++++++------------------------ src/display/nr-arena-item.h | 23 ++--- src/display/nr-arena-shape.cpp | 137 ++++++++++-------------------- src/display/nr-arena-shape.h | 11 +-- src/display/nr-arena.cpp | 9 +- src/display/nr-arena.h | 3 +- src/display/nr-filter-image.cpp | 24 +++--- src/display/nr-filter-slot.cpp | 33 ++++---- src/display/nr-filter-slot.h | 12 +-- src/display/nr-filter.cpp | 55 ++++++------ src/display/nr-filter.h | 8 +- src/display/nr-style.cpp | 40 +++++---- src/display/nr-style.h | 13 +-- 25 files changed, 872 insertions(+), 516 deletions(-) create mode 100644 src/display/drawing-context.cpp create mode 100644 src/display/drawing-context.h create mode 100644 src/display/drawing-surface.cpp create mode 100644 src/display/drawing-surface.h (limited to 'src/display') 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 #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 + * + * 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 ¢er, 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 + * + * 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 +#include +#include +#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 ¢er, 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 + * + * 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 + * + * 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 +#include +#include +#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 #endif -#include "libnr/nr-convert2geom.h" +#include #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 #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; 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(object); + NRArenaGlyphsGroup *group = static_cast(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(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 #include #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 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(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); + FilterSlot slot(const_cast(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 +#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 { -- cgit v1.2.3