diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-07-22 02:09:27 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2011-07-22 02:09:27 +0000 |
| commit | 328fad57dbfb65e3bd31062021d5cc3081e68515 (patch) | |
| tree | 55b02cfb325a87d994fefb0e4ea88311812e9444 /src | |
| parent | Clean up some commented-out code (diff) | |
| download | inkscape-328fad57dbfb65e3bd31062021d5cc3081e68515.tar.gz inkscape-328fad57dbfb65e3bd31062021d5cc3081e68515.zip | |
Replace direct use of Cairo contexts and surfaces in the rendering tree
with wrappers which keep some extra information about the surface,
amd NRRect and NRRectL use with Geom::Rect and Geom::IntRect.
Should simplify implementing filter primitive subregions.
(bzr r10347.1.17)
Diffstat (limited to 'src')
45 files changed, 1139 insertions, 756 deletions
diff --git a/src/2geom/affine.h b/src/2geom/affine.h index b07fba0f7..d7a7a0692 100644 --- a/src/2geom/affine.h +++ b/src/2geom/affine.h @@ -65,7 +65,8 @@ class Affine , MultipliableNoncommutative< Affine, Rotate , MultipliableNoncommutative< Affine, HShear , MultipliableNoncommutative< Affine, VShear - > > > > > > > + , MultipliableNoncommutative< Affine, Zoom + > > > > > > > > { Coord _c[6]; public: @@ -113,6 +114,7 @@ public: Affine &operator*=(Rotate const &r); Affine &operator*=(HShear const &h); Affine &operator*=(VShear const &v); + Affine &operator*=(Zoom const &); /// @} bool operator==(Affine const &o) const { diff --git a/src/2geom/bezier-curve.cpp b/src/2geom/bezier-curve.cpp index 46aff8b49..8c40e5e42 100644 --- a/src/2geom/bezier-curve.cpp +++ b/src/2geom/bezier-curve.cpp @@ -106,10 +106,11 @@ namespace Geom BezierCurve::BezierCurve(std::vector<Point> const &pts) { - inner = D2<Bezier>(Bezier::Order(pts.size()-1), Bezier::Order(pts.size()-1)); + inner = D2<Bezier>(Bezier::Order(pts.size() - 1), Bezier::Order(pts.size() - 1)); for (unsigned d = 0; d < 2; ++d) { - for(unsigned i = 0; i <= pts.size(); i++) + for(unsigned i = 0; i < pts.size(); i++) { inner[d][i] = pts[i][d]; + } } } diff --git a/src/2geom/coord.h b/src/2geom/coord.h index c7bbcdcd4..f7bf2c5d0 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -69,9 +69,6 @@ struct CoordTraits<IntCoord> { typedef OptIntInterval OptIntervalType; typedef IntRect RectType; typedef OptIntRect OptRectType; - inline static bool contains(IntCoord low, IntCoord high, IntCoord testlow, IntCoord testhigh) { - return low <= testlow && testhigh < high; - } }; template<> @@ -81,9 +78,6 @@ struct CoordTraits<Coord> { typedef OptInterval OptIntervalType; typedef Rect RectType; typedef OptRect OptRectType; - inline static bool contains(Coord low, Coord high, Coord testlow, Coord testhigh) { - return low <= testlow && testhigh <= high; - } }; } // end namespace Geom diff --git a/src/2geom/forward.h b/src/2geom/forward.h index b1cad6f1f..0dbd9fa94 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -97,6 +97,7 @@ class Rotate; class Scale; class HShear; class VShear; +class Zoom; // templates template <typename> class D2; diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h index d719c16c8..a32e97d4b 100644 --- a/src/2geom/generic-interval.h +++ b/src/2geom/generic-interval.h @@ -106,11 +106,11 @@ public: /// @{ /** @brief Check whether the interval includes this number. */ bool contains(C val) const { - return CoordTraits<C>::contains(min(), max(), val, val); + return min() <= val && val <= max(); } /** @brief Check whether the interval includes the given interval. */ bool contains(Self const &val) const { - return CoordTraits<C>::contains(min(), max(), val.min(), val.max()); + return min() <= val.min() && val.max() <= max(); } /** @brief Check whether the intervals have any common elements. */ bool intersects(Self const &val) const { diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h index d60c4bb0f..6dc57b169 100644 --- a/src/2geom/generic-rect.h +++ b/src/2geom/generic-rect.h @@ -40,6 +40,7 @@ #ifndef LIB2GEOM_SEEN_GENERIC_RECT_H #define LIB2GEOM_SEEN_GENERIC_RECT_H +#include <limits> #include <boost/optional.hpp> namespace Geom { @@ -93,30 +94,37 @@ public: * @param end End of the range * @return Rectangle that contains all points from [start, end). */ template <typename InputIterator> - static GenericRect<C> from_range(InputIterator start, InputIterator end) { + static CRect from_range(InputIterator start, InputIterator end) { assert(start != end); CPoint p1 = *start++; - GenericRect<C> result(p1, p1); + CRect result(p1, p1); for (; start != end; ++start) { result.expandTo(*start); } return result; } /** @brief Create a rectangle from a C-style array of points it should contain. */ - static GenericRect<C> from_array(CPoint const *c, unsigned n) { - GenericRect<C> result = GenericRect<C>::from_range(c, c+n); + static CRect from_array(CPoint const *c, unsigned n) { + CRect result = GenericRect<C>::from_range(c, c+n); return result; } /** @brief Create rectangle from origin and dimensions. */ - static GenericRect<C> from_xywh(C x, C y, C w, C h) { + static CRect from_xywh(C x, C y, C w, C h) { CPoint xy(x, y); CPoint wh(w, h); - GenericRect<C> result(xy, xy + wh); + CRect result(xy, xy + wh); return result; } /** @brief Create rectangle from origin and dimensions. */ - static GenericRect<C> from_xywh(CPoint const &xy, CPoint const &wh) { - GenericRect<C> result(xy, xy + wh); + static CRect from_xywh(CPoint const &xy, CPoint const &wh) { + CRect result(xy, xy + wh); + return result; + } + /// Create infinite rectangle. + static CRect infinite() { + CPoint p0(std::numeric_limits<C>::min(), std::numeric_limits<C>::min()); + CPoint p1(std::numeric_limits<C>::max(), std::numeric_limits<C>::max()); + CRect result(p0, p1); return result; } /// @} @@ -155,6 +163,8 @@ public: C width() const { return f[X].extent(); } /** @brief Get the vertical extent of the rectangle. */ C height() const { return f[Y].extent(); } + /** @brief Get the ratio of width to height of the rectangle. */ + Coord aspectRatio() const { return Coord(width()) / Coord(height()); } /** @brief Get rectangle's width and height as a point. * @return Point with X coordinate corresponding to the width and the Y coordinate diff --git a/src/2geom/int-point.h b/src/2geom/int-point.h index cf2fe720f..1a16ecb7a 100644 --- a/src/2geom/int-point.h +++ b/src/2geom/int-point.h @@ -83,6 +83,11 @@ public: } IntCoord operator[](Dim2 d) const { return _pt[d]; } IntCoord &operator[](Dim2 d) { return _pt[d]; } + + IntCoord x() const throw() { return _pt[X]; } + IntCoord &x() throw() { return _pt[X]; } + IntCoord y() const throw() { return _pt[Y]; } + IntCoord &y() throw() { return _pt[Y]; } /// @} /// @name Vector-like arithmetic operations diff --git a/src/2geom/interval.h b/src/2geom/interval.h index ee6d674d2..e95da4811 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -64,7 +64,7 @@ typedef GenericOptInterval<Coord> OptInterval; class Interval : public GenericInterval<Coord> , boost::multipliable< Interval - , boost::multipliable< Interval, Coord + , boost::multiplicative< Interval, Coord > > { typedef GenericInterval<Coord> Base; @@ -180,7 +180,20 @@ public: /// @} }; +// functions required for Python bindings +inline Interval unify(Interval const &a, Interval const &b) +{ + Interval r = a | b; + return r; +} +inline OptInterval intersect(Interval const &a, Interval const &b) +{ + OptInterval r = a & b; + return r; } + +} // end namespace Geom + #endif //SEEN_INTERVAL_H /* diff --git a/src/2geom/path-intersection.cpp b/src/2geom/path-intersection.cpp index 7aa662abb..be3e3b7cc 100644 --- a/src/2geom/path-intersection.cpp +++ b/src/2geom/path-intersection.cpp @@ -271,6 +271,8 @@ intersect_polish_root (Curve const &A, double &s, } #ifdef HAVE_GSL + int status; + size_t iter = 0; if(0) { // the GSL version is more accurate, but taints this with GPL const size_t n = 2; struct rparams p = {A, B}; diff --git a/src/2geom/point.h b/src/2geom/point.h index 69da8a4ae..0eb771874 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -58,7 +58,8 @@ class Point , MultipliableNoncommutative< Point, Scale , MultipliableNoncommutative< Point, HShear , MultipliableNoncommutative< Point, VShear - > > > > > > > > > // this uses chaining so it looks weird, but works + , MultipliableNoncommutative< Point, Zoom + > > > > > > > > > > // this uses chaining so it looks weird, but works { Coord _pt[2]; public: @@ -111,6 +112,11 @@ public: Coord operator[](Dim2 d) const throw() { return _pt[d]; } Coord &operator[](Dim2 d) throw() { return _pt[d]; } + + Coord x() const throw() { return _pt[X]; } + Coord &x() throw() { return _pt[X]; } + Coord y() const throw() { return _pt[Y]; } + Coord &y() throw() { return _pt[Y]; } /// @} /// @name Vector operations @@ -172,12 +178,7 @@ public: Point &operator*=(Rotate const &r); Point &operator*=(HShear const &s); Point &operator*=(VShear const &s); - /** @brief Transform the point by the inverse of the specified matrix. */ - template <typename T> - Point &operator/=(T const &m) { - *this *= m.inverse(); - return *this; - } + Point &operator*=(Zoom const &z); /// @} /// @name Conversion to integer points diff --git a/src/2geom/rect.h b/src/2geom/rect.h index e9f6cbeb7..f7d331523 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -73,31 +73,7 @@ public: Rect(Point const &a, Point const &b) : Base(a,b) {} Rect(Coord x0, Coord y0, Coord x1, Coord y1) : Base(x0, y0, x1, y1) {} Rect(Base const &b) : Base(b) {} - /** @brief Create a rectangle from a range of points. - * The resulting rectangle will contain all ponts from the range. - * The return type of iterators must be convertible to Point. - * The range must not be empty. For possibly empty ranges, see OptRect. - * @param start Beginning of the range - * @param end End of the range - * @return Rectangle that contains all points from [start, end). */ - template <typename InputIterator> - static Rect from_range(InputIterator start, InputIterator end) { - Rect result = Base::from_range(start, end); - return result; - } - /** @brief Create a rectangle from a C-style array of points it should contain. */ - static Rect from_array(Point const *c, unsigned n) { - Rect result = Rect::from_range(c, c+n); - return result; - } - static Rect from_xywh(Coord x, Coord y, Coord w, Coord h) { - Rect result = Base::from_xywh(x, y, w, h); - return result; - } - static Rect from_xywh(Point const &o, Point const &dim) { - Rect result = Base::from_xywh(o, dim); - return result; - } + Rect(IntRect const &ir) : Base(ir.min(), ir.max()) {} /// @} /// @name Inspect dimensions. @@ -114,6 +90,10 @@ public: bool interiorIntersects(Rect const &r) const { return f[X].interiorIntersects(r[X]) && f[Y].interiorIntersects(r[Y]); } + /** @brief Check whether the interior includes the given point. */ + bool interiorContains(Point const &p) const { + return f[X].interiorContains(p[X]) && f[Y].interiorContains(p[Y]); + } /** @brief Check whether the interior includes all points in the given rectangle. * Interior of the rectangle is the entire rectangle without its borders. */ bool interiorContains(Rect const &r) const { diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 9623bed26..5627e8b6f 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -106,13 +106,14 @@ T pow(T const &t, int n) { class Translate : public TransformOperations< Translate > { - Translate() : vec(0, 0) {} Point vec; public: - /** @brief Construct a translation from its vector. */ - explicit Translate(Point const &p) : vec(p) {} - /** @brief Construct a translation from its coordinates. */ - explicit Translate(Coord x, Coord y) : vec(x, y) {} + /// Create a translation that doesn't do anything. + Translate() : vec(0, 0) {} + /// Construct a translation from its vector. + Translate(Point const &p) : vec(p) {} + /// Construct a translation from its coordinates. + Translate(Coord x, Coord y) : vec(x, y) {} operator Affine() const { Affine ret(1, 0, 0, 1, vec[X], vec[Y]); return ret; } Coord operator[](Dim2 dim) const { return vec[dim]; } @@ -120,9 +121,10 @@ public: Translate &operator*=(Translate const &o) { vec += o.vec; return *this; } bool operator==(Translate const &o) const { return vec == o.vec; } - /** @brief Get the inverse translation. */ + Point vector() const { return vec; } + /// Get the inverse translation. Translate inverse() const { return Translate(-vec); } - /** @brief Get a translation that doesn't do anything. */ + /// Get a translation that doesn't do anything. static Translate identity() { Translate ret; return ret; } friend class Point; @@ -136,10 +138,14 @@ class Scale : public TransformOperations< Scale > { Point vec; - Scale() : vec(1, 1) {} public: + /// Create a scaling that doesn't do anything. + Scale() : vec(1, 1) {} + /// Create a scaling from two scaling factors given as coordinates of a point. explicit Scale(Point const &p) : vec(p) {} + /// Create a scaling from two scaling factors. Scale(Coord x, Coord y) : vec(x, y) {} + /// Create an uniform scaling from a single scaling factor. explicit Scale(Coord s) : vec(s, s) {} inline operator Affine() const { Affine ret(vec[X], 0, 0, vec[Y], 0, 0); return ret; } @@ -150,6 +156,8 @@ public: Coord &operator[](unsigned d) { return vec[d]; } Scale &operator*=(Scale const &b) { vec[X] *= b[X]; vec[Y] *= b[Y]; return *this; } bool operator==(Scale const &o) const { return vec == o.vec; } + + Point vector() const { return vec; } Scale inverse() const { return Scale(1./vec[0], 1./vec[1]); } static Scale identity() { Scale ret; return ret; } @@ -162,15 +170,16 @@ public: class Rotate : public TransformOperations< Rotate > { - Rotate() : vec(1, 0) {} - Point vec; + Point vec; ///< @todo Convert to storing the angle, as it's more space-efficient. public: + /// Construct a zero-degree rotation. + Rotate() : vec(1, 0) {} /** @brief Construct a rotation from its angle in radians. * Positive arguments correspond to counter-clockwise rotations (if Y grows upwards). */ explicit Rotate(Coord theta) : vec(Point::polar(theta)) {} - /** @brief Construct a rotation from its characteristic vector. */ + /// Construct a rotation from its characteristic vector. explicit Rotate(Point const &p) : vec(unit_vector(p)) {} - /** @brief Construct a rotation from the coordinates of its characteristic vector. */ + /// Construct a rotation from the coordinates of its characteristic vector. explicit Rotate(Coord x, Coord y) { Rotate(Point(x, y)); } operator Affine() const { Affine ret(vec[X], vec[Y], -vec[Y], vec[X], 0, 0); return ret; } @@ -186,10 +195,10 @@ public: r.vec = Point(vec[X], -vec[Y]); return r; } - /** @brief Get a 0-degree rotation. */ + /// @brief Get a zero-degree rotation. static Rotate identity() { Rotate ret; return ret; } /** @brief Construct a rotation from its angle in degrees. - * Positive arguments correspond to counter-clockwise rotations (if Y grows upwards). */ + * Positive arguments correspond to clockwise rotations if Y grows downwards. */ static Rotate from_degrees(Coord deg) { Coord rad = (deg / 180.0) * M_PI; return Rotate(rad); @@ -213,8 +222,8 @@ public: void setFactor(Coord nf) { f = nf; } S &operator*=(S const &s) { f += s.f; return static_cast<S &>(*this); } bool operator==(S const &s) const { return f == s.f; } - S inverse() const { return S(-f); } - static S identity() { return S(0); } + S inverse() const { S ret(-f); return ret; } + static S identity() { S ret(0); return ret; } friend class Point; friend class Affine; @@ -244,6 +253,48 @@ public: operator Affine() const { Affine ret(1, f, 0, 1, 0, 0); return ret; } }; +/** @brief Combination of a translation and uniform scale. + * The translation part is applied first, then the result is scaled from the new origin. + * This way when the class is used to accumulate a zoom transform, trans always points + * to the new origin in original coordinates. + * @ingroup Transform */ +class Zoom + : public TransformOperations< Zoom > +{ + Coord _scale; + Point _trans; + Zoom() : _scale(1), _trans() {} +public: + /// Construct a zoom from a scaling factor. + explicit Zoom(Coord s) : _scale(s), _trans() {} + /// Construct a zoom from a translation. + explicit Zoom(Translate const &t) : _scale(1), _trans(t.vector()) {} + /// Construct a zoom from a scaling factor and a translation. + Zoom(Coord s, Translate const &t) : _scale(s), _trans(t.vector()) {} + + operator Affine() const { + Affine ret(_scale, 0, 0, _scale, _trans[X] * _scale, _trans[Y] * _scale); + return ret; + } + Zoom &operator*=(Zoom const &z) { + _trans += z._trans / _scale; + _scale *= z._scale; + return *this; + } + bool operator==(Zoom const &z) const { return _scale == z._scale && _trans == z._trans; } + + Coord scale() const { return _scale; } + void setScale(Coord s) { _scale = s; } + Point translation() const { return _trans; } + void setTranslation(Point const &p) { _trans = p; } + Zoom inverse() const { Zoom ret(1/_scale, Translate(-_trans*_scale)); return ret; } + static Zoom identity() { Zoom ret(1.0); return ret; } + static Zoom map_rect(Rect const &old_r, Rect const &new_r); + + friend class Point; + friend class Affine; +}; + /** @brief Specialization of exponentiation for Scale. * @relates Scale */ template<> @@ -259,7 +310,7 @@ inline Translate pow(Translate const &t, int n) { return ret; } -//TODO: matrix to trans/scale/rotate +//TODO: decomposition of Affine into some finite combination of the above classes } // end namespace Geom diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index f8553f2aa..1738754b4 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -14,6 +14,8 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include <climits> #include <glib/gmem.h> #include <gtk/gtk.h> #include <glibmm/i18n.h> @@ -23,6 +25,7 @@ #include "desktop-handles.h" #include "dialog-events.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "document.h" @@ -875,29 +878,20 @@ static guint32 clonetiler_trace_pick(Geom::Rect box) nr_arena_item_set_transform(trace_root, &t); NRGC gc(NULL); gc.transform.setIdentity(); - nr_arena_item_invoke_update( trace_root, NULL, &gc, + nr_arena_item_invoke_update( trace_root, Geom::IntRect::infinite(), &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE ); /* Item integer bbox in points */ - NRRectL ibox; - ibox.x0 = floor(trace_zoom * box[Geom::X].min()); - ibox.y0 = floor(trace_zoom * box[Geom::Y].min()); - ibox.x1 = ceil(trace_zoom * box[Geom::X].max()); - ibox.y1 = ceil(trace_zoom * box[Geom::Y].max()); + Geom::IntRect ibox = (box * Geom::Scale(trace_zoom)).roundOutwards(); /* Find visible area */ - int width = ibox.x1 - ibox.x0; - int height = ibox.y1 - ibox.y0; - double R = 0, G = 0, B = 0, A = 0; - - cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t *ct = cairo_create(s); - cairo_translate(ct, -ibox.x0, -ibox.y0); + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ibox.width(), ibox.height()); + Inkscape::DrawingContext ct(s, ibox.min()); /* Render */ - nr_arena_item_invoke_render(ct, trace_root, &ibox, NULL, + nr_arena_item_invoke_render(ct, trace_root, ibox, NR_ARENA_ITEM_RENDER_NO_CACHE ); - cairo_destroy(ct); + double R = 0, G = 0, B = 0, A = 0; ink_cairo_surface_average_color(s, R, G, B, A); cairo_surface_destroy(s); diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index fc7c8e9ab..53f87efb1 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -23,6 +23,10 @@ ink_common_sources += \ display/canvas-text.h \ display/curve.cpp \ display/curve.h \ + display/drawing-context.cpp \ + display/drawing-context.h \ + display/drawing-surface.cpp \ + display/drawing-surface.h \ display/gnome-canvas-acetate.cpp \ display/gnome-canvas-acetate.h \ display/grayscale.cpp \ diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h index a79f58548..d4c8e1493 100644 --- a/src/display/cairo-templates.h +++ b/src/display/cairo-templates.h @@ -12,6 +12,10 @@ #ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H #define SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #ifdef HAVE_OPENMP #include <omp.h> #include "preferences.h" diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 4c105cd09..1d5cfe826 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -19,6 +19,8 @@ #include "display/nr-arena-group.h" #include "display/canvas-arena.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" enum { ARENA_EVENT, @@ -161,12 +163,15 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned guint reset; reset = (flags & SP_CANVAS_UPDATE_AFFINE)? NR_ARENA_ITEM_STATE_ALL : NR_ARENA_ITEM_STATE_NONE; - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); - item->x1 = arena->root->bbox.x0 - 1; - item->y1 = arena->root->bbox.y0 - 1; - item->x2 = arena->root->bbox.x1 + 1; - item->y2 = arena->root->bbox.y1 + 1; + Geom::OptIntRect b = arena->root->bbox; + if (b) { + item->x1 = b->left() - 1; + item->y1 = b->top() - 1; + item->x2 = b->right() + 1; + item->y2 = b->bottom() + 1; + } if (arena->cursor) { /* Mess with enter/leave notifiers */ @@ -228,27 +233,23 @@ static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect cons Geom::OptIntRect r = Geom::intersect(arena->cache_area, area); if (!r || r->hasZeroArea()) return; // nothing to do - - cairo_t *ct = cairo_create(arena->cache); - cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top()); - - // clear area to paint - cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height()); - cairo_clip(ct); - cairo_save(ct); - cairo_set_source_rgba(ct, 0,0,0,0); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - cairo_restore(ct); - - NRRectL nr_area(r); - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, + Inkscape::DrawingSurface cache(arena->cache, arena->cache_area.min()); + Inkscape::DrawingContext ct(cache); + + ct.rectangle(area); + ct.clip(); + + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(0,0,0,0); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); + } + + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render (ct, arena->root, &nr_area, NULL, 0); - - cairo_destroy(ct); + nr_arena_item_invoke_render (ct, arena->root, *r, 0); } static void @@ -267,7 +268,7 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ { SPCanvasArena *arena = SP_CANVAS_ARENA (item); - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); @@ -367,7 +368,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->crossing.x, event->crossing.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); arena->active = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); if (arena->active) nr_object_ref ((NRObject *) arena->active); ret = sp_canvas_arena_send_event (arena, event); @@ -388,7 +389,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->motion.x, event->motion.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); new_arena = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; @@ -474,10 +475,10 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR g_return_if_fail (ca != NULL); g_return_if_fail (SP_IS_CANVAS_ARENA (ca)); - cairo_t *ct = cairo_create(surface); - cairo_translate(ct, -r.x0, -r.y0); - nr_arena_item_invoke_render (ct, ca->root, &r, NULL, 0); - cairo_destroy(ct); + Geom::OptIntRect area = r.upgrade_2geom(); + if (!area) return; + Inkscape::DrawingContext ct(surface, area->min()); + nr_arena_item_invoke_render (ct, ca->root, *area, 0); } diff --git a/src/display/display-forward.h b/src/display/display-forward.h index bc7013214..288da829a 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -12,6 +12,9 @@ struct SPCanvasGroupClass; class SPCurve; namespace Inkscape { +class DrawingContext; +class DrawingSurface; + namespace Display { class TemporaryItem; class TemporaryItemList; diff --git a/src/display/drawing-context.cpp b/src/display/drawing-context.cpp new file mode 100644 index 000000000..8f37bb693 --- /dev/null +++ b/src/display/drawing-context.cpp @@ -0,0 +1,135 @@ +/** + * @file + * @brief Cairo drawing context with Inkscape extensions + *//* + * Authors: + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/cairo-utils.h" +#include "helper/geom.h" + +namespace Inkscape { + +using Geom::X; +using Geom::Y; + +/** @class DrawingContext::Save + * @brief RAII idiom for saving the state of DrawingContext. */ + +DrawingContext::Save::Save() + : _ct(NULL) +{} +DrawingContext::Save::Save(DrawingContext &ct) + : _ct(&ct) +{ + _ct->save(); +} +DrawingContext::Save::~Save() +{ + if (_ct) { + _ct->restore(); + } +} +void DrawingContext::Save::save(DrawingContext &ct) +{ + if (_ct) { + // TODO: it might be better to treat this occurence as a bug + _ct->restore(); + } + _ct = &ct; + _ct->save(); +} + +/** @class DrawingContext + * @brief Minimal wrapper over Cairo. + * + * This is a wrapper over cairo_t, extended with operations that work + * with 2Geom geometrical primitives. Some of this is probably duplicated + * in cairo-render-context.cpp, which provides higher level operations + * for drawing entire SPObjects when exporting. + */ + +DrawingContext::DrawingContext(cairo_surface_t *surface, Geom::Point const &origin) + : _ct(NULL) + , _surface(new DrawingSurface(surface, origin)) + , _delete_surface(true) +{ + _surface->_has_context = true; + _ct = _surface->createRawContext(); +} + +DrawingContext::DrawingContext(DrawingSurface &s) + : _ct(s.createRawContext()) + , _surface(&s) + , _delete_surface(false) +{} + +DrawingContext::~DrawingContext() +{ + cairo_destroy(_ct); + _surface->_has_context = false; + if (_delete_surface) { + delete _surface; + } +} + +void DrawingContext::arc(Geom::Point const ¢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 <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H + +#include <boost/utility.hpp> +#include <glib.h> +#include <cairo.h> +#include <2geom/affine.h> +#include <2geom/angle.h> +#include <2geom/rect.h> +#include <2geom/transforms.h> + +namespace Inkscape { + +class DrawingSurface; + +class DrawingContext + : boost::noncopyable +{ +public: + class Save { + public: + Save(); + Save(DrawingContext &ct); + ~Save(); + void save(DrawingContext &ct); + private: + DrawingContext *_ct; + }; + + DrawingContext(cairo_surface_t *surface, Geom::Point const &origin); + DrawingContext(DrawingSurface &s); + ~DrawingContext(); + + void save() { cairo_save(_ct); } + void restore() { cairo_restore(_ct); } + void pushGroup() { cairo_push_group(_ct); } + void pushAlphaGroup() { cairo_push_group_with_content(_ct, CAIRO_CONTENT_ALPHA); } + void popGroupToSource() { cairo_pop_group_to_source(_ct); } + + void transform(Geom::Affine const &trans); + void translate(Geom::Point const &t) { cairo_translate(_ct, t[Geom::X], t[Geom::Y]); } // todo: take Translate + void translate(double dx, double dy) { cairo_translate(_ct, dx, dy); } + void scale(Geom::Scale const &s) { cairo_scale(_ct, s[Geom::X], s[Geom::Y]); } + void scale(double sx, double sy) { cairo_scale(_ct, sx, sy); } + + void moveTo(Geom::Point const &p) { cairo_move_to(_ct, p[Geom::X], p[Geom::Y]); } + void lineTo(Geom::Point const &p) { cairo_line_to(_ct, p[Geom::X], p[Geom::Y]); } + void curveTo(Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) { + cairo_curve_to(_ct, p1[Geom::X], p1[Geom::Y], p2[Geom::X], p2[Geom::Y], p3[Geom::X], p3[Geom::Y]); + } + void arc(Geom::Point const ¢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 <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/drawing-surface.h" +#include "display/cairo-utils.h" + +namespace Inkscape { + +using Geom::X; +using Geom::Y; + + +/** @class DrawingSurface + * @brief Drawing surface that remembers its origin. + * + * This is a very minimalistic wrapper over cairo_surface_t. The main + * extra functionality provided by this class is that it automates + * the mapping from "logical space" (coordinates in the rendering) + * and the "physical space" (surface pixels). For example, patterns + * have to be rendered on surfaces which have possibly non-integer + * widths and heights. + */ + +/** @brief Creates a surface with the given physical extents. + * When a drawing context is created for this surface, its pixels + * will cover the area under the given rectangle. */ +DrawingSurface::DrawingSurface(Geom::IntRect const &area) + : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, area.width(), area.height())) + , _origin(area.min()) + , _scale(1, 1) +{} + +/** @brief Creates a surface with the given logical extents. + * When a drawing context is created for this surface, its pixels + * will cover the area under the given rectangle. If the rectangle + * has non-integer width, there will be slightly more than 1 pixel + * per logical unit. */ +DrawingSurface::DrawingSurface(Geom::Rect const &area) + : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil(area.width()), ceil(area.height()))) + , _origin(area.min()) + , _scale(ceil(area.width()) / area.width(), ceil(area.height()) / area.height()) +{} + +/** @brief Creates a surface with the given logical and physical extents. + * When a drawing context is created for this surface, its pixels + * will cover the area under the given rectangle. IT will contain + * the number of pixels specified by the second argument. + * @param logbox Logical extents of the surface + * @param pixdims Pixel dimensions of the surface. */ +DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims) + : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pixdims[X], pixdims[Y])) + , _origin(logbox.min()) + , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height()) +{} + +/** @brief Wrap a cairo_surface_t. + * This constructor will take an extra reference on @a surface, which will + * be released on destruction. */ +DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin) + : _surface(surface) + , _origin(origin) + , _scale(1, 1) +{ + cairo_surface_reference(surface); +} + +DrawingSurface::~DrawingSurface() +{ + cairo_surface_destroy(_surface); +} + +/// Get the logical extents of the surface. +Geom::Rect +DrawingSurface::area() const +{ + Geom::Rect r = Geom::Rect::from_xywh(_origin, dimensions()); + return r; +} + +/// Get the logical width and weight of the surface as a point. +Geom::Point +DrawingSurface::dimensions() const +{ + double w = cairo_image_surface_get_width(_surface); + double h = cairo_image_surface_get_height(_surface); + Geom::Point logical_dims(w / _scale[X], h / _scale[Y]); + return logical_dims; +} + +Geom::Point +DrawingSurface::origin() const +{ + return _origin; +} + +Geom::Scale +DrawingSurface::scale() const +{ + return _scale; +} + +/// Get the transformation applied to the drawing context on construction. +Geom::Affine +DrawingSurface::drawingTransform() const +{ + Geom::Affine ret = _scale * Geom::Translate(-_origin); + return ret; +} + +cairo_surface_type_t +DrawingSurface::type() const +{ + // currently hardcoded + return CAIRO_SURFACE_TYPE_IMAGE; +} + +/** @brief Create a drawing context for this surface. + * It's better to use the surface constructor of DrawingContext. */ +cairo_t * +DrawingSurface::createRawContext() +{ + cairo_t *ct = cairo_create(_surface); + if (_scale != Geom::Scale::identity()) { + cairo_scale(ct, _scale[X], _scale[Y]); + } + cairo_translate(ct, -_origin[X], -_origin[Y]); + return ct; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h new file mode 100644 index 000000000..2d0e147e2 --- /dev/null +++ b/src/display/drawing-surface.h @@ -0,0 +1,78 @@ +/** + * @file + * @brief Cairo surface that remembers its origin + *//* + * Authors: + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H + +#include <boost/shared_ptr.hpp> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <2geom/affine.h> +#include <2geom/rect.h> +#include <2geom/transforms.h> + +namespace Inkscape { +class DrawingContext; + +class DrawingSurface +{ +public: + explicit DrawingSurface(Geom::IntRect const &area); + explicit DrawingSurface(Geom::Rect const &area); + DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims); + DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin); + virtual ~DrawingSurface(); + + Geom::Rect area() const; + Geom::Point dimensions() const; + Geom::Point origin() const; + Geom::Scale scale() const; + Geom::Affine drawingTransform() const; + cairo_surface_type_t type() const; + + cairo_surface_t *raw() { return _surface; } + cairo_t *createRawContext(); + +protected: + cairo_surface_t *_surface; + Geom::Point _origin; + Geom::Scale _scale; + bool _has_context; + + friend class DrawingContext; +}; + +class PixbufSurface + : public DrawingSurface +{ +public: + explicit PixbufSurface(GdkPixbuf *pb, Geom::Point const &origin = Geom::Point(0,0)); + ~PixbufSurface(); +protected: + GdkPixbuf *pb; + + friend class DrawingContext; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index d09f66a2f..99b0a004e 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -14,13 +14,15 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include "libnr/nr-convert2geom.h" +#include <cairo.h> #include <2geom/affine.h> +#include <2geom/rect.h> +#include "libnr/nr-convert2geom.h" #include "style.h" #include "display/nr-arena.h" #include "display/nr-arena-glyphs.h" -#include <cairo.h> #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "helper/geom.h" #ifdef test_glyph_liv @@ -39,9 +41,8 @@ static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass); static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs); static void nr_arena_glyphs_finalize(NRObject *object); -static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static guint nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static guint nr_arena_glyphs_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); +static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static NRArenaItemClass *glyphs_parent_class; @@ -75,7 +76,6 @@ nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass) object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>; item_class->update = nr_arena_glyphs_update; - item_class->clip = nr_arena_glyphs_clip; item_class->pick = nr_arena_glyphs_pick; } @@ -102,7 +102,7 @@ nr_arena_glyphs_finalize(NRObject *object) } static guint -nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) +nr_arena_glyphs_update(NRArenaItem *item, Geom::IntRect const &/*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) { NRArenaGlyphs *glyphs = NR_ARENA_GLYPHS(item); NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item->parent); @@ -132,50 +132,32 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s // (one for each point on the curve) b->expandBy(miterMax); } - } + } if (b) { - item->bbox.x0 = floor(b->left()); - item->bbox.y0 = floor(b->top()); - item->bbox.x1 = ceil (b->right()); - item->bbox.y1 = ceil (b->bottom()); + item->bbox = b->roundOutwards(); } else { - item->bbox.x0 = 0; - item->bbox.y0 = 0; - item->bbox.x1 = -1; - item->bbox.y1 = -1; + item->bbox = Geom::OptIntRect(); } return NR_ARENA_ITEM_STATE_ALL; } -static guint nr_arena_glyphs_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/) -{ - NRArenaGlyphs *glyphs; - - glyphs = NR_ARENA_GLYPHS(item); - - if (!glyphs->font) return item->state; - - // TODO : render to greyscale pixblock provided for clipping - - return item->state; -} - static NRArenaItem * -nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int /*sticky*/) +nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int /*sticky*/) { NRArenaGlyphs *glyphs; glyphs = NR_ARENA_GLYPHS(item); if (!glyphs->font ) return NULL; + if (!item->bbox) return NULL; - double const x = p[Geom::X]; - double const y = p[Geom::Y]; - /* With text we take a simple approach: pick if the point is in a characher bbox */ - if ((x + delta >= item->bbox.x0) && (y + delta >= item->bbox.y0) && (x - delta <= item->bbox.x1) && (y - delta <= item->bbox.y1)) return item; - + // With text we take a simple approach: pick if the point is in a characher bbox + Geom::Rect expanded(*item->bbox); + expanded.expandBy(delta); + if (expanded.contains(p)) + return item; return NULL; } @@ -205,10 +187,10 @@ static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass); static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group); static void nr_arena_glyphs_group_finalize(NRObject *object); -static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky); +static guint nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); +static unsigned int nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky); static NRArenaGroupClass *group_parent_class; @@ -251,14 +233,12 @@ static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group) { group->style = NULL; - group->paintbox.x0 = group->paintbox.y0 = 0.0F; - group->paintbox.x1 = group->paintbox.y1 = -1.0F; } static void nr_arena_glyphs_group_finalize(NRObject *object) { - NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object); + NRArenaGlyphsGroup *group = static_cast<NRArenaGlyphsGroup *>(object); if (group->style) { sp_style_unref(group->style); @@ -269,7 +249,7 @@ nr_arena_glyphs_group_finalize(NRObject *object) } static guint -nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset) +nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset) { NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item); @@ -283,24 +263,20 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s static unsigned int -nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/) +nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int /*flags*/) { NRArenaItem *child = 0; NRArenaGroup *group = NR_ARENA_GROUP(item); NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - if (!ct) { - return item->state; - } - if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - cairo_save(ct); + Inkscape::DrawingContext::Save save(ct); guint32 rgba = item->arena->outlinecolor; - ink_cairo_set_source_rgba32(ct, rgba); - cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode - cairo_new_path(ct); - ink_cairo_transform(ct, ggroup->ctm); + ct.setSource(rgba); + ct.setTolerance(1.25); // low quality, but good enough for outline mode + ct.newPath(); + ct.transform(ggroup->ctm); for (child = group->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); @@ -308,83 +284,78 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi Geom::PathVector const * pathv = g->font->PathVector(g->glyph); Geom::Affine transform = g->g_transform; - cairo_save(ct); - ink_cairo_transform(ct, transform); - feed_pathvector_to_cairo (ct, *pathv); - cairo_fill(ct); - cairo_restore(ct); + Inkscape::DrawingContext::Save save(ct); + ct.transform(transform); + ct.path(*pathv); + ct.fill(); } - cairo_restore(ct); return item->state; } // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding bool has_stroke, has_fill; - cairo_save(ct); - ink_cairo_transform(ct, ggroup->ctm); + Inkscape::DrawingContext::Save save(ct); + ct.transform(ggroup->ctm); - has_fill = ggroup->nrstyle.prepareFill(ct, &ggroup->paintbox); - has_stroke = ggroup->nrstyle.prepareStroke(ct, &ggroup->paintbox); + has_fill = ggroup->nrstyle.prepareFill(ct, ggroup->paintbox); + has_stroke = ggroup->nrstyle.prepareStroke(ct, ggroup->paintbox); if (has_fill || has_stroke) { for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - cairo_save(ct); - ink_cairo_transform(ct, g->g_transform); - feed_pathvector_to_cairo(ct, pathv); - cairo_restore(ct); + Inkscape::DrawingContext::Save save(ct); + ct.transform(g->g_transform); + ct.path(pathv); } if (has_fill) { ggroup->nrstyle.applyFill(ct); - cairo_fill_preserve(ct); + ct.fillPreserve(); } if (has_stroke) { ggroup->nrstyle.applyStroke(ct); - cairo_stroke_preserve(ct); + ct.strokePreserve(); } - cairo_new_path(ct); // clear path + ct.newPath(); // clear path } // has fill or stroke pattern - cairo_restore(ct); return item->state; } -static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) +static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) { NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - cairo_save(ct); + Inkscape::DrawingContext::Save save(ct); + // handle clip-rule if (ggroup->style) { if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); } else { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + ct.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ink_cairo_transform(ct, ggroup->ctm); + ct.transform(ggroup->ctm); for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - cairo_save(ct); - ink_cairo_transform(ct, g->g_transform); - feed_pathvector_to_cairo(ct, pathv); - cairo_restore(ct); + Inkscape::DrawingContext::Save save(ct); + ct.transform(g->g_transform); + ct.path(pathv); } - cairo_fill(ct); - cairo_restore(ct); + ct.fill(); return item->state; } static NRArenaItem * -nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky) +nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky) { NRArenaItem *picked = NULL; @@ -450,15 +421,7 @@ nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox) nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg)); nr_return_if_fail(pbox != NULL); - if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) { - gg->paintbox.x0 = pbox->x0; - gg->paintbox.y0 = pbox->y0; - gg->paintbox.x1 = pbox->x1; - gg->paintbox.y1 = pbox->y1; - } else { - gg->paintbox.x0 = gg->paintbox.y0 = 0.0F; - gg->paintbox.x1 = gg->paintbox.y1 = -1.0F; - } + gg->paintbox = pbox->upgrade_2geom(); nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE); } diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h index c43095cb2..4b2aed7b9 100644 --- a/src/display/nr-arena-glyphs.h +++ b/src/display/nr-arena-glyphs.h @@ -70,7 +70,7 @@ typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass; NRType nr_arena_glyphs_group_get_type (void); struct NRArenaGlyphsGroup : public NRArenaGroup { - NRRect paintbox; + Geom::OptRect paintbox; NRStyle nrstyle; static NRArenaGlyphsGroup *create(NRArena *arena) { diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 1d552fbc2..1f7c421d0 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -24,6 +24,7 @@ #include "filters/blend.h" #include "display/nr-filter-blend.h" #include "helper/geom.h" +#include "display/drawing-context.h" static void nr_arena_group_class_init (NRArenaGroupClass *klass); static void nr_arena_group_init (NRArenaGroup *group); @@ -34,10 +35,10 @@ static void nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRA static void nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child); static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static unsigned int nr_arena_group_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); +static unsigned int nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static unsigned int nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static NRArenaItemClass *parent_class; @@ -163,7 +164,7 @@ nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRAren } static unsigned int -nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset) +nr_arena_group_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset) { unsigned int newstate; NRArenaGroup *group = NR_ARENA_GROUP (item); @@ -178,10 +179,10 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - item->bbox = NR_RECT_L_EMPTY; + item->bbox = Geom::OptIntRect(); for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) - nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox); + item->bbox.unionWith(outline ? child->bbox : child->drawbox); } } @@ -217,7 +218,7 @@ void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style) } static unsigned int -nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags) +nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) { NRArenaGroup *group = NR_ARENA_GROUP (item); @@ -225,7 +226,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock /* Just compose children into parent buffer */ for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_item_invoke_render (ct, child, area, pb, flags); + ret = nr_arena_item_invoke_render (ct, child, area, flags); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; } @@ -233,7 +234,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } static unsigned int -nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) +nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area) { NRArenaGroup *group = NR_ARENA_GROUP (item); unsigned int ret = item->state; @@ -247,7 +248,7 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) } static NRArenaItem * -nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky) +nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky) { NRArenaGroup *group = NR_ARENA_GROUP (item); diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index a943a6214..5336fcda9 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -17,6 +17,7 @@ #include "nr-arena-image.h" #include "style.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-filter.h" #include "sp-filter.h" @@ -34,9 +35,9 @@ static void nr_arena_image_class_init (NRArenaImageClass *klass); static void nr_arena_image_init (NRArenaImage *image); static void nr_arena_image_finalize (NRObject *object); -static unsigned int nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static unsigned int nr_arena_image_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); +static unsigned int nr_arena_image_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static Geom::Rect nr_arena_image_rect (NRArenaImage *image); static NRArenaItemClass *parent_class; @@ -104,7 +105,7 @@ nr_arena_image_finalize (NRObject *object) } static unsigned int -nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ ) +nr_arena_image_update( NRArenaItem *item, Geom::IntRect const &/*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ ) { // clear old bbox nr_arena_item_request_render(item); @@ -116,30 +117,17 @@ nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned /* Calculate bbox */ if (image->pixbuf) { - NRRect bbox; - Geom::Rect r = nr_arena_image_rect(image) * gc->transform; - - item->bbox.x0 = floor(r.left()); // Floor gives the coordinate in which the point resides - item->bbox.y0 = floor(r.top()); - item->bbox.x1 = ceil(r.right()); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = ceil(r.bottom()); + item->bbox = r.roundOutwards(); } else { - item->bbox.x0 = (int) gc->transform[4]; - item->bbox.y0 = (int) gc->transform[5]; - item->bbox.x1 = item->bbox.x0 - 1; - item->bbox.y1 = item->bbox.y0 - 1; + item->bbox = Geom::OptIntRect(); } return NR_ARENA_ITEM_STATE_ALL; } -static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/, NRPixBlock * /*pb*/, unsigned int /*flags*/ ) +static unsigned int nr_arena_image_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/, unsigned int /*flags*/ ) { - if (!ct) { - return item->state; - } - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); NRArenaImage *image = NR_ARENA_IMAGE (item); @@ -151,69 +139,63 @@ static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRec // FIXME: at the moment gdk_cairo_set_source_pixbuf creates an ARGB copy // of the pixbuf. Fix this in Cairo and/or GDK. - cairo_save(ct); - ink_cairo_transform(ct, image->ctm); + Inkscape::DrawingContext::Save save(ct); + ct.transform(image->ctm); + ct.newPath(); + ct.rectangle(image->clipbox); + ct.clip(); - cairo_new_path(ct); - cairo_rectangle(ct, image->clipbox.left(), image->clipbox.top(), - image->clipbox.width(), image->clipbox.height()); - cairo_clip(ct); - - cairo_translate(ct, image->ox, image->oy); - cairo_scale(ct, image->sx, image->sy); - - cairo_set_source_surface(ct, image->surface, 0, 0); + ct.translate(image->ox, image->oy); + ct.scale(image->sx, image->sy); + ct.setSource(image->surface, 0, 0); cairo_matrix_t tt; Geom::Affine total; - cairo_get_matrix(ct, &tt); + cairo_get_matrix(ct.raw(), &tt); ink_matrix_to_2geom(total, tt); if (total.expansionX() > 1.0 || total.expansionY() > 1.0) { - cairo_pattern_t *p = cairo_get_source(ct); + cairo_pattern_t *p = cairo_get_source(ct.raw()); cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST); } - - cairo_paint_with_alpha(ct, ((double) item->opacity) / 255.0); - cairo_restore(ct); + ct.paint(((double) item->opacity) / 255.0); } else { // outline; draw a rect instead Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff); - cairo_save(ct); - ink_cairo_transform(ct, image->ctm); - - cairo_new_path(ct); - - Geom::Rect r = nr_arena_image_rect (image); - Geom::Point c00 = r.corner(0); - Geom::Point c01 = r.corner(3); - Geom::Point c11 = r.corner(2); - Geom::Point c10 = r.corner(1); + { Inkscape::DrawingContext::Save save(ct); + ct.transform(image->ctm); + ct.newPath(); + + Geom::Rect r = nr_arena_image_rect (image); + Geom::Point c00 = r.corner(0); + Geom::Point c01 = r.corner(3); + Geom::Point c11 = r.corner(2); + Geom::Point c10 = r.corner(1); + + ct.moveTo(c00); + // the box + ct.lineTo(c10); + ct.lineTo(c11); + ct.lineTo(c01); + ct.lineTo(c00); + // the diagonals + ct.lineTo(c11); + ct.moveTo(c10); + ct.lineTo(c01); + } - cairo_move_to (ct, c00[Geom::X], c00[Geom::Y]); - // the box - cairo_line_to (ct, c10[Geom::X], c10[Geom::Y]); - cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]); - cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]); - cairo_line_to (ct, c00[Geom::X], c00[Geom::Y]); - // the diagonals - cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]); - cairo_move_to (ct, c10[Geom::X], c10[Geom::Y]); - cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]); - cairo_restore(ct); - - cairo_set_line_width(ct, 0.5); - ink_cairo_set_source_rgba32(ct, rgba); - cairo_stroke(ct); + ct.setLineWidth(0.5); + ct.setSource(rgba); + ct.stroke(); } return item->state; } /** Calculates the closest distance from p to the segment a1-a2*/ double -distance_to_segment (Geom::Point p, Geom::Point a1, Geom::Point a2) +distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2) { // calculate sides of the triangle and their squares double d1 = Geom::L2(p - a1); @@ -233,7 +215,7 @@ distance_to_segment (Geom::Point p, Geom::Point a1, Geom::Point a2) } static NRArenaItem * -nr_arena_image_pick( NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/ ) +nr_arena_image_pick( NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/ ) { NRArenaImage *image = NR_ARENA_IMAGE (item); diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 9ca5a7463..c1ffefa1d 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -21,6 +21,8 @@ #include "display/cairo-utils.h" #include "display/cairo-templates.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" #include "display/canvas-arena.h" #include "nr-arena.h" #include "nr-arena-item.h" @@ -210,7 +212,7 @@ nr_arena_item_unref (NRArenaItem *item) } unsigned int -nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, +nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset) { NRGC childgc (gc); @@ -243,8 +245,8 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, if (!(~item->state & state)) return item->state; /* Test whether to return immediately */ - if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) { - if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox)) + if (item->state & NR_ARENA_ITEM_STATE_BBOX) { + if (!area.intersects(outline ? item->bbox : item->drawbox)) return item->state; } @@ -269,13 +271,9 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, /* Enlarge the drawbox to contain filter effects */ if (item->filter && filter && item->item_bbox) { - item->drawbox.x0 = item->item_bbox->min()[Geom::X]; - item->drawbox.y0 = item->item_bbox->min()[Geom::Y]; - item->drawbox.x1 = item->item_bbox->max()[Geom::X]; - item->drawbox.y1 = item->item_bbox->max()[Geom::Y]; - item->filter->compute_drawbox (item, item->drawbox); + item->drawbox = item->filter->compute_drawbox(item, *item->item_bbox); } else { - memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); + item->drawbox = item->bbox; } /* Clipping */ @@ -289,10 +287,9 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; } if (outline) { - nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox); + item->bbox.unionWith(item->clip->bbox); } else { - // for clipping, we need geometric bbox - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); + item->drawbox.intersectWith(item->clip->bbox); } } /* Masking */ @@ -303,10 +300,10 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; } if (outline) { - nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox); + item->bbox.unionWith(item->mask->bbox); } else { // for masking, we need full drawbox of mask - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); + item->drawbox.intersectWith(item->mask->drawbox); } } @@ -331,8 +328,8 @@ struct MaskLuminanceToAlpha { }; unsigned int -nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area, - NRPixBlock *pb, unsigned int flags) +nr_arena_item_invoke_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, + unsigned int flags) { bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); bool filter = (item->arena->rendermode != Inkscape::RENDERMODE_OUTLINE && @@ -343,15 +340,6 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX, item->state); - if (!ct) return item->state; - -#ifdef NR_ARENA_ITEM_VERBOSE - g_message ("Invoke render %p on %p: %d %d - %d %d, %d %d - %d %d", item, pb, - area->x0, area->y0, - area->x1, area->y1, - item->drawbox.x0, item->drawbox.y0, - item->drawbox.x1, item->drawbox.y1); -#endif /* If we are invisible, just return successfully */ if (!item->visible) @@ -360,15 +348,14 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area if (outline) { // intersect with bbox rather than drawbox, as we want to render things outside // of the clipping path as well - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->bbox); - if (nr_rect_l_test_empty(carea)) + Geom::OptIntRect carea = Geom::intersect(area, item->bbox); + if (!carea) return item->state | NR_ARENA_ITEM_STATE_RENDER; // No caching in outline mode for now; investigate if it really gives any advantage with cairo. // Also no attempts to clip anything; just render everything: item, clip, mask // First, render the object itself - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); + unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { /* Clean up and return error */ item->state |= NR_ARENA_ITEM_STATE_INVALID; @@ -381,12 +368,12 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (item->clip) { item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips - NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags); - } + NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, *carea, flags); + } // render mask as an object, using a different color if (item->mask) { item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks - NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags); + NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, *carea, flags); } item->arena->outlinecolor = saved_rgba; // restore outline color @@ -395,13 +382,12 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // carea is the bounding box for intermediate rendering. // NOTE: carea might be larger than area, because of filter effects. - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->drawbox); - if (nr_rect_l_test_empty(carea)) + Geom::OptIntRect carea = Geom::intersect(area, item->drawbox); + if (!carea) return item->state | NR_ARENA_ITEM_STATE_RENDER; if (item->filter && filter) { - item->filter->area_enlarge (carea, item); - nr_rect_l_intersect (&carea, &carea, &item->drawbox); + item->filter->area_enlarge(*carea, item); + carea.intersectWith(item->drawbox); } using namespace Inkscape; @@ -436,7 +422,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // short-circuit the simple case. if (!needs_intermediate_rendering) { - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; @@ -444,51 +430,48 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area return item->state | NR_ARENA_ITEM_STATE_RENDER; } - cairo_surface_t *intermediate = cairo_surface_create_similar( - cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA, - carea.x1 - carea.x0, carea.y1 - carea.y0); - cairo_t *ict = cairo_create(intermediate); - cairo_translate(ict, -carea.x0, -carea.y0); + DrawingSurface intermediate(*carea); + DrawingContext ict(intermediate); // 1. Render clipping path with alpha = opacity. - cairo_set_source_rgba(ict, 0,0,0,opacity); + ict.setSource(0,0,0,opacity); // Since clip can be combined with opacity, the result could be incorrect // for overlapping clip children. To fix this we use the SOURCE operator // instead of the default OVER. - cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); + ict.setOperator(CAIRO_OPERATOR_SOURCE); if (item->clip) { - state = nr_arena_item_invoke_clip(ict, item->clip, const_cast<NRRectL*>(area)); + state = nr_arena_item_invoke_clip(ict, item->clip, *carea); // fixme: carea or area? if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } } else { // if there is no clipping path, fill the entire surface with alpha = opacity. - cairo_paint(ict); + ict.paint(); } // reset back to default - cairo_set_operator(ict, CAIRO_OPERATOR_OVER); + ict.setOperator(CAIRO_OPERATOR_OVER); // 2. Render the mask if present and compose it with the clipping path + opacity. if (item->mask) { - cairo_push_group(ict); - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); + ict.pushGroup(); + state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } - cairo_surface_t *mask_s = cairo_get_group_target(ict); + cairo_surface_t *mask_s = ict.rawTarget(); // Convert mask's luminance to alpha ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha()); - cairo_pop_group_to_source(ict); - cairo_set_operator(ict, CAIRO_OPERATOR_IN); - cairo_paint(ict); - cairo_set_operator(ict, CAIRO_OPERATOR_OVER); + ict.popGroupToSource(); + ict.setOperator(CAIRO_OPERATOR_IN); + ict.paint(); + ict.setOperator(CAIRO_OPERATOR_OVER); } // 3. Render object itself. - cairo_push_group(ict); - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); + ict.pushGroup(); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; @@ -496,71 +479,53 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // 4. Apply filter. if (item->filter && filter) { - // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering - // Proper fix: call this function with a drawing context class - // that contains information about the surface's bounds - NRRectL bgarea; - if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) { - bgarea = carea; - } else { - bgarea = NRRectL(item->arena->canvasarena->cache_area); - } - item->filter->render(item, ct, &bgarea, ict, &carea); + item->filter->render(item, ct, ict); // Note that because the object was rendered to a group, // the internals of the filter need to use cairo_get_group_target() // instead of cairo_get_target(). } // 5. Render object inside the composited mask + clip - cairo_pop_group_to_source(ict); - cairo_set_operator(ict, CAIRO_OPERATOR_IN); - cairo_paint(ict); + ict.popGroupToSource(); + ict.setOperator(CAIRO_OPERATOR_IN); + ict.paint(); // 6. Paint the completed rendering onto the base context - cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); - cairo_paint(ct); - cairo_set_source_rgba(ct, 0,0,0,0); + ct.setSource(&intermediate); + ct.paint(); + ct.setSource(0,0,0,0); // the call above is to clear a ref on the intermediate surface held by ct retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; cleanup: - cairo_destroy(ict); - cairo_surface_destroy(intermediate); - return retstate; } unsigned int -nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) +nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area) { nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID); -#ifdef NR_ARENA_ITEM_VERBOSE - printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n", - item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0, - (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1); -#endif - unsigned retstate = 0; - + // don't bother if the object does not implement clipping (e.g. NRArenaImage) if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) return retstate; - if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { + if (item->visible && area.intersects(item->bbox)) { // The item used as the clipping path itself has a clipping path. - // Render this item's clipping path onto a temporary surface, then composite it with the item - // using the IN operator + // Render this item's clipping path onto a temporary surface, then composite it + // with the item using the IN operator if (item->clip) { - cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); - cairo_save(ct); - cairo_set_source_rgba(ct, 0,0,0,1); - nr_arena_item_invoke_clip(ct, item->clip, area); - cairo_restore(ct); - cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + ct.pushAlphaGroup(); + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(0,0,0,1); + nr_arena_item_invoke_clip(ct, item->clip, area); + } + ct.pushAlphaGroup(); } // rasterize the clipping path @@ -568,12 +533,12 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) clip (ct, item, area); if (item->clip) { - cairo_pop_group_to_source(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_IN); - cairo_paint(ct); - cairo_pop_group_to_source(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); + ct.popGroupToSource(); + ct.setOperator(CAIRO_OPERATOR_IN); + ct.paint(); + ct.popGroupToSource(); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); } } @@ -581,7 +546,7 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) } NRArenaItem * -nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, +nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky) { nr_return_val_if_fail (item != NULL, NULL); @@ -595,14 +560,11 @@ nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, if (!sticky && !(item->visible && item->sensitive)) return NULL; - // TODO: rewrite using Geom::Rect - const double x = p[Geom::X]; - const double y = p[Geom::Y]; + if (!item->bbox) return NULL; + Geom::Rect expanded(*item->bbox); + expanded.expandBy(delta); - if (((x + delta) >= item->bbox.x0) && - ((x - delta) < item->bbox.x1) && - ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) - { + if (expanded.contains(p)) { if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick) return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> pick (item, p, delta, sticky); @@ -639,7 +601,7 @@ nr_arena_item_request_render (NRArenaItem *item) nr_return_if_fail (NR_IS_ARENA_ITEM (item)); bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox); + nr_arena_request_render_rect (item->arena, outline ? item->bbox : item->drawbox); } /* Public */ @@ -694,6 +656,7 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform) const Geom::Affine *ms = (transform) ? transform : &GEOM_MATRIX_IDENTITY; if (!Geom::matrix_equalp(*md, *ms, NR_EPSILON)) { + // mark the area where the object was for redraw. nr_arena_item_request_render (item); if (!transform || transform->isIdentity()) { /* Set to identity affine */ @@ -703,6 +666,8 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform) item->transform = new (GC::ATOMIC) Geom::Affine (); *item->transform = *transform; } + // when update is called, the area where the object was moved + // will be redrawn as well nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE); } } @@ -800,7 +765,7 @@ nr_arena_item_set_order (NRArenaItem *item, int order) } void -nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox) +nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox) { nr_return_if_fail(item != NULL); nr_return_if_fail(NR_IS_ARENA_ITEM(item)); diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index d65a75ed8..4b43e4da8 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -23,6 +23,7 @@ #include "nr-arena-forward.h" namespace Inkscape { +class DrawingContext; namespace Filters { class Filter; } } @@ -92,8 +93,8 @@ struct NRArenaItem : public NRObject { unsigned int key; ///< Some SPItems can have more than one NRArenaItem, ///this value is a hack used to distinguish between them - NRRectL bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin - NRRectL drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks + Geom::OptIntRect bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin + Geom::OptIntRect drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks Geom::OptRect item_bbox; ///< Bounding box in item coordinates, required by filters Geom::Affine *transform; ///< Incremental transform of this item, as given by the transform= attribute Geom::Affine ctm; ///< Total transform from pixel grid to item coords @@ -119,10 +120,10 @@ struct NRArenaItemClass : public NRObjectClass { void (* remove_child) (NRArenaItem *item, NRArenaItem *child); void (* set_child_position) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - unsigned int (* update) (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); - unsigned int (* render) (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); - unsigned int (* clip) (cairo_t *ct, NRArenaItem *item, NRRectL *area); - NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); + unsigned int (* update) (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); + unsigned int (* render) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); + unsigned int (* clip) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); + NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); }; #define NR_ARENA_ITEM_ARENA(ai) (((NRArenaItem *) (ai))->arena) @@ -147,12 +148,12 @@ void nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, NR * reset - reset to state (bitwise or of flags to reset) */ -unsigned int nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); +unsigned int nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); -unsigned int nr_arena_item_invoke_render(cairo_t *ct, NRArenaItem *item, NRRectL const *area, NRPixBlock *pb, unsigned int flags); +unsigned int nr_arena_item_invoke_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -unsigned int nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); -NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +unsigned int nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); void nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, unsigned int propagate); void nr_arena_item_request_render (NRArenaItem *item); @@ -171,7 +172,7 @@ void nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible); void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip); void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask); void nr_arena_item_set_order (NRArenaItem *item, int order); -void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox); +void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox); NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item); diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 6d65611bf..ff985550c 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -23,6 +23,7 @@ #include "display/canvas-arena.h" #include "display/canvas-bpath.h" #include "display/curve.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-arena-shape.h" #include "display/nr-filter.h" @@ -44,10 +45,10 @@ static void nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRAr static void nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child); static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -static guint nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static guint nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); +static unsigned int nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static NRArenaItemClass *shape_parent_class; @@ -99,14 +100,6 @@ nr_arena_shape_init(NRArenaShape *shape) { shape->curve = NULL; shape->style = NULL; - shape->paintbox.x0 = shape->paintbox.y0 = 0.0F; - shape->paintbox.x1 = shape->paintbox.y1 = 256.0F; - shape->delayed_shp = false; - shape->path = NULL; - - shape->approx_bbox.x0 = shape->approx_bbox.y0 = 0; - shape->approx_bbox.x1 = shape->approx_bbox.y1 = 0; - shape->markers = NULL; shape->last_pick = NULL; shape->repick_after = 0; @@ -117,7 +110,6 @@ nr_arena_shape_finalize(NRObject *object) { NRArenaShape *shape = (NRArenaShape *) object; - if (shape->path) cairo_path_destroy(shape->path); if (shape->style) sp_style_unref(shape->style); if (shape->curve) shape->curve->unref(); shape->last_pick = NULL; @@ -203,7 +195,7 @@ nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArena * Updates the arena shape 'item' and all of its children, including the markers. */ static guint -nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset) +nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset) { Geom::OptRect boundingbox; @@ -224,34 +216,26 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); if (boundingbox) { - item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides - item->bbox.y0 = floor((*boundingbox)[1][0]); - item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = ceil ((*boundingbox)[1][1]); + item->bbox = boundingbox->roundOutwards(); } else { - item->bbox = NR_RECT_L_EMPTY; + item->bbox = Geom::OptIntRect(); } } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox); + item->bbox.unionWith(child->bbox); } } } return (state | item->state); } - shape->delayed_shp=true; boundingbox = Geom::OptRect(); bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); // clear Cairo data to force update shape->nrstyle.update(); - if (shape->path) { - cairo_path_destroy(shape->path); - shape->path = NULL; - } if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); @@ -273,19 +257,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g } } - /// \todo just write item->bbox = boundingbox - if (boundingbox) { - shape->approx_bbox.x0 = floor(boundingbox->left()); - shape->approx_bbox.y0 = floor(boundingbox->top()); - shape->approx_bbox.x1 = ceil (boundingbox->right()); - shape->approx_bbox.y1 = ceil (boundingbox->bottom()); - } else { - shape->approx_bbox = NR_RECT_L_EMPTY; - } - if ( area && nr_rect_l_test_intersect_ptr(area, &shape->approx_bbox) ) shape->delayed_shp=false; - - // TODO: compute a better bounding box that respects miters - item->bbox = shape->approx_bbox; + item->bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect(); if (!shape->curve || !shape->style || @@ -299,7 +271,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (beststate & NR_ARENA_ITEM_STATE_BBOX) { for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox); + item->bbox.unionWith(child->bbox); } } @@ -308,25 +280,22 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g // cairo outline rendering: static unsigned int -cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /*area*/) +cairo_arena_shape_render_outline(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); - if (!ct) - return item->state; - guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor; - cairo_save(ct); - ink_cairo_transform(ct, shape->ctm); - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector()); - cairo_restore(ct); - cairo_save(ct); - ink_cairo_set_source_rgba32(ct, rgba); - cairo_set_line_width(ct, 0.5); - cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode - cairo_stroke(ct); - cairo_restore(ct); + { Inkscape::DrawingContext::Save save(ct); + ct.transform(shape->ctm); + ct.path(shape->curve->get_pathvector()); + } + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(rgba); + ct.setLineWidth(0.5); + ct.setTolerance(1.25); + ct.stroke(); + } return item->state; } @@ -335,59 +304,55 @@ cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect / * Renders the item. Markers are just composed into the parent buffer. */ static unsigned int -nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags) +nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) { NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) return item->state; if (!shape->style) return item->state; - if (!ct) return item->state; // skip if not within bounding box - if (!nr_rect_l_test_intersect_ptr(area, &item->bbox)) { + if (!area.intersects(item->bbox)) { return item->state; } bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - if (outline) { // cairo outline rendering - - NRRect temp(area->x0, area->y0, area->x1, area->y1); - unsigned int ret = cairo_arena_shape_render_outline (ct, item, temp.upgrade_2geom()); + if (outline) { + // cairo outline rendering + unsigned int ret = cairo_arena_shape_render_outline (ct, item, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } else { bool has_stroke, has_fill; // we assume the context has no path - cairo_save(ct); - ink_cairo_transform(ct, shape->ctm); + Inkscape::DrawingContext::Save save(ct); + ct.transform(shape->ctm); // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = shape->nrstyle.prepareFill(ct, &shape->paintbox); - has_stroke = shape->nrstyle.prepareStroke(ct, &shape->paintbox); + has_fill = shape->nrstyle.prepareFill(ct, shape->paintbox); + has_stroke = shape->nrstyle.prepareStroke(ct, shape->paintbox); has_stroke &= (shape->nrstyle.stroke_width != 0); if (has_fill || has_stroke) { // TODO: remove segments outside of bbox when no dashes present - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); + ct.path(shape->curve->get_pathvector()); if (has_fill) { shape->nrstyle.applyFill(ct); - cairo_fill_preserve(ct); + ct.fillPreserve(); } if (has_stroke) { shape->nrstyle.applyStroke(ct); - cairo_stroke_preserve(ct); + ct.strokePreserve(); } - cairo_new_path(ct); // clear path + ct.newPath(); // clear path } // has fill or stroke pattern - cairo_restore(ct); } // marker rendering for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - unsigned int ret = nr_arena_item_invoke_render(ct, child, area, pb, flags); + unsigned int ret = nr_arena_item_invoke_render(ct, child, area, flags); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; } @@ -395,32 +360,31 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } -static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) +static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) { return item->state; } - cairo_save(ct); + Inkscape::DrawingContext::Save save(ct); // handle clip-rule if (shape->style) { if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); } else { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + ct.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ink_cairo_transform(ct, shape->ctm); - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); - cairo_fill(ct); - cairo_restore(ct); + ct.transform(shape->ctm); + ct.path(shape->curve->get_pathvector()); + ct.fill(); return item->state; } static NRArenaItem * -nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/) +nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); @@ -577,23 +541,14 @@ nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox) g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); g_return_if_fail(pbox != NULL); - if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) { - shape->paintbox = *pbox; - } else { - /* fixme: We kill warning, although not sure what to do here (Lauris) */ - shape->paintbox.x0 = shape->paintbox.y0 = 0.0F; - shape->paintbox.x1 = shape->paintbox.y1 = 256.0F; - } + shape->paintbox = pbox->upgrade_2geom(); nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE); } void NRArenaShape::setPaintBox(Geom::Rect const &pbox) { - paintbox.x0 = pbox.min()[Geom::X]; - paintbox.y0 = pbox.min()[Geom::Y]; - paintbox.x1 = pbox.max()[Geom::X]; - paintbox.y1 = pbox.max()[Geom::Y]; + paintbox = pbox; nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE); } diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h index 7b86f7f59..317cff7fb 100644 --- a/src/display/nr-arena-shape.h +++ b/src/display/nr-arena-shape.h @@ -31,16 +31,7 @@ struct NRArenaShape : public NRArenaItem { SPCurve *curve; SPStyle *style; NRStyle nrstyle; - NRRect paintbox; - - cairo_path_t *path; - - // delayed_shp=true means the *_shp polygons are not computed yet - // they'll be computed on demand in *_render(), *_pick() or *_clip() - // the goal is to not uncross polygons that are outside the viewing region - bool delayed_shp; - // approximate bounding box, for the case when the polygons have been delayed - NRRectL approx_bbox; + Geom::OptRect paintbox; /* Markers */ NRArenaItem *markers; diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index ce62a81dc..5747de26c 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -104,13 +104,13 @@ nr_arena_request_update (NRArena *arena, NRArenaItem *item) } void -nr_arena_request_render_rect (NRArena *arena, NRRectL *area) +nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area) { NRActiveObject *aobject = (NRActiveObject *) arena; nr_return_if_fail (arena != NULL); nr_return_if_fail (NR_IS_ARENA (arena)); - nr_return_if_fail (area != NULL); + if (!area) return; // setup render parameter if (arena->renderoffscreen == false) { @@ -123,12 +123,13 @@ nr_arena_request_render_rect (NRArena *arena, NRRectL *area) arena->rendermode = Inkscape::RENDERMODE_NORMAL; arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; } - if (aobject->callbacks && area && !nr_rect_l_test_empty_ptr(area)) { + NRRectL nr_area(*area); + if (aobject->callbacks) { for (unsigned int i = 0; i < aobject->callbacks->length; i++) { NRObjectListener *listener = aobject->callbacks->listeners + i; NRArenaEventVector *avector = (NRArenaEventVector *) listener->vector; if ((listener->size >= sizeof (NRArenaEventVector)) && avector->request_render) { - avector->request_render (arena, area, listener->data); + avector->request_render (arena, &nr_area, listener->data); } } } diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index 1c8216434..49d133f9f 100644 --- a/src/display/nr-arena.h +++ b/src/display/nr-arena.h @@ -27,6 +27,7 @@ G_END_DECLS #define NR_ARENA(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA, NRArena)) #define NR_IS_ARENA(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA)) +#include <2geom/rect.h> #include <libnr/nr-forward.h> #include <libnr/nr-object.h> #include "nr-arena-forward.h" @@ -61,7 +62,7 @@ struct NRArenaClass : public NRActiveObjectClass { }; void nr_arena_request_update (NRArena *arena, NRArenaItem *item); -void nr_arena_request_render_rect (NRArena *arena, NRRectL *area); +void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area); void nr_arena_set_renderoffscreen (NRArena *arena); void nr_arena_separate_color_plates(guint32* rgba); diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 0cb7901b3..01d2eca64 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -13,6 +13,7 @@ #include "document.h" #include "sp-item.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "display/nr-filter.h" @@ -94,28 +95,23 @@ void FilterImage::render_cairo(FilterSlot &slot) Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width(), sa.height()); - cairo_t *ct = cairo_create(out); - cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]); - ink_cairo_transform(ct, pu2pb); // we are now in primitive units - cairo_translate(ct, feImageX, feImageY); - cairo_scale(ct, scaleX, scaleY); - - NRRectL render_rect; - render_rect.x0 = floor(area.left()); - render_rect.y0 = floor(area.top()); - render_rect.x1 = ceil(area.right()); - render_rect.y1 = ceil(area.bottom()); - cairo_translate(ct, render_rect.x0, render_rect.y0); + Inkscape::DrawingContext ct(out, sa.min()); + ct.transform(pu2pb); // we are now in primitive units + ct.translate(feImageX, feImageY); + ct.scale(scaleX, scaleY); + + Geom::IntRect render_rect = area.roundOutwards(); + ct.translate(render_rect.min()); // Update to renderable state NRGC gc(NULL); Geom::Affine t = Geom::identity(); nr_arena_item_set_transform(ai, &t); gc.transform.setIdentity(); - nr_arena_item_invoke_update(ai, NULL, &gc, + nr_arena_item_invoke_update(ai, render_rect, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render(ct, ai, &render_rect, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE); + nr_arena_item_invoke_render(ct, ai, render_rect, NR_ARENA_ITEM_RENDER_NO_CACHE); SVGElem->invoke_hide(key); nr_object_unref((NRObject*) arena); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 3464fda66..494d77749 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -16,6 +16,7 @@ #include <2geom/transforms.h> #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena-item.h" #include "display/nr-filter-types.h" #include "display/nr-filter-gaussian.h" @@ -25,13 +26,13 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, - cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u) +FilterSlot::FilterSlot(NRArenaItem *item, DrawingContext &bgct, + DrawingContext &graphic, FilterUnits const &u) : _item(item) - , _source_graphic(graphic) - , _background_ct(bgct) - , _source_graphic_area(graphicarea) - , _background_area(bgarea) + , _source_graphic(graphic.rawTarget()) + , _background_ct(bgct.raw()) + , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme + , _background_area(bgct.targetLogicalBounds().roundOutwards()) // fixme , _units(u) , _last_out(NR_FILTER_SOURCEGRAPHIC) , filterquality(FILTER_QUALITY_BEST) @@ -41,19 +42,15 @@ FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, using Geom::Y; // compute slot bbox - Geom::Rect bbox( - Geom::Point(_source_graphic_area->x0, _source_graphic_area->y0), - Geom::Point(_source_graphic_area->x1, _source_graphic_area->y1)); - Geom::Affine trans = _units.get_matrix_display2pb(); - Geom::Rect bbox_trans = bbox * trans; + Geom::Rect bbox_trans = graphic.targetLogicalBounds() * trans; Geom::Point min = bbox_trans.min(); _slot_x = min[X]; _slot_y = min[Y]; if (trans.isTranslation()) { - _slot_w = _source_graphic_area->x1 - _source_graphic_area->x0; - _slot_h = _source_graphic_area->y1 - _source_graphic_area->y0; + _slot_w = _source_graphic_area.width(); + _slot_h = _source_graphic_area.height(); } else { _slot_w = ceil(bbox_trans.width()); _slot_h = ceil(bbox_trans.height()); @@ -143,7 +140,7 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() cairo_translate(tsg_ct, -_slot_x, -_slot_y); ink_cairo_transform(tsg_ct, trans); - cairo_translate(tsg_ct, _source_graphic_area->x0, _source_graphic_area->y0); + cairo_translate(tsg_ct, _source_graphic_area.left(), _source_graphic_area.top()); cairo_set_source_surface(tsg_ct, _source_graphic, 0, 0); cairo_set_operator(tsg_ct, CAIRO_OPERATOR_SOURCE); cairo_paint(tsg_ct); @@ -164,7 +161,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background() cairo_translate(tbg_ct, -_slot_x, -_slot_y); ink_cairo_transform(tbg_ct, trans); - cairo_translate(tbg_ct, _background_area->x0, _background_area->y0); + cairo_translate(tbg_ct, _background_area.left(), _background_area.top()); cairo_set_source_surface(tbg_ct, bg, 0, 0); cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE); cairo_paint(tbg_ct); @@ -184,11 +181,11 @@ cairo_surface_t *FilterSlot::get_result(int res) cairo_surface_t *r = cairo_surface_create_similar(_source_graphic, cairo_surface_get_content(_source_graphic), - _source_graphic_area->x1 - _source_graphic_area->x0, - _source_graphic_area->y1 - _source_graphic_area->y0); + _source_graphic_area.width(), + _source_graphic_area.height()); cairo_t *r_ct = cairo_create(r); - cairo_translate(r_ct, -_source_graphic_area->x0, -_source_graphic_area->y0); + cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top()); ink_cairo_transform(r_ct, trans); cairo_translate(r_ct, _slot_x, _slot_y); cairo_set_source_surface(r_ct, getcairo(res), 0, 0); diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 3b08743ed..6a86ded8c 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -22,13 +22,15 @@ struct NRArenaItem; namespace Inkscape { +class DrawingContext; + namespace Filters { class FilterSlot { public: /** Creates a new FilterSlot object. */ - FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, - cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u); + FilterSlot(NRArenaItem *item, DrawingContext &bgct, + DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); @@ -66,7 +68,7 @@ public: FilterUnits const &get_units() const { return _units; } Geom::Rect get_slot_area() const; - NRRectL const &get_sg_area() const { return *_source_graphic_area; } + NRRectL get_sg_area() const { NRRectL ret(_source_graphic_area); return ret; } private: typedef std::map<int, cairo_surface_t *> SlotMap; @@ -81,8 +83,8 @@ private: double _slot_x, _slot_y; cairo_surface_t *_source_graphic; cairo_t *_background_ct; - NRRectL const *_source_graphic_area; - NRRectL const *_background_area; ///< needed to extract background + Geom::IntRect _source_graphic_area; + Geom::IntRect _background_area; ///< needed to extract background FilterUnits const &_units; int _last_out; FilterQuality filterquality; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 963d98654..25ef80c17 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -40,6 +40,7 @@ #include "display/nr-arena.h" #include "display/nr-arena-item.h" +#include "display/drawing-context.h" #include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" @@ -96,14 +97,14 @@ Filter::~Filter() } -int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area) +int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic - cairo_set_source_rgba(graphic, 0,0,0,0); - cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); - cairo_paint(graphic); - cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + graphic.setSource(0,0,0,0); + graphic.setOperator(CAIRO_OPERATOR_SOURCE); + graphic.paint(); + graphic.setOperator(CAIRO_OPERATOR_OVER); return 1; } @@ -136,10 +137,10 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea = _filter_resolution(filter_area, trans, filterquality); if (!(resolution.first > 0 && resolution.second > 0)) { // zero resolution - clear source graphic and return - cairo_set_source_rgba(graphic, 0,0,0,0); - cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); - cairo_paint(graphic); - cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + graphic.setSource(0,0,0,0); + graphic.setOperator(CAIRO_OPERATOR_SOURCE); + graphic.paint(); + graphic.setOperator(CAIRO_OPERATOR_OVER); return 1; } @@ -160,7 +161,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea } } - FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); + FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -168,11 +169,12 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea _primitive[i]->render_cairo(slot); } + Geom::Point origin = graphic.targetLogicalBounds().min(); cairo_surface_t *result = slot.get_result(_output_slot); - cairo_set_source_surface(graphic, result, area->x0, area->y0); - cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); - cairo_paint(graphic); - cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + graphic.setSource(result, origin[Geom::X], origin[Geom::Y]); + graphic.setOperator(CAIRO_OPERATOR_SOURCE); + graphic.paint(); + graphic.setOperator(CAIRO_OPERATOR_OVER); cairo_surface_destroy(result); return 0; @@ -186,10 +188,12 @@ void Filter::set_primitive_units(SPFilterUnits unit) { _primitive_units = unit; } -void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { +void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { + NRRectL b(bbox); for (unsigned i = 0 ; i < _primitive.size() ; i++) { - if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm); + if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm); } + bbox = *b.upgrade_2geom(); /* TODO: something. See images at the bottom of filters.svg with medium-low @@ -224,22 +228,13 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { */ } -void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) { - // Modifying empty bounding boxes confuses rest of the renderer, so - // let's not do that. - if (item_bbox.x0 > item_bbox.x1 || item_bbox.y0 > item_bbox.y1) return; +Geom::IntRect Filter::compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox) { - Geom::Point min(item_bbox.x0, item_bbox.y0); - Geom::Point max(item_bbox.x1, item_bbox.y1); - Geom::Rect tmp_bbox(min, max); + Geom::Rect enlarged = filter_effect_area(item_bbox); + enlarged *= item->ctm; - Geom::Rect enlarged = filter_effect_area(tmp_bbox); - enlarged = enlarged * item->ctm; - - item_bbox.x0 = floor(enlarged.min()[X]); - item_bbox.y0 = floor(enlarged.min()[Y]); - item_bbox.x1 = ceil(enlarged.max()[X]); - item_bbox.y1 = ceil(enlarged.max()[Y]); + Geom::IntRect ret(enlarged.roundOutwards()); + return ret; } Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index e1d4c10e5..5cebf3ad3 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -24,6 +24,8 @@ struct NRArenaItem; namespace Inkscape { +class DrawingContext; + namespace Filters { class Filter : public Inkscape::GC::Managed<> { @@ -33,7 +35,7 @@ public: * the results of filter rendering. @a bgarea and @a area specify bounding boxes * of both surfaces in world coordinates; Cairo contexts are assumed to be in default state * (0,0 = surface origin, no path, OVER operator) */ - int render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area); + int render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic); /** * Creates a new filter primitive under this filter object. @@ -149,13 +151,13 @@ public: * to be rendered so that after filtering, the original area is * drawn correctly. */ - void area_enlarge(NRRectL &area, NRArenaItem const *item) const; + void area_enlarge(Geom::IntRect &area, NRArenaItem const *item) const; /** * Given an item bounding box (in user coords), this function enlarges it * to contain the filter effects region and transforms it to screen * coordinates */ - void compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox); + Geom::IntRect compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 72fa0c444..fa5dd0d98 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -13,6 +13,8 @@ #include "style.h" #include "sp-paint-server.h" #include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!) +#include "display/drawing-context.h" +#include "libnr/nr-rect.h" void NRStyle::Paint::clear() { @@ -142,14 +144,15 @@ void NRStyle::set(SPStyle *style) update(); } -bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) +bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) { // update fill pattern if (!fill_pattern) { switch (fill.type) { - case PAINT_SERVER: - fill_pattern = sp_paint_server_create_pattern(fill.server, ct, paintbox, fill.opacity); - break; + case PAINT_SERVER: { + NRRect pb(paintbox); + fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), &pb, fill.opacity); + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -162,19 +165,20 @@ bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) return true; } -void NRStyle::applyFill(cairo_t *ct) +void NRStyle::applyFill(Inkscape::DrawingContext &ct) { - cairo_set_source(ct, fill_pattern); - cairo_set_fill_rule(ct, fill_rule); + ct.setSource(fill_pattern); + ct.setFillRule(fill_rule); } -bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) +bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) { if (!stroke_pattern) { switch (stroke.type) { - case PAINT_SERVER: - stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct, paintbox, stroke.opacity); - break; + case PAINT_SERVER: { + NRRect pb(paintbox); + stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), &pb, stroke.opacity); + } break; case PAINT_COLOR: { SPColor const &c = stroke.color; stroke_pattern = cairo_pattern_create_rgba( @@ -187,14 +191,14 @@ bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) return true; } -void NRStyle::applyStroke(cairo_t *ct) +void NRStyle::applyStroke(Inkscape::DrawingContext &ct) { - cairo_set_source(ct, stroke_pattern); - cairo_set_line_width(ct, stroke_width); - cairo_set_line_cap(ct, line_cap); - cairo_set_line_join(ct, line_join); - cairo_set_miter_limit(ct, miter_limit); - cairo_set_dash(ct, dash, n_dash, dash_offset); + ct.setSource(stroke_pattern); + ct.setLineWidth(stroke_width); + ct.setLineCap(line_cap); + ct.setLineJoin(line_join); + ct.setMiterLimit(miter_limit); + cairo_set_dash(ct.raw(), dash, n_dash, dash_offset); // fixme } void NRStyle::update() diff --git a/src/display/nr-style.h b/src/display/nr-style.h index e741e46b4..0ba6ce2c6 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -13,22 +13,25 @@ #define SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H #include <cairo.h> +#include <2geom/rect.h> #include "color.h" class SPColor; class SPPaintServer; class SPStyle; -struct NRRect; +namespace Inkscape { +class DrawingContext; +} struct NRStyle { NRStyle(); ~NRStyle(); void set(SPStyle *); - bool prepareFill(cairo_t *ct, NRRect *paintbox); - bool prepareStroke(cairo_t *ct, NRRect *paintbox); - void applyFill(cairo_t *ct); - void applyStroke(cairo_t *ct); + bool prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox); + bool prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox); + void applyFill(Inkscape::DrawingContext &ct); + void applyStroke(Inkscape::DrawingContext &ct); void update(); enum PaintType { diff --git a/src/flood-context.cpp b/src/flood-context.cpp index 90278ac95..d93e0284d 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -53,6 +53,7 @@ #include "display/nr-arena-image.h" #include "display/canvas-arena.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include <2geom/pathvector.h> #include "sp-item.h" #include "sp-root.h" @@ -805,8 +806,8 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even Geom::Point origin(screen.min()[Geom::X], document->getHeight() - screen.height() - screen.min()[Geom::Y]); - origin[Geom::X] = origin[Geom::X] + (screen.width() * ((1 - padding) / 2)); - origin[Geom::Y] = origin[Geom::Y] + (screen.height() * ((1 - padding) / 2)); + origin[Geom::X] += (screen.width() * ((1 - padding) / 2)); + origin[Geom::Y] += (screen.height() * ((1 - padding) / 2)); Geom::Scale scale(zoom_scale, zoom_scale); Geom::Affine affine = scale * Geom::Translate(-origin * scale); @@ -817,44 +818,42 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even NRGC gc(NULL); gc.transform.setIdentity(); + + Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height); - NRRectL final_bbox; - final_bbox.x0 = 0; - final_bbox.y0 = 0; //row; - final_bbox.x1 = width; - final_bbox.y1 = height; //row + num_rows; - - nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_update(root, final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); guchar *px = g_new(guchar, stride * height); - - cairo_surface_t *s = cairo_image_surface_create_for_data( - px, CAIRO_FORMAT_ARGB32, width, height, stride); - cairo_t *ct = cairo_create(s); - // cairo_translate not necessary here - surface origin is at 0,0 - - SPNamedView *nv = sp_desktop_namedview(desktop); - guint32 bgcolor = nv->pagecolor; - // bgcolor is 0xrrggbbaa, we need 0xaarrggbb - guint32 dtc = (bgcolor >> 8) | (bgcolor << 24); - - ink_cairo_set_source_rgba32(ct, bgcolor); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_OVER); - - nr_arena_item_invoke_render(ct, root, &final_bbox, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); - - cairo_surface_flush(s); - cairo_destroy(ct); - cairo_surface_destroy(s); - - // Hide items - SP_ITEM(document->getRoot())->invoke_hide(dkey); + guint32 bgcolor, dtc; + + { // this block limits the lifetime of DrawingContext + cairo_surface_t *s = cairo_image_surface_create_for_data( + px, CAIRO_FORMAT_ARGB32, width, height, stride); + Inkscape::DrawingContext ct(s, Geom::Point(0,0)); + // cairo_translate not necessary here - surface origin is at 0,0 + + SPNamedView *nv = sp_desktop_namedview(desktop); + bgcolor = nv->pagecolor; + // bgcolor is 0xrrggbbaa, we need 0xaarrggbb + dtc = (bgcolor >> 8) | (bgcolor << 24); + + ct.setSource(bgcolor); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); + ct.setOperator(CAIRO_OPERATOR_OVER); + + nr_arena_item_invoke_render(ct, root, final_bbox, NR_ARENA_ITEM_RENDER_NO_CACHE ); + + cairo_surface_flush(s); + cairo_surface_destroy(s); + + // Hide items + SP_ITEM(document->getRoot())->invoke_hide(dkey); + + nr_object_unref((NRObject *) arena); + } - nr_object_unref((NRObject *) arena); - guchar *trace_px = g_new(guchar, width * height); memset(trace_px, 0x00, width * height); diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index e1ced31b4..df0a40858 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -23,6 +23,7 @@ #include "interface.h" #include "helper/png-write.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena-item.h" #include "display/nr-arena.h" #include "document.h" @@ -144,27 +145,17 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, hide_other_items_recursively(doc->getRoot(), items_only, dkey); } - NRRectL final_bbox; - final_bbox.x0 = 0; - final_bbox.y0 = 0;//row; - final_bbox.x1 = width; - final_bbox.y1 = height;//row + num_rows; + Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height); - nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_update(root, final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS) { - cairo_t *ct = cairo_create(surface); - - // clear to background - ink_cairo_set_source_rgba32(ct, bgcolor); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + Inkscape::DrawingContext ct(surface, Geom::Point(0,0)); // render items - nr_arena_item_invoke_render(ct, root, &final_bbox, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); + nr_arena_item_invoke_render(ct, root, final_bbox, NR_ARENA_ITEM_RENDER_NO_CACHE ); pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(surface), GDK_COLORSPACE_RGB, TRUE, diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 5a20ac363..f75f96afb 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -23,6 +23,7 @@ #include <png.h> #include "png-write.h" #include "io/sys.h" +#include "display/drawing-context.h" #include "display/nr-arena-item.h" #include "display/nr-arena.h" #include "document.h" @@ -322,16 +323,13 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v // bbox is now set to the entire image to prevent discontinuities // in the image when blur is used (the borders may still be a bit // off, but that's less noticeable). - NRRectL bbox; - bbox.x0 = 0; - bbox.y0 = row; - bbox.x1 = ebp->width; - bbox.y1 = row + num_rows; + Geom::IntRect bbox = Geom::IntRect::from_xywh(0, row, ebp->width, num_rows); + /* Update to renderable state */ NRGC gc(NULL); gc.transform.setIdentity(); - nr_arena_item_invoke_update(ebp->root, &bbox, &gc, + nr_arena_item_invoke_update(ebp->root, bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ebp->width); @@ -339,18 +337,14 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v cairo_surface_t *s = cairo_image_surface_create_for_data( px, CAIRO_FORMAT_ARGB32, ebp->width, num_rows, stride); - cairo_t *ct = cairo_create(s); - cairo_translate(ct, -bbox.x0, -bbox.y0); - - ink_cairo_set_source_rgba32(ct, ebp->background); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + Inkscape::DrawingContext ct(s, bbox.min()); + ct.setSource(ebp->background); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); + ct.setOperator(CAIRO_OPERATOR_OVER); /* Render */ - nr_arena_item_invoke_render(ct, ebp->root, &bbox, NULL, 0); - - cairo_destroy(ct); + nr_arena_item_invoke_render(ct, ebp->root, bbox, 0); cairo_surface_destroy(s); *to_free = px; diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index d1e7671ed..3a3d01ebd 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -22,6 +22,8 @@ #include "macros.h" #include "svg/svg.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" #include "display/nr-arena.h" #include "display/nr-arena-group.h" #include "attributes.h" @@ -658,9 +660,8 @@ sp_pattern_create_pattern(SPPaintServer *ps, } ps2user = Geom::Translate (pattern_x (pat), pattern_y (pat)) * ps2user; - Geom::Point p(pattern_x(pat), pattern_y(pat)); - Geom::Point pd(pattern_width(pat), pattern_height(pat)); - Geom::Rect pattern_tile(p, p + pd); + Geom::Rect pattern_tile = Geom::Rect::from_xywh(pattern_x(pat), pattern_y(pat), + pattern_width(pat), pattern_height(pat)); if (pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { // interpret x, y, width, height in relation to bbox @@ -674,34 +675,24 @@ sp_pattern_create_pattern(SPPaintServer *ps, // oversample the pattern slightly // TODO: find optimum value - Geom::Point c(pattern_tile.dimensions()*ps2user.descrim()*full.descrim()*1.2); + Geom::Point c(pattern_tile.dimensions()*ps2user.descrim()*full.descrim()*1.1); c[Geom::X] = ceil(c[Geom::X]); c[Geom::Y] = ceil(c[Geom::Y]); - Geom::Affine t = Geom::Scale(c) * Geom::Scale(pattern_tile.dimensions()).inverse(); - - NRRectL one_tile; - one_tile.x0 = (int) floor(pattern_tile[Geom::X].min()); - one_tile.y0 = (int) floor(pattern_tile[Geom::Y].min()); - one_tile.x1 = (int) ceil(pattern_tile[Geom::X].max()); - one_tile.y1 = (int) ceil(pattern_tile[Geom::Y].max()); - - cairo_surface_t *target = cairo_get_target(base_ct); - cairo_surface_t *temp = cairo_surface_create_similar(target, CAIRO_CONTENT_COLOR_ALPHA, - c[Geom::X], c[Geom::Y]); - cairo_t *ct = cairo_create(temp); - // scale into a coord system where the surface w,h are equal to tile w,h - ink_cairo_transform(ct, t); + + Geom::IntRect one_tile = pattern_tile.roundOutwards(); + Inkscape::DrawingSurface temp(pattern_tile, c.ceil()); + Inkscape::DrawingContext ct(temp); // render pattern. if (needs_opacity) { - cairo_push_group(ct); // this group is for pattern + opacity + ct.pushGroup(); // this group is for pattern + opacity } // TODO: make sure there are no leaks. NRGC gc(NULL); gc.transform = vb2ps; - nr_arena_item_invoke_update (root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_ALL); - nr_arena_item_invoke_render (ct, root, &one_tile, NULL, 0); + nr_arena_item_invoke_update (root, Geom::IntRect::infinite(), &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_ALL); + nr_arena_item_invoke_render (ct, root, one_tile, 0); for (SPObject *child = shown->firstChild() ; child != NULL; child = child->getNext() ) { if (SP_IS_ITEM (child)) { SP_ITEM(child)->invoke_hide(dkey); @@ -711,16 +702,14 @@ sp_pattern_create_pattern(SPPaintServer *ps, nr_object_unref(arena); if (needs_opacity) { - cairo_pop_group_to_source(ct); // pop raw pattern - cairo_paint_with_alpha(ct, opacity); // apply opacity + ct.popGroupToSource(); // pop raw pattern + ct.paint(opacity); // apply opacity } - cairo_pattern_t *cp = cairo_pattern_create_for_surface(temp); - cairo_destroy(ct); - cairo_surface_destroy(temp); + cairo_pattern_t *cp = cairo_pattern_create_for_surface(temp.raw()); // Apply transformation to user space. Also compensate for oversampling. - ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * t); + ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * temp.drawingTransform()); cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT); return cp; diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 813f532a4..ef75d8b23 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -251,11 +251,11 @@ Tracer::sioxProcessImage(SPImage *img, //g_message("img: %d %d %d %d\n", aImg->bbox.x0, aImg->bbox.y0, // aImg->bbox.x1, aImg->bbox.y1); - double width = (double)(aImg->bbox.x1 - aImg->bbox.x0); - double height = (double)(aImg->bbox.y1 - aImg->bbox.y0); + double width = aImg->bbox->width(); + double height = aImg->bbox->height(); - double iwidth = (double)simage.getWidth(); - double iheight = (double)simage.getHeight(); + double iwidth = simage.getWidth(); + double iheight = simage.getHeight(); double iwscale = width / iwidth; double ihscale = height / iheight; @@ -278,11 +278,11 @@ Tracer::sioxProcessImage(SPImage *img, for (int row=0 ; row<iheight ; row++) { - double ypos = ((double)aImg->bbox.y0) + ihscale * (double) row; + double ypos = aImg->bbox->top() + ihscale * (double) row; for (int col=0 ; col<simage.getWidth() ; col++) { //Get absolute X,Y position - double xpos = ((double)aImg->bbox.x0) + iwscale * (double)col; + double xpos = aImg->bbox->left() + iwscale * (double)col; Geom::Point point(xpos, ypos); if (aImg->transform) point *= *aImg->transform; diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index cd1d65ba7..67ec701cb 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -27,9 +27,10 @@ #include "inkscape.h" #include "sp-rect.h" #include "document-private.h" +#include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" -#include "display/cairo-utils.h" #include "ui/cache/svg_preview_cache.h" @@ -38,43 +39,33 @@ GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rec Geom::Affine t(Geom::Scale(scale_factor, scale_factor)); nr_arena_item_set_transform(root, t); - gc.transform.setIdentity(); - nr_arena_item_invoke_update( root, NULL, &gc, + + Geom::IntRect ibox = (dbox * Geom::Scale(scale_factor)).roundOutwards(); + + nr_arena_item_invoke_update( root, ibox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE ); - /* Item integer bbox in points */ - NRRectL ibox; - ibox.x0 = floor(scale_factor * dbox.min()[Geom::X]); - ibox.y0 = floor(scale_factor * dbox.min()[Geom::Y]); - ibox.x1 = ceil(scale_factor * dbox.max()[Geom::X]); - ibox.y1 = ceil(scale_factor * dbox.max()[Geom::Y]); - /* Find visible area */ - int width = ibox.x1 - ibox.x0; - int height = ibox.y1 - ibox.y0; + int width = ibox.width(); + int height = ibox.height(); int dx = psize; int dy = psize; dx = (dx - width)/2; // watch out for size, since 'unsigned'-'signed' can cause problems if the result is negative dy = (dy - height)/2; - NRRectL area; - area.x0 = ibox.x0 - dx; - area.y0 = ibox.y0 - dy; - area.x1 = area.x0 + psize; - area.y1 = area.y0 + psize; + Geom::IntRect area = Geom::IntRect::from_xywh( + ibox.min() - Geom::IntPoint(dx, dy), Geom::IntPoint(psize, psize)); /* Render */ cairo_surface_t *s = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, psize, psize); - cairo_t *ct = cairo_create(s); - cairo_translate(ct, -area.x0, -area.y0); + Inkscape::DrawingContext ct(s, area.min()); - nr_arena_item_invoke_render(ct, root, &area, NULL, + nr_arena_item_invoke_render(ct, root, area, NR_ARENA_ITEM_RENDER_NO_CACHE ); cairo_surface_flush(s); - cairo_destroy(ct); GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, @@ -135,6 +126,17 @@ GdkPixbuf* SvgPreview::get_preview(const gchar* uri, const gchar* id, NRArenaIte return px; } -}; -}; -}; +} +} +} + +/* + 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/widgets/icon.cpp b/src/widgets/icon.cpp index 95cb23a22..bb2029bcf 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -31,6 +31,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 "io/sys.h" @@ -1073,6 +1074,19 @@ GdkPixbuf *IconImpl::loadPixmap(gchar const *name, unsigned /*lsize*/, unsigned return pb; } +static Geom::IntRect round_rect(Geom::Rect const &r) +{ + using Geom::X; + using Geom::Y; + Geom::IntPoint a, b; + a[X] = round(r.left()); + a[Y] = round(r.top()); + b[X] = round(r.right()); + b[Y] = round(r.bottom()); + Geom::IntRect ret(a, b); + return ret; +} + // takes doc, root, icon, and icon name to produce pixels extern "C" guchar * sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, @@ -1102,23 +1116,20 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, double sf = 1.0; nr_arena_item_set_transform(root, (Geom::Affine)Geom::Scale(sf, sf)); gc.transform.setIdentity(); - nr_arena_item_invoke_update( root, NULL, &gc, + nr_arena_item_invoke_update( root, Geom::IntRect::infinite(), &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE ); /* Item integer bbox in points */ - NRRectL ibox; - ibox.x0 = (int) floor(sf * dbox->min()[Geom::X] + 0.5); - ibox.y0 = (int) floor(sf * dbox->min()[Geom::Y] + 0.5); - ibox.x1 = (int) floor(sf * dbox->max()[Geom::X] + 0.5); - ibox.y1 = (int) floor(sf * dbox->max()[Geom::Y] + 0.5); + // NOTE: previously, each rect coordinate was rounded using floor(c + 0.5) + Geom::IntRect ibox = round_rect(*dbox); if ( dump ) { - g_message( " box --'%s' (%f,%f)-(%f,%f)", name, (double)ibox.x0, (double)ibox.y0, (double)ibox.x1, (double)ibox.y1 ); + g_message( " box --'%s' (%f,%f)-(%f,%f)", name, (double)ibox.left(), (double)ibox.top(), (double)ibox.right(), (double)ibox.bottom() ); } /* Find button visible area */ - int width = ibox.x1 - ibox.x0; - int height = ibox.y1 - ibox.y0; + int width = ibox.width(); + int height = ibox.height(); if ( dump ) { g_message( " vis --'%s' (%d,%d)", name, width, height ); @@ -1134,49 +1145,38 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, nr_arena_item_set_transform(root, (Geom::Affine)Geom::Scale(sf, sf)); gc.transform.setIdentity(); - nr_arena_item_invoke_update( root, NULL, &gc, + nr_arena_item_invoke_update( root, Geom::IntRect::infinite(), &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE ); - /* Item integer bbox in points */ - ibox.x0 = (int) floor(sf * dbox->min()[Geom::X] + 0.5); - ibox.y0 = (int) floor(sf * dbox->min()[Geom::Y] + 0.5); - ibox.x1 = (int) floor(sf * dbox->max()[Geom::X] + 0.5); - ibox.y1 = (int) floor(sf * dbox->max()[Geom::Y] + 0.5); + ibox = round_rect(*dbox * Geom::Scale(sf)); if ( dump ) { - g_message( " box2 --'%s' (%f,%f)-(%f,%f)", name, (double)ibox.x0, (double)ibox.y0, (double)ibox.x1, (double)ibox.y1 ); + g_message( " box2 --'%s' (%f,%f)-(%f,%f)", name, (double)ibox.left(), (double)ibox.top(), (double)ibox.right(), (double)ibox.bottom() ); } /* Find button visible area */ - width = ibox.x1 - ibox.x0; - height = ibox.y1 - ibox.y0; + width = ibox.width(); + height = ibox.height(); if ( dump ) { g_message( " vis2 --'%s' (%d,%d)", name, width, height ); } } } + Geom::IntPoint pdim(psize, psize); int dx, dy; //dx = (psize - width) / 2; //dy = (psize - height) / 2; dx=dy=psize; dx=(dx-width)/2; // watch out for psize, since 'unsigned'-'signed' can cause problems if the result is negative dy=(dy-height)/2; - NRRectL area; - area.x0 = ibox.x0 - dx; - area.y0 = ibox.y0 - dy; - area.x1 = area.x0 + psize; - area.y1 = area.y0 + psize; + Geom::IntRect area = Geom::IntRect::from_xywh(ibox.min() - Geom::IntPoint(dx,dy), pdim); /* Actual renderable area */ - NRRectL ua; - ua.x0 = MAX(ibox.x0, area.x0); - ua.y0 = MAX(ibox.y0, area.y0); - ua.x1 = MIN(ibox.x1, area.x1); - ua.y1 = MIN(ibox.y1, area.y1); + Geom::IntRect ua = *Geom::intersect(ibox, area); if ( dump ) { - g_message( " area --'%s' (%f,%f)-(%f,%f)", name, (double)area.x0, (double)area.y0, (double)area.x1, (double)area.y1 ); - g_message( " ua --'%s' (%f,%f)-(%f,%f)", name, (double)ua.x0, (double)ua.y0, (double)ua.x1, (double)ua.y1 ); + g_message( " area --'%s' (%f,%f)-(%f,%f)", name, (double)area.left(), (double)area.top(), (double)area.right(), (double)area.bottom() ); + g_message( " ua --'%s' (%f,%f)-(%f,%f)", name, (double)ua.left(), (double)ua.top(), (double)ua.right(), (double)ua.bottom() ); } stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, psize); @@ -1188,12 +1188,10 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, /* Render */ cairo_surface_t *s = cairo_image_surface_create_for_data(px, CAIRO_FORMAT_ARGB32, psize, psize, stride); - cairo_t *ct = cairo_create(s); - cairo_translate(ct, -ua.x0, -ua.y0); + Inkscape::DrawingContext ct(s, ua.min()); - nr_arena_item_invoke_render(ct, root, &ua, NULL, + nr_arena_item_invoke_render(ct, root, ua, NR_ARENA_ITEM_RENDER_NO_CACHE ); - cairo_destroy(ct); cairo_surface_destroy(s); // convert to GdkPixbuf format |
