From 70598b9113a9356674a842ca3786c6ee02de1cb9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 19 Jul 2011 00:07:10 +0200 Subject: Clean up some commented-out code (bzr r10347.1.16) --- src/display/canvas-arena.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'src') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index dd4a4ed5c..4c105cd09 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -199,12 +199,8 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) { + // todo: handle NR_ARENA_ITEM_RENDER_NO_CACHE SPCanvasArena *arena = SP_CANVAS_ARENA (item); - //SPCanvas *canvas = item->canvas; - - //nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, - // NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, - // NR_ARENA_ITEM_STATE_NONE); Geom::OptIntRect r = buf->rect; if (!r || r->hasZeroArea()) return; @@ -221,11 +217,8 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) cairo_save(buf->ct); cairo_translate(buf->ct, -r->left(), -r->top()); - //cairo_rectangle(buf->ct, r->left(), r->top(), r->width(), r->height()); - //cairo_clip(buf->ct); cairo_set_source_surface(buf->ct, arena->cache, arena->cache_area.left(), arena->cache_area.top()); cairo_paint(buf->ct); - //nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0); cairo_restore(buf->ct); } -- cgit v1.2.3 From 328fad57dbfb65e3bd31062021d5cc3081e68515 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 22 Jul 2011 04:09:27 +0200 Subject: Replace direct use of Cairo contexts and surfaces in the rendering tree with wrappers which keep some extra information about the surface, amd NRRect and NRRectL use with Geom::Rect and Geom::IntRect. Should simplify implementing filter primitive subregions. (bzr r10347.1.17) --- src/2geom/affine.h | 4 +- src/2geom/bezier-curve.cpp | 5 +- src/2geom/coord.h | 6 -- src/2geom/forward.h | 1 + src/2geom/generic-interval.h | 4 +- src/2geom/generic-rect.h | 26 ++++-- src/2geom/int-point.h | 5 + src/2geom/interval.h | 15 ++- src/2geom/path-intersection.cpp | 2 + src/2geom/point.h | 15 +-- src/2geom/rect.h | 30 +----- src/2geom/transforms.h | 85 +++++++++++++---- src/dialogs/clonetiler.cpp | 24 ++--- src/display/Makefile_insert | 4 + src/display/cairo-templates.h | 4 + src/display/canvas-arena.cpp | 61 +++++++------ src/display/display-forward.h | 3 + src/display/drawing-context.cpp | 135 +++++++++++++++++++++++++++ src/display/drawing-context.h | 123 +++++++++++++++++++++++++ src/display/drawing-surface.cpp | 149 ++++++++++++++++++++++++++++++ src/display/drawing-surface.h | 78 ++++++++++++++++ src/display/nr-arena-glyphs.cpp | 147 +++++++++++------------------ src/display/nr-arena-glyphs.h | 2 +- src/display/nr-arena-group.cpp | 23 ++--- src/display/nr-arena-image.cpp | 108 +++++++++------------- src/display/nr-arena-item.cpp | 183 +++++++++++++++---------------------- src/display/nr-arena-item.h | 23 ++--- src/display/nr-arena-shape.cpp | 137 ++++++++++----------------- src/display/nr-arena-shape.h | 11 +-- src/display/nr-arena.cpp | 9 +- src/display/nr-arena.h | 3 +- src/display/nr-filter-image.cpp | 24 ++--- src/display/nr-filter-slot.cpp | 33 +++---- src/display/nr-filter-slot.h | 12 ++- src/display/nr-filter.cpp | 55 +++++------ src/display/nr-filter.h | 8 +- src/display/nr-style.cpp | 40 ++++---- src/display/nr-style.h | 13 ++- src/flood-context.cpp | 69 +++++++------- src/helper/pixbuf-ops.cpp | 19 +--- src/helper/png-write.cpp | 26 ++---- src/sp-pattern.cpp | 43 ++++----- src/trace/trace.cpp | 12 +-- src/ui/cache/svg_preview_cache.cpp | 50 +++++----- src/widgets/icon.cpp | 66 +++++++------ 45 files changed, 1139 insertions(+), 756 deletions(-) create mode 100644 src/display/drawing-context.cpp create mode 100644 src/display/drawing-context.h create mode 100644 src/display/drawing-surface.cpp create mode 100644 src/display/drawing-surface.h (limited to 'src') 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 const &pts) { - inner = D2(Bezier::Order(pts.size()-1), Bezier::Order(pts.size()-1)); + inner = D2(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 { 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 { 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 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::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::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 #include namespace Geom { @@ -93,30 +94,37 @@ public: * @param end End of the range * @return Rectangle that contains all points from [start, end). */ template - static GenericRect from_range(InputIterator start, InputIterator end) { + static CRect from_range(InputIterator start, InputIterator end) { assert(start != end); CPoint p1 = *start++; - GenericRect 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 from_array(CPoint const *c, unsigned n) { - GenericRect result = GenericRect::from_range(c, c+n); + static CRect from_array(CPoint const *c, unsigned n) { + CRect result = GenericRect::from_range(c, c+n); return result; } /** @brief Create rectangle from origin and dimensions. */ - static GenericRect 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 result(xy, xy + wh); + CRect result(xy, xy + wh); return result; } /** @brief Create rectangle from origin and dimensions. */ - static GenericRect from_xywh(CPoint const &xy, CPoint const &wh) { - GenericRect 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::min(), std::numeric_limits::min()); + CPoint p1(std::numeric_limits::max(), std::numeric_limits::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 OptInterval; class Interval : public GenericInterval , boost::multipliable< Interval - , boost::multipliable< Interval, Coord + , boost::multiplicative< Interval, Coord > > { typedef GenericInterval 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 - 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 - 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(*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 #include #include #include @@ -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 #include "preferences.h" diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 4c105cd09..1d5cfe826 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -19,6 +19,8 @@ #include "display/nr-arena-group.h" #include "display/canvas-arena.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" enum { ARENA_EVENT, @@ -161,12 +163,15 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned guint reset; reset = (flags & SP_CANVAS_UPDATE_AFFINE)? NR_ARENA_ITEM_STATE_ALL : NR_ARENA_ITEM_STATE_NONE; - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); - item->x1 = arena->root->bbox.x0 - 1; - item->y1 = arena->root->bbox.y0 - 1; - item->x2 = arena->root->bbox.x1 + 1; - item->y2 = arena->root->bbox.y1 + 1; + Geom::OptIntRect b = arena->root->bbox; + if (b) { + item->x1 = b->left() - 1; + item->y1 = b->top() - 1; + item->x2 = b->right() + 1; + item->y2 = b->bottom() + 1; + } if (arena->cursor) { /* Mess with enter/leave notifiers */ @@ -228,27 +233,23 @@ static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect cons Geom::OptIntRect r = Geom::intersect(arena->cache_area, area); if (!r || r->hasZeroArea()) return; // nothing to do - - cairo_t *ct = cairo_create(arena->cache); - cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top()); - - // clear area to paint - cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height()); - cairo_clip(ct); - cairo_save(ct); - cairo_set_source_rgba(ct, 0,0,0,0); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - cairo_restore(ct); - - NRRectL nr_area(r); - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, + Inkscape::DrawingSurface cache(arena->cache, arena->cache_area.min()); + Inkscape::DrawingContext ct(cache); + + ct.rectangle(area); + ct.clip(); + + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(0,0,0,0); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); + } + + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render (ct, arena->root, &nr_area, NULL, 0); - - cairo_destroy(ct); + nr_arena_item_invoke_render (ct, arena->root, *r, 0); } static void @@ -267,7 +268,7 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ { SPCanvasArena *arena = SP_CANVAS_ARENA (item); - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); @@ -367,7 +368,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->crossing.x, event->crossing.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); arena->active = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); if (arena->active) nr_object_ref ((NRObject *) arena->active); ret = sp_canvas_arena_send_event (arena, event); @@ -388,7 +389,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->motion.x, event->motion.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); new_arena = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; @@ -474,10 +475,10 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR g_return_if_fail (ca != NULL); g_return_if_fail (SP_IS_CANVAS_ARENA (ca)); - cairo_t *ct = cairo_create(surface); - cairo_translate(ct, -r.x0, -r.y0); - nr_arena_item_invoke_render (ct, ca->root, &r, NULL, 0); - cairo_destroy(ct); + Geom::OptIntRect area = r.upgrade_2geom(); + if (!area) return; + Inkscape::DrawingContext ct(surface, area->min()); + nr_arena_item_invoke_render (ct, ca->root, *area, 0); } diff --git a/src/display/display-forward.h b/src/display/display-forward.h index bc7013214..288da829a 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -12,6 +12,9 @@ struct SPCanvasGroupClass; class SPCurve; namespace Inkscape { +class DrawingContext; +class DrawingSurface; + namespace Display { class TemporaryItem; class TemporaryItemList; diff --git a/src/display/drawing-context.cpp b/src/display/drawing-context.cpp new file mode 100644 index 000000000..8f37bb693 --- /dev/null +++ b/src/display/drawing-context.cpp @@ -0,0 +1,135 @@ +/** + * @file + * @brief Cairo drawing context with Inkscape extensions + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/cairo-utils.h" +#include "helper/geom.h" + +namespace Inkscape { + +using Geom::X; +using Geom::Y; + +/** @class DrawingContext::Save + * @brief RAII idiom for saving the state of DrawingContext. */ + +DrawingContext::Save::Save() + : _ct(NULL) +{} +DrawingContext::Save::Save(DrawingContext &ct) + : _ct(&ct) +{ + _ct->save(); +} +DrawingContext::Save::~Save() +{ + if (_ct) { + _ct->restore(); + } +} +void DrawingContext::Save::save(DrawingContext &ct) +{ + if (_ct) { + // TODO: it might be better to treat this occurence as a bug + _ct->restore(); + } + _ct = &ct; + _ct->save(); +} + +/** @class DrawingContext + * @brief Minimal wrapper over Cairo. + * + * This is a wrapper over cairo_t, extended with operations that work + * with 2Geom geometrical primitives. Some of this is probably duplicated + * in cairo-render-context.cpp, which provides higher level operations + * for drawing entire SPObjects when exporting. + */ + +DrawingContext::DrawingContext(cairo_surface_t *surface, Geom::Point const &origin) + : _ct(NULL) + , _surface(new DrawingSurface(surface, origin)) + , _delete_surface(true) +{ + _surface->_has_context = true; + _ct = _surface->createRawContext(); +} + +DrawingContext::DrawingContext(DrawingSurface &s) + : _ct(s.createRawContext()) + , _surface(&s) + , _delete_surface(false) +{} + +DrawingContext::~DrawingContext() +{ + cairo_destroy(_ct); + _surface->_has_context = false; + if (_delete_surface) { + delete _surface; + } +} + +void DrawingContext::arc(Geom::Point const ¢er, double radius, Geom::AngleInterval const &angle) +{ + double from = angle.initialAngle(); + double to = angle.finalAngle(); + if (to > from) { + cairo_arc(_ct, center[X], center[Y], radius, from, to); + } else { + cairo_arc_negative(_ct, center[X], center[Y], radius, to, from); + } +} + +void DrawingContext::transform(Geom::Affine const &trans) { + ink_cairo_transform(_ct, trans); +} + +void DrawingContext::path(Geom::PathVector const &pv) { + feed_pathvector_to_cairo(_ct, pv); +} + +void DrawingContext::paint(double alpha) { + if (alpha == 1.0) cairo_paint(_ct); + else cairo_paint_with_alpha(_ct, alpha); +} +void DrawingContext::setSource(guint32 rgba) { + ink_cairo_set_source_rgba32(_ct, rgba); +} +void DrawingContext::setSource(DrawingSurface *s) { + Geom::Point origin = s->origin(); + cairo_set_source_surface(_ct, s->raw(), origin[X], origin[Y]); +} +void DrawingContext::setSourceCheckerboard() { + cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); + cairo_set_source(_ct, check); + cairo_pattern_destroy(check); +} + +Geom::Rect DrawingContext::targetLogicalBounds() const +{ + Geom::Rect ret(_surface->area()); + return ret; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h new file mode 100644 index 000000000..c0ea81874 --- /dev/null +++ b/src/display/drawing-context.h @@ -0,0 +1,123 @@ +/** + * @file + * @brief Cairo drawing context with Inkscape extensions + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H + +#include +#include +#include +#include <2geom/affine.h> +#include <2geom/angle.h> +#include <2geom/rect.h> +#include <2geom/transforms.h> + +namespace Inkscape { + +class DrawingSurface; + +class DrawingContext + : boost::noncopyable +{ +public: + class Save { + public: + Save(); + Save(DrawingContext &ct); + ~Save(); + void save(DrawingContext &ct); + private: + DrawingContext *_ct; + }; + + DrawingContext(cairo_surface_t *surface, Geom::Point const &origin); + DrawingContext(DrawingSurface &s); + ~DrawingContext(); + + void save() { cairo_save(_ct); } + void restore() { cairo_restore(_ct); } + void pushGroup() { cairo_push_group(_ct); } + void pushAlphaGroup() { cairo_push_group_with_content(_ct, CAIRO_CONTENT_ALPHA); } + void popGroupToSource() { cairo_pop_group_to_source(_ct); } + + void transform(Geom::Affine const &trans); + void translate(Geom::Point const &t) { cairo_translate(_ct, t[Geom::X], t[Geom::Y]); } // todo: take Translate + void translate(double dx, double dy) { cairo_translate(_ct, dx, dy); } + void scale(Geom::Scale const &s) { cairo_scale(_ct, s[Geom::X], s[Geom::Y]); } + void scale(double sx, double sy) { cairo_scale(_ct, sx, sy); } + + void moveTo(Geom::Point const &p) { cairo_move_to(_ct, p[Geom::X], p[Geom::Y]); } + void lineTo(Geom::Point const &p) { cairo_line_to(_ct, p[Geom::X], p[Geom::Y]); } + void curveTo(Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) { + cairo_curve_to(_ct, p1[Geom::X], p1[Geom::Y], p2[Geom::X], p2[Geom::Y], p3[Geom::X], p3[Geom::Y]); + } + void arc(Geom::Point const ¢er, double radius, Geom::AngleInterval const &angle); + void rectangle(Geom::Rect const &r) { + cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); + } + void newPath() { cairo_new_path(_ct); } + void newSubpath() { cairo_new_sub_path(_ct); } + void path(Geom::PathVector const &pv); + + void paint(double alpha = 1.0); + void fill() { cairo_fill(_ct); } + void fillPreserve() { cairo_fill_preserve(_ct); } + void stroke() { cairo_stroke(_ct); } + void strokePreserve() { cairo_stroke_preserve(_ct); } + void clip() { cairo_clip(_ct); } + + void setLineWidth(double w) { cairo_set_line_width(_ct, w); } + void setLineCap(cairo_line_cap_t cap) { cairo_set_line_cap(_ct, cap); } + void setLineJoin(cairo_line_join_t join) { cairo_set_line_join(_ct, join); } + void setMiterLimit(double miter) { cairo_set_miter_limit(_ct, miter); } + void setFillRule(cairo_fill_rule_t rule) { cairo_set_fill_rule(_ct, rule); } + void setOperator(cairo_operator_t op) { cairo_set_operator(_ct, op); } + void setTolerance(double tol) { cairo_set_tolerance(_ct, tol); } + void setSource(cairo_pattern_t *source) { cairo_set_source(_ct, source); } + void setSource(cairo_surface_t *surface, double x, double y) { + cairo_set_source_surface(_ct, surface, x, y); + } + void setSource(double r, double g, double b, double a = 1.0) { + cairo_set_source_rgba(_ct, r, g, b, a); + } + void setSource(guint32 rgba); + void setSource(DrawingSurface *s); + void setSourceCheckerboard(); + + Geom::Rect targetLogicalBounds() const; + + cairo_t *raw() { return _ct; } + cairo_surface_t *rawTarget() { return cairo_get_group_target(_ct); } + +private: + DrawingContext(cairo_t *ct, DrawingSurface *surface, bool destroy); + + cairo_t *_ct; + DrawingSurface *_surface; + bool _delete_surface; + + friend class DrawingSurface; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp new file mode 100644 index 000000000..e50a732c6 --- /dev/null +++ b/src/display/drawing-surface.cpp @@ -0,0 +1,149 @@ +/** + * @file + * @brief Cairo surface that remembers its origin + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/drawing-surface.h" +#include "display/cairo-utils.h" + +namespace Inkscape { + +using Geom::X; +using Geom::Y; + + +/** @class DrawingSurface + * @brief Drawing surface that remembers its origin. + * + * This is a very minimalistic wrapper over cairo_surface_t. The main + * extra functionality provided by this class is that it automates + * the mapping from "logical space" (coordinates in the rendering) + * and the "physical space" (surface pixels). For example, patterns + * have to be rendered on surfaces which have possibly non-integer + * widths and heights. + */ + +/** @brief Creates a surface with the given physical extents. + * When a drawing context is created for this surface, its pixels + * will cover the area under the given rectangle. */ +DrawingSurface::DrawingSurface(Geom::IntRect const &area) + : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, area.width(), area.height())) + , _origin(area.min()) + , _scale(1, 1) +{} + +/** @brief Creates a surface with the given logical extents. + * When a drawing context is created for this surface, its pixels + * will cover the area under the given rectangle. If the rectangle + * has non-integer width, there will be slightly more than 1 pixel + * per logical unit. */ +DrawingSurface::DrawingSurface(Geom::Rect const &area) + : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil(area.width()), ceil(area.height()))) + , _origin(area.min()) + , _scale(ceil(area.width()) / area.width(), ceil(area.height()) / area.height()) +{} + +/** @brief Creates a surface with the given logical and physical extents. + * When a drawing context is created for this surface, its pixels + * will cover the area under the given rectangle. IT will contain + * the number of pixels specified by the second argument. + * @param logbox Logical extents of the surface + * @param pixdims Pixel dimensions of the surface. */ +DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims) + : _surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pixdims[X], pixdims[Y])) + , _origin(logbox.min()) + , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height()) +{} + +/** @brief Wrap a cairo_surface_t. + * This constructor will take an extra reference on @a surface, which will + * be released on destruction. */ +DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin) + : _surface(surface) + , _origin(origin) + , _scale(1, 1) +{ + cairo_surface_reference(surface); +} + +DrawingSurface::~DrawingSurface() +{ + cairo_surface_destroy(_surface); +} + +/// Get the logical extents of the surface. +Geom::Rect +DrawingSurface::area() const +{ + Geom::Rect r = Geom::Rect::from_xywh(_origin, dimensions()); + return r; +} + +/// Get the logical width and weight of the surface as a point. +Geom::Point +DrawingSurface::dimensions() const +{ + double w = cairo_image_surface_get_width(_surface); + double h = cairo_image_surface_get_height(_surface); + Geom::Point logical_dims(w / _scale[X], h / _scale[Y]); + return logical_dims; +} + +Geom::Point +DrawingSurface::origin() const +{ + return _origin; +} + +Geom::Scale +DrawingSurface::scale() const +{ + return _scale; +} + +/// Get the transformation applied to the drawing context on construction. +Geom::Affine +DrawingSurface::drawingTransform() const +{ + Geom::Affine ret = _scale * Geom::Translate(-_origin); + return ret; +} + +cairo_surface_type_t +DrawingSurface::type() const +{ + // currently hardcoded + return CAIRO_SURFACE_TYPE_IMAGE; +} + +/** @brief Create a drawing context for this surface. + * It's better to use the surface constructor of DrawingContext. */ +cairo_t * +DrawingSurface::createRawContext() +{ + cairo_t *ct = cairo_create(_surface); + if (_scale != Geom::Scale::identity()) { + cairo_scale(ct, _scale[X], _scale[Y]); + } + cairo_translate(ct, -_origin[X], -_origin[Y]); + return ct; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h new file mode 100644 index 000000000..2d0e147e2 --- /dev/null +++ b/src/display/drawing-surface.h @@ -0,0 +1,78 @@ +/** + * @file + * @brief Cairo surface that remembers its origin + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H + +#include +#include +#include +#include <2geom/affine.h> +#include <2geom/rect.h> +#include <2geom/transforms.h> + +namespace Inkscape { +class DrawingContext; + +class DrawingSurface +{ +public: + explicit DrawingSurface(Geom::IntRect const &area); + explicit DrawingSurface(Geom::Rect const &area); + DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims); + DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin); + virtual ~DrawingSurface(); + + Geom::Rect area() const; + Geom::Point dimensions() const; + Geom::Point origin() const; + Geom::Scale scale() const; + Geom::Affine drawingTransform() const; + cairo_surface_type_t type() const; + + cairo_surface_t *raw() { return _surface; } + cairo_t *createRawContext(); + +protected: + cairo_surface_t *_surface; + Geom::Point _origin; + Geom::Scale _scale; + bool _has_context; + + friend class DrawingContext; +}; + +class PixbufSurface + : public DrawingSurface +{ +public: + explicit PixbufSurface(GdkPixbuf *pb, Geom::Point const &origin = Geom::Point(0,0)); + ~PixbufSurface(); +protected: + GdkPixbuf *pb; + + friend class DrawingContext; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index d09f66a2f..99b0a004e 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -14,13 +14,15 @@ #ifdef HAVE_CONFIG_H # include #endif -#include "libnr/nr-convert2geom.h" +#include #include <2geom/affine.h> +#include <2geom/rect.h> +#include "libnr/nr-convert2geom.h" #include "style.h" #include "display/nr-arena.h" #include "display/nr-arena-glyphs.h" -#include #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "helper/geom.h" #ifdef test_glyph_liv @@ -39,9 +41,8 @@ static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass); static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs); static void nr_arena_glyphs_finalize(NRObject *object); -static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static guint nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static guint nr_arena_glyphs_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); +static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static NRArenaItemClass *glyphs_parent_class; @@ -75,7 +76,6 @@ nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass) object_class->cpp_ctor = NRObject::invoke_ctor; item_class->update = nr_arena_glyphs_update; - item_class->clip = nr_arena_glyphs_clip; item_class->pick = nr_arena_glyphs_pick; } @@ -102,7 +102,7 @@ nr_arena_glyphs_finalize(NRObject *object) } static guint -nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) +nr_arena_glyphs_update(NRArenaItem *item, Geom::IntRect const &/*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) { NRArenaGlyphs *glyphs = NR_ARENA_GLYPHS(item); NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item->parent); @@ -132,50 +132,32 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s // (one for each point on the curve) b->expandBy(miterMax); } - } + } if (b) { - item->bbox.x0 = floor(b->left()); - item->bbox.y0 = floor(b->top()); - item->bbox.x1 = ceil (b->right()); - item->bbox.y1 = ceil (b->bottom()); + item->bbox = b->roundOutwards(); } else { - item->bbox.x0 = 0; - item->bbox.y0 = 0; - item->bbox.x1 = -1; - item->bbox.y1 = -1; + item->bbox = Geom::OptIntRect(); } return NR_ARENA_ITEM_STATE_ALL; } -static guint nr_arena_glyphs_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/) -{ - NRArenaGlyphs *glyphs; - - glyphs = NR_ARENA_GLYPHS(item); - - if (!glyphs->font) return item->state; - - // TODO : render to greyscale pixblock provided for clipping - - return item->state; -} - static NRArenaItem * -nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int /*sticky*/) +nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int /*sticky*/) { NRArenaGlyphs *glyphs; glyphs = NR_ARENA_GLYPHS(item); if (!glyphs->font ) return NULL; + if (!item->bbox) return NULL; - double const x = p[Geom::X]; - double const y = p[Geom::Y]; - /* With text we take a simple approach: pick if the point is in a characher bbox */ - if ((x + delta >= item->bbox.x0) && (y + delta >= item->bbox.y0) && (x - delta <= item->bbox.x1) && (y - delta <= item->bbox.y1)) return item; - + // With text we take a simple approach: pick if the point is in a characher bbox + Geom::Rect expanded(*item->bbox); + expanded.expandBy(delta); + if (expanded.contains(p)) + return item; return NULL; } @@ -205,10 +187,10 @@ static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass); static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group); static void nr_arena_glyphs_group_finalize(NRObject *object); -static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky); +static guint nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); +static unsigned int nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky); static NRArenaGroupClass *group_parent_class; @@ -251,14 +233,12 @@ static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group) { group->style = NULL; - group->paintbox.x0 = group->paintbox.y0 = 0.0F; - group->paintbox.x1 = group->paintbox.y1 = -1.0F; } static void nr_arena_glyphs_group_finalize(NRObject *object) { - NRArenaGlyphsGroup *group=static_cast(object); + NRArenaGlyphsGroup *group = static_cast(object); if (group->style) { sp_style_unref(group->style); @@ -269,7 +249,7 @@ nr_arena_glyphs_group_finalize(NRObject *object) } static guint -nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset) +nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset) { NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item); @@ -283,24 +263,20 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s static unsigned int -nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/) +nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int /*flags*/) { NRArenaItem *child = 0; NRArenaGroup *group = NR_ARENA_GROUP(item); NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - if (!ct) { - return item->state; - } - if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - cairo_save(ct); + Inkscape::DrawingContext::Save save(ct); guint32 rgba = item->arena->outlinecolor; - ink_cairo_set_source_rgba32(ct, rgba); - cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode - cairo_new_path(ct); - ink_cairo_transform(ct, ggroup->ctm); + ct.setSource(rgba); + ct.setTolerance(1.25); // low quality, but good enough for outline mode + ct.newPath(); + ct.transform(ggroup->ctm); for (child = group->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); @@ -308,83 +284,78 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi Geom::PathVector const * pathv = g->font->PathVector(g->glyph); Geom::Affine transform = g->g_transform; - cairo_save(ct); - ink_cairo_transform(ct, transform); - feed_pathvector_to_cairo (ct, *pathv); - cairo_fill(ct); - cairo_restore(ct); + Inkscape::DrawingContext::Save save(ct); + ct.transform(transform); + ct.path(*pathv); + ct.fill(); } - cairo_restore(ct); return item->state; } // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding bool has_stroke, has_fill; - cairo_save(ct); - ink_cairo_transform(ct, ggroup->ctm); + Inkscape::DrawingContext::Save save(ct); + ct.transform(ggroup->ctm); - has_fill = ggroup->nrstyle.prepareFill(ct, &ggroup->paintbox); - has_stroke = ggroup->nrstyle.prepareStroke(ct, &ggroup->paintbox); + has_fill = ggroup->nrstyle.prepareFill(ct, ggroup->paintbox); + has_stroke = ggroup->nrstyle.prepareStroke(ct, ggroup->paintbox); if (has_fill || has_stroke) { for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - cairo_save(ct); - ink_cairo_transform(ct, g->g_transform); - feed_pathvector_to_cairo(ct, pathv); - cairo_restore(ct); + Inkscape::DrawingContext::Save save(ct); + ct.transform(g->g_transform); + ct.path(pathv); } if (has_fill) { ggroup->nrstyle.applyFill(ct); - cairo_fill_preserve(ct); + ct.fillPreserve(); } if (has_stroke) { ggroup->nrstyle.applyStroke(ct); - cairo_stroke_preserve(ct); + ct.strokePreserve(); } - cairo_new_path(ct); // clear path + ct.newPath(); // clear path } // has fill or stroke pattern - cairo_restore(ct); return item->state; } -static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) +static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) { NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - cairo_save(ct); + Inkscape::DrawingContext::Save save(ct); + // handle clip-rule if (ggroup->style) { if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); } else { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + ct.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ink_cairo_transform(ct, ggroup->ctm); + ct.transform(ggroup->ctm); for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - cairo_save(ct); - ink_cairo_transform(ct, g->g_transform); - feed_pathvector_to_cairo(ct, pathv); - cairo_restore(ct); + Inkscape::DrawingContext::Save save(ct); + ct.transform(g->g_transform); + ct.path(pathv); } - cairo_fill(ct); - cairo_restore(ct); + ct.fill(); return item->state; } static NRArenaItem * -nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky) +nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky) { NRArenaItem *picked = NULL; @@ -450,15 +421,7 @@ nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox) nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg)); nr_return_if_fail(pbox != NULL); - if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) { - gg->paintbox.x0 = pbox->x0; - gg->paintbox.y0 = pbox->y0; - gg->paintbox.x1 = pbox->x1; - gg->paintbox.y1 = pbox->y1; - } else { - gg->paintbox.x0 = gg->paintbox.y0 = 0.0F; - gg->paintbox.x1 = gg->paintbox.y1 = -1.0F; - } + gg->paintbox = pbox->upgrade_2geom(); nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE); } diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h index c43095cb2..4b2aed7b9 100644 --- a/src/display/nr-arena-glyphs.h +++ b/src/display/nr-arena-glyphs.h @@ -70,7 +70,7 @@ typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass; NRType nr_arena_glyphs_group_get_type (void); struct NRArenaGlyphsGroup : public NRArenaGroup { - NRRect paintbox; + Geom::OptRect paintbox; NRStyle nrstyle; static NRArenaGlyphsGroup *create(NRArena *arena) { diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 1d552fbc2..1f7c421d0 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -24,6 +24,7 @@ #include "filters/blend.h" #include "display/nr-filter-blend.h" #include "helper/geom.h" +#include "display/drawing-context.h" static void nr_arena_group_class_init (NRArenaGroupClass *klass); static void nr_arena_group_init (NRArenaGroup *group); @@ -34,10 +35,10 @@ static void nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRA static void nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child); static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static unsigned int nr_arena_group_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); +static unsigned int nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static unsigned int nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static NRArenaItemClass *parent_class; @@ -163,7 +164,7 @@ nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRAren } static unsigned int -nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset) +nr_arena_group_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset) { unsigned int newstate; NRArenaGroup *group = NR_ARENA_GROUP (item); @@ -178,10 +179,10 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - item->bbox = NR_RECT_L_EMPTY; + item->bbox = Geom::OptIntRect(); for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) - nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox); + item->bbox.unionWith(outline ? child->bbox : child->drawbox); } } @@ -217,7 +218,7 @@ void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style) } static unsigned int -nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags) +nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) { NRArenaGroup *group = NR_ARENA_GROUP (item); @@ -225,7 +226,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock /* Just compose children into parent buffer */ for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_item_invoke_render (ct, child, area, pb, flags); + ret = nr_arena_item_invoke_render (ct, child, area, flags); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; } @@ -233,7 +234,7 @@ nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } static unsigned int -nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) +nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area) { NRArenaGroup *group = NR_ARENA_GROUP (item); unsigned int ret = item->state; @@ -247,7 +248,7 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) } static NRArenaItem * -nr_arena_group_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky) +nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky) { NRArenaGroup *group = NR_ARENA_GROUP (item); diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index a943a6214..5336fcda9 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -17,6 +17,7 @@ #include "nr-arena-image.h" #include "style.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-filter.h" #include "sp-filter.h" @@ -34,9 +35,9 @@ static void nr_arena_image_class_init (NRArenaImageClass *klass); static void nr_arena_image_init (NRArenaImage *image); static void nr_arena_image_finalize (NRObject *object); -static unsigned int nr_arena_image_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_image_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static unsigned int nr_arena_image_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); +static unsigned int nr_arena_image_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static Geom::Rect nr_arena_image_rect (NRArenaImage *image); static NRArenaItemClass *parent_class; @@ -104,7 +105,7 @@ nr_arena_image_finalize (NRObject *object) } static unsigned int -nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ ) +nr_arena_image_update( NRArenaItem *item, Geom::IntRect const &/*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ ) { // clear old bbox nr_arena_item_request_render(item); @@ -116,30 +117,17 @@ nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned /* Calculate bbox */ if (image->pixbuf) { - NRRect bbox; - Geom::Rect r = nr_arena_image_rect(image) * gc->transform; - - item->bbox.x0 = floor(r.left()); // Floor gives the coordinate in which the point resides - item->bbox.y0 = floor(r.top()); - item->bbox.x1 = ceil(r.right()); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = ceil(r.bottom()); + item->bbox = r.roundOutwards(); } else { - item->bbox.x0 = (int) gc->transform[4]; - item->bbox.y0 = (int) gc->transform[5]; - item->bbox.x1 = item->bbox.x0 - 1; - item->bbox.y1 = item->bbox.y0 - 1; + item->bbox = Geom::OptIntRect(); } return NR_ARENA_ITEM_STATE_ALL; } -static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/, NRPixBlock * /*pb*/, unsigned int /*flags*/ ) +static unsigned int nr_arena_image_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/, unsigned int /*flags*/ ) { - if (!ct) { - return item->state; - } - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); NRArenaImage *image = NR_ARENA_IMAGE (item); @@ -151,69 +139,63 @@ static unsigned int nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRec // FIXME: at the moment gdk_cairo_set_source_pixbuf creates an ARGB copy // of the pixbuf. Fix this in Cairo and/or GDK. - cairo_save(ct); - ink_cairo_transform(ct, image->ctm); + Inkscape::DrawingContext::Save save(ct); + ct.transform(image->ctm); + ct.newPath(); + ct.rectangle(image->clipbox); + ct.clip(); - cairo_new_path(ct); - cairo_rectangle(ct, image->clipbox.left(), image->clipbox.top(), - image->clipbox.width(), image->clipbox.height()); - cairo_clip(ct); - - cairo_translate(ct, image->ox, image->oy); - cairo_scale(ct, image->sx, image->sy); - - cairo_set_source_surface(ct, image->surface, 0, 0); + ct.translate(image->ox, image->oy); + ct.scale(image->sx, image->sy); + ct.setSource(image->surface, 0, 0); cairo_matrix_t tt; Geom::Affine total; - cairo_get_matrix(ct, &tt); + cairo_get_matrix(ct.raw(), &tt); ink_matrix_to_2geom(total, tt); if (total.expansionX() > 1.0 || total.expansionY() > 1.0) { - cairo_pattern_t *p = cairo_get_source(ct); + cairo_pattern_t *p = cairo_get_source(ct.raw()); cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST); } - - cairo_paint_with_alpha(ct, ((double) item->opacity) / 255.0); - cairo_restore(ct); + ct.paint(((double) item->opacity) / 255.0); } else { // outline; draw a rect instead Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff); - cairo_save(ct); - ink_cairo_transform(ct, image->ctm); - - cairo_new_path(ct); - - Geom::Rect r = nr_arena_image_rect (image); - Geom::Point c00 = r.corner(0); - Geom::Point c01 = r.corner(3); - Geom::Point c11 = r.corner(2); - Geom::Point c10 = r.corner(1); + { Inkscape::DrawingContext::Save save(ct); + ct.transform(image->ctm); + ct.newPath(); + + Geom::Rect r = nr_arena_image_rect (image); + Geom::Point c00 = r.corner(0); + Geom::Point c01 = r.corner(3); + Geom::Point c11 = r.corner(2); + Geom::Point c10 = r.corner(1); + + ct.moveTo(c00); + // the box + ct.lineTo(c10); + ct.lineTo(c11); + ct.lineTo(c01); + ct.lineTo(c00); + // the diagonals + ct.lineTo(c11); + ct.moveTo(c10); + ct.lineTo(c01); + } - cairo_move_to (ct, c00[Geom::X], c00[Geom::Y]); - // the box - cairo_line_to (ct, c10[Geom::X], c10[Geom::Y]); - cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]); - cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]); - cairo_line_to (ct, c00[Geom::X], c00[Geom::Y]); - // the diagonals - cairo_line_to (ct, c11[Geom::X], c11[Geom::Y]); - cairo_move_to (ct, c10[Geom::X], c10[Geom::Y]); - cairo_line_to (ct, c01[Geom::X], c01[Geom::Y]); - cairo_restore(ct); - - cairo_set_line_width(ct, 0.5); - ink_cairo_set_source_rgba32(ct, rgba); - cairo_stroke(ct); + ct.setLineWidth(0.5); + ct.setSource(rgba); + ct.stroke(); } return item->state; } /** Calculates the closest distance from p to the segment a1-a2*/ double -distance_to_segment (Geom::Point p, Geom::Point a1, Geom::Point a2) +distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2) { // calculate sides of the triangle and their squares double d1 = Geom::L2(p - a1); @@ -233,7 +215,7 @@ distance_to_segment (Geom::Point p, Geom::Point a1, Geom::Point a2) } static NRArenaItem * -nr_arena_image_pick( NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/ ) +nr_arena_image_pick( NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/ ) { NRArenaImage *image = NR_ARENA_IMAGE (item); diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 9ca5a7463..c1ffefa1d 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -21,6 +21,8 @@ #include "display/cairo-utils.h" #include "display/cairo-templates.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" #include "display/canvas-arena.h" #include "nr-arena.h" #include "nr-arena-item.h" @@ -210,7 +212,7 @@ nr_arena_item_unref (NRArenaItem *item) } unsigned int -nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, +nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset) { NRGC childgc (gc); @@ -243,8 +245,8 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, if (!(~item->state & state)) return item->state; /* Test whether to return immediately */ - if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) { - if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox)) + if (item->state & NR_ARENA_ITEM_STATE_BBOX) { + if (!area.intersects(outline ? item->bbox : item->drawbox)) return item->state; } @@ -269,13 +271,9 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, /* Enlarge the drawbox to contain filter effects */ if (item->filter && filter && item->item_bbox) { - item->drawbox.x0 = item->item_bbox->min()[Geom::X]; - item->drawbox.y0 = item->item_bbox->min()[Geom::Y]; - item->drawbox.x1 = item->item_bbox->max()[Geom::X]; - item->drawbox.y1 = item->item_bbox->max()[Geom::Y]; - item->filter->compute_drawbox (item, item->drawbox); + item->drawbox = item->filter->compute_drawbox(item, *item->item_bbox); } else { - memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); + item->drawbox = item->bbox; } /* Clipping */ @@ -289,10 +287,9 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; } if (outline) { - nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox); + item->bbox.unionWith(item->clip->bbox); } else { - // for clipping, we need geometric bbox - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); + item->drawbox.intersectWith(item->clip->bbox); } } /* Masking */ @@ -303,10 +300,10 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; } if (outline) { - nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox); + item->bbox.unionWith(item->mask->bbox); } else { // for masking, we need full drawbox of mask - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); + item->drawbox.intersectWith(item->mask->drawbox); } } @@ -331,8 +328,8 @@ struct MaskLuminanceToAlpha { }; unsigned int -nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area, - NRPixBlock *pb, unsigned int flags) +nr_arena_item_invoke_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, + unsigned int flags) { bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); bool filter = (item->arena->rendermode != Inkscape::RENDERMODE_OUTLINE && @@ -343,15 +340,6 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX, item->state); - if (!ct) return item->state; - -#ifdef NR_ARENA_ITEM_VERBOSE - g_message ("Invoke render %p on %p: %d %d - %d %d, %d %d - %d %d", item, pb, - area->x0, area->y0, - area->x1, area->y1, - item->drawbox.x0, item->drawbox.y0, - item->drawbox.x1, item->drawbox.y1); -#endif /* If we are invisible, just return successfully */ if (!item->visible) @@ -360,15 +348,14 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area if (outline) { // intersect with bbox rather than drawbox, as we want to render things outside // of the clipping path as well - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->bbox); - if (nr_rect_l_test_empty(carea)) + Geom::OptIntRect carea = Geom::intersect(area, item->bbox); + if (!carea) return item->state | NR_ARENA_ITEM_STATE_RENDER; // No caching in outline mode for now; investigate if it really gives any advantage with cairo. // Also no attempts to clip anything; just render everything: item, clip, mask // First, render the object itself - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); + unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { /* Clean up and return error */ item->state |= NR_ARENA_ITEM_STATE_INVALID; @@ -381,12 +368,12 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (item->clip) { item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips - NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags); - } + NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, *carea, flags); + } // render mask as an object, using a different color if (item->mask) { item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks - NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags); + NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, *carea, flags); } item->arena->outlinecolor = saved_rgba; // restore outline color @@ -395,13 +382,12 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // carea is the bounding box for intermediate rendering. // NOTE: carea might be larger than area, because of filter effects. - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->drawbox); - if (nr_rect_l_test_empty(carea)) + Geom::OptIntRect carea = Geom::intersect(area, item->drawbox); + if (!carea) return item->state | NR_ARENA_ITEM_STATE_RENDER; if (item->filter && filter) { - item->filter->area_enlarge (carea, item); - nr_rect_l_intersect (&carea, &carea, &item->drawbox); + item->filter->area_enlarge(*carea, item); + carea.intersectWith(item->drawbox); } using namespace Inkscape; @@ -436,7 +422,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // short-circuit the simple case. if (!needs_intermediate_rendering) { - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; @@ -444,51 +430,48 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area return item->state | NR_ARENA_ITEM_STATE_RENDER; } - cairo_surface_t *intermediate = cairo_surface_create_similar( - cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA, - carea.x1 - carea.x0, carea.y1 - carea.y0); - cairo_t *ict = cairo_create(intermediate); - cairo_translate(ict, -carea.x0, -carea.y0); + DrawingSurface intermediate(*carea); + DrawingContext ict(intermediate); // 1. Render clipping path with alpha = opacity. - cairo_set_source_rgba(ict, 0,0,0,opacity); + ict.setSource(0,0,0,opacity); // Since clip can be combined with opacity, the result could be incorrect // for overlapping clip children. To fix this we use the SOURCE operator // instead of the default OVER. - cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); + ict.setOperator(CAIRO_OPERATOR_SOURCE); if (item->clip) { - state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); + state = nr_arena_item_invoke_clip(ict, item->clip, *carea); // fixme: carea or area? if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } } else { // if there is no clipping path, fill the entire surface with alpha = opacity. - cairo_paint(ict); + ict.paint(); } // reset back to default - cairo_set_operator(ict, CAIRO_OPERATOR_OVER); + ict.setOperator(CAIRO_OPERATOR_OVER); // 2. Render the mask if present and compose it with the clipping path + opacity. if (item->mask) { - cairo_push_group(ict); - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); + ict.pushGroup(); + state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } - cairo_surface_t *mask_s = cairo_get_group_target(ict); + cairo_surface_t *mask_s = ict.rawTarget(); // Convert mask's luminance to alpha ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha()); - cairo_pop_group_to_source(ict); - cairo_set_operator(ict, CAIRO_OPERATOR_IN); - cairo_paint(ict); - cairo_set_operator(ict, CAIRO_OPERATOR_OVER); + ict.popGroupToSource(); + ict.setOperator(CAIRO_OPERATOR_IN); + ict.paint(); + ict.setOperator(CAIRO_OPERATOR_OVER); } // 3. Render object itself. - cairo_push_group(ict); - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); + ict.pushGroup(); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, *carea, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; @@ -496,71 +479,53 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // 4. Apply filter. if (item->filter && filter) { - // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering - // Proper fix: call this function with a drawing context class - // that contains information about the surface's bounds - NRRectL bgarea; - if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) { - bgarea = carea; - } else { - bgarea = NRRectL(item->arena->canvasarena->cache_area); - } - item->filter->render(item, ct, &bgarea, ict, &carea); + item->filter->render(item, ct, ict); // Note that because the object was rendered to a group, // the internals of the filter need to use cairo_get_group_target() // instead of cairo_get_target(). } // 5. Render object inside the composited mask + clip - cairo_pop_group_to_source(ict); - cairo_set_operator(ict, CAIRO_OPERATOR_IN); - cairo_paint(ict); + ict.popGroupToSource(); + ict.setOperator(CAIRO_OPERATOR_IN); + ict.paint(); // 6. Paint the completed rendering onto the base context - cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); - cairo_paint(ct); - cairo_set_source_rgba(ct, 0,0,0,0); + ct.setSource(&intermediate); + ct.paint(); + ct.setSource(0,0,0,0); // the call above is to clear a ref on the intermediate surface held by ct retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; cleanup: - cairo_destroy(ict); - cairo_surface_destroy(intermediate); - return retstate; } unsigned int -nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) +nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area) { nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID); -#ifdef NR_ARENA_ITEM_VERBOSE - printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n", - item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0, - (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1); -#endif - unsigned retstate = 0; - + // don't bother if the object does not implement clipping (e.g. NRArenaImage) if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) return retstate; - if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { + if (item->visible && area.intersects(item->bbox)) { // The item used as the clipping path itself has a clipping path. - // Render this item's clipping path onto a temporary surface, then composite it with the item - // using the IN operator + // Render this item's clipping path onto a temporary surface, then composite it + // with the item using the IN operator if (item->clip) { - cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); - cairo_save(ct); - cairo_set_source_rgba(ct, 0,0,0,1); - nr_arena_item_invoke_clip(ct, item->clip, area); - cairo_restore(ct); - cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + ct.pushAlphaGroup(); + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(0,0,0,1); + nr_arena_item_invoke_clip(ct, item->clip, area); + } + ct.pushAlphaGroup(); } // rasterize the clipping path @@ -568,12 +533,12 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) clip (ct, item, area); if (item->clip) { - cairo_pop_group_to_source(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_IN); - cairo_paint(ct); - cairo_pop_group_to_source(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); + ct.popGroupToSource(); + ct.setOperator(CAIRO_OPERATOR_IN); + ct.paint(); + ct.popGroupToSource(); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); } } @@ -581,7 +546,7 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) } NRArenaItem * -nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, +nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky) { nr_return_val_if_fail (item != NULL, NULL); @@ -595,14 +560,11 @@ nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, if (!sticky && !(item->visible && item->sensitive)) return NULL; - // TODO: rewrite using Geom::Rect - const double x = p[Geom::X]; - const double y = p[Geom::Y]; + if (!item->bbox) return NULL; + Geom::Rect expanded(*item->bbox); + expanded.expandBy(delta); - if (((x + delta) >= item->bbox.x0) && - ((x - delta) < item->bbox.x1) && - ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) - { + if (expanded.contains(p)) { if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick) return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> pick (item, p, delta, sticky); @@ -639,7 +601,7 @@ nr_arena_item_request_render (NRArenaItem *item) nr_return_if_fail (NR_IS_ARENA_ITEM (item)); bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox); + nr_arena_request_render_rect (item->arena, outline ? item->bbox : item->drawbox); } /* Public */ @@ -694,6 +656,7 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform) const Geom::Affine *ms = (transform) ? transform : &GEOM_MATRIX_IDENTITY; if (!Geom::matrix_equalp(*md, *ms, NR_EPSILON)) { + // mark the area where the object was for redraw. nr_arena_item_request_render (item); if (!transform || transform->isIdentity()) { /* Set to identity affine */ @@ -703,6 +666,8 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform) item->transform = new (GC::ATOMIC) Geom::Affine (); *item->transform = *transform; } + // when update is called, the area where the object was moved + // will be redrawn as well nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE); } } @@ -800,7 +765,7 @@ nr_arena_item_set_order (NRArenaItem *item, int order) } void -nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox) +nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox) { nr_return_if_fail(item != NULL); nr_return_if_fail(NR_IS_ARENA_ITEM(item)); diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index d65a75ed8..4b43e4da8 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -23,6 +23,7 @@ #include "nr-arena-forward.h" namespace Inkscape { +class DrawingContext; namespace Filters { class Filter; } } @@ -92,8 +93,8 @@ struct NRArenaItem : public NRObject { unsigned int key; ///< Some SPItems can have more than one NRArenaItem, ///this value is a hack used to distinguish between them - NRRectL bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin - NRRectL drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks + Geom::OptIntRect bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin + Geom::OptIntRect drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks Geom::OptRect item_bbox; ///< Bounding box in item coordinates, required by filters Geom::Affine *transform; ///< Incremental transform of this item, as given by the transform= attribute Geom::Affine ctm; ///< Total transform from pixel grid to item coords @@ -119,10 +120,10 @@ struct NRArenaItemClass : public NRObjectClass { void (* remove_child) (NRArenaItem *item, NRArenaItem *child); void (* set_child_position) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - unsigned int (* update) (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); - unsigned int (* render) (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); - unsigned int (* clip) (cairo_t *ct, NRArenaItem *item, NRRectL *area); - NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); + unsigned int (* update) (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); + unsigned int (* render) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); + unsigned int (* clip) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); + NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); }; #define NR_ARENA_ITEM_ARENA(ai) (((NRArenaItem *) (ai))->arena) @@ -147,12 +148,12 @@ void nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, NR * reset - reset to state (bitwise or of flags to reset) */ -unsigned int nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset); +unsigned int nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); -unsigned int nr_arena_item_invoke_render(cairo_t *ct, NRArenaItem *item, NRRectL const *area, NRPixBlock *pb, unsigned int flags); +unsigned int nr_arena_item_invoke_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -unsigned int nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); -NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +unsigned int nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); void nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, unsigned int propagate); void nr_arena_item_request_render (NRArenaItem *item); @@ -171,7 +172,7 @@ void nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible); void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip); void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask); void nr_arena_item_set_order (NRArenaItem *item, int order); -void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox); +void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox); NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item); diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 6d65611bf..ff985550c 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -23,6 +23,7 @@ #include "display/canvas-arena.h" #include "display/canvas-bpath.h" #include "display/curve.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-arena-shape.h" #include "display/nr-filter.h" @@ -44,10 +45,10 @@ static void nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRAr static void nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child); static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -static guint nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); -static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area); -static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); +static guint nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); +static unsigned int nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); +static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); +static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); static NRArenaItemClass *shape_parent_class; @@ -99,14 +100,6 @@ nr_arena_shape_init(NRArenaShape *shape) { shape->curve = NULL; shape->style = NULL; - shape->paintbox.x0 = shape->paintbox.y0 = 0.0F; - shape->paintbox.x1 = shape->paintbox.y1 = 256.0F; - shape->delayed_shp = false; - shape->path = NULL; - - shape->approx_bbox.x0 = shape->approx_bbox.y0 = 0; - shape->approx_bbox.x1 = shape->approx_bbox.y1 = 0; - shape->markers = NULL; shape->last_pick = NULL; shape->repick_after = 0; @@ -117,7 +110,6 @@ nr_arena_shape_finalize(NRObject *object) { NRArenaShape *shape = (NRArenaShape *) object; - if (shape->path) cairo_path_destroy(shape->path); if (shape->style) sp_style_unref(shape->style); if (shape->curve) shape->curve->unref(); shape->last_pick = NULL; @@ -203,7 +195,7 @@ nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArena * Updates the arena shape 'item' and all of its children, including the markers. */ static guint -nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset) +nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset) { Geom::OptRect boundingbox; @@ -224,34 +216,26 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); if (boundingbox) { - item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides - item->bbox.y0 = floor((*boundingbox)[1][0]); - item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = ceil ((*boundingbox)[1][1]); + item->bbox = boundingbox->roundOutwards(); } else { - item->bbox = NR_RECT_L_EMPTY; + item->bbox = Geom::OptIntRect(); } } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox); + item->bbox.unionWith(child->bbox); } } } return (state | item->state); } - shape->delayed_shp=true; boundingbox = Geom::OptRect(); bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); // clear Cairo data to force update shape->nrstyle.update(); - if (shape->path) { - cairo_path_destroy(shape->path); - shape->path = NULL; - } if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); @@ -273,19 +257,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g } } - /// \todo just write item->bbox = boundingbox - if (boundingbox) { - shape->approx_bbox.x0 = floor(boundingbox->left()); - shape->approx_bbox.y0 = floor(boundingbox->top()); - shape->approx_bbox.x1 = ceil (boundingbox->right()); - shape->approx_bbox.y1 = ceil (boundingbox->bottom()); - } else { - shape->approx_bbox = NR_RECT_L_EMPTY; - } - if ( area && nr_rect_l_test_intersect_ptr(area, &shape->approx_bbox) ) shape->delayed_shp=false; - - // TODO: compute a better bounding box that respects miters - item->bbox = shape->approx_bbox; + item->bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect(); if (!shape->curve || !shape->style || @@ -299,7 +271,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (beststate & NR_ARENA_ITEM_STATE_BBOX) { for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox); + item->bbox.unionWith(child->bbox); } } @@ -308,25 +280,22 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g // cairo outline rendering: static unsigned int -cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /*area*/) +cairo_arena_shape_render_outline(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); - if (!ct) - return item->state; - guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor; - cairo_save(ct); - ink_cairo_transform(ct, shape->ctm); - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector()); - cairo_restore(ct); - cairo_save(ct); - ink_cairo_set_source_rgba32(ct, rgba); - cairo_set_line_width(ct, 0.5); - cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode - cairo_stroke(ct); - cairo_restore(ct); + { Inkscape::DrawingContext::Save save(ct); + ct.transform(shape->ctm); + ct.path(shape->curve->get_pathvector()); + } + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(rgba); + ct.setLineWidth(0.5); + ct.setTolerance(1.25); + ct.stroke(); + } return item->state; } @@ -335,59 +304,55 @@ cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect / * Renders the item. Markers are just composed into the parent buffer. */ static unsigned int -nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags) +nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) { NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) return item->state; if (!shape->style) return item->state; - if (!ct) return item->state; // skip if not within bounding box - if (!nr_rect_l_test_intersect_ptr(area, &item->bbox)) { + if (!area.intersects(item->bbox)) { return item->state; } bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - if (outline) { // cairo outline rendering - - NRRect temp(area->x0, area->y0, area->x1, area->y1); - unsigned int ret = cairo_arena_shape_render_outline (ct, item, temp.upgrade_2geom()); + if (outline) { + // cairo outline rendering + unsigned int ret = cairo_arena_shape_render_outline (ct, item, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } else { bool has_stroke, has_fill; // we assume the context has no path - cairo_save(ct); - ink_cairo_transform(ct, shape->ctm); + Inkscape::DrawingContext::Save save(ct); + ct.transform(shape->ctm); // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = shape->nrstyle.prepareFill(ct, &shape->paintbox); - has_stroke = shape->nrstyle.prepareStroke(ct, &shape->paintbox); + has_fill = shape->nrstyle.prepareFill(ct, shape->paintbox); + has_stroke = shape->nrstyle.prepareStroke(ct, shape->paintbox); has_stroke &= (shape->nrstyle.stroke_width != 0); if (has_fill || has_stroke) { // TODO: remove segments outside of bbox when no dashes present - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); + ct.path(shape->curve->get_pathvector()); if (has_fill) { shape->nrstyle.applyFill(ct); - cairo_fill_preserve(ct); + ct.fillPreserve(); } if (has_stroke) { shape->nrstyle.applyStroke(ct); - cairo_stroke_preserve(ct); + ct.strokePreserve(); } - cairo_new_path(ct); // clear path + ct.newPath(); // clear path } // has fill or stroke pattern - cairo_restore(ct); } // marker rendering for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - unsigned int ret = nr_arena_item_invoke_render(ct, child, area, pb, flags); + unsigned int ret = nr_arena_item_invoke_render(ct, child, area, flags); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; } @@ -395,32 +360,31 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } -static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) +static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) { return item->state; } - cairo_save(ct); + Inkscape::DrawingContext::Save save(ct); // handle clip-rule if (shape->style) { if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); } else { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + ct.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ink_cairo_transform(ct, shape->ctm); - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); - cairo_fill(ct); - cairo_restore(ct); + ct.transform(shape->ctm); + ct.path(shape->curve->get_pathvector()); + ct.fill(); return item->state; } static NRArenaItem * -nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/) +nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); @@ -577,23 +541,14 @@ nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox) g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); g_return_if_fail(pbox != NULL); - if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) { - shape->paintbox = *pbox; - } else { - /* fixme: We kill warning, although not sure what to do here (Lauris) */ - shape->paintbox.x0 = shape->paintbox.y0 = 0.0F; - shape->paintbox.x1 = shape->paintbox.y1 = 256.0F; - } + shape->paintbox = pbox->upgrade_2geom(); nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE); } void NRArenaShape::setPaintBox(Geom::Rect const &pbox) { - paintbox.x0 = pbox.min()[Geom::X]; - paintbox.y0 = pbox.min()[Geom::Y]; - paintbox.x1 = pbox.max()[Geom::X]; - paintbox.y1 = pbox.max()[Geom::Y]; + paintbox = pbox; nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE); } diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h index 7b86f7f59..317cff7fb 100644 --- a/src/display/nr-arena-shape.h +++ b/src/display/nr-arena-shape.h @@ -31,16 +31,7 @@ struct NRArenaShape : public NRArenaItem { SPCurve *curve; SPStyle *style; NRStyle nrstyle; - NRRect paintbox; - - cairo_path_t *path; - - // delayed_shp=true means the *_shp polygons are not computed yet - // they'll be computed on demand in *_render(), *_pick() or *_clip() - // the goal is to not uncross polygons that are outside the viewing region - bool delayed_shp; - // approximate bounding box, for the case when the polygons have been delayed - NRRectL approx_bbox; + Geom::OptRect paintbox; /* Markers */ NRArenaItem *markers; diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index ce62a81dc..5747de26c 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -104,13 +104,13 @@ nr_arena_request_update (NRArena *arena, NRArenaItem *item) } void -nr_arena_request_render_rect (NRArena *arena, NRRectL *area) +nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area) { NRActiveObject *aobject = (NRActiveObject *) arena; nr_return_if_fail (arena != NULL); nr_return_if_fail (NR_IS_ARENA (arena)); - nr_return_if_fail (area != NULL); + if (!area) return; // setup render parameter if (arena->renderoffscreen == false) { @@ -123,12 +123,13 @@ nr_arena_request_render_rect (NRArena *arena, NRRectL *area) arena->rendermode = Inkscape::RENDERMODE_NORMAL; arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; } - if (aobject->callbacks && area && !nr_rect_l_test_empty_ptr(area)) { + NRRectL nr_area(*area); + if (aobject->callbacks) { for (unsigned int i = 0; i < aobject->callbacks->length; i++) { NRObjectListener *listener = aobject->callbacks->listeners + i; NRArenaEventVector *avector = (NRArenaEventVector *) listener->vector; if ((listener->size >= sizeof (NRArenaEventVector)) && avector->request_render) { - avector->request_render (arena, area, listener->data); + avector->request_render (arena, &nr_area, listener->data); } } } diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index 1c8216434..49d133f9f 100644 --- a/src/display/nr-arena.h +++ b/src/display/nr-arena.h @@ -27,6 +27,7 @@ G_END_DECLS #define NR_ARENA(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA, NRArena)) #define NR_IS_ARENA(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA)) +#include <2geom/rect.h> #include #include #include "nr-arena-forward.h" @@ -61,7 +62,7 @@ struct NRArenaClass : public NRActiveObjectClass { }; void nr_arena_request_update (NRArena *arena, NRArenaItem *item); -void nr_arena_request_render_rect (NRArena *arena, NRRectL *area); +void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area); void nr_arena_set_renderoffscreen (NRArena *arena); void nr_arena_separate_color_plates(guint32* rgba); diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 0cb7901b3..01d2eca64 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -13,6 +13,7 @@ #include "document.h" #include "sp-item.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "display/nr-filter.h" @@ -94,28 +95,23 @@ void FilterImage::render_cairo(FilterSlot &slot) Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width(), sa.height()); - cairo_t *ct = cairo_create(out); - cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]); - ink_cairo_transform(ct, pu2pb); // we are now in primitive units - cairo_translate(ct, feImageX, feImageY); - cairo_scale(ct, scaleX, scaleY); - - NRRectL render_rect; - render_rect.x0 = floor(area.left()); - render_rect.y0 = floor(area.top()); - render_rect.x1 = ceil(area.right()); - render_rect.y1 = ceil(area.bottom()); - cairo_translate(ct, render_rect.x0, render_rect.y0); + Inkscape::DrawingContext ct(out, sa.min()); + ct.transform(pu2pb); // we are now in primitive units + ct.translate(feImageX, feImageY); + ct.scale(scaleX, scaleY); + + Geom::IntRect render_rect = area.roundOutwards(); + ct.translate(render_rect.min()); // Update to renderable state NRGC gc(NULL); Geom::Affine t = Geom::identity(); nr_arena_item_set_transform(ai, &t); gc.transform.setIdentity(); - nr_arena_item_invoke_update(ai, NULL, &gc, + nr_arena_item_invoke_update(ai, render_rect, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render(ct, ai, &render_rect, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE); + nr_arena_item_invoke_render(ct, ai, render_rect, NR_ARENA_ITEM_RENDER_NO_CACHE); SVGElem->invoke_hide(key); nr_object_unref((NRObject*) arena); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 3464fda66..494d77749 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -16,6 +16,7 @@ #include <2geom/transforms.h> #include "display/cairo-utils.h" +#include "display/drawing-context.h" #include "display/nr-arena-item.h" #include "display/nr-filter-types.h" #include "display/nr-filter-gaussian.h" @@ -25,13 +26,13 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, - cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u) +FilterSlot::FilterSlot(NRArenaItem *item, DrawingContext &bgct, + DrawingContext &graphic, FilterUnits const &u) : _item(item) - , _source_graphic(graphic) - , _background_ct(bgct) - , _source_graphic_area(graphicarea) - , _background_area(bgarea) + , _source_graphic(graphic.rawTarget()) + , _background_ct(bgct.raw()) + , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme + , _background_area(bgct.targetLogicalBounds().roundOutwards()) // fixme , _units(u) , _last_out(NR_FILTER_SOURCEGRAPHIC) , filterquality(FILTER_QUALITY_BEST) @@ -41,19 +42,15 @@ FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, using Geom::Y; // compute slot bbox - Geom::Rect bbox( - Geom::Point(_source_graphic_area->x0, _source_graphic_area->y0), - Geom::Point(_source_graphic_area->x1, _source_graphic_area->y1)); - Geom::Affine trans = _units.get_matrix_display2pb(); - Geom::Rect bbox_trans = bbox * trans; + Geom::Rect bbox_trans = graphic.targetLogicalBounds() * trans; Geom::Point min = bbox_trans.min(); _slot_x = min[X]; _slot_y = min[Y]; if (trans.isTranslation()) { - _slot_w = _source_graphic_area->x1 - _source_graphic_area->x0; - _slot_h = _source_graphic_area->y1 - _source_graphic_area->y0; + _slot_w = _source_graphic_area.width(); + _slot_h = _source_graphic_area.height(); } else { _slot_w = ceil(bbox_trans.width()); _slot_h = ceil(bbox_trans.height()); @@ -143,7 +140,7 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() cairo_translate(tsg_ct, -_slot_x, -_slot_y); ink_cairo_transform(tsg_ct, trans); - cairo_translate(tsg_ct, _source_graphic_area->x0, _source_graphic_area->y0); + cairo_translate(tsg_ct, _source_graphic_area.left(), _source_graphic_area.top()); cairo_set_source_surface(tsg_ct, _source_graphic, 0, 0); cairo_set_operator(tsg_ct, CAIRO_OPERATOR_SOURCE); cairo_paint(tsg_ct); @@ -164,7 +161,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background() cairo_translate(tbg_ct, -_slot_x, -_slot_y); ink_cairo_transform(tbg_ct, trans); - cairo_translate(tbg_ct, _background_area->x0, _background_area->y0); + cairo_translate(tbg_ct, _background_area.left(), _background_area.top()); cairo_set_source_surface(tbg_ct, bg, 0, 0); cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE); cairo_paint(tbg_ct); @@ -184,11 +181,11 @@ cairo_surface_t *FilterSlot::get_result(int res) cairo_surface_t *r = cairo_surface_create_similar(_source_graphic, cairo_surface_get_content(_source_graphic), - _source_graphic_area->x1 - _source_graphic_area->x0, - _source_graphic_area->y1 - _source_graphic_area->y0); + _source_graphic_area.width(), + _source_graphic_area.height()); cairo_t *r_ct = cairo_create(r); - cairo_translate(r_ct, -_source_graphic_area->x0, -_source_graphic_area->y0); + cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top()); ink_cairo_transform(r_ct, trans); cairo_translate(r_ct, _slot_x, _slot_y); cairo_set_source_surface(r_ct, getcairo(res), 0, 0); diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 3b08743ed..6a86ded8c 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -22,13 +22,15 @@ struct NRArenaItem; namespace Inkscape { +class DrawingContext; + namespace Filters { class FilterSlot { public: /** Creates a new FilterSlot object. */ - FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, - cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u); + FilterSlot(NRArenaItem *item, DrawingContext &bgct, + DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); @@ -66,7 +68,7 @@ public: FilterUnits const &get_units() const { return _units; } Geom::Rect get_slot_area() const; - NRRectL const &get_sg_area() const { return *_source_graphic_area; } + NRRectL get_sg_area() const { NRRectL ret(_source_graphic_area); return ret; } private: typedef std::map SlotMap; @@ -81,8 +83,8 @@ private: double _slot_x, _slot_y; cairo_surface_t *_source_graphic; cairo_t *_background_ct; - NRRectL const *_source_graphic_area; - NRRectL const *_background_area; ///< needed to extract background + Geom::IntRect _source_graphic_area; + Geom::IntRect _background_area; ///< needed to extract background FilterUnits const &_units; int _last_out; FilterQuality filterquality; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 963d98654..25ef80c17 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -40,6 +40,7 @@ #include "display/nr-arena.h" #include "display/nr-arena-item.h" +#include "display/drawing-context.h" #include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" @@ -96,14 +97,14 @@ Filter::~Filter() } -int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area) +int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic - cairo_set_source_rgba(graphic, 0,0,0,0); - cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); - cairo_paint(graphic); - cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + graphic.setSource(0,0,0,0); + graphic.setOperator(CAIRO_OPERATOR_SOURCE); + graphic.paint(); + graphic.setOperator(CAIRO_OPERATOR_OVER); return 1; } @@ -136,10 +137,10 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea = _filter_resolution(filter_area, trans, filterquality); if (!(resolution.first > 0 && resolution.second > 0)) { // zero resolution - clear source graphic and return - cairo_set_source_rgba(graphic, 0,0,0,0); - cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); - cairo_paint(graphic); - cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + graphic.setSource(0,0,0,0); + graphic.setOperator(CAIRO_OPERATOR_SOURCE); + graphic.paint(); + graphic.setOperator(CAIRO_OPERATOR_OVER); return 1; } @@ -160,7 +161,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea } } - FilterSlot slot(const_cast(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); + FilterSlot slot(const_cast(item), bgct, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -168,11 +169,12 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea _primitive[i]->render_cairo(slot); } + Geom::Point origin = graphic.targetLogicalBounds().min(); cairo_surface_t *result = slot.get_result(_output_slot); - cairo_set_source_surface(graphic, result, area->x0, area->y0); - cairo_set_operator(graphic, CAIRO_OPERATOR_SOURCE); - cairo_paint(graphic); - cairo_set_operator(graphic, CAIRO_OPERATOR_OVER); + graphic.setSource(result, origin[Geom::X], origin[Geom::Y]); + graphic.setOperator(CAIRO_OPERATOR_SOURCE); + graphic.paint(); + graphic.setOperator(CAIRO_OPERATOR_OVER); cairo_surface_destroy(result); return 0; @@ -186,10 +188,12 @@ void Filter::set_primitive_units(SPFilterUnits unit) { _primitive_units = unit; } -void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { +void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { + NRRectL b(bbox); for (unsigned i = 0 ; i < _primitive.size() ; i++) { - if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm); + if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm); } + bbox = *b.upgrade_2geom(); /* TODO: something. See images at the bottom of filters.svg with medium-low @@ -224,22 +228,13 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { */ } -void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) { - // Modifying empty bounding boxes confuses rest of the renderer, so - // let's not do that. - if (item_bbox.x0 > item_bbox.x1 || item_bbox.y0 > item_bbox.y1) return; +Geom::IntRect Filter::compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox) { - Geom::Point min(item_bbox.x0, item_bbox.y0); - Geom::Point max(item_bbox.x1, item_bbox.y1); - Geom::Rect tmp_bbox(min, max); + Geom::Rect enlarged = filter_effect_area(item_bbox); + enlarged *= item->ctm; - Geom::Rect enlarged = filter_effect_area(tmp_bbox); - enlarged = enlarged * item->ctm; - - item_bbox.x0 = floor(enlarged.min()[X]); - item_bbox.y0 = floor(enlarged.min()[Y]); - item_bbox.x1 = ceil(enlarged.max()[X]); - item_bbox.y1 = ceil(enlarged.max()[Y]); + Geom::IntRect ret(enlarged.roundOutwards()); + return ret; } Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index e1d4c10e5..5cebf3ad3 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -24,6 +24,8 @@ struct NRArenaItem; namespace Inkscape { +class DrawingContext; + namespace Filters { class Filter : public Inkscape::GC::Managed<> { @@ -33,7 +35,7 @@ public: * the results of filter rendering. @a bgarea and @a area specify bounding boxes * of both surfaces in world coordinates; Cairo contexts are assumed to be in default state * (0,0 = surface origin, no path, OVER operator) */ - int render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area); + int render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic); /** * Creates a new filter primitive under this filter object. @@ -149,13 +151,13 @@ public: * to be rendered so that after filtering, the original area is * drawn correctly. */ - void area_enlarge(NRRectL &area, NRArenaItem const *item) const; + void area_enlarge(Geom::IntRect &area, NRArenaItem const *item) const; /** * Given an item bounding box (in user coords), this function enlarges it * to contain the filter effects region and transforms it to screen * coordinates */ - void compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox); + Geom::IntRect compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 72fa0c444..fa5dd0d98 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -13,6 +13,8 @@ #include "style.h" #include "sp-paint-server.h" #include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!) +#include "display/drawing-context.h" +#include "libnr/nr-rect.h" void NRStyle::Paint::clear() { @@ -142,14 +144,15 @@ void NRStyle::set(SPStyle *style) update(); } -bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) +bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) { // update fill pattern if (!fill_pattern) { switch (fill.type) { - case PAINT_SERVER: - fill_pattern = sp_paint_server_create_pattern(fill.server, ct, paintbox, fill.opacity); - break; + case PAINT_SERVER: { + NRRect pb(paintbox); + fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), &pb, fill.opacity); + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -162,19 +165,20 @@ bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) return true; } -void NRStyle::applyFill(cairo_t *ct) +void NRStyle::applyFill(Inkscape::DrawingContext &ct) { - cairo_set_source(ct, fill_pattern); - cairo_set_fill_rule(ct, fill_rule); + ct.setSource(fill_pattern); + ct.setFillRule(fill_rule); } -bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) +bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) { if (!stroke_pattern) { switch (stroke.type) { - case PAINT_SERVER: - stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct, paintbox, stroke.opacity); - break; + case PAINT_SERVER: { + NRRect pb(paintbox); + stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), &pb, stroke.opacity); + } break; case PAINT_COLOR: { SPColor const &c = stroke.color; stroke_pattern = cairo_pattern_create_rgba( @@ -187,14 +191,14 @@ bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) return true; } -void NRStyle::applyStroke(cairo_t *ct) +void NRStyle::applyStroke(Inkscape::DrawingContext &ct) { - cairo_set_source(ct, stroke_pattern); - cairo_set_line_width(ct, stroke_width); - cairo_set_line_cap(ct, line_cap); - cairo_set_line_join(ct, line_join); - cairo_set_miter_limit(ct, miter_limit); - cairo_set_dash(ct, dash, n_dash, dash_offset); + ct.setSource(stroke_pattern); + ct.setLineWidth(stroke_width); + ct.setLineCap(line_cap); + ct.setLineJoin(line_join); + ct.setMiterLimit(miter_limit); + cairo_set_dash(ct.raw(), dash, n_dash, dash_offset); // fixme } void NRStyle::update() diff --git a/src/display/nr-style.h b/src/display/nr-style.h index e741e46b4..0ba6ce2c6 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -13,22 +13,25 @@ #define SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H #include +#include <2geom/rect.h> #include "color.h" class SPColor; class SPPaintServer; class SPStyle; -struct NRRect; +namespace Inkscape { +class DrawingContext; +} struct NRStyle { NRStyle(); ~NRStyle(); void set(SPStyle *); - bool prepareFill(cairo_t *ct, NRRect *paintbox); - bool prepareStroke(cairo_t *ct, NRRect *paintbox); - void applyFill(cairo_t *ct); - void applyStroke(cairo_t *ct); + bool prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox); + bool prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox); + void applyFill(Inkscape::DrawingContext &ct); + void applyStroke(Inkscape::DrawingContext &ct); void update(); enum PaintType { 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 #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 ; rowbbox.y0) + ihscale * (double) row; + double ypos = aImg->bbox->top() + ihscale * (double) row; for (int col=0 ; colbbox.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 -- cgit v1.2.3 From c1ad04d91b5cac237f184c3c6943ab520dd21cf7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 26 Jul 2011 00:03:48 +0200 Subject: Add deferred allocation functionality to DrawingSurface (bzr r10347.1.19) --- src/display/drawing-surface.cpp | 45 +++++++++++++++++++++++++++++++++-------- src/display/drawing-surface.h | 3 +++ 2 files changed, 40 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index e50a732c6..41ff14167 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -25,17 +25,22 @@ using Geom::Y; * 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 + * have to be rendered on tiles which have possibly non-integer * widths and heights. + * + * This class has delayed allocation functionality - it creates + * the Cairo surface it wraps on the first call to createRawContext() + * of when a DrawingContext is constructed. */ /** @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())) + : _surface(NULL) , _origin(area.min()) , _scale(1, 1) + , _pixels(area.dimensions()) {} /** @brief Creates a surface with the given logical extents. @@ -44,9 +49,10 @@ DrawingSurface::DrawingSurface(Geom::IntRect const &area) * 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()))) + : _surface(NULL) , _origin(area.min()) , _scale(ceil(area.width()) / area.width(), ceil(area.height()) / area.height()) + , _pixels(area.dimensions().ceil()) {} /** @brief Creates a surface with the given logical and physical extents. @@ -56,9 +62,10 @@ DrawingSurface::DrawingSurface(Geom::Rect const &area) * @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])) + : _surface(NULL) , _origin(logbox.min()) , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height()) + , _pixels(pixdims) {} /** @brief Wrap a cairo_surface_t. @@ -70,11 +77,14 @@ DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &orig , _scale(1, 1) { cairo_surface_reference(surface); + _pixels[X] = cairo_image_surface_get_width(surface); + _pixels[Y] = cairo_image_surface_get_height(surface); } DrawingSurface::~DrawingSurface() { - cairo_surface_destroy(_surface); + if (_surface) + cairo_surface_destroy(_surface); } /// Get the logical extents of the surface. @@ -85,13 +95,18 @@ DrawingSurface::area() const return r; } +/// Get the pixel dimensions of the surface +Geom::IntPoint +DrawingSurface::pixels() const +{ + return _pixels; +} + /// 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]); + Geom::Point logical_dims(_pixels[X] / _scale[X], _pixels[Y] / _scale[Y]); return logical_dims; } @@ -122,11 +137,25 @@ DrawingSurface::type() const return CAIRO_SURFACE_TYPE_IMAGE; } +/// Drop contents of the surface and release the underlying Cairo object. +void +DrawingSurface::dropContents() +{ + if (_surface) { + cairo_surface_destroy(_surface); + _surface = NULL; + } +} + /** @brief Create a drawing context for this surface. * It's better to use the surface constructor of DrawingContext. */ cairo_t * DrawingSurface::createRawContext() { + // deferred allocation + if (!_surface) { + _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _pixels[X], _pixels[Y]); + } cairo_t *ct = cairo_create(_surface); if (_scale != Geom::Scale::identity()) { cairo_scale(ct, _scale[X], _scale[Y]); diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index 2d0e147e2..e26bc28fa 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -32,11 +32,13 @@ public: virtual ~DrawingSurface(); Geom::Rect area() const; + Geom::IntPoint pixels() const; Geom::Point dimensions() const; Geom::Point origin() const; Geom::Scale scale() const; Geom::Affine drawingTransform() const; cairo_surface_type_t type() const; + void dropContents(); cairo_surface_t *raw() { return _surface; } cairo_t *createRawContext(); @@ -45,6 +47,7 @@ protected: cairo_surface_t *_surface; Geom::Point _origin; Geom::Scale _scale; + Geom::IntPoint _pixels; bool _has_context; friend class DrawingContext; -- cgit v1.2.3 From 905b8a96963f78358abfd109c0c49758c6fe4e9d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 28 Jul 2011 07:04:08 +0200 Subject: Per-item render cache. Cache some offscreen data to facilitate smoother navigation. (bzr r10347.1.20) --- src/display/canvas-arena.cpp | 125 +++--------------------------------- src/display/canvas-arena.h | 4 -- src/display/drawing-context.cpp | 17 +++++ src/display/drawing-context.h | 2 + src/display/drawing-surface.cpp | 137 ++++++++++++++++++++++++++++++++++++---- src/display/drawing-surface.h | 22 +++++-- src/display/nr-arena-item.cpp | 121 +++++++++++++++++++++++++++++------ src/display/nr-arena-item.h | 24 ++++--- src/display/nr-arena.cpp | 11 ++++ src/display/nr-arena.h | 4 ++ src/display/sp-canvas-item.h | 2 +- src/display/sp-canvas.cpp | 27 +++++--- 12 files changed, 320 insertions(+), 176 deletions(-) (limited to 'src') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 1d5cfe826..0f653a258 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -33,10 +33,8 @@ static void sp_canvas_arena_destroy(GtkObject *object); static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf); -static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area); -static void sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area); static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); -static void sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); +static void sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area); static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event); static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event); @@ -98,7 +96,7 @@ sp_canvas_arena_class_init (SPCanvasArenaClass *klass) item_class->render = sp_canvas_arena_render; item_class->point = sp_canvas_arena_point; item_class->event = sp_canvas_arena_event; - item_class->visible_area_changed = sp_canvas_arena_visible_area_changed; + item_class->viewbox_changed = sp_canvas_arena_viewbox_changed; } static void @@ -110,11 +108,9 @@ sp_canvas_arena_init (SPCanvasArena *arena) arena->arena->canvasarena = arena; arena->root = NRArenaGroup::create(arena->arena); nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE); + nr_arena_item_set_cache(arena->root, true); arena->active = NULL; - arena->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - arena->cache_area = Geom::IntRect::from_xywh(0,0,1,1); - arena->dirty = cairo_region_create(); nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena); } @@ -140,11 +136,6 @@ sp_canvas_arena_destroy (GtkObject *object) nr_object_unref ((NRObject *) arena->arena); arena->arena = NULL; } - if (arena->cache) { - cairo_surface_destroy(arena->cache); - arena->cache = NULL; - } - cairo_region_destroy(arena->dirty); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -209,42 +200,8 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) Geom::OptIntRect r = buf->rect; if (!r || r->hasZeroArea()) return; - - cairo_rectangle_int_t crect; - crect.x = r->left(); - crect.y = r->top(); - crect.width = r->width(); - crect.height = r->height(); - if (cairo_region_contains_rectangle(arena->dirty, &crect) != CAIRO_REGION_OVERLAP_OUT) { - sp_canvas_arena_render_cache(item, *r); - cairo_region_subtract_rectangle(arena->dirty, &crect); - } - - cairo_save(buf->ct); - cairo_translate(buf->ct, -r->left(), -r->top()); - cairo_set_source_surface(buf->ct, arena->cache, arena->cache_area.left(), arena->cache_area.top()); - cairo_paint(buf->ct); - cairo_restore(buf->ct); -} - -static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area) -{ - SPCanvasArena *arena = SP_CANVAS_ARENA (item); - - Geom::OptIntRect r = Geom::intersect(arena->cache_area, area); - if (!r || r->hasZeroArea()) return; // nothing to do - - 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(); - } + Inkscape::DrawingContext ct(buf->ct, r->min()); nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, @@ -252,17 +209,6 @@ static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect cons nr_arena_item_invoke_render (ct, arena->root, *r, 0); } -static void -sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area) -{ - cairo_rectangle_int_t rect; - rect.x = area->x0; - rect.y = area->y0; - rect.width = area->x1 - area->x0; - rect.height = area->y1 - area->y0; - cairo_region_union_rectangle(arena->dirty, &rect); -} - static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) { @@ -285,64 +231,14 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ } static void -sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area) +sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area) { SPCanvasArena *arena = SP_CANVAS_ARENA(item); - - cairo_surface_t *new_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - new_area.width(), new_area.height()); - cairo_t *ct = cairo_create(new_cache); - cairo_set_source_surface(ct, arena->cache, old_area.left() - new_area.left(), old_area.top() - new_area.top()); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - cairo_destroy(ct); - cairo_surface_destroy(arena->cache); - arena->cache = new_cache; - arena->cache_area = new_area; - - cairo_rectangle_int_t crect; - crect.x = new_area.left(); - crect.y = new_area.top(); - crect.width = new_area.width(); - crect.height = new_area.height(); - cairo_region_intersect_rectangle(arena->dirty, &crect); - - // invalidate newly exposed areas - /* - * +----------------------+ - * | top strip | - * +-------+------+-------+ - * | | | | - * | left | old | right | - * | strip | area | strip | - * | | | | - * +-------+------+-------+ - * | bottom strip | - * +----------------------+ - */ - - // top strip - if (new_area.top() < old_area.top()) { - NRRectL top_strip(new_area.left(), new_area.top(), new_area.right(), old_area.top()); - sp_canvas_arena_dirty_cache(arena, &top_strip); - } - // left strip - if (new_area.left() < old_area.left()) { - NRRectL left_strip(new_area.left(), std::max(new_area.top(), old_area.top()), - old_area.left(), std::min(new_area.bottom(), old_area.bottom())); - sp_canvas_arena_dirty_cache(arena, &left_strip); - } - // right strip - if (new_area.right() > old_area.right()) { - NRRectL right_strip(old_area.right(), std::max(new_area.top(), old_area.top()), - new_area.right(), std::min(new_area.bottom(), old_area.bottom())); - sp_canvas_arena_dirty_cache(arena, &right_strip); - } - // bottom strip - if (new_area.bottom() > old_area.bottom()) { - NRRectL bottom_strip(new_area.left(), old_area.bottom(), new_area.right(), new_area.bottom()); - sp_canvas_arena_dirty_cache(arena, &bottom_strip); - } + // make the cache limit larger than screen to facilitate smooth scrolling + Geom::IntRect expanded = new_area; + Geom::IntPoint expansion(new_area.width()/2, new_area.height()/2); + expanded.expandBy(expansion); + nr_arena_set_cache_limit(arena->arena, expanded); } static gint @@ -445,7 +341,6 @@ static void sp_canvas_arena_request_render (NRArena */*arena*/, NRRectL *area, void *data) { if (!area) return; - sp_canvas_arena_dirty_cache (SP_CANVAS_ARENA(data), area); sp_canvas_request_redraw (SP_CANVAS_ITEM (data)->canvas, area->x0, area->y0, area->x1, area->y1); } diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 220976da0..4cfeccb5a 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -45,10 +45,6 @@ struct _SPCanvasArena { /* fixme: */ NRArenaItem *picked; gdouble delta; - - Geom::IntRect cache_area; - cairo_surface_t *cache; - cairo_region_t *dirty; }; struct _SPCanvasArenaClass { diff --git a/src/display/drawing-context.cpp b/src/display/drawing-context.cpp index 8f37bb693..3c0c2163b 100644 --- a/src/display/drawing-context.cpp +++ b/src/display/drawing-context.cpp @@ -55,10 +55,23 @@ void DrawingContext::Save::save(DrawingContext &ct) * for drawing entire SPObjects when exporting. */ +DrawingContext::DrawingContext(cairo_t *ct, Geom::Point const &origin) + : _ct(ct) + , _surface(new DrawingSurface(cairo_get_group_target(ct), origin)) + , _delete_surface(true) + , _restore_context(true) +{ + _surface->_has_context = true; + cairo_reference(_ct); + cairo_save(_ct); + cairo_translate(_ct, -origin[Geom::X], -origin[Geom::Y]); +} + DrawingContext::DrawingContext(cairo_surface_t *surface, Geom::Point const &origin) : _ct(NULL) , _surface(new DrawingSurface(surface, origin)) , _delete_surface(true) + , _restore_context(false) { _surface->_has_context = true; _ct = _surface->createRawContext(); @@ -68,10 +81,14 @@ DrawingContext::DrawingContext(DrawingSurface &s) : _ct(s.createRawContext()) , _surface(&s) , _delete_surface(false) + , _restore_context(false) {} DrawingContext::~DrawingContext() { + if (_restore_context) { + cairo_restore(_ct); + } cairo_destroy(_ct); _surface->_has_context = false; if (_delete_surface) { diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index c0ea81874..8d2e7d68a 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -38,6 +38,7 @@ public: DrawingContext *_ct; }; + DrawingContext(cairo_t *ct, Geom::Point const &origin); DrawingContext(cairo_surface_t *surface, Geom::Point const &origin); DrawingContext(DrawingSurface &s); ~DrawingContext(); @@ -103,6 +104,7 @@ private: cairo_t *_ct; DrawingSurface *_surface; bool _delete_surface; + bool _restore_context; friend class DrawingSurface; }; diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 41ff14167..28bdc1f3c 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -10,6 +10,7 @@ */ #include "display/drawing-surface.h" +#include "display/drawing-context.h" #include "display/cairo-utils.h" namespace Inkscape { @@ -43,18 +44,6 @@ DrawingSurface::DrawingSurface(Geom::IntRect const &area) , _pixels(area.dimensions()) {} -/** @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(NULL) - , _origin(area.min()) - , _scale(ceil(area.width()) / area.width(), ceil(area.height()) / area.height()) - , _pixels(area.dimensions().ceil()) -{} - /** @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 @@ -164,6 +153,130 @@ DrawingSurface::createRawContext() return ct; } +Geom::IntRect +DrawingSurface::pixelArea() const +{ + Geom::IntRect ret = Geom::IntRect::from_xywh(_origin.round(), _pixels); + return ret; +} + +////////////////////////////////////////////////////////////////////////////// + +DrawingCache::DrawingCache(Geom::IntRect const &area) + : DrawingSurface(area) + , _clean_region(cairo_region_create()) +{} + +DrawingCache::~DrawingCache() +{ + cairo_region_destroy(_clean_region); +} + +void +DrawingCache::markDirty(Geom::IntRect const &area) +{ + cairo_rectangle_int_t dirty = _convertRect(area); + cairo_region_subtract_rectangle(_clean_region, &dirty); +} +void +DrawingCache::markClean(Geom::IntRect const &area) +{ + Geom::OptIntRect r = Geom::intersect(area, pixelArea()); + if (!r) return; + cairo_rectangle_int_t clean = _convertRect(*r); + cairo_region_union_rectangle(_clean_region, &clean); +} +bool +DrawingCache::isClean(Geom::IntRect const &area) const +{ + cairo_rectangle_int_t test = _convertRect(area); + if (cairo_region_contains_rectangle(_clean_region, &test) == CAIRO_REGION_OVERLAP_IN) { + return true; + } else { + return false; + } +} +void +DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine const &trans) +{ + Geom::IntRect old_area = pixelArea(); + bool is_identity = false; + bool is_integer_translation = false; + if (trans.isIdentity()) { + is_identity = true; + if (new_area == old_area) return; + } + if (!is_identity && trans.isTranslation()) { + Geom::IntPoint t = trans.translation().round(); + if (Geom::are_near(Geom::Point(t), trans.translation())) { + // integer translation or identity with change of area + is_integer_translation = true; + cairo_region_translate(_clean_region, t[X], t[Y]); + if (old_area + t == new_area) { + // if the areas match, the only thing to do + // is to ensure that the clean area is not too large + cairo_rectangle_int_t limit = _convertRect(new_area); + cairo_region_intersect_rectangle(_clean_region, &limit); + _origin += t; + return; + } + } + } + // otherwise, we need to transform the cache + Geom::IntPoint old_origin = old_area.min(); + cairo_surface_t *old_surface = _surface; + _surface = NULL; + _pixels = new_area.dimensions(); + _origin = new_area.min(); + + cairo_t *ct = createRawContext(); + if (!is_identity) { + ink_cairo_transform(ct, trans); + } + cairo_set_source_surface(ct, old_surface, old_origin[X], old_origin[Y]); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + + cairo_surface_destroy(old_surface); + cairo_destroy(ct); + + if (!is_identity && !is_integer_translation) { + // dirty everything + cairo_region_destroy(_clean_region); + _clean_region = cairo_region_create(); + } else { + cairo_rectangle_int_t limit = _convertRect(new_area); + cairo_region_intersect_rectangle(_clean_region, &limit); + } +} + +/** @brief Paints the clean area from cache and returns the remaining part */ +bool +DrawingCache::paintFromCache(DrawingContext &ct, Geom::IntRect const &area) +{ + if (!isClean(area)) + return false; + + Inkscape::DrawingContext::Save save(ct); + ct.rectangle(area); + ct.clip(); + ct.setSource(this); + ct.paint(); + + return true; +} + +cairo_rectangle_int_t +DrawingCache::_convertRect(Geom::IntRect const &area) +{ + cairo_rectangle_int_t ret; + ret.x = area.left(); + ret.y = area.top(); + ret.width = area.width(); + ret.height = area.height(); + return ret; +} + } // end namespace Inkscape /* diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index e26bc28fa..f279d771b 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -26,7 +26,6 @@ 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(); @@ -44,6 +43,8 @@ public: cairo_t *createRawContext(); protected: + Geom::IntRect pixelArea() const; + cairo_surface_t *_surface; Geom::Point _origin; Geom::Scale _scale; @@ -53,16 +54,23 @@ protected: friend class DrawingContext; }; -class PixbufSurface +class DrawingCache : public DrawingSurface { public: - explicit PixbufSurface(GdkPixbuf *pb, Geom::Point const &origin = Geom::Point(0,0)); - ~PixbufSurface(); -protected: - GdkPixbuf *pb; + explicit DrawingCache(Geom::IntRect const &area); + ~DrawingCache(); - friend class DrawingContext; + void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite()); + void markClean(Geom::IntRect const &area = Geom::IntRect::infinite()); + bool isClean(Geom::IntRect const &area) const; + void resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); + bool paintFromCache(DrawingContext &ct, Geom::IntRect const &area); + +protected: + cairo_region_t *_clean_region; +private: + static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r); }; } // end namespace Inkscape diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index c1ffefa1d..264b8ab10 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -90,14 +90,14 @@ nr_arena_item_init (NRArenaItem *item) item->ctm.setIdentity(); item->opacity = 255; item->render_opacity = FALSE; + item->render_cache = FALSE; item->transform = NULL; item->clip = NULL; item->mask = NULL; - item->px = NULL; + item->cache = NULL; item->data = NULL; item->filter = NULL; - item->background_pb = NULL; item->background_new = false; } @@ -106,13 +106,13 @@ nr_arena_item_private_finalize (NRObject *object) { NRArenaItem *item = static_cast < NRArenaItem * >(object); - item->px = NULL; item->transform = NULL; if (item->clip) nr_arena_item_detach(item, item->clip); if (item->mask) nr_arena_item_detach(item, item->mask); + delete item->cache; ((NRObjectClass *) (parent_class))->finalize (object); } @@ -246,21 +246,18 @@ nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC return item->state; /* Test whether to return immediately */ if (item->state & NR_ARENA_ITEM_STATE_BBOX) { + // we have up-to-date bbox if (!area.intersects(outline ? item->bbox : item->drawbox)) return item->state; } - /* Reset image cache, if not to be kept */ - if (!(item->state & NR_ARENA_ITEM_STATE_IMAGE) && (item->px)) { - item->px = NULL; - } - /* Set up local gc */ childgc = *gc; if (item->transform) { childgc.transform = (*item->transform) * childgc.transform; } /* Remember the transformation matrix */ + Geom::Affine ctm_change = item->ctm.inverse() * childgc.transform; item->ctm = childgc.transform; /* Invoke the real method */ @@ -307,10 +304,31 @@ nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC } } + // update cache if enabled + if (item->render_cache) { + Geom::OptIntRect cl = item->arena->cache_limit; + cl.intersectWith(item->drawbox); + if (cl) { + if (item->cache) { + // this takes care of invalidation on transform + item->cache->resizeAndTransform(*cl, ctm_change); + } else { + item->cache = new Inkscape::DrawingCache(*cl); + // the cache is initially dirty + } + } else { + // disable cache for this item - not visible + delete item->cache; + item->cache = NULL; + } + } + // now that we know drawbox, dirty the corresponding rect on canvas: if (!NR_IS_ARENA_GROUP(item) || (item->filter && filter)) { // unless filtered, groups do not need to render by themselves, only their members - nr_arena_item_request_render (item); + if (state & ~NR_ARENA_ITEM_STATE_CACHE) { + nr_arena_item_request_render (item); + } } return item->state; @@ -379,12 +397,19 @@ nr_arena_item_invoke_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Ge return item->state | NR_ARENA_ITEM_STATE_RENDER; } - + // carea is the bounding box for intermediate rendering. - // NOTE: carea might be larger than area, because of filter effects. Geom::OptIntRect carea = Geom::intersect(area, item->drawbox); if (!carea) return item->state | NR_ARENA_ITEM_STATE_RENDER; + + // render from cache + if (item->render_cache && item->cache) { + if(item->cache->paintFromCache(ct, *carea)) + return item->state | NR_ARENA_ITEM_STATE_RENDER; + } + + // expand carea to contain the dependent area of filters. if (item->filter && filter) { item->filter->area_enlarge(*carea, item); carea.intersectWith(item->drawbox); @@ -422,12 +447,40 @@ nr_arena_item_invoke_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Ge // short-circuit the simple case. if (!needs_intermediate_rendering) { - 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; + if (item->render_cache && item->cache) { + Inkscape::DrawingContext cachect(*item->cache); + cachect.rectangle(area); + cachect.clip(); + + { // 1. clear the corresponding part of cache + Inkscape::DrawingContext::Save save(cachect); + cachect.setSource(0,0,0,0); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.paint(); + } + // 2. render to cache + state = NR_ARENA_ITEM_VIRTUAL (item, render) (cachect, item, *carea, flags); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + item->state |= NR_ARENA_ITEM_STATE_INVALID; + return item->state; + } + // 3. copy from cache to output + Inkscape::DrawingContext::Save save(ct); + ct.rectangle(*carea); + ct.clip(); + ct.setSource(item->cache); + ct.paint(); + // 4. mark as clean + item->cache->markClean(area); + return item->state | NR_ARENA_ITEM_STATE_RENDER; + } else { + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + item->state |= NR_ARENA_ITEM_STATE_INVALID; + return item->state; + } + return item->state | NR_ARENA_ITEM_STATE_RENDER; } - return item->state | NR_ARENA_ITEM_STATE_RENDER; } DrawingSurface intermediate(*carea); @@ -490,7 +543,16 @@ nr_arena_item_invoke_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Ge ict.setOperator(CAIRO_OPERATOR_IN); ict.paint(); - // 6. Paint the completed rendering onto the base context + // 6. Paint the completed rendering onto the base context (or into cache) + if (item->render_cache && item->cache) { + DrawingContext cachect(*item->cache); + cachect.rectangle(area); + cachect.clip(); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.setSource(&intermediate); + cachect.paint(); + item->cache->markClean(area); + } ct.setSource(&intermediate); ct.paint(); ct.setSource(0,0,0,0); @@ -601,7 +663,17 @@ 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); + Geom::OptIntRect dirty = outline ? item->bbox : item->drawbox; + if (!dirty) return; + + // dirty the caches of all parents + for (NRArenaItem *i = item; i; i = i->parent) { + if (i->render_cache && i->cache) { + i->cache->markDirty(*dirty); + } + } + + nr_arena_request_render_rect (item->arena, dirty); } /* Public */ @@ -773,6 +845,19 @@ nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox) item->item_bbox = bbox; } +void +nr_arena_item_set_cache (NRArenaItem *item, bool cache) +{ + if (cache) { + item->render_cache = TRUE; + item->arena->cached_items.insert(item); + } else { + item->render_cache = FALSE; + item->arena->cached_items.erase(item); + } + nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE); +} + /** Returns a background image for use with filter effects. */ NRPixBlock *nr_arena_item_get_background(NRArenaItem const * /*item*/) { diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index 4b43e4da8..2c00c0bf3 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -24,6 +24,7 @@ namespace Inkscape { class DrawingContext; +class DrawingCache; namespace Filters { class Filter; } } @@ -57,15 +58,17 @@ class Filter; #define NR_ARENA_ITEM_STATE_MASK (1 << 6) #define NR_ARENA_ITEM_STATE_PICK (1 << 7) #define NR_ARENA_ITEM_STATE_IMAGE (1 << 8) +#define NR_ARENA_ITEM_STATE_CACHE (1 << 9) #define NR_ARENA_ITEM_STATE_NONE 0x0000 -#define NR_ARENA_ITEM_STATE_ALL 0x01fe +#define NR_ARENA_ITEM_STATE_ALL 0x03fe #define NR_ARENA_ITEM_STATE(i,s) (NR_ARENA_ITEM (i)->state & (s)) #define NR_ARENA_ITEM_SET_STATE(i,s) (NR_ARENA_ITEM (i)->state |= (s)) #define NR_ARENA_ITEM_UNSET_STATE(i,s) (NR_ARENA_ITEM (i)->state &= ~(s)) #define NR_ARENA_ITEM_RENDER_NO_CACHE (1 << 0) +#define NR_ARENA_ITEM_RENDER_CACHE (1 << 1) struct NRGC { NRGC(NRGC const *p) : parent(p) {} @@ -81,14 +84,15 @@ struct NRArenaItem : public NRObject { Inkscape::GC::soft_ptr prev; /* Item state */ - unsigned int state : 16; - unsigned int propagate : 1; - unsigned int sensitive : 1; - unsigned int visible : 1; - /* Whether items renders opacity itself */ - unsigned int render_opacity : 1; + unsigned state : 16; /* Opacity itself */ - unsigned int opacity : 8; + unsigned opacity : 8; + unsigned propagate : 1; + unsigned sensitive : 1; + unsigned visible : 1; + /* Whether items renders opacity itself */ + unsigned render_opacity : 1; + unsigned render_cache : 1; unsigned int key; ///< Some SPItems can have more than one NRArenaItem, ///this value is a hack used to distinguish between them @@ -101,11 +105,10 @@ struct NRArenaItem : public NRObject { NRArenaItem *clip; ///< Clipping path NRArenaItem *mask; ///< Mask Inkscape::Filters::Filter *filter; ///< Filter - unsigned char *px; ///< Render cache; unused + Inkscape::DrawingCache *cache; ///< Render cache void *data; ///< Anonymous data member - this is used to associate SPItems with arena items - NRPixBlock *background_pb; ///< Background for filters; unused bool background_new; void init(NRArena *arena) { @@ -173,6 +176,7 @@ void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip); void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask); void nr_arena_item_set_order (NRArenaItem *item, int order); void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox); +void nr_arena_item_set_cache (NRArenaItem *item, bool cache); NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item); diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index 5747de26c..735d44e9e 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -151,6 +151,17 @@ nr_arena_set_renderoffscreen (NRArena *arena) } +void +nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit) +{ + arena->cache_limit = cache_limit; + for (std::set::iterator i = arena->cached_items.begin(); + i != arena->cached_items.end(); ++i) + { + nr_arena_item_request_update(*i, NR_ARENA_ITEM_STATE_CACHE, FALSE); + } +} + #define FLOAT_TO_UINT8(f) (int(f*255)) #define RGBA_R(v) ((v) >> 24) #define RGBA_G(v) (((v) >> 16) & 0xff) diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index 49d133f9f..5d078e19d 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 #include <2geom/rect.h> #include #include @@ -53,6 +54,8 @@ struct NRArena : public NRActiveObject { Inkscape::ColorRenderMode colorrendermode; int blurquality; // will be updated during update from preferences int filterquality; // will be updated during update from preferences + Geom::OptIntRect cache_limit; + std::set cached_items; guint32 outlinecolor; SPCanvasArena *canvasarena; // may be NULL is this arena is not the screen but used for export etc. @@ -64,6 +67,7 @@ struct NRArenaClass : public NRActiveObjectClass { void nr_arena_request_update (NRArena *arena, NRArenaItem *item); void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area); void nr_arena_set_renderoffscreen (NRArena *arena); +void nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit); void nr_arena_separate_color_plates(guint32* rgba); diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h index 4c731e56b..415c36566 100644 --- a/src/display/sp-canvas-item.h +++ b/src/display/sp-canvas-item.h @@ -64,7 +64,7 @@ struct _SPCanvasItemClass : public GtkObjectClass { double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); int (* event) (SPCanvasItem *item, GdkEvent *event); - void (* visible_area_changed) (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); + void (* viewbox_changed) (SPCanvasItem *item, Geom::IntRect const &new_area); }; SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GType type, const gchar *first_arg_name, ...); diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 71f608118..7d6727ff3 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -689,7 +689,7 @@ static void sp_canvas_group_destroy (GtkObject *object); static void sp_canvas_group_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static double sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); static void sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf); -static void sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); +static void sp_canvas_group_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area); static SPCanvasItemClass *group_parent_class; @@ -733,7 +733,7 @@ sp_canvas_group_class_init (SPCanvasGroupClass *klass) item_class->update = sp_canvas_group_update; item_class->render = sp_canvas_group_render; item_class->point = sp_canvas_group_point; - item_class->visible_area_changed = sp_canvas_group_visible_area_changed; + item_class->viewbox_changed = sp_canvas_group_viewbox_changed; } /** @@ -878,15 +878,15 @@ sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf) } static void -sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area) +sp_canvas_group_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_area) { SPCanvasGroup *group = SP_CANVAS_GROUP (item); for (GList *list = group->items; list; list = list->next) { SPCanvasItem *child = (SPCanvasItem *)list->data; if (child->flags & SP_CANVAS_ITEM_VISIBLE) { - if (SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed) - SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed (child, old_area, new_area); + if (SP_CANVAS_ITEM_GET_CLASS (child)->viewbox_changed) + SP_CANVAS_ITEM_GET_CLASS (child)->viewbox_changed (child, new_area); } } } @@ -1234,8 +1234,8 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) /* Schedule redraw of new region */ sp_canvas_resize_tiles(canvas,canvas->x0,canvas->y0,canvas->x0+allocation->width,canvas->y0+allocation->height); - if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed) - SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area); + if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed) + SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed (canvas->root, new_area); if (allocation->width > widget->allocation.width) { sp_canvas_request_redraw (canvas, @@ -1655,6 +1655,15 @@ static void sp_canvas_paint_single_buffer(SPCanvas *canvas, int x0, int y0, int buf.is_empty = true; //buf.ct = gdk_cairo_create(widget->window); + /* + cairo_t *xctt = gdk_cairo_create(widget->window); + cairo_translate(xctt, x0 - canvas->x0, y0 - canvas->y0); + cairo_set_source_rgb(xctt, 1,0,0); + cairo_rectangle(xctt, 0, 0, x1-x0, y1-y0); + cairo_fill(xctt); + cairo_destroy(xctt); + //*/ + // create temporary surface int w = x1 - x0; int h = y1 - y0; @@ -2168,8 +2177,8 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear, canvas->y0 = iy; sp_canvas_resize_tiles (canvas, canvas->x0, canvas->y0, canvas->x0+canvas->widget.allocation.width, canvas->y0+canvas->widget.allocation.height); - if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed) - SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area); + if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed) + SP_CANVAS_ITEM_GET_CLASS (canvas->root)->viewbox_changed (canvas->root, new_area); if (!clear) { // scrolling without zoom; redraw only the newly exposed areas -- cgit v1.2.3 From 4dd33aa4d5c57706c7f64f63391174954160a308 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 14:18:32 +0200 Subject: Rewrite NRArenaItem hierarchy into C++ (bzr r10347.1.21) --- src/2geom/affine.cpp | 12 + src/2geom/affine.h | 10 +- src/2geom/coord.h | 38 + src/2geom/generic-interval.h | 8 +- src/2geom/generic-rect.h | 105 ++- src/2geom/interval.h | 3 - src/2geom/linear.h | 2 +- src/2geom/rect.h | 1 - src/2geom/transforms.h | 30 +- src/context-fns.h | 1 + src/desktop.cpp | 89 ++- src/desktop.h | 12 +- src/dialogs/clonetiler.cpp | 18 +- src/display/Makefile_insert | 22 +- src/display/canvas-arena.cpp | 95 +-- src/display/canvas-arena.h | 15 +- src/display/display-forward.h | 8 + src/display/drawing-group.cpp | 141 ++++ src/display/drawing-group.h | 61 ++ src/display/drawing-image.cpp | 263 ++++++ src/display/drawing-image.h | 66 ++ src/display/drawing-item.cpp | 620 ++++++++++++++ src/display/drawing-item.h | 168 ++++ src/display/drawing-shape.cpp | 340 ++++++++ src/display/drawing-shape.h | 64 ++ src/display/drawing-text.cpp | 275 +++++++ src/display/drawing-text.h | 84 ++ src/display/grayscale.cpp | 2 +- src/display/nr-arena-forward.h | 51 -- src/display/nr-arena-glyphs.cpp | 439 ---------- src/display/nr-arena-glyphs.h | 108 --- src/display/nr-arena-group.cpp | 300 ------- src/display/nr-arena-group.h | 61 -- src/display/nr-arena-image.cpp | 390 --------- src/display/nr-arena-image.h | 66 -- src/display/nr-arena-item.cpp | 932 ---------------------- src/display/nr-arena-item.h | 205 ----- src/display/nr-arena-shape.cpp | 565 ------------- src/display/nr-arena-shape.h | 72 -- src/display/nr-arena.cpp | 23 +- src/display/nr-arena.h | 23 +- src/display/nr-filter-diffuselighting.cpp | 1 - src/display/nr-filter-image.cpp | 19 +- src/display/nr-filter-slot.cpp | 3 +- src/display/nr-filter-slot.h | 7 +- src/display/nr-filter.cpp | 28 +- src/display/nr-filter.h | 11 +- src/display/rendermode.h | 8 +- src/document.cpp | 14 +- src/extension/internal/cairo-png-out.cpp | 3 +- src/extension/internal/cairo-ps-out.cpp | 1 - src/extension/internal/cairo-render-context.cpp | 7 +- src/extension/internal/cairo-renderer-pdf-out.cpp | 1 - src/extension/internal/cairo-renderer.cpp | 7 +- src/extension/internal/latex-pstricks-out.cpp | 4 +- src/extension/print.h | 10 +- src/flood-context.cpp | 76 +- src/helper/Makefile_insert | 1 - src/helper/pixbuf-ops.cpp | 55 +- src/helper/png-write.cpp | 15 +- src/interface.cpp | 8 +- src/libnrtype/Layout-TNG-Output.cpp | 17 +- src/libnrtype/Layout-TNG.h | 5 +- src/marker.cpp | 34 +- src/marker.h | 2 +- src/print.cpp | 15 +- src/print.h | 1 + src/select-context.cpp | 18 +- src/sp-clippath.cpp | 34 +- src/sp-clippath.h | 4 +- src/sp-flowtext.cpp | 39 +- src/sp-flowtext.h | 4 +- src/sp-image.cpp | 29 +- src/sp-item-group.cpp | 69 +- src/sp-item-group.h | 4 +- src/sp-item.cpp | 158 ++-- src/sp-item.h | 15 +- src/sp-mask.cpp | 32 +- src/sp-mask.h | 4 +- src/sp-pattern.cpp | 19 +- src/sp-root.cpp | 14 +- src/sp-shape.cpp | 63 +- src/sp-shape.h | 4 +- src/sp-switch.cpp | 10 +- src/sp-switch.h | 2 +- src/sp-symbol.cpp | 16 +- src/sp-text.cpp | 43 +- src/sp-text.h | 2 +- src/sp-tref.cpp | 1 - src/sp-use.cpp | 33 +- src/svg-view.cpp | 9 +- src/trace/trace.cpp | 53 +- src/ui/cache/svg_preview_cache.cpp | 19 +- src/ui/cache/svg_preview_cache.h | 23 +- src/ui/dialog/icon-preview.cpp | 4 +- src/widgets/desktop-widget.cpp | 4 +- src/widgets/icon.cpp | 28 +- src/widgets/stroke-style.cpp | 7 +- 98 files changed, 2919 insertions(+), 3986 deletions(-) create mode 100644 src/display/drawing-group.cpp create mode 100644 src/display/drawing-group.h create mode 100644 src/display/drawing-image.cpp create mode 100644 src/display/drawing-image.h create mode 100644 src/display/drawing-item.cpp create mode 100644 src/display/drawing-item.h create mode 100644 src/display/drawing-shape.cpp create mode 100644 src/display/drawing-shape.h create mode 100644 src/display/drawing-text.cpp create mode 100644 src/display/drawing-text.h delete mode 100644 src/display/nr-arena-forward.h delete mode 100644 src/display/nr-arena-glyphs.cpp delete mode 100644 src/display/nr-arena-glyphs.h delete mode 100644 src/display/nr-arena-group.cpp delete mode 100644 src/display/nr-arena-group.h delete mode 100644 src/display/nr-arena-image.cpp delete mode 100644 src/display/nr-arena-image.h delete mode 100644 src/display/nr-arena-item.cpp delete mode 100644 src/display/nr-arena-item.h delete mode 100644 src/display/nr-arena-shape.cpp delete mode 100644 src/display/nr-arena-shape.h (limited to 'src') diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp index 2a1f18d77..c31b9ba90 100644 --- a/src/2geom/affine.cpp +++ b/src/2geom/affine.cpp @@ -410,6 +410,9 @@ Affine &Affine::operator*=(Affine const &o) { } //TODO: What's this!?! +/** Given a matrix m such that unit_circle = m*x, this returns the + * quadratic form x*A*x = 1. + * @relates Affine */ Affine elliptic_quadratic_form(Affine const &m) { double od = m[0] * m[1] + m[2] * m[3]; Affine ret (m[0]*m[0] + m[1]*m[1], od, @@ -469,6 +472,15 @@ Eigen::Eigen(double m[2][2]) { vectors[i] = Point(0,0); } +/** @brief Nearness predicate for affine transforms + * @returns True if all entries of matrices are within eps of each other */ +bool are_near(Affine const &a, Affine const &b, Coord eps) +{ + return are_near(a[0], b[0], eps) && are_near(a[1], b[1], eps) && + are_near(a[2], b[2], eps) && are_near(a[3], b[3], eps) && + are_near(a[4], b[4], eps) && are_near(a[5], b[5], eps); +} + } //namespace Geom /* diff --git a/src/2geom/affine.h b/src/2geom/affine.h index d7a7a0692..22f8bd9f5 100644 --- a/src/2geom/affine.h +++ b/src/2geom/affine.h @@ -200,9 +200,8 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::Affine &m) return out_file; } -/** Given a matrix m such that unit_circle = m*x, this returns the - * quadratic form x*A*x = 1. - * @relates Affine */ +// Affine factories +Affine from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0)); Affine elliptic_quadratic_form(Affine const &m); /** Given a matrix (ignoring the translation) this returns the eigen @@ -215,9 +214,6 @@ public: Eigen(double M[2][2]); }; -// Affine factories -Affine from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0)); - /** @brief Create an identity matrix. * This is a convenience function identical to Affine::identity(). */ inline Affine identity() { @@ -239,6 +235,8 @@ inline Affine Affine::identity() { return ret; // allow NRVO } +bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON); + } // end namespace Geom #endif // LIB2GEOM_SEEN_AFFINE_H diff --git a/src/2geom/coord.h b/src/2geom/coord.h index f7bf2c5d0..90e776665 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -34,6 +34,7 @@ #include #include +#include #include <2geom/forward.h> namespace Geom { @@ -62,6 +63,9 @@ inline bool rel_error_bound(Coord a, Coord b, double eps=EPSILON) { return a <= template struct CoordTraits {}; +// NOTE: operator helpers for Rect and Interval are defined here. +// This is to avoid increasing their size through multiple inheritance. + template<> struct CoordTraits { typedef IntPoint PointType; @@ -69,6 +73,22 @@ struct CoordTraits { typedef OptIntInterval OptIntervalType; typedef IntRect RectType; typedef OptIntRect OptRectType; + + typedef + boost::equality_comparable< IntervalType + , boost::additive< IntervalType + , boost::additive< IntervalType, IntCoord + , boost::orable< IntervalType + > > > > + IntervalOps; + + typedef + boost::equality_comparable< RectType + , boost::orable< RectType + , boost::orable< RectType, OptRectType + , boost::additive< RectType, PointType + > > > > + RectOps; }; template<> @@ -78,6 +98,24 @@ struct CoordTraits { typedef OptInterval OptIntervalType; typedef Rect RectType; typedef OptRect OptRectType; + + typedef + boost::equality_comparable< IntervalType + , boost::additive< IntervalType + , boost::multipliable< IntervalType + , boost::orable< IntervalType + , boost::arithmetic< IntervalType, Coord + > > > > > + IntervalOps; + + typedef + boost::equality_comparable< RectType + , boost::orable< RectType + , boost::orable< RectType, OptRectType + , boost::additive< RectType, PointType + , boost::multipliable< RectType, Affine + > > > > > + RectOps; }; } // end namespace Geom diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h index a32e97d4b..0212da676 100644 --- a/src/2geom/generic-interval.h +++ b/src/2geom/generic-interval.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include <2geom/coord.h> namespace Geom { @@ -47,11 +47,7 @@ class GenericOptInterval; */ template class GenericInterval - : boost::equality_comparable< GenericInterval - , boost::additive< GenericInterval - , boost::additive< GenericInterval, C - , boost::orable< GenericInterval - > > > > + : CoordTraits::IntervalOps { typedef GenericInterval Self; protected: diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h index 2db30dfa9..efe499809 100644 --- a/src/2geom/generic-rect.h +++ b/src/2geom/generic-rect.h @@ -42,6 +42,7 @@ #include #include +#include <2geom/coord.h> namespace Geom { @@ -54,11 +55,7 @@ class GenericOptRect; */ template class GenericRect - : boost::additive< typename CoordTraits::RectType, typename CoordTraits::PointType - , boost::equality_comparable< typename CoordTraits::RectType - , boost::orable< typename CoordTraits::RectType - , boost::orable< typename CoordTraits::RectType, typename CoordTraits::OptRectType - > > > > + : CoordTraits::RectOps { typedef typename CoordTraits::IntervalType CInterval; typedef typename CoordTraits::PointType CPoint; @@ -131,15 +128,22 @@ public: /// @name Inspect dimensions. /// @{ - CInterval &operator[](unsigned i) { return f[i]; } + CInterval &operator[](unsigned i) { return f[i]; } CInterval const &operator[](unsigned i) const { return f[i]; } + CInterval &operator[](Dim2 d) { return f[d]; } + CInterval const &operator[](Dim2 d) const { return f[d]; } + /** @brief Get the corner of the rectangle with smallest coordinate values. + * In 2Geom standard coordinate system, this means upper left. */ CPoint min() const { return CPoint(f[X].min(), f[Y].min()); } + /** @brief Get the corner of the rectangle with largest coordinate values. + * In 2Geom standard coordinate system, this means lower right. */ CPoint max() const { return CPoint(f[X].max(), f[Y].max()); } /** @brief Return the n-th corner of the rectangle. - * If the Y axis grows upwards, this returns corners in clockwise order - * starting from the lower left. If Y grows downwards, it returns the corners - * in counter-clockwise order starting from the upper left. */ + * Returns corners in the direction of growing angles, starting from + * the one given by min(). For the standard coordinate system used + * in 2Geom (+Y downwards), this means clockwise starting from + * the upper left. */ CPoint corner(unsigned i) const { switch(i % 4) { case 0: return CPoint(f[X].min(), f[Y].min()); @@ -196,10 +200,10 @@ public: } /** @brief Check whether the rectangles have any common points. - * A non-empty rectangle will not intersect empty rectangles. */ + * Empty rectangles will not intersect with any other rectangle. */ inline bool intersects(OptCRect const &r) const; /** @brief Check whether the rectangle includes all points in the given rectangle. - * A non-empty rectangle will contain any empty rectangle. */ + * Empty rectangles will be contained in any non-empty rectangle. */ inline bool contains(OptCRect const &r) const; /** @brief Check whether the given point is within the rectangle. */ @@ -224,11 +228,11 @@ public: void expandTo(CPoint const &p) { f[X].expandTo(p[X]); f[Y].expandTo(p[Y]); } - /** @brief Enlarge the rectangle to contain the given rectangle. */ + /** @brief Enlarge the rectangle to contain the argument. */ void unionWith(CRect const &b) { f[X].unionWith(b[X]); f[Y].unionWith(b[Y]); } - /** @brief Enlarge the rectangle to contain the given rectangle. + /** @brief Enlarge the rectangle to contain the argument. * Unioning with an empty rectangle results in no changes. */ void unionWith(OptCRect const &b); @@ -244,7 +248,8 @@ public: * This will expand the width by the X coordinate of the point in both directions * and the height by Y coordinate of the point. Negative coordinate values will * shrink the rectangle. If -p[X] is larger than half of the width, - * the X interval will contain only the X coordinate of the midpoint; same for height. */ + * the X interval will contain only the X coordinate of the midpoint; + * same for height. */ void expandBy(CPoint const &p) { f[X].expandBy(p[X]); f[Y].expandBy(p[Y]); } @@ -297,30 +302,66 @@ class GenericOptRect typedef typename CoordTraits::OptRectType OptCRect; typedef boost::optional Base; public: + /// @name Create potentially empty rectangles. + /// @{ GenericOptRect() : Base() {} GenericOptRect(GenericRect const &a) : Base(CRect(a)) {} GenericOptRect(CPoint const &a, CPoint const &b) : Base(CRect(a, b)) {} - /** - * Creates an empty OptRect when one of the argument intervals is empty. - */ + /// Creates an empty OptRect when one of the argument intervals is empty. GenericOptRect(OptCInterval const &x_int, OptCInterval const &y_int) { if (x_int && y_int) { *this = CRect(*x_int, *y_int); } // else, stay empty. } + /** @brief Create a rectangle from a range of points. + * The resulting rectangle will contain all ponts from the range. + * If the range contains no points, the result will be an empty rectangle. + * The return type of iterators must be convertible to the corresponding + * point type (Point or IntPoint). + * @param start Beginning of the range + * @param end End of the range + * @return Rectangle that contains all points from [start, end). */ + template + static OptCRect from_range(InputIterator start, InputIterator end) { + OptCRect result; + for (; start != end; ++start) { + result.expandTo(*start); + } + return result; + } + /// @} + /// @name Check other rectangles and points for inclusion. + /// @{ /** @brief Check for emptiness. */ inline bool isEmpty() const { return !*this; }; - + /** @brief Check whether the rectangles have any common points. + * Empty rectangles will not intersect with any other rectangle. */ bool intersects(CRect const &r) const { return r.intersects(*this); } + /** @brief Check whether the rectangle includes all points in the given rectangle. + * Empty rectangles will be contained in any non-empty rectangle. */ bool contains(CRect const &r) const { return *this && (*this)->contains(r); } + /** @brief Check whether the rectangles have any common points. + * Empty rectangles will not intersect with any other rectangle. + * Two empty rectangles will not intersect each other. */ bool intersects(OptCRect const &r) const { return *this && (*this)->intersects(r); } + /** @brief Check whether the rectangle includes all points in the given rectangle. + * Empty rectangles will be contained in any non-empty rectangle. + * An empty rectangle will not contain other empty rectangles. */ bool contains(OptCRect const &r) const { return *this && (*this)->contains(r); } + /** @brief Check whether the given point is within the rectangle. + * An empty rectangle will not contain any points. */ bool contains(CPoint const &p) const { return *this && (*this)->contains(p); } + /// @} + /// @name Modify the potentially empty rectangle. + /// @{ + /** @brief Enlarge the rectangle to contain the argument. + * If this rectangle is empty, after callng this method it will + * be equal to the argument. */ void unionWith(CRect const &b) { if (*this) { (*this)->unionWith(b); @@ -328,9 +369,16 @@ public: *this = b; } } + /** @brief Enlarge the rectangle to contain the argument. + * Unioning with an empty rectangle results in no changes. + * If this rectangle is empty, after calling this method it will + * be equal to the argument. */ void unionWith(OptCRect const &b) { if (b) unionWith(*b); } + /** @brief Leave only the area overlapping with the argument. + * If the rectangles do not have any points in common, after calling + * this method the rectangle will be empty. */ void intersectWith(CRect const &b) { if (!*this) return; OptCInterval x = (**this)[X] & b[X], y = (**this)[Y] & b[Y]; @@ -340,6 +388,9 @@ public: *(static_cast(this)) = boost::none; } } + /** @brief Leave only the area overlapping with the argument. + * If the argument is empty or the rectangles do not have any points + * in common, after calling this method the rectangle will be empty. */ void intersectWith(OptCRect const &b) { if (b) { intersectWith(*b); @@ -347,18 +398,36 @@ public: *(static_cast(this)) = boost::none; } } + /** @brief Create or enlarge the rectangle to contain the given point. + * If the rectangle is empty, after calling this method it will be non-empty + * and it will contain only the given point. */ + void expandTo(CPoint const &p) { + if (*this) { + (*this).expandTo(p); + } else { + *this = CRect(p, p); + } + } + /// @} + + /// @name Operators + /// @{ + /** @brief Union with @a b */ GenericOptRect &operator|=(OptCRect const &b) { unionWith(b); return *this; } + /** @brief Intersect with @a b */ GenericOptRect &operator&=(CRect const &b) { intersectWith(b); return *this; } + /** @brief Intersect with @a b */ GenericOptRect &operator&=(OptCRect const &b) { intersectWith(b); return *this; } + /// @} }; template diff --git a/src/2geom/interval.h b/src/2geom/interval.h index e95da4811..711eaa5e2 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -63,9 +63,6 @@ typedef GenericOptInterval OptInterval; */ class Interval : public GenericInterval - , boost::multipliable< Interval - , boost::multiplicative< Interval, Coord - > > { typedef GenericInterval Base; public: diff --git a/src/2geom/linear.h b/src/2geom/linear.h index df6dd9904..448ab3bb7 100644 --- a/src/2geom/linear.h +++ b/src/2geom/linear.h @@ -55,7 +55,7 @@ class SBasis; class Linear{ public: double a[2]; - Linear() {} + Linear() { a[0] = 0; a[1] = 0; } Linear(double aa, double b) {a[0] = aa; a[1] = b;} Linear(double aa) {a[0] = aa; a[1] = aa;} diff --git a/src/2geom/rect.h b/src/2geom/rect.h index f7d331523..b79a0a04f 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -59,7 +59,6 @@ typedef GenericOptRect OptRect; */ class Rect : public GenericRect - , boost::multipliable< Rect, Affine > { typedef GenericRect Base; public: diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 5627e8b6f..eaf869056 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -45,10 +45,11 @@ namespace Geom { * @ingroup Concepts */ template struct TransformConcept { - T t; + T t, t2; Affine m; Point p; bool bool_; + Coord epsilon; void constraints() { m = t; //implicit conversion m *= t; @@ -63,6 +64,8 @@ struct TransformConcept { bool_ = (t != t); t = T::identity(); t = t.inverse(); + bool_ = are_near(t, t2); + bool_ = are_near(t, t2, epsilon); } }; @@ -130,6 +133,10 @@ public: friend class Point; }; +inline bool are_near(Translate const &a, Translate const &b, Coord eps=EPSILON) { + return are_near(a[X], b[X], eps) && are_near(a[Y], b[Y], eps); +} + /** @brief Scaling from the origin. * During scaling, the point (0,0) will not move. To obtain a scale with a different * invariant point, combine with translation to the origin and back. @@ -164,6 +171,10 @@ public: friend class Point; }; +inline bool are_near(Scale const &a, Scale const &b, Coord eps=EPSILON) { + return are_near(a[X], b[X], eps) && are_near(a[Y], b[Y], eps); +} + /** @brief Rotation around the origin. * Combine with translations to the origin and back to get a rotation around a different point. * @ingroup Transforms */ @@ -207,6 +218,10 @@ public: friend class Point; }; +inline bool are_near(Rotate const &a, Rotate const &b, Coord eps=EPSILON) { + return are_near(a[X], b[X], eps) && are_near(a[Y], b[Y], eps); +} + /** @brief Common base for shearing transforms. * This class is an implementation detail and should not be used directly. * @ingroup Transforms */ @@ -241,6 +256,10 @@ public: operator Affine() const { Affine ret(1, 0, f, 1, 0, 0); return ret; } }; +inline bool are_near(HShear const &a, HShear const &b, Coord eps=EPSILON) { + return are_near(a.factor(), b.factor(), eps); +} + /** @brief Vertical shearing. * Points on the Y axis will not move. Combine with translations to get a shear * with a different invariant line. @@ -253,6 +272,10 @@ public: operator Affine() const { Affine ret(1, f, 0, 1, 0, 0); return ret; } }; +inline bool are_near(VShear const &a, VShear const &b, Coord eps=EPSILON) { + return are_near(a.factor(), b.factor(), eps); +} + /** @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 @@ -295,6 +318,11 @@ public: friend class Affine; }; +inline bool are_near(Zoom const &a, Zoom const &b, Coord eps=EPSILON) { + return are_near(a.scale(), b.scale(), eps) && + are_near(a.translation(), b.translation(), eps); +} + /** @brief Specialization of exponentiation for Scale. * @relates Scale */ template<> diff --git a/src/context-fns.h b/src/context-fns.h index c86640aba..c56c67a27 100644 --- a/src/context-fns.h +++ b/src/context-fns.h @@ -16,6 +16,7 @@ struct SPDesktop; struct SPItem; +struct SPEventContext; const double goldenratio = 1.61803398874989484820; // golden ratio diff --git a/src/desktop.cpp b/src/desktop.cpp index 5e968b08b..cceee9499 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -59,55 +59,56 @@ #include <2geom/transforms.h> #include <2geom/rect.h> -#include "macros.h" -#include "inkscape-private.h" -#include "desktop.h" + +#include "box3d-context.h" +#include "color.h" #include "desktop-events.h" +#include "desktop.h" #include "desktop-handles.h" -#include "document.h" -#include "message-stack.h" -#include "selection.h" -#include "select-context.h" -#include "sp-namedview.h" -#include "color.h" -#include "sp-item-group.h" -#include "preferences.h" -#include "object-hierarchy.h" -#include "helper/units.h" +#include "desktop-style.h" +#include "device-manager.h" #include "display/canvas-arena.h" -#include "display/nr-arena.h" -#include "display/gnome-canvas-acetate.h" -#include "display/sodipodi-ctrlrect.h" -#include "display/sp-canvas-util.h" +#include "display/canvas-grid.h" #include "display/canvas-temporary-item-list.h" +#include "display/drawing-group.h" +#include "display/gnome-canvas-acetate.h" +#include "display/nr-arena.h" #include "display/snap-indicator.h" +#include "display/sodipodi-ctrlrect.h" #include "display/sp-canvas-group.h" -#include "ui/dialog/dialog-manager.h" -#include "xml/repr.h" -#include "message-context.h" -#include "device-manager.h" +#include "display/sp-canvas.h" +#include "display/sp-canvas-util.h" +#include "document.h" +#include "event-log.h" +#include "helper/units.h" +#include "inkscape-private.h" #include "layer-fns.h" #include "layer-manager.h" +#include "macros.h" +#include "message-context.h" +#include "message-stack.h" +#include "object-hierarchy.h" +#include "preferences.h" #include "resource-manager.h" -#include "event-log.h" -#include "display/canvas-grid.h" -#include "widgets/desktop-widget.h" -#include "box3d-context.h" -#include "desktop-style.h" +#include "select-context.h" +#include "selection.h" #include "sp-item-group.h" +#include "sp-item-group.h" +#include "sp-namedview.h" #include "sp-root.h" +#include "ui/dialog/dialog-manager.h" +#include "widgets/desktop-widget.h" +#include "xml/repr.h" // TODO those includes are only for node tool quick zoom. Remove them after fixing it. #include "ui/tool/node-tool.h" #include "ui/tool/control-point-selection.h" -#include "display/sp-canvas.h" - namespace Inkscape { namespace XML { class Node; }} // Callback declarations static void _onSelectionChanged (Inkscape::Selection *selection, SPDesktop *desktop); -static gint _arena_handler (SPCanvasArena *arena, NRArenaItem *ai, GdkEvent *event, SPDesktop *desktop); +static gint _arena_handler (SPCanvasArena *arena, Inkscape::DrawingItem *ai, GdkEvent *event, SPDesktop *desktop); static void _layer_activated(SPObject *layer, SPDesktop *desktop); static void _layer_deactivated(SPObject *layer, SPDesktop *desktop); static void _layer_hierarchy_changed(SPObject *top, SPObject *bottom, SPDesktop *desktop); @@ -158,7 +159,7 @@ SPDesktop::SPDesktop() : _layer_hierarchy( 0 ), _reconstruction_old_layer_id( 0 ), _display_mode(Inkscape::RENDERMODE_NORMAL), - _display_color_mode(Inkscape::COLORRENDERMODE_NORMAL), + _display_color_mode(Inkscape::COLORMODE_NORMAL), _widget( 0 ), _inkscape( 0 ), _guides_message_context( 0 ), @@ -285,12 +286,12 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); - NRArenaItem *ai = document->getRoot()->invoke_show( + Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( SP_CANVAS_ARENA (drawing)->arena, dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL); + SP_CANVAS_ARENA (drawing)->root->prependChild(ai); } namedview->show(this); @@ -460,8 +461,8 @@ void SPDesktop::_setDisplayMode(Inkscape::RenderMode mode) { sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw _widget->setTitle( sp_desktop_document(this)->getName() ); } -void SPDesktop::_setDisplayColorMode(Inkscape::ColorRenderMode mode) { - SP_CANVAS_ARENA (drawing)->arena->colorrendermode = mode; +void SPDesktop::_setDisplayColorMode(Inkscape::ColorMode mode) { + SP_CANVAS_ARENA (drawing)->arena->colormode = mode; canvas->colorrendermode = mode; _display_color_mode = mode; sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw @@ -485,15 +486,15 @@ void SPDesktop::displayModeToggle() { } void SPDesktop::displayColorModeToggle() { switch (_display_color_mode) { - case Inkscape::COLORRENDERMODE_NORMAL: - _setDisplayColorMode(Inkscape::COLORRENDERMODE_GRAYSCALE); + case Inkscape::COLORMODE_NORMAL: + _setDisplayColorMode(Inkscape::COLORMODE_GRAYSCALE); break; - case Inkscape::COLORRENDERMODE_GRAYSCALE: - _setDisplayColorMode(Inkscape::COLORRENDERMODE_NORMAL); + case Inkscape::COLORMODE_GRAYSCALE: + _setDisplayColorMode(Inkscape::COLORMODE_NORMAL); break; -// case Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW: +// case Inkscape::COLORMODE_PRINT_COLORS_PREVIEW: default: - _setDisplayColorMode(Inkscape::COLORRENDERMODE_NORMAL); + _setDisplayColorMode(Inkscape::COLORMODE_NORMAL); } } @@ -1562,7 +1563,7 @@ SPDesktop::setDocument (SPDocument *doc) /// are surely more safe methods to accomplish this. // TODO since the comment had reversed logic, check the intent of this block of code: if (drawing) { - NRArenaItem *ai = 0; + Inkscape::DrawingItem *ai = 0; namedview = sp_document_namedview (doc, NULL); _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); @@ -1573,7 +1574,7 @@ SPDesktop::setDocument (SPDocument *doc) dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL); + SP_CANVAS_ARENA (drawing)->root->prependChild(ai); } namedview->show(this); /* Ugly hack */ @@ -1662,10 +1663,10 @@ _onSelectionChanged * \todo fixme */ static gint -_arena_handler (SPCanvasArena */*arena*/, NRArenaItem *ai, GdkEvent *event, SPDesktop *desktop) +_arena_handler (SPCanvasArena */*arena*/, Inkscape::DrawingItem *ai, GdkEvent *event, SPDesktop *desktop) { if (ai) { - SPItem *spi = (SPItem*)NR_ARENA_ITEM_GET_DATA (ai); + SPItem *spi = (SPItem*) ai->data(); return sp_event_context_item_handler (desktop->event_context, spi, event); } else { return sp_event_context_root_handler (desktop->event_context, event); diff --git a/src/desktop.h b/src/desktop.h index a7264e4aa..26c308f5d 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -211,19 +211,19 @@ public: Inkscape::RenderMode _display_mode; Inkscape::RenderMode getMode() const { return _display_mode; } - void _setDisplayColorMode(Inkscape::ColorRenderMode mode); + void _setDisplayColorMode(Inkscape::ColorMode mode); void setDisplayColorModeNormal() { - _setDisplayColorMode(Inkscape::COLORRENDERMODE_NORMAL); + _setDisplayColorMode(Inkscape::COLORMODE_NORMAL); } void setDisplayColorModeGrayscale() { - _setDisplayColorMode(Inkscape::COLORRENDERMODE_GRAYSCALE); + _setDisplayColorMode(Inkscape::COLORMODE_GRAYSCALE); } // void setDisplayColorModePrintColorsPreview() { -// _setDisplayColorMode(Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW); +// _setDisplayColorMode(Inkscape::COLORMODE_PRINT_COLORS_PREVIEW); // } void displayColorModeToggle(); - Inkscape::ColorRenderMode _display_color_mode; - Inkscape::ColorRenderMode getColorMode() const { return _display_color_mode; } + Inkscape::ColorMode _display_color_mode; + Inkscape::ColorMode getColorMode() const { return _display_color_mode; } Inkscape::UI::Widget::Dock* getDock() { return _widget->getDock(); } diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index 55b405523..2b08a307a 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -27,7 +27,7 @@ #include "display/cairo-utils.h" #include "display/drawing-context.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "document.h" #include "filter-chemistry.h" #include "helper/unit-menu.h" @@ -834,7 +834,7 @@ static bool clonetiler_is_a_clone_of(SPObject *tile, SPObject *obj) static NRArena const *trace_arena = NULL; static unsigned trace_visionkey; -static NRArenaItem *trace_root; +static Inkscape::DrawingItem *trace_root; static gdouble trace_zoom; static SPDocument *trace_doc; @@ -852,6 +852,8 @@ static void clonetiler_trace_hide_tiled_clones_recursively(SPObject *from) static void clonetiler_trace_setup(SPDocument *doc, gdouble zoom, SPItem *original) { + // FIXME MEMORY LEAK: the stuff here is never freed + trace_arena = NRArena::create(); /* Create ArenaItem and set transform */ trace_visionkey = SPItem::display_key_new(1); @@ -874,13 +876,8 @@ static guint32 clonetiler_trace_pick(Geom::Rect box) return 0; } - Geom::Affine t(Geom::Scale(trace_zoom, trace_zoom)); - nr_arena_item_set_transform(trace_root, &t); - NRGC gc(NULL); - gc.transform.setIdentity(); - nr_arena_item_invoke_update( trace_root, Geom::IntRect::infinite(), &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); + trace_root->setTransform(Geom::Scale(trace_zoom)); + trace_root->update(); /* Item integer bbox in points */ Geom::IntRect ibox = (box * Geom::Scale(trace_zoom)).roundOutwards(); @@ -889,8 +886,7 @@ static guint32 clonetiler_trace_pick(Geom::Rect box) 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, - NR_ARENA_ITEM_RENDER_NO_CACHE ); + trace_root->render(ct, ibox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); 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 53f87efb1..1c51f19a0 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -25,8 +25,18 @@ ink_common_sources += \ display/curve.h \ display/drawing-context.cpp \ display/drawing-context.h \ + display/drawing-group.cpp \ + display/drawing-group.h \ + display/drawing-image.cpp \ + display/drawing-image.h \ + display/drawing-item.cpp \ + display/drawing-item.h \ + display/drawing-shape.cpp \ + display/drawing-shape.h \ display/drawing-surface.cpp \ display/drawing-surface.h \ + display/drawing-text.cpp \ + display/drawing-text.h \ display/gnome-canvas-acetate.cpp \ display/gnome-canvas-acetate.h \ display/grayscale.cpp \ @@ -35,19 +45,9 @@ ink_common_sources += \ display/guideline.h \ display/nr-3dutils.cpp \ display/nr-3dutils.h \ + display/nr-arena.h \ display/nr-arena.cpp \ display/nr-arena-forward.h \ - display/nr-arena-glyphs.cpp \ - display/nr-arena-glyphs.h \ - display/nr-arena-group.cpp \ - display/nr-arena-group.h \ - display/nr-arena.h \ - display/nr-arena-image.cpp \ - display/nr-arena-image.h \ - display/nr-arena-item.cpp \ - display/nr-arena-item.h \ - display/nr-arena-shape.cpp \ - display/nr-arena-shape.h \ display/nr-filter-blend.cpp \ display/nr-filter-blend.h \ display/nr-filter-colormatrix.cpp \ diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 0f653a258..81416fefb 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -16,12 +16,15 @@ #include "display/sp-canvas-util.h" #include "helper/sp-marshal.h" #include "display/nr-arena.h" -#include "display/nr-arena-group.h" #include "display/canvas-arena.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing-group.h" #include "display/drawing-surface.h" +using namespace Inkscape; + enum { ARENA_EVENT, LAST_SIGNAL @@ -31,6 +34,7 @@ static void sp_canvas_arena_class_init(SPCanvasArenaClass *klass); static void sp_canvas_arena_init(SPCanvasArena *group); static void sp_canvas_arena_destroy(GtkObject *object); +static void sp_canvas_arena_item_deleted(SPCanvasArena *arena, Inkscape::DrawingItem *item); static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf); static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); @@ -39,7 +43,7 @@ static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event); static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event); -static void sp_canvas_arena_request_update (NRArena *arena, NRArenaItem *item, void *data); +static void sp_canvas_arena_request_update (NRArena *arena, DrawingItem *item, void *data); static void sp_canvas_arena_request_render (NRArena *arena, NRRectL *area, void *data); NRArenaEventVector carenaev = { @@ -105,10 +109,16 @@ sp_canvas_arena_init (SPCanvasArena *arena) arena->sticky = FALSE; arena->arena = NRArena::create(); + nr_object_ref(arena->arena); arena->arena->canvasarena = arena; - arena->root = NRArenaGroup::create(arena->arena); - nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE); - nr_arena_item_set_cache(arena->root, true); + arena->arena->item_deleted.connect( + sigc::bind<0>( + sigc::ptr_fun(&sp_canvas_arena_item_deleted), + arena)); + + arena->root = new DrawingGroup(arena->arena); + arena->root->setPickChildren(true); + arena->root->setCached(true); arena->active = NULL; @@ -120,22 +130,11 @@ sp_canvas_arena_destroy (GtkObject *object) { SPCanvasArena *arena = SP_CANVAS_ARENA (object); - if (arena->active) { - nr_object_unref ((NRObject *) arena->active); - arena->active = NULL; - } - - if (arena->root) { - nr_arena_item_unref (arena->root); - arena->root = NULL; - } - - if (arena->arena) { - nr_active_object_remove_listener_by_data ((NRActiveObject *) arena->arena, arena); + delete arena->root; - nr_object_unref ((NRObject *) arena->arena); - arena->arena = NULL; - } + nr_active_object_remove_listener_by_data ((NRActiveObject *) arena->arena, arena); + nr_object_unref ((NRObject *) arena->arena); + arena->arena = NULL; if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -149,14 +148,12 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned if (((SPCanvasItemClass *) parent_class)->update) (* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags); - arena->gc.transform = affine; + arena->ctx.ctm = affine; - guint reset; - reset = (flags & SP_CANVAS_UPDATE_AFFINE)? NR_ARENA_ITEM_STATE_ALL : NR_ARENA_ITEM_STATE_NONE; + unsigned reset = flags & SP_CANVAS_UPDATE_AFFINE ? DrawingItem::STATE_ALL : 0; + arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, reset); - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); - - Geom::OptIntRect b = arena->root->bbox; + Geom::OptIntRect b = arena->root->visualBounds(); if (b) { item->x1 = b->left() - 1; item->y1 = b->top() - 1; @@ -166,7 +163,7 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned if (arena->cursor) { /* Mess with enter/leave notifiers */ - NRArenaItem *new_arena = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); + DrawingItem *new_arena = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = GTK_WIDGET (item->canvas)->window; @@ -180,10 +177,7 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned ec.type = GDK_LEAVE_NOTIFY; sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } - /* fixme: This is not optimal - better track ::destroy (Lauris) */ - if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = new_arena; - if (arena->active) nr_object_ref ((NRObject *) arena->active); if (arena->active) { ec.type = GDK_ENTER_NOTIFY; sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); @@ -192,6 +186,14 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned } } +static void +sp_canvas_arena_item_deleted(SPCanvasArena *arena, Inkscape::DrawingItem *item) +{ + if (arena->active == item) { + arena->active = NULL; + } +} + static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) { @@ -203,10 +205,8 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) Inkscape::DrawingContext ct(buf->ct, r->min()); - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, - NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, - NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render (ct, arena->root, *r, 0); + arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, 0); + arena->root->render(ct, *r, 0); } static double @@ -214,11 +214,8 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ { SPCanvasArena *arena = SP_CANVAS_ARENA (item); - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, - NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK, - NR_ARENA_ITEM_STATE_NONE); - - NRArenaItem *picked = nr_arena_item_invoke_pick (arena->root, p, arena->arena->delta, arena->sticky); + arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + DrawingItem *picked = arena->root->pick(p, arena->arena->delta, arena->sticky); arena->picked = picked; @@ -244,7 +241,7 @@ sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_ar static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) { - NRArenaItem *new_arena; + Inkscape::DrawingItem *new_arena; /* fixme: This sucks, we have to handle enter/leave notifiers */ SPCanvasArena *arena = SP_CANVAS_ARENA (item); @@ -256,7 +253,6 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) if (!arena->cursor) { if (arena->active) { //g_warning ("Cursor entered to arena with already active item"); - nr_object_unref ((NRObject *) arena->active); } arena->cursor = TRUE; @@ -264,9 +260,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->crossing.x, event->crossing.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); - arena->active = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); - if (arena->active) nr_object_ref ((NRObject *) arena->active); + arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + arena->active = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); ret = sp_canvas_arena_send_event (arena, event); } break; @@ -274,7 +269,6 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) case GDK_LEAVE_NOTIFY: if (arena->cursor) { ret = sp_canvas_arena_send_event (arena, event); - if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = NULL; arena->cursor = FALSE; } @@ -285,8 +279,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->motion.x, event->motion.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - nr_arena_item_invoke_update (arena->root, Geom::IntRect::infinite(), &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); - new_arena = nr_arena_item_invoke_pick (arena->root, arena->c, arena->arena->delta, arena->sticky); + arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + new_arena = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = event->motion.window; @@ -300,9 +294,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) ec.type = GDK_LEAVE_NOTIFY; ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } - if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = new_arena; - if (arena->active) nr_object_ref ((NRObject *) arena->active); if (arena->active) { ec.type = GDK_ENTER_NOTIFY; ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); @@ -332,7 +324,7 @@ sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event) } static void -sp_canvas_arena_request_update (NRArena */*arena*/, NRArenaItem */*item*/, void *data) +sp_canvas_arena_request_update (NRArena */*arena*/, DrawingItem */*item*/, void *data) { sp_canvas_item_request_update (SP_CANVAS_ITEM (data)); } @@ -373,7 +365,8 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR Geom::OptIntRect area = r.upgrade_2geom(); if (!area) return; Inkscape::DrawingContext ct(surface, area->min()); - nr_arena_item_invoke_render (ct, ca->root, *area, 0); + ca->root->update(Geom::IntRect::infinite(), ca->ctx, DrawingItem::STATE_ALL, 0); + ca->root->render(ct, *area, 0); } diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 4cfeccb5a..e63a524f2 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -15,9 +15,10 @@ #include #include <2geom/rect.h> +#include "display/display-forward.h" +#include "display/drawing-item.h" #include "display/sp-canvas.h" #include "display/sp-canvas-item.h" -#include "display/nr-arena-item.h" G_BEGIN_DECLS @@ -38,19 +39,19 @@ struct _SPCanvasArena { Geom::Point c; // what is this? NRArena *arena; - NRArenaItem *root; - NRGC gc; + Inkscape::DrawingGroup *root; + Inkscape::UpdateContext ctx; - NRArenaItem *active; + Inkscape::DrawingItem *active; /* fixme: */ - NRArenaItem *picked; - gdouble delta; + Inkscape::DrawingItem *picked; + double delta; }; struct _SPCanvasArenaClass { SPCanvasItemClass parent_class; - gint (* arena_event) (SPCanvasArena *carena, NRArenaItem *item, GdkEvent *event); + gint (* arena_event) (SPCanvasArena *carena, Inkscape::DrawingItem *item, GdkEvent *event); }; GType sp_canvas_arena_get_type (void); diff --git a/src/display/display-forward.h b/src/display/display-forward.h index 288da829a..d7e7d72ab 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -11,9 +11,17 @@ struct SPCanvasGroup; struct SPCanvasGroupClass; class SPCurve; +class NRArena; + namespace Inkscape { class DrawingContext; class DrawingSurface; +class DrawingItem; +class DrawingGroup; +class DrawingImage; +class DrawingShape; +class DrawingGlyphs; +class DrawingText; namespace Display { class TemporaryItem; diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp new file mode 100644 index 000000000..2d40f0a83 --- /dev/null +++ b/src/display/drawing-group.cpp @@ -0,0 +1,141 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing-group.h" +#include "libnr/nr-values.h" +#include "nr-arena.h" +#include "style.h" + +namespace Inkscape { + +DrawingGroup::DrawingGroup(Drawing *drawing) + : DrawingItem(drawing) + , _style(NULL) + , _child_transform(NULL) +{} + +DrawingGroup::~DrawingGroup() +{ + if (_style) + sp_style_unref(_style); +} + +void +DrawingGroup::setPickChildren(bool p) +{ + _pick_children = p; +} + +void +DrawingGroup::setStyle(SPStyle *style) +{ + _setStyleCommon(_style, style); +} + +void +DrawingGroup::setChildTransform(Geom::Affine const &new_trans) +{ + Geom::Affine current; + if (_child_transform) { + current = *_child_transform; + } + + if (!Geom::are_near(current, new_trans, NR_EPSILON)) { + // mark the area where the object was for redraw. + _markForRendering(); + if (new_trans.isIdentity()) { + delete _child_transform; // delete NULL; is safe + _child_transform = NULL; + } else { + _child_transform = new Geom::Affine(new_trans); + } + _markForUpdate(STATE_ALL, true); + } +} + +unsigned +DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + unsigned beststate = STATE_ALL; + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + UpdateContext child_ctx(ctx); + if (_child_transform) { + child_ctx.ctm = *_child_transform * ctx.ctm; + } + i->update(area, child_ctx, flags, reset); + } + if (beststate & STATE_BBOX) { + _bbox = Geom::OptIntRect(); + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + if (i->visible()) { + _bbox.unionWith(outline ? i->geometricBounds() : i->visualBounds()); + } + } + } + return beststate; +} + +void +DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->render(ct, area, flags); + } +} + +void +DrawingGroup::_clipItem(DrawingContext &ct, Geom::IntRect const &area) +{ + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->clip(ct, area); + } +} + +DrawingItem * +DrawingGroup::_pickItem(Geom::Point const &p, double delta) +{ + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingItem *picked = i->pick(p, delta, false); + if (picked) { + return _pick_children ? picked : this; + } + } + return NULL; +} + +bool +DrawingGroup::_canClip() +{ + return true; +} + +bool is_drawing_group(DrawingItem *item) +{ + return dynamic_cast(item) != NULL; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h new file mode 100644 index 000000000..f7d6a2be3 --- /dev/null +++ b/src/display/drawing-group.h @@ -0,0 +1,61 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_GROUP_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_GROUP_H + +#include "display/drawing-item.h" + +class SPStyle; + +namespace Inkscape { + +class DrawingGroup + : public DrawingItem +{ +public: + DrawingGroup(Drawing *drawing); + ~DrawingGroup(); + + bool pickChildren() { return _pick_children; } + void setPickChildren(bool p); + + void setStyle(SPStyle *style); + void setChildTransform(Geom::Affine const &new_trans); + +protected: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual bool _canClip(); + + SPStyle *_style; + Geom::Affine *_child_transform; +}; + +bool is_drawing_group(DrawingItem *item); + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp new file mode 100644 index 000000000..ea6f6ce3c --- /dev/null +++ b/src/display/drawing-image.cpp @@ -0,0 +1,263 @@ +/** + * @file + * @brief Bitmap image belonging to an SVG drawing + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-image.h" +#include "nr-arena.h" +#include "preferences.h" +#include "style.h" + +namespace Inkscape { + +DrawingImage::DrawingImage(Drawing *drawing) + : DrawingItem(drawing) + , _pixbuf(NULL) + , _surface(NULL) + , _style(NULL) +{} + +DrawingImage::~DrawingImage() +{ + if (_style) + sp_style_unref(_style); + if (_pixbuf) { + cairo_surface_destroy(_surface); + g_object_unref(_pixbuf); + } +} + +void +DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) +{ + // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1 + if (pb != NULL) { + g_object_ref (pb); + } + if (_pixbuf != NULL) { + g_object_unref(_pixbuf); + cairo_surface_destroy(_surface); + } + _pixbuf = pb; + _surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; + + _markForUpdate(STATE_ALL, false); +} + +void +DrawingImage::setStyle(SPStyle *style) +{ + _setStyleCommon(_style, style); +} + +void +DrawingImage::setScale(double sx, double sy) +{ + _scale = Geom::Scale(sx, sy); + _markForUpdate(STATE_ALL, false); +} + +void +DrawingImage::setOrigin(Geom::Point const &o) +{ + _origin = o; + _markForUpdate(STATE_ALL, false); +} + +void +DrawingImage::setClipbox(Geom::Rect const &box) +{ + _clipbox = box; + _markForUpdate(STATE_ALL, false); +} + +Geom::Rect +DrawingImage::bounds() const +{ + if (!_pixbuf) return _clipbox; + + double pw = gdk_pixbuf_get_width(_pixbuf); + double ph = gdk_pixbuf_get_height(_pixbuf); + double vw = pw * _scale[Geom::X]; + double vh = ph * _scale[Geom::Y]; + Geom::Point wh(vw, vh); + Geom::Rect view(_origin, _origin+wh); + Geom::OptRect res = _clipbox & view; + Geom::Rect ret = res ? *res : _clipbox; + + return ret; +} + +unsigned +DrawingImage::_updateItem(Geom::IntRect const &, UpdateContext const &, unsigned, unsigned) +{ + _markForRendering(); + + // Calculate bbox + if (_pixbuf) { + Geom::Rect r = bounds() * _ctm; + _bbox = r.roundOutwards(); + } else { + _bbox = Geom::OptIntRect(); + } + + return STATE_ALL; +} + +void +DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + if (!outline) { + if (!_pixbuf) return; + + Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + ct.newPath(); + ct.rectangle(_clipbox); + ct.clip(); + + ct.translate(_origin); + ct.scale(_scale); + ct.setSource(_surface, 0, 0); + + cairo_matrix_t tt; + Geom::Affine total; + cairo_get_matrix(ct.raw(), &tt); + ink_matrix_to_2geom(total, tt); + + if (total.expansionX() > 1.0 || total.expansionY() > 1.0) { + cairo_pattern_t *p = cairo_get_source(ct.raw()); + cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST); + } + //ct.paint(_opacity); + ct.paint(); + + } else { // outline; draw a rect instead + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff); + + { Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + ct.newPath(); + + Geom::Rect r = bounds(); + Geom::Point c00 = r.corner(0); + Geom::Point c01 = r.corner(3); + Geom::Point c11 = r.corner(2); + Geom::Point c10 = r.corner(1); + + ct.moveTo(c00); + // the box + ct.lineTo(c10); + ct.lineTo(c11); + ct.lineTo(c01); + ct.lineTo(c00); + // the diagonals + ct.lineTo(c11); + ct.moveTo(c10); + ct.lineTo(c01); + } + + ct.setLineWidth(0.5); + ct.setSource(rgba); + ct.stroke(); + } +} + +/** Calculates the closest distance from p to the segment a1-a2*/ +static double +distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2) +{ + // calculate sides of the triangle and their squares + double d1 = Geom::L2(p - a1); + double d1_2 = d1 * d1; + double d2 = Geom::L2(p - a2); + double d2_2 = d2 * d2; + double a = Geom::L2(a1 - a2); + double a_2 = a * a; + + // if one of the angles at the base is > 90, return the corresponding side + if (d1_2 + a_2 <= d2_2) return d1; + if (d2_2 + a_2 <= d1_2) return d2; + + // otherwise calculate the height to the base + double peri = (a + d1 + d2)/2; + return (2*sqrt(peri * (peri - a) * (peri - d1) * (peri - d2))/a); +} + +DrawingItem * +DrawingImage::_pickItem(Geom::Point const &p, double delta) +{ + if (!_pixbuf) return NULL; + + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + if (outline) { + Geom::Rect r = bounds(); + + Geom::Point c00 = r.corner(0); + Geom::Point c01 = r.corner(3); + Geom::Point c11 = r.corner(2); + Geom::Point c10 = r.corner(1); + + // frame + if (distance_to_segment (p, c00, c10) < delta) return this; + if (distance_to_segment (p, c10, c11) < delta) return this; + if (distance_to_segment (p, c11, c01) < delta) return this; + if (distance_to_segment (p, c01, c00) < delta) return this; + + // diagonals + if (distance_to_segment (p, c00, c11) < delta) return this; + if (distance_to_segment (p, c10, c01) < delta) return this; + + return NULL; + + } else { + unsigned char *const pixels = gdk_pixbuf_get_pixels(_pixbuf); + int width = gdk_pixbuf_get_width(_pixbuf); + int height = gdk_pixbuf_get_height(_pixbuf); + int rowstride = gdk_pixbuf_get_rowstride(_pixbuf); + + Geom::Point tp = p * _ctm.inverse(); + Geom::Rect r = bounds(); + + if (!r.contains(tp)) + return NULL; + + double vw = width * _scale[Geom::X]; + double vh = height * _scale[Geom::Y]; + int ix = floor((tp[Geom::X] - _origin[Geom::X]) / vw * width); + int iy = floor((tp[Geom::Y] - _origin[Geom::Y]) / vh * height); + + if ((ix < 0) || (iy < 0) || (ix >= width) || (iy >= height)) + return NULL; + + unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4; + // pick if the image is less than 99% transparent + float alpha = (pix_ptr[3] / 255.0f) * _opacity; + return alpha > 0.01 ? this : NULL; + } +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h new file mode 100644 index 000000000..570c10360 --- /dev/null +++ b/src/display/drawing-image.h @@ -0,0 +1,66 @@ +/** + * @file + * @brief Bitmap image belonging to an SVG drawing + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_IMAGE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_IMAGE_H + +#include +#include +#include <2geom/transforms.h> + +#include "display/drawing-item.h" + +namespace Inkscape { + +class DrawingImage + : public DrawingItem +{ +public: + DrawingImage(Drawing *drawing); + ~DrawingImage(); + + void setARGB32Pixbuf(GdkPixbuf *pb); + void setStyle(SPStyle *style); + void setScale(double sx, double sy); + void setOrigin(Geom::Point const &o); + void setClipbox(Geom::Rect const &box); + Geom::Rect bounds() const; + +protected: + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + + GdkPixbuf *_pixbuf; + cairo_surface_t *_surface; + SPStyle *_style; + + // TODO: the following three should probably be merged into a new Geom::Viewbox object + Geom::Rect _clipbox; ///< for preserveAspectRatio + Geom::Point _origin; + Geom::Scale _scale; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp new file mode 100644 index 000000000..318ff28e7 --- /dev/null +++ b/src/display/drawing-item.cpp @@ -0,0 +1,620 @@ +/** + * @file + * @brief Canvas item belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/cairo-templates.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing-group.h" +#include "display/drawing-surface.h" +#include "nr-arena.h" +#include "nr-filter.h" +#include "preferences.h" +#include "style.h" + +namespace Inkscape { + +DrawingItem::DrawingItem(Drawing *drawing) + : _drawing(drawing) + , _parent(NULL) + , _key(0) + , _opacity(1.0) + , _transform(NULL) + , _clip(NULL) + , _mask(NULL) + , _filter(NULL) + , _user_data(NULL) + , _cache(NULL) + , _state(0) + , _visible(true) + , _sensitive(true) + , _cached(0) + , _propagate(0) +// , _renders_opacity(0) + , _clip_child(0) + , _mask_child(0) + , _pick_children(0) +{ + nr_object_ref(_drawing); +} + +DrawingItem::~DrawingItem() +{ + _drawing->item_deleted.emit(this); + //if (!_children.empty()) { + // g_warning("Removing item with children"); + //} + + // remove from the set of cached items + if (_cached) { + _drawing->cached_items.erase(this); + } + // remove this item from parent's children list + // due to the effect of clearChildren(), this only happens for the top-level deleted item + if (_parent) { + _markForRendering(); + // we cannot call setClip(NULL) or setMask(NULL), + // because that would be an endless loop + if (_clip_child) { + _parent->_clip = NULL; + } else if (_mask_child) { + _parent->_mask = NULL; + } else { + ChildrenList::iterator ithis = _parent->_children.iterator_to(*this); + _parent->_children.erase(ithis); + } + _parent->_markForUpdate(STATE_ALL, false); + } + clearChildren(); + delete _transform; + delete _clip; + delete _mask; + delete _filter; + nr_object_unref(_drawing); +} + +DrawingItem * +DrawingItem::parent() const +{ + //if (_clip_child || _mask_child) + // return NULL; + + return _parent; +} + +void +DrawingItem::appendChild(DrawingItem *item) +{ + item->_parent = this; + _children.push_back(*item); + _markForUpdate(STATE_ALL, false); +} + +void +DrawingItem::prependChild(DrawingItem *item) +{ + item->_parent = this; + _children.push_front(*item); + _markForUpdate(STATE_ALL, false); +} + +void +DrawingItem::clearChildren() +{ + // prevent children from referencing the parent during deletion + // this way, children won't try to remove themselves from a list + // from which they have already been removed by clear_and_dispose + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->_parent = NULL; + } + _children.clear_and_dispose(DeleteDisposer()); +} + +void +DrawingItem::setTransform(Geom::Affine const &new_trans) +{ + Geom::Affine current; + if (_transform) { + current = *_transform; + } + + if (!Geom::are_near(current, new_trans, NR_EPSILON)) { + // mark the area where the object was for redraw. + _markForRendering(); + if (new_trans.isIdentity()) { + delete _transform; // delete NULL; is safe + _transform = NULL; + } else { + _transform = new Geom::Affine(new_trans); + } + _markForUpdate(STATE_ALL, true); + } +} + +void +DrawingItem::setOpacity(float opacity) +{ + _opacity = opacity; + _markForRendering(); +} + +void +DrawingItem::setVisible(bool v) +{ + _visible = v; + _markForRendering(); +} + +void +DrawingItem::setSensitive(bool s) +{ + _sensitive = s; +} + +void +DrawingItem::setCached(bool c) +{ + _cached = c; + if (c) { + _drawing->cached_items.insert(this); + } else { + _drawing->cached_items.erase(this); + } + _markForUpdate(STATE_CACHE, false); +} + +void +DrawingItem::setClip(DrawingItem *item) +{ + _markForRendering(); + delete _clip; + _clip = item; + if (item) { + item->_parent = this; + item->_clip_child = true; + } + _markForUpdate(STATE_ALL, true); +} + +void +DrawingItem::setMask(DrawingItem *item) +{ + _markForRendering(); + delete _mask; + _mask = item; + if (item) { + item->_parent = this; + item->_mask_child = true; + } + _markForUpdate(STATE_ALL, true); +} + +void +DrawingItem::setZOrder(unsigned z) +{ + if (!_parent) return; + + ChildrenList::iterator it = _parent->_children.iterator_to(*this); + _parent->_children.erase(it); + + ChildrenList::iterator i = _parent->_children.begin(); + std::advance(i, std::min(z, unsigned(_parent->_children.size()))); + _parent->_children.insert(i, *this); + _markForRendering(); +} + +void +DrawingItem::setItemBounds(Geom::OptRect const &bounds) +{ + _item_bbox = bounds; +} + +void +DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + bool render_filters = (_drawing->rendermode == Inkscape::RENDERMODE_NORMAL); + bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + + // Set reset flags according to propagation status + if (_propagate) { + reset |= ~_state; + _propagate = FALSE; + } + _state &= ~reset; // reset state of this item + + if ((~_state & flags) == 0) return; // nothing to do + + // TODO this might be wrong + if (_state & STATE_BBOX) { + // we have up-to-date bbox + if (!area.intersects(outline ? _bbox : _drawbox)) return; + } + + UpdateContext child_ctx(ctx); + if (_transform) { + child_ctx.ctm = *_transform * ctx.ctm; + } + /* Remember the transformation matrix */ + Geom::Affine ctm_change = _ctm.inverse() * child_ctx.ctm; + _ctm = child_ctx.ctm; + + // update _bbox + _state = _updateItem(area, child_ctx, flags, reset); + + // compute drawbox + if (_filter && render_filters && _item_bbox) { + _drawbox = _filter->compute_drawbox(this, *_item_bbox); + } else { + _drawbox = _bbox; + } + + // Clipping + if (_clip) { + _clip->update(area, child_ctx, flags, reset); + if (outline) { + _bbox.unionWith(_clip->_bbox); + } else { + _drawbox.intersectWith(_clip->_bbox); + } + } + // masking + if (_mask) { + _mask->update(area, child_ctx, flags, reset); + if (outline) { + _bbox.unionWith(_mask->_bbox); + } else { + // for masking, we need full drawbox of mask + _drawbox.intersectWith(_mask->_drawbox); + } + } + + // update cache if enabled + if (_cached) { + Geom::OptIntRect cl = _drawing->cache_limit; + cl.intersectWith(_drawbox); + if (cl) { + if (_cache) { + // this takes care of invalidation on transform + _cache->resizeAndTransform(*cl, ctm_change); + } else { + _cache = new Inkscape::DrawingCache(*cl); + // the cache is initially dirty + } + } else { + // disable cache for this item - not visible + delete _cache; + _cache = NULL; + } + } + + // now that we know drawbox, dirty the corresponding rect on canvas + // unless filtered, groups do not need to render by themselves, only their members + if (!is_drawing_group(this) || (_filter && render_filters)) { + if (flags & ~STATE_CACHE) { + _markForRendering(); + } + } +} + +struct MaskLuminanceToAlpha { + guint32 operator()(guint32 in) { + EXTRACT_ARGB32(in, a, r, g, b) + // the operation of unpremul -> luminance-to-alpha -> multiply by alpha + // is equivalent to luminance-to-alpha on premultiplied color values + // original computation in double: r*0.2125 + g*0.7154 + b*0.0721 + guint32 ao = r*109 + g*366 + b*37; // coeffs add up to 512 + return ((ao + 256) << 15) & 0xff000000; // equivalent to ((ao + 256) / 512) << 24 + } +}; + +void +DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + bool render_filters = (_drawing->rendermode == Inkscape::RENDERMODE_NORMAL); + + /* If we are invisible, just return successfully */ + if (!_visible) return; + + if (outline) { + _renderOutline(ct, area, flags); + return; + } + + // carea is the bounding box for intermediate rendering. + Geom::OptIntRect carea = Geom::intersect(area, _drawbox); + if (!carea) return; + + // render from cache + if (_cached && _cache) { + if (_cache->paintFromCache(ct, *carea)) + return; + } + + // expand carea to contain the dependent area of filters. + if (_filter && render_filters) { + _filter->area_enlarge(*carea, this); + carea.intersectWith(_drawbox); + } + + // determine whether this shape needs intermediate rendering. + bool needs_intermediate_rendering = false; + bool &nir = needs_intermediate_rendering; + bool needs_opacity = (_opacity < 0.995); + + // this item needs an intermediate rendering if: + nir |= (_clip != NULL); // 1. it has a clipping path + nir |= (_mask != NULL); // 2. it has a mask + nir |= (_filter != NULL && render_filters); // 3. it has a filter + nir |= needs_opacity; // 4. it is non-opaque + + /* How the rendering is done. + * + * Clipping, masking and opacity are done by rendering them to a surface + * and then compositing the object's rendering onto it with the IN operator. + * The object itself is rendered to a group. + * + * Opacity is done by rendering the clipping path with an alpha + * value corresponding to the opacity. If there is no clipping path, + * the entire intermediate surface is painted with alpha corresponding + * to the opacity value. + */ + + // short-circuit the simple case. + if (!needs_intermediate_rendering) { + if (_cached && _cache) { + Inkscape::DrawingContext cachect(*_cache); + cachect.rectangle(area); + cachect.clip(); + + { // 1. clear the corresponding part of cache + Inkscape::DrawingContext::Save save(cachect); + cachect.setSource(0,0,0,0); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.paint(); + } + // 2. render to cache + _renderItem(cachect, *carea, flags); + // 3. copy from cache to output + Inkscape::DrawingContext::Save save(ct); + ct.rectangle(*carea); + ct.clip(); + ct.setSource(_cache); + ct.paint(); + // 4. mark as clean + _cache->markClean(area); + return; + } else { + _renderItem(ct, *carea, flags); + return; + } + } + + DrawingSurface intermediate(*carea); + DrawingContext ict(intermediate); + + // 1. Render clipping path with alpha = opacity. + ict.setSource(0,0,0,_opacity); + // Since clip can be combined with opacity, the result could be incorrect + // for overlapping clip children. To fix this we use the SOURCE operator + // instead of the default OVER. + ict.setOperator(CAIRO_OPERATOR_SOURCE); + if (_clip) { + _clip->clip(ict, *carea); // fixme: carea or area? + } else { + // if there is no clipping path, fill the entire surface with alpha = opacity. + ict.paint(); + } + ict.setOperator(CAIRO_OPERATOR_OVER); // reset back to default + + // 2. Render the mask if present and compose it with the clipping path + opacity. + if (_mask) { + ict.pushGroup(); + _mask->render(ict, *carea, flags); + + cairo_surface_t *mask_s = ict.rawTarget(); + // Convert mask's luminance to alpha + ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha()); + ict.popGroupToSource(); + ict.setOperator(CAIRO_OPERATOR_IN); + ict.paint(); + ict.setOperator(CAIRO_OPERATOR_OVER); + } + + // 3. Render object itself. + ict.pushGroup(); + _renderItem(ict, *carea, flags); + + // 4. Apply filter. + if (_filter && render_filters) { + _filter->render(this, ct, ict); + // Note that because the object was rendered to a group, + // the internals of the filter need to use cairo_get_group_target() + // instead of cairo_get_target(). + } + + // 5. Render object inside the composited mask + clip + ict.popGroupToSource(); + ict.setOperator(CAIRO_OPERATOR_IN); + ict.paint(); + + // 6. Paint the completed rendering onto the base context (or into cache) + if (_cached && _cache) { + DrawingContext cachect(*_cache); + cachect.rectangle(area); + cachect.clip(); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.setSource(&intermediate); + cachect.paint(); + _cache->markClean(area); + } + ct.setSource(&intermediate); + ct.paint(); + ct.setSource(0,0,0,0); + // the call above is to clear a ref on the intermediate surface held by ct +} + +void +DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + // intersect with bbox rather than drawbox, as we want to render things outside + // of the clipping path as well + Geom::OptIntRect carea = Geom::intersect(area, _bbox); + if (!carea) return; + + // just render everything: item, clip, mask + // First, render the object itself + _renderItem(ct, *carea, flags); + + // render clip and mask, if any + guint32 saved_rgba = _drawing->outlinecolor; // save current outline color + // render clippath as an object, using a different color + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (_clip) { + _drawing->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips + _clip->render(ct, *carea, flags); + } + // render mask as an object, using a different color + if (_mask) { + _drawing->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks + _mask->render(ct, *carea, flags); + } + _drawing->outlinecolor = saved_rgba; // restore outline color +} + +void +DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area) +{ + // don't bother if the object does not implement clipping (e.g. DrawingImage) + if (!_canClip()) return; + if (!_visible) return; + if (!area.intersects(_bbox)) return; + + // The item used as the clipping path itself has a clipping path. + // Render this item's clipping path onto a temporary surface, then composite it + // with the item using the IN operator + if (_clip) { + ct.pushAlphaGroup(); + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(0,0,0,1); + _clip->clip(ct, area); + } + ct.pushAlphaGroup(); + } + + // rasterize the clipping path + _clipItem(ct, area); + + if (_clip) { + ct.popGroupToSource(); + ct.setOperator(CAIRO_OPERATOR_IN); + ct.paint(); + ct.popGroupToSource(); + ct.setOperator(CAIRO_OPERATOR_SOURCE); + ct.paint(); + } +} + +DrawingItem * +DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) +{ + // Sometimes there's no BBOX in state, reason unknown (bug 992817) + // I made this not an assert to remove the warning + if (!(_state & STATE_BBOX) || !(_state & STATE_PICK)) + return NULL; + + if (!sticky && !(_visible && _sensitive)) + return NULL; + + if (!_bbox) return NULL; + Geom::Rect expanded(*_bbox); + expanded.expandBy(delta); + + if (expanded.contains(p)) { + return _pickItem(p, delta); + } + return NULL; +} + +void +DrawingItem::_markForRendering() +{ + bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + Geom::OptIntRect dirty = outline ? _bbox : _drawbox; + if (!dirty) return; + + // dirty the caches of all parents + for (DrawingItem *i = this; i; i = i->_parent) { + if (i->_cached && i->_cache) { + i->_cache->markDirty(*dirty); + } + } + + nr_arena_request_render_rect (_drawing, dirty); +} + +void +DrawingItem::_markForUpdate(unsigned flags, bool propagate) +{ + // here we can't simply assign because a previous markForUpdate call + // could have had propagate=true even if this one has propagate=false + if (propagate) + _propagate = true; + + if (_state & flags) { + _state &= ~flags; + if (_parent) { + _parent->_markForUpdate(flags, false); + } else { + nr_arena_request_update (_drawing, this); + } + } +} + +void +DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style) +{ + if (style) sp_style_ref(style); + if (_style) sp_style_unref(_style); + _style = style; + + // if group has a filter + if (style->filter.set && style->getFilter()) { + if (!_filter) { + int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter())); + _filter = new Inkscape::Filters::Filter(primitives); + } + sp_filter_build_renderer(SP_FILTER(style->getFilter()), _filter); + } else { + // no filter set for this group + delete _filter; + _filter = NULL; + } + + /* + if (style && style->enable_background.set + && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { + _background_new = true; + }*/ +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h new file mode 100644 index 000000000..b34ddf0e4 --- /dev/null +++ b/src/display/drawing-item.h @@ -0,0 +1,168 @@ +/** + * @file + * @brief Canvas item belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +#include +#include +#include <2geom/rect.h> +#include <2geom/affine.h> + +class NRArena; +class SPStyle; +void nr_arena_set_cache_limit(NRArena *, Geom::OptIntRect const &); + +namespace Inkscape { + +typedef ::NRArena Drawing; +class DrawingContext; +class DrawingCache; +class DrawingItem; +namespace Filters { class Filter; } + +struct UpdateContext { + Geom::Affine ctm; +}; + +class InvalidItemException : public std::exception { + virtual const char *what() const throw() { + return "Invalid item in drawing"; + } +}; + +typedef boost::intrusive::list_base_hook<> ChildrenListHook; + +class DrawingItem + : public ChildrenListHook +{ +public: + enum RenderFlags { + RENDER_DEFAULT = 0, + RENDER_CACHE_ONLY = 1, + RENDER_BYPASS_CACHE = 2 + }; + enum StateFlags { + STATE_NONE = 0, + STATE_BBOX = (1<<0), // geometric bounding box is up-to-date + STATE_DRAWBOX = (1<<1), // visual bounding box is up-to-date + STATE_CACHE = (1<<2), // cache extents and clean area are up-to-date + STATE_PICK = (1<<3), // can process pick requests + STATE_RENDER = (1<<4), // can be rendered + STATE_ALL = (1<<5)-1 + }; + typedef boost::intrusive::list ChildrenList; + + DrawingItem(Drawing *drawing); + virtual ~DrawingItem(); + + Geom::OptIntRect geometricBounds() const { return _bbox; } + Geom::OptIntRect visualBounds() const { return _drawbox; } + Geom::OptRect itemBounds() const { return _item_bbox; } + Geom::Affine ctm() const { return _ctm; } + Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } + Drawing *drawing() const { return _drawing; } + DrawingItem *parent() const; + + void appendChild(DrawingItem *item); + void prependChild(DrawingItem *item); + void clearChildren(); + + bool visible() const { return _visible; } + void setVisible(bool v); + bool sensitive() const { return _sensitive; } + void setSensitive(bool v); + bool cached() const { return _cached; } + void setCached(bool c); + + void setOpacity(float opacity); + void setTransform(Geom::Affine const &trans); + void setClip(DrawingItem *item); + void setMask(DrawingItem *item); + void setZOrder(unsigned z); + void setItemBounds(Geom::OptRect const &bounds); + + void setKey(unsigned key) { _key = key; } + unsigned key() const { return _key; } + void setData(void *data) { _user_data = data; } + void *data() const { return _user_data; } + + void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = STATE_ALL, unsigned reset = 0); + void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); + void clip(DrawingContext &ct, Geom::IntRect const &area); + DrawingItem *pick(Geom::Point const &p, double delta, bool sticky); + +protected: + void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + void _markForUpdate(unsigned state, bool propagate); + void _markForRendering(); + void _setStyleCommon(SPStyle *&_style, SPStyle *style); + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset) { return 0; } + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta) { return NULL; } + virtual bool _canClip() { return false; } + + Drawing *_drawing; + DrawingItem *_parent; + ChildrenList _children; + + unsigned _key; ///< Some SPItems can have more than one NRArenaItem; + /// this value is a hack used to distinguish between them + float _opacity; + + Geom::Affine *_transform; ///< Incremental transform from parent to this item's coords + Geom::Affine _ctm; ///< Total transform from item coords to display coords + Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords + Geom::OptIntRect _drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks + Geom::OptRect _item_bbox; ///< Bounding box in item coordinates + + DrawingItem *_clip; + DrawingItem *_mask; + Inkscape::Filters::Filter *_filter; + void *_user_data; ///< Used to associate DrawingItems with SPItems that created them + DrawingCache *_cache; + + unsigned _state : 8; + unsigned _visible : 1; + unsigned _sensitive : 1; ///< Whether this item responds to events + unsigned _cached : 1; ///< Whether the rendering is stored for reuse + unsigned _propagate : 1; ///< Whether to call update for all children on next update + //unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity + unsigned _clip_child : 1; ///< If set, this is not a child of _parent, but a clipping path + unsigned _mask_child : 1; ///< If set, this is not a child of _parent, but a mask + unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(), + /// otherwise the group is returned + + // temporary hacks until I rewrite NRArena to Inkscape::Drawing + friend class NRArena; + friend void ::nr_arena_set_cache_limit(NRArena *, Geom::OptIntRect const &); +}; + +struct DeleteDisposer { + void operator()(DrawingItem *item) { delete item; } +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp new file mode 100644 index 000000000..1a56eea9b --- /dev/null +++ b/src/display/drawing-shape.cpp @@ -0,0 +1,340 @@ +/** + * @file + * @brief Shape (styled path) belonging to an SVG drawing + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include <2geom/curves.h> +#include <2geom/pathvector.h> +#include <2geom/svg-path.h> +#include <2geom/svg-path-parser.h> + +#include "display/cairo-utils.h" +#include "display/canvas-arena.h" +#include "display/canvas-bpath.h" +#include "display/curve.h" +#include "display/drawing-context.h" +#include "display/drawing-group.h" +#include "display/drawing-shape.h" +#include "display/nr-arena.h" +#include "helper/geom-curves.h" +#include "helper/geom.h" +#include "libnr/nr-convert2geom.h" +#include "preferences.h" +#include "style.h" +#include "svg/svg.h" + +namespace Inkscape { + +DrawingShape::DrawingShape(Drawing *drawing) + : DrawingItem(drawing) + , _curve(NULL) + , _style(NULL) + , _last_pick(NULL) + , _repick_after(0) +{} + +DrawingShape::~DrawingShape() +{ + if (_style) + sp_style_unref(_style); + if (_curve) + _curve->unref(); +} + +void +DrawingShape::setPath(SPCurve *curve) +{ + _markForRendering(); + + if (_curve) { + _curve->unref(); + _curve = NULL; + } + if (curve) { + _curve = curve; + curve->ref(); + } + + _markForUpdate(STATE_ALL, false); +} + +void +DrawingShape::setStyle(SPStyle *style) +{ + _setStyleCommon(_style, style); + _nrstyle.set(style); +} + +void +DrawingShape::setPaintBox(Geom::Rect const &box) +{ + _paintbox = box; + _markForUpdate(STATE_ALL, false); +} + +unsigned +DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + Geom::OptRect boundingbox; + + unsigned beststate = STATE_ALL; + + // update markers + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->update(area, ctx, flags, reset); + } + + if (!(flags & STATE_RENDER)) { + /* We do not have to create rendering structures */ + if (flags & STATE_BBOX) { + if (_curve) { + boundingbox = bounds_exact_transformed(_curve->get_pathvector(), ctx.ctm); + if (boundingbox) { + _bbox = boundingbox->roundOutwards(); + } else { + _bbox = Geom::OptIntRect(); + } + } + if (beststate & STATE_BBOX) { + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + _bbox.unionWith(i->geometricBounds()); + } + } + } + return (flags | _state); + } + + boundingbox = Geom::OptRect(); + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + // clear Cairo data to force update + _nrstyle.update(); + + if (_curve) { + boundingbox = bounds_exact_transformed(_curve->get_pathvector(), ctx.ctm); + + if (boundingbox && (_nrstyle.stroke.type != NRStyle::PAINT_NONE || outline)) { + float width, scale; + scale = ctx.ctm.descrim(); + width = std::max(0.125f, _nrstyle.stroke_width * scale); + if ( fabs(_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true + boundingbox->expandBy(width); + } + // those pesky miters, now + float miterMax = width * _nrstyle.miter_limit; + if ( miterMax > 0.01 ) { + // grunt mode. we should compute the various miters instead + // (one for each point on the curve) + boundingbox->expandBy(miterMax); + } + } + } + + _bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect(); + + if (!_curve || + !_style || + _curve->is_empty() || + (( _nrstyle.fill.type != NRStyle::PAINT_NONE ) && + ( _nrstyle.stroke.type != NRStyle::PAINT_NONE && !outline) )) + { + return STATE_ALL; + } + + if (beststate & STATE_BBOX) { + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + _bbox.unionWith(i->geometricBounds()); + } + } + + return STATE_ALL; +} + +void +DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (!_curve || !_style) return; + if (!area.intersects(_bbox)) return; // skip if not within bounding box + + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + if (outline) { + guint32 rgba = _drawing->outlinecolor; + + { Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + ct.path(_curve->get_pathvector()); + } + { Inkscape::DrawingContext::Save save(ct); + ct.setSource(rgba); + ct.setLineWidth(0.5); + ct.setTolerance(1.25); + ct.stroke(); + } + } else { + bool has_stroke, has_fill; + // we assume the context has no path + Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + + // update fill and stroke paints. + // this cannot be done during nr_arena_shape_update, because we need a Cairo context + // to render svg:pattern + has_fill = _nrstyle.prepareFill(ct, _paintbox); + has_stroke = _nrstyle.prepareStroke(ct, _paintbox); + has_stroke &= (_nrstyle.stroke_width != 0); + + if (has_fill || has_stroke) { + // TODO: remove segments outside of bbox when no dashes present + ct.path(_curve->get_pathvector()); + if (has_fill) { + _nrstyle.applyFill(ct); + ct.fillPreserve(); + } + if (has_stroke) { + _nrstyle.applyStroke(ct); + ct.strokePreserve(); + } + ct.newPath(); // clear path + } // has fill or stroke pattern + } + + // marker rendering + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->render(ct, area, flags); + } +} + +void +DrawingShape::_clipItem(DrawingContext &ct, Geom::IntRect const &area) +{ + if (!_curve) return; + + Inkscape::DrawingContext::Save save(ct); + // handle clip-rule + if (_style) { + if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); + } else { + ct.setFillRule(CAIRO_FILL_RULE_WINDING); + } + } + ct.transform(_ctm); + ct.path(_curve->get_pathvector()); + ct.fill(); +} + +DrawingItem * +DrawingShape::_pickItem(Geom::Point const &p, double delta) +{ + if (_repick_after > 0) + --_repick_after; + + if (_repick_after > 0) // we are a slow, huge path. skip this pick, returning what was returned last time + return _last_pick; + + if (!_curve) return NULL; + if (!_style) return NULL; + + bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + + if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline) + // fully transparent, no pick unless outline mode + return NULL; + + GTimeVal tstart, tfinish; + g_get_current_time (&tstart); + + double width; + if (outline) { + width = 0.5; + } else if (_nrstyle.stroke.type != NRStyle::PAINT_NONE && _nrstyle.stroke.opacity > 1e-3) { + float const scale = _ctm.descrim(); + width = std::max(0.125f, _nrstyle.stroke_width * scale) / 2; + } else { + width = 0; + } + + double dist = Geom::infinity(); + int wind = 0; + bool needfill = (_nrstyle.fill.type != NRStyle::PAINT_NONE + && _nrstyle.fill.opacity > 1e-3 && !outline); + + if (_drawing->canvasarena) { + Geom::Rect viewbox = _drawing->canvasarena->item.canvas->getViewbox(); + viewbox.expandBy (width); + pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox); + } else { + pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL); + } + + g_get_current_time (&tfinish); + glong this_pick = (tfinish.tv_sec - tstart.tv_sec) * 1000000 + (tfinish.tv_usec - tstart.tv_usec); + //g_print ("pick time %lu\n", this_pick); + + if (this_pick > 10000) { // slow picking, remember to skip several new picks + _repick_after = this_pick / 5000; + } + + // covered by fill? + if (needfill) { + if (!_style->fill_rule.computed) { + if (wind != 0) { + _last_pick = this; + return this; + } + } else { + if (wind & 0x1) { + _last_pick = this; + return this; + } + } + } + + // close to the edge, as defined by strokewidth and delta? + // this ignores dashing (as if the stroke is solid) and always works as if caps are round + if (needfill || width > 0) { // if either fill or stroke visible, + if ((dist - width) < delta) { + _last_pick = this; + return this; + } + } + + // if not picked on the shape itself, try its markers + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingItem *ret = i->pick(p, delta, false); + if (ret) { + _last_pick = this; + return this; + } + } + + _last_pick = NULL; + return NULL; +} + +bool +DrawingShape::_canClip() +{ + return true; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h new file mode 100644 index 000000000..7fd16374e --- /dev/null +++ b/src/display/drawing-shape.h @@ -0,0 +1,64 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SHAPE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_SHAPE_H + +#include "display/drawing-item.h" +#include "display/nr-style.h" + +class SPStyle; +class SPCurve; + +namespace Inkscape { + +class DrawingShape + : public DrawingItem +{ +public: + DrawingShape(Drawing *drawing); + ~DrawingShape(); + + void setPath(SPCurve *curve); + void setStyle(SPStyle *style); + void setPaintBox(Geom::Rect const &box); + +protected: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual bool _canClip(); + + SPCurve *_curve; + SPStyle *_style; + NRStyle _nrstyle; + + Geom::OptRect _paintbox; + DrawingItem *_last_pick; + unsigned _repick_after; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp new file mode 100644 index 000000000..784888bd7 --- /dev/null +++ b/src/display/drawing-text.cpp @@ -0,0 +1,275 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/canvas-bpath.h" // for SPWindRule (WTF!) +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/drawing-text.h" +#include "display/nr-arena.h" +#include "helper/geom.h" +#include "libnrtype/font-instance.h" +#include "style.h" + +namespace Inkscape { + +DrawingGlyphs::DrawingGlyphs(Drawing *drawing) + : DrawingItem(drawing) + , _glyph_transform(NULL) + , _font(NULL) + , _glyph(0) +{} + +DrawingGlyphs::~DrawingGlyphs() +{ + if (_font) { + _font->Unref(); + _font = NULL; + } + delete _glyph_transform; +} + +void +DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &trans) +{ + _markForRendering(); + + if (trans.isIdentity()) { + delete _glyph_transform; // delete NULL; is safe + _glyph_transform = NULL; + } else { + _glyph_transform = new Geom::Affine(trans); + } + + if (font) font->Ref(); + if (_font) _font->Unref(); + _font = font; + _glyph = glyph; + + _markForUpdate(STATE_ALL, false); +} + +unsigned +DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + DrawingText *ggroup = dynamic_cast(_parent); + if (!ggroup) throw InvalidItemException(); + + if (!_font || !ggroup->_style) return STATE_ALL; + if (ggroup->_nrstyle.fill.type == NRStyle::PAINT_NONE && + ggroup->_nrstyle.stroke.type == NRStyle::PAINT_NONE) + { + return STATE_ALL; + } + + Geom::OptRect b; + Geom::Affine t = _glyph_transform ? *_glyph_transform * ctx.ctm : ctx.ctm; + _x = t[4]; + _y = t[5]; + + b = bounds_exact_transformed(*_font->PathVector(_glyph), t); + if (b && ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) { + float width, scale; + scale = ctx.ctm.descrim(); + width = MAX(0.125, ggroup->_nrstyle.stroke_width * scale); + if ( fabs(ggroup->_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true + b->expandBy(width); + } + // those pesky miters, now + float miterMax = width * ggroup->_nrstyle.miter_limit; + if ( miterMax > 0.01 ) { + // grunt mode. we should compute the various miters instead + // (one for each point on the curve) + b->expandBy(miterMax); + } + } + + if (b) { + _bbox = b->roundOutwards(); + } else { + _bbox = Geom::OptIntRect(); + } + + return STATE_ALL; +} + +DrawingItem * +DrawingGlyphs::_pickItem(Geom::Point const &p, double delta) +{ + if (!_font || !_bbox) return NULL; + + // With text we take a simple approach: pick if the point is in a characher bbox + Geom::Rect expanded(*_bbox); + expanded.expandBy(delta); + if (expanded.contains(p)) return this; + return NULL; +} + + + +DrawingText::DrawingText(Drawing *drawing) + : DrawingGroup(drawing) +{} + +DrawingText::~DrawingText() +{} + +void +DrawingText::clear() +{ + _markForRendering(); + _children.clear_and_dispose(DeleteDisposer()); +} + +void +DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &trans) +{ + if (!font || !font->PathVector(glyph)) return; + + _markForRendering(); + DrawingGlyphs *ng = new DrawingGlyphs(_drawing); + ng->setGlyph(font, glyph, trans); + appendChild(ng); +} + +void +DrawingText::setStyle(SPStyle *style) +{ + _nrstyle.set(style); + DrawingGroup::setStyle(style); +} + +void +DrawingText::setPaintBox(Geom::OptRect const &box) +{ + _paintbox = box; + _markForUpdate(STATE_ALL, false); +} + +unsigned +DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + _nrstyle.update(); + return DrawingGroup::_updateItem(area, ctx, flags, reset); +} + +void +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (_drawing->rendermode == RENDERMODE_OUTLINE) { + DrawingContext::Save save(ct); + guint32 rgba = _drawing->outlinecolor; + ct.setSource(rgba); + ct.setTolerance(1.25); // low quality, but good enough for outline mode + ct.newPath(); + ct.transform(_ctm); + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + ct.fill(); + } + return; + } + + // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding + bool has_stroke, has_fill; + + Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + + has_fill = _nrstyle.prepareFill(ct, _paintbox); + has_stroke = _nrstyle.prepareStroke(ct, _paintbox); + + if (has_fill || has_stroke) { + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + } + + if (has_fill) { + _nrstyle.applyFill(ct); + ct.fillPreserve(); + } + if (has_stroke) { + _nrstyle.applyStroke(ct); + ct.strokePreserve(); + } + ct.newPath(); // clear path + } +} + +void +DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) +{ + Inkscape::DrawingContext::Save save(ct); + + // handle clip-rule + if (_style) { + if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); + } else { + ct.setFillRule(CAIRO_FILL_RULE_WINDING); + } + } + ct.transform(_ctm); + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + } + ct.fill(); +} + +DrawingItem * +DrawingText::_pickItem(Geom::Point const &p, double delta) +{ + DrawingItem *picked = DrawingGroup::_pickItem(p, delta); + if (picked) return this; + return NULL; +} + +bool +DrawingText::_canClip() +{ + return true; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h new file mode 100644 index 000000000..58fecc067 --- /dev/null +++ b/src/display/drawing-text.h @@ -0,0 +1,84 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_TEXT_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_TEXT_H + +#include "display/drawing-group.h" +#include "display/nr-style.h" + +class SPStyle; +class font_instance; + +namespace Inkscape { + +class DrawingGlyphs + : public DrawingItem +{ +public: + DrawingGlyphs(Drawing *drawing); + ~DrawingGlyphs(); + + void setGlyph(font_instance *font, int glyph, Geom::Affine const &trans); + +protected: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + + Geom::Affine *_glyph_transform; + font_instance *_font; + int _glyph; + float _x, _y; + + friend class DrawingText; +}; + +class DrawingText + : public DrawingGroup +{ +public: + DrawingText(Drawing *drawing); + ~DrawingText(); + + void clear(); + void addComponent(font_instance *font, int glyph, Geom::Affine const &trans); + void setStyle(SPStyle *style); + void setPaintBox(Geom::OptRect const &box); + +protected: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual bool _canClip(); + + Geom::OptRect _paintbox; + NRStyle _nrstyle; + + friend class DrawingGlyphs; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/grayscale.cpp b/src/display/grayscale.cpp index 745a08c1e..e468044d3 100644 --- a/src/display/grayscale.cpp +++ b/src/display/grayscale.cpp @@ -82,7 +82,7 @@ guchar luminance(guchar r, guchar g, guchar b) { */ bool activeDesktopIsGrayscale() { if (SP_ACTIVE_DESKTOP) { - return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORRENDERMODE_GRAYSCALE); + return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORMODE_GRAYSCALE); } else { return false; } diff --git a/src/display/nr-arena-forward.h b/src/display/nr-arena-forward.h deleted file mode 100644 index 5a5cf228a..000000000 --- a/src/display/nr-arena-forward.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __NR_ARENA_FORWARD_H__ -#define __NR_ARENA_FORWARD_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -struct NRArena; -struct NRArenaClass; - -struct NRArenaItem; -struct NRArenaItemClass; - -struct NRArenaGroup; -struct NRArenaGroupClass; - -struct NRArenaShape; -struct NRArenaShapeClass; - -struct NRArenaShapeGroup; -struct NRArenaShapeGroupClass; - -struct NRArenaImage; -struct NRArenaImageClass; - -struct NRArenaGlyphs; -struct NRArenaGlyphsClass; - -struct NRArenaGlyphsGroup; -struct NRArenaGlyphsGroupClass; - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp deleted file mode 100644 index 99b0a004e..000000000 --- a/src/display/nr-arena-glyphs.cpp +++ /dev/null @@ -1,439 +0,0 @@ -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2002 Lauris Kaplinski - * - * Released under GNU GPL - * - */ - - -#ifdef HAVE_CONFIG_H -# include -#endif -#include -#include <2geom/affine.h> -#include <2geom/rect.h> -#include "libnr/nr-convert2geom.h" -#include "style.h" -#include "display/nr-arena.h" -#include "display/nr-arena-glyphs.h" -#include "display/cairo-utils.h" -#include "display/drawing-context.h" -#include "helper/geom.h" - -#ifdef test_glyph_liv -#include "../display/canvas-bpath.h" -#include "libnrtype/font-instance.h" - -// defined in nr-arena-shape.cpp -void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS); -#endif - -#ifdef ENABLE_SVG_FONTS -#include "nr-svgfonts.h" -#endif //#ifdef ENABLE_SVG_FONTS - -static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass); -static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs); -static void nr_arena_glyphs_finalize(NRObject *object); - -static guint nr_arena_glyphs_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); -static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); - -static NRArenaItemClass *glyphs_parent_class; - -NRType -nr_arena_glyphs_get_type(void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type(NR_TYPE_ARENA_ITEM, - "NRArenaGlyphs", - sizeof(NRArenaGlyphsClass), - sizeof(NRArenaGlyphs), - (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init, - (void (*)(NRObject *)) nr_arena_glyphs_init); - } - return type; -} - -static void -nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_glyphs_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor; - - item_class->update = nr_arena_glyphs_update; - item_class->pick = nr_arena_glyphs_pick; -} - -static void -nr_arena_glyphs_init(NRArenaGlyphs *glyphs) -{ - glyphs->g_transform.setIdentity(); - glyphs->font = NULL; - glyphs->glyph = 0; - glyphs->x = glyphs->y = 0.0; -} - -static void -nr_arena_glyphs_finalize(NRObject *object) -{ - NRArenaGlyphs *glyphs = static_cast(object); - - if (glyphs->font) { - glyphs->font->Unref(); - glyphs->font=NULL; - } - - ((NRObjectClass *) glyphs_parent_class)->finalize(object); -} - -static guint -nr_arena_glyphs_update(NRArenaItem *item, Geom::IntRect const &/*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) -{ - NRArenaGlyphs *glyphs = NR_ARENA_GLYPHS(item); - NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item->parent); - - if (!glyphs->font || !ggroup->style) - return NR_ARENA_ITEM_STATE_ALL; - if (ggroup->nrstyle.fill.type == NRStyle::PAINT_NONE && ggroup->nrstyle.stroke.type == NRStyle::PAINT_NONE) - return NR_ARENA_ITEM_STATE_ALL; - - Geom::OptRect b; - Geom::Affine t = glyphs->g_transform * gc->transform; - glyphs->x = t[4]; - glyphs->y = t[5]; - - b = bounds_exact_transformed(*glyphs->font->PathVector(glyphs->glyph), t); - if (b && ggroup->nrstyle.stroke.type != NRStyle::PAINT_NONE) { - float width, scale; - scale = gc->transform.descrim(); - width = MAX(0.125, ggroup->nrstyle.stroke_width * scale); - if ( fabs(ggroup->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true - b->expandBy(width); - } - // those pesky miters, now - float miterMax = width * ggroup->nrstyle.miter_limit; - if ( miterMax > 0.01 ) { - // grunt mode. we should compute the various miters instead - // (one for each point on the curve) - b->expandBy(miterMax); - } - } - - if (b) { - item->bbox = b->roundOutwards(); - } else { - item->bbox = Geom::OptIntRect(); - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -static NRArenaItem * -nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int /*sticky*/) -{ - NRArenaGlyphs *glyphs; - - glyphs = NR_ARENA_GLYPHS(item); - - if (!glyphs->font ) return NULL; - if (!item->bbox) return NULL; - - // With text we take a simple approach: pick if the point is in a characher bbox - Geom::Rect expanded(*item->bbox); - expanded.expandBy(delta); - if (expanded.contains(p)) - return item; - return NULL; -} - -void -nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, Geom::Affine const *transform) -{ - nr_return_if_fail(glyphs != NULL); - nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs)); - - nr_arena_item_request_render(NR_ARENA_ITEM(glyphs)); - - if (transform) { - glyphs->g_transform = *transform; - } else { - glyphs->g_transform.setIdentity(); - } - - if (font) font->Ref(); - if (glyphs->font) glyphs->font->Unref(); - glyphs->font=font; - glyphs->glyph = glyph; - - nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass); -static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group); -static void nr_arena_glyphs_group_finalize(NRObject *object); - -static guint nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky); - -static NRArenaGroupClass *group_parent_class; - -NRType -nr_arena_glyphs_group_get_type(void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type(NR_TYPE_ARENA_GROUP, - "NRArenaGlyphsGroup", - sizeof(NRArenaGlyphsGroupClass), - sizeof(NRArenaGlyphsGroup), - (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init, - (void (*)(NRObject *)) nr_arena_glyphs_group_init); - } - return type; -} - -static void -nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_glyphs_group_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor; - - item_class->update = nr_arena_glyphs_group_update; - item_class->render = nr_arena_glyphs_group_render; - item_class->clip = nr_arena_glyphs_group_clip; - item_class->pick = nr_arena_glyphs_group_pick; -} - -static void -nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group) -{ - group->style = NULL; -} - -static void -nr_arena_glyphs_group_finalize(NRObject *object) -{ - NRArenaGlyphsGroup *group = static_cast(object); - - if (group->style) { - sp_style_unref(group->style); - group->style = NULL; - } - - ((NRObjectClass *) group_parent_class)->finalize(object); -} - -static guint -nr_arena_glyphs_group_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset) -{ - NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item); - - group->nrstyle.update(); - - if (((NRArenaItemClass *) group_parent_class)->update) - return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset); - - return NR_ARENA_ITEM_STATE_ALL; -} - - -static unsigned int -nr_arena_glyphs_group_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int /*flags*/) -{ - NRArenaItem *child = 0; - - NRArenaGroup *group = NR_ARENA_GROUP(item); - NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - - if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - Inkscape::DrawingContext::Save save(ct); - guint32 rgba = item->arena->outlinecolor; - ct.setSource(rgba); - ct.setTolerance(1.25); // low quality, but good enough for outline mode - ct.newPath(); - ct.transform(ggroup->ctm); - - for (child = group->children; child != NULL; child = child->next) { - NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); - - Geom::PathVector const * pathv = g->font->PathVector(g->glyph); - Geom::Affine transform = g->g_transform; - - Inkscape::DrawingContext::Save save(ct); - ct.transform(transform); - ct.path(*pathv); - ct.fill(); - } - return item->state; - } - - // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding - bool has_stroke, has_fill; - - Inkscape::DrawingContext::Save save(ct); - ct.transform(ggroup->ctm); - - has_fill = ggroup->nrstyle.prepareFill(ct, ggroup->paintbox); - has_stroke = ggroup->nrstyle.prepareStroke(ct, ggroup->paintbox); - - if (has_fill || has_stroke) { - for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { - NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); - Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - - Inkscape::DrawingContext::Save save(ct); - ct.transform(g->g_transform); - ct.path(pathv); - } - - if (has_fill) { - ggroup->nrstyle.applyFill(ct); - ct.fillPreserve(); - } - if (has_stroke) { - ggroup->nrstyle.applyStroke(ct); - ct.strokePreserve(); - } - ct.newPath(); // clear path - } // has fill or stroke pattern - - return item->state; -} - -static unsigned int nr_arena_glyphs_group_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) -{ - NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - - Inkscape::DrawingContext::Save save(ct); - - // handle clip-rule - if (ggroup->style) { - if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); - } else { - ct.setFillRule(CAIRO_FILL_RULE_WINDING); - } - } - ct.transform(ggroup->ctm); - - for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { - NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); - Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - - Inkscape::DrawingContext::Save save(ct); - ct.transform(g->g_transform); - ct.path(pathv); - } - ct.fill(); - - return item->state; -} - -static NRArenaItem * -nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point const &p, gdouble delta, unsigned int sticky) -{ - NRArenaItem *picked = NULL; - - if (((NRArenaItemClass *) group_parent_class)->pick) - picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky); - - if (picked) picked = item; - - return picked; -} - -void -nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg) -{ - NRArenaGroup *group = NR_ARENA_GROUP(sg); - - nr_arena_item_request_render(NR_ARENA_ITEM(group)); - - while (group->children) { - nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children); - } -} - -void -nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, Geom::Affine const &transform) -{ - NRArenaGroup *group; - - group = NR_ARENA_GROUP(sg); - - Geom::PathVector const * pathv = ( font - ? font->PathVector(glyph) - : NULL ); - if ( pathv ) { - nr_arena_item_request_render(NR_ARENA_ITEM(group)); - - NRArenaItem *new_arena = NRArenaGlyphs::create(group->arena); - nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena); - nr_arena_item_unref(new_arena); - nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, &transform); - } -} - -void -nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style) -{ - nr_return_if_fail(sg != NULL); - nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg)); - - if (style) sp_style_ref(style); - if (sg->style) sp_style_unref(sg->style); - sg->style = style; - - sg->nrstyle.set(style); - - nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox) -{ - nr_return_if_fail(gg != NULL); - nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg)); - nr_return_if_fail(pbox != NULL); - - gg->paintbox = pbox->upgrade_2geom(); - - nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h deleted file mode 100644 index 4b2aed7b9..000000000 --- a/src/display/nr-arena-glyphs.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef SEEN_NR_ARENA_GLYPHS_H -#define SEEN_NR_ARENA_GLYPHS_H - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2002 Lauris Kaplinski - * - * Released under GNU GPL - * - */ - -#define NR_TYPE_ARENA_GLYPHS (nr_arena_glyphs_get_type ()) -#define NR_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_GLYPHS, NRArenaGlyphs)) -#define NR_IS_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS)) - -#include "libnrtype/nrtype-forward.h" -#include "display/display-forward.h" -#include "forward.h" -#include "display/nr-arena-item.h" -#include "display/nr-style.h" - -#define test_glyph_liv - -struct SPCurve; -class Shape; -class SPPainter; - -NRType nr_arena_glyphs_get_type (void); - -struct NRArenaGlyphs : public NRArenaItem { - /* Glyphs data */ - Geom::Affine g_transform; - - font_instance *font; - gint glyph; - float x, y; - - static NRArenaGlyphs *create(NRArena *arena) { - NRArenaGlyphs *obj=reinterpret_cast(nr_object_new(NR_TYPE_ARENA_GLYPHS)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaGlyphsClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_glyphs_set_path ( NRArenaGlyphs *glyphs, - SPCurve *curve, unsigned int lieutenant, - font_instance *font, int glyph, - Geom::Affine const *transform ); -void nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style); - -/* Integrated group of component glyphss */ - -typedef struct NRArenaGlyphsGroup NRArenaGlyphsGroup; -typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass; - -#include "nr-arena-group.h" - -#define NR_TYPE_ARENA_GLYPHS_GROUP (nr_arena_glyphs_group_get_type ()) -#define NR_ARENA_GLYPHS_GROUP(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_GLYPHS_GROUP, NRArenaGlyphsGroup)) -#define NR_IS_ARENA_GLYPHS_GROUP(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS_GROUP)) - -NRType nr_arena_glyphs_group_get_type (void); - -struct NRArenaGlyphsGroup : public NRArenaGroup { - Geom::OptRect paintbox; - NRStyle nrstyle; - - static NRArenaGlyphsGroup *create(NRArena *arena) { - NRArenaGlyphsGroup *obj=reinterpret_cast(nr_object_new(NR_TYPE_ARENA_GLYPHS_GROUP)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaGlyphsGroupClass { - NRArenaGroupClass parent_class; -}; - -/* Utility functions */ - -void nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *group); - -void nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *group, font_instance *font, int glyph, Geom::Affine const &transform); - -void nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *group, SPStyle *style); - -void nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *group, const NRRect *pbox); - -#endif // SEEN_NR_ARENA_GLYPHS_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp deleted file mode 100644 index 1f7c421d0..000000000 --- a/src/display/nr-arena-group.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#define __NR_ARENA_GROUP_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "display/canvas-bpath.h" -#include "display/nr-arena.h" -#include "display/nr-arena-group.h" -#include "display/nr-filter.h" -#include "display/nr-filter-types.h" -#include "display/rendermode.h" -#include "style.h" -#include "sp-filter.h" -#include "sp-filter-reference.h" -#include "filters/blend.h" -#include "display/nr-filter-blend.h" -#include "helper/geom.h" -#include "display/drawing-context.h" - -static void nr_arena_group_class_init (NRArenaGroupClass *klass); -static void nr_arena_group_init (NRArenaGroup *group); - -static NRArenaItem *nr_arena_group_children (NRArenaItem *item); -static NRArenaItem *nr_arena_group_last_child (NRArenaItem *item); -static void nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -static void nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child); -static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - -static unsigned int nr_arena_group_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static unsigned int nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); - -static NRArenaItemClass *parent_class; - -NRType -nr_arena_group_get_type (void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type (NR_TYPE_ARENA_ITEM, - "NRArenaGroup", - sizeof (NRArenaGroupClass), - sizeof (NRArenaGroup), - (void (*) (NRObjectClass *)) nr_arena_group_class_init, - (void (*) (NRObject *)) nr_arena_group_init); - } - return type; -} - -static void -nr_arena_group_class_init (NRArenaGroupClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->cpp_ctor = NRObject::invoke_ctor; - - item_class->children = nr_arena_group_children; - item_class->last_child = nr_arena_group_last_child; - item_class->add_child = nr_arena_group_add_child; - item_class->set_child_position = nr_arena_group_set_child_position; - item_class->remove_child = nr_arena_group_remove_child; - item_class->update = nr_arena_group_update; - item_class->render = nr_arena_group_render; - item_class->clip = nr_arena_group_clip; - item_class->pick = nr_arena_group_pick; -} - -static void -nr_arena_group_init (NRArenaGroup *group) -{ - group->transparent = FALSE; - group->children = NULL; - group->last = NULL; - group->style = NULL; - group->child_transform.setIdentity(); -} - -static NRArenaItem * -nr_arena_group_children (NRArenaItem *item) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - return group->children; -} - -static NRArenaItem * -nr_arena_group_last_child (NRArenaItem *item) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - return group->last; -} - -static void -nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - if (!ref) { - group->children = nr_arena_item_attach (item, child, NULL, group->children); - } else { - ref->next = nr_arena_item_attach (item, child, ref, ref->next); - } - - if (ref == group->last) group->last = child; - - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static void -nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - if (child == group->last) group->last = child->prev; - - if (child->prev) { - nr_arena_item_detach (item, child); - } else { - group->children = nr_arena_item_detach (item, child); - } - - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static void -nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - if (child == group->last) group->last = child->prev; - - if (child->prev) { - nr_arena_item_detach (item, child); - } else { - group->children = nr_arena_item_detach (item, child); - } - - if (!ref) { - group->children = nr_arena_item_attach (item, child, NULL, group->children); - } else { - ref->next = nr_arena_item_attach (item, child, ref, ref->next); - } - - if (ref == group->last) group->last = child; - - nr_arena_item_request_render (child); -} - -static unsigned int -nr_arena_group_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset) -{ - unsigned int newstate; - NRArenaGroup *group = NR_ARENA_GROUP (item); - unsigned int beststate = NR_ARENA_ITEM_STATE_ALL; - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - NRGC cgc(gc); - cgc.transform = group->child_transform * gc->transform; - newstate = nr_arena_item_invoke_update (child, area, &cgc, state, reset); - beststate = beststate & newstate; - } - - if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - item->bbox = Geom::OptIntRect(); - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - if (child->visible) - item->bbox.unionWith(outline ? child->bbox : child->drawbox); - } - } - - return beststate; -} - -void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style) -{ - g_return_if_fail(group != NULL); - g_return_if_fail(NR_IS_ARENA_GROUP(group)); - - if (style) sp_style_ref(style); - if (group->style) sp_style_unref(group->style); - group->style = style; - - //if group has a filter - if (style->filter.set && style->getFilter()) { - if (!group->filter) { - int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter())); - group->filter = new Inkscape::Filters::Filter(primitives); - } - sp_filter_build_renderer(SP_FILTER(style->getFilter()), group->filter); - } else { - //no filter set for this group - delete group->filter; - group->filter = NULL; - } - - if (style && style->enable_background.set - && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { - group->background_new = true; - } -} - -static unsigned int -nr_arena_group_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - unsigned int ret = item->state; - - /* Just compose children into parent buffer */ - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_item_invoke_render (ct, child, area, flags); - if (ret & NR_ARENA_ITEM_STATE_INVALID) break; - } - - return ret; -} - -static unsigned int -nr_arena_group_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - unsigned int ret = item->state; - - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_item_invoke_clip (ct, child, area); - if (ret & NR_ARENA_ITEM_STATE_INVALID) break; - } - - return ret; -} - -static NRArenaItem * -nr_arena_group_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - for (NRArenaItem *child = group->last; child != NULL; child = child->prev) { - NRArenaItem *picked = nr_arena_item_invoke_pick (child, p, delta, sticky); - if (picked) - return (group->transparent) ? picked : item; - } - - return NULL; -} - -void -nr_arena_group_set_transparent (NRArenaGroup *group, unsigned int transparent) -{ - nr_return_if_fail (group != NULL); - nr_return_if_fail (NR_IS_ARENA_GROUP (group)); - - group->transparent = transparent; -} - -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t) -{ - Geom::Affine nt(t); - nr_arena_group_set_child_transform(group, &nt); -} - -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t) -{ - if (!t) t = &GEOM_MATRIX_IDENTITY; - - if (!Geom::matrix_equalp(*t, group->child_transform, NR_EPSILON)) { - nr_arena_item_request_render (NR_ARENA_ITEM (group)); - group->child_transform = *t; - nr_arena_item_request_update (NR_ARENA_ITEM (group), NR_ARENA_ITEM_STATE_ALL, TRUE); - } -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-group.h b/src/display/nr-arena-group.h deleted file mode 100644 index 58394643c..000000000 --- a/src/display/nr-arena-group.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __NR_ARENA_GROUP_H__ -#define __NR_ARENA_GROUP_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. - * - * Released under GNU GPL - * - */ - -#define NR_TYPE_ARENA_GROUP (nr_arena_group_get_type ()) -#define NR_ARENA_GROUP(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_GROUP, NRArenaGroup)) -#define NR_IS_ARENA_GROUP(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_GROUP)) - -#include "nr-arena-item.h" -#include "style.h" - -NRType nr_arena_group_get_type (void); - -struct NRArenaGroup : public NRArenaItem{ - unsigned int transparent : 1; - NRArenaItem *children; - NRArenaItem *last; - Geom::Affine child_transform; - SPStyle *style; - - static NRArenaGroup *create(NRArena *arena) { - NRArenaGroup *obj = reinterpret_cast(nr_object_new(NR_TYPE_ARENA_GROUP)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaGroupClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_group_set_transparent(NRArenaGroup *group, unsigned int transparent); - -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t); -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t); -void nr_arena_group_set_style(NRArenaGroup *group, SPStyle *style); - -#endif - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp deleted file mode 100644 index 5336fcda9..000000000 --- a/src/display/nr-arena-image.cpp +++ /dev/null @@ -1,390 +0,0 @@ -#define __NR_ARENA_IMAGE_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <2geom/transforms.h> -#include "../preferences.h" -#include "nr-arena-image.h" -#include "style.h" -#include "display/cairo-utils.h" -#include "display/drawing-context.h" -#include "display/nr-arena.h" -#include "display/nr-filter.h" -#include "sp-filter.h" -#include "sp-filter-reference.h" - -int nr_arena_image_x_sample = 1; -int nr_arena_image_y_sample = 1; - -/* - * NRArenaCanvasImage - * - */ - -static void nr_arena_image_class_init (NRArenaImageClass *klass); -static void nr_arena_image_init (NRArenaImage *image); -static void nr_arena_image_finalize (NRObject *object); - -static unsigned int nr_arena_image_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); -static unsigned int nr_arena_image_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static NRArenaItem *nr_arena_image_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); -static Geom::Rect nr_arena_image_rect (NRArenaImage *image); - -static NRArenaItemClass *parent_class; - -NRType -nr_arena_image_get_type (void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type (NR_TYPE_ARENA_ITEM, - "NRArenaImage", - sizeof (NRArenaImageClass), - sizeof (NRArenaImage), - (void (*) (NRObjectClass *)) nr_arena_image_class_init, - (void (*) (NRObject *)) nr_arena_image_init); - } - return type; -} - -static void -nr_arena_image_class_init (NRArenaImageClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_image_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor; - - item_class->update = nr_arena_image_update; - item_class->render = nr_arena_image_render; - item_class->pick = nr_arena_image_pick; -} - -static void -nr_arena_image_init (NRArenaImage *image) -{ - image->pixbuf = NULL; - image->ctm.setIdentity(); - image->clipbox = Geom::Rect(); - image->ox = image->oy = 0.0; - image->sx = image->sy = 1.0; - - image->style = 0; - image->render_opacity = TRUE; -} - -static void -nr_arena_image_finalize (NRObject *object) -{ - NRArenaImage *image = NR_ARENA_IMAGE (object); - - if (image->pixbuf != NULL) { - g_object_unref(image->pixbuf); - cairo_surface_destroy(image->surface); - } - if (image->style) - sp_style_unref(image->style); - - ((NRObjectClass *) parent_class)->finalize (object); -} - -static unsigned int -nr_arena_image_update( NRArenaItem *item, Geom::IntRect const &/*area*/, NRGC *gc, unsigned int /*state*/, unsigned int /*reset*/ ) -{ - // clear old bbox - nr_arena_item_request_render(item); - - NRArenaImage *image = NR_ARENA_IMAGE (item); - - /* Copy affine */ - image->ctm = gc->transform; - - /* Calculate bbox */ - if (image->pixbuf) { - Geom::Rect r = nr_arena_image_rect(image) * gc->transform; - item->bbox = r.roundOutwards(); - } else { - item->bbox = Geom::OptIntRect(); - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -static unsigned int nr_arena_image_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/, unsigned int /*flags*/ ) -{ - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - NRArenaImage *image = NR_ARENA_IMAGE (item); - - if (!outline) { - if (!image->pixbuf) { - return item->state; - } - - // FIXME: at the moment gdk_cairo_set_source_pixbuf creates an ARGB copy - // of the pixbuf. Fix this in Cairo and/or GDK. - Inkscape::DrawingContext::Save save(ct); - ct.transform(image->ctm); - ct.newPath(); - ct.rectangle(image->clipbox); - ct.clip(); - - ct.translate(image->ox, image->oy); - ct.scale(image->sx, image->sy); - ct.setSource(image->surface, 0, 0); - - cairo_matrix_t tt; - Geom::Affine total; - cairo_get_matrix(ct.raw(), &tt); - ink_matrix_to_2geom(total, tt); - - if (total.expansionX() > 1.0 || total.expansionY() > 1.0) { - cairo_pattern_t *p = cairo_get_source(ct.raw()); - cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST); - } - ct.paint(((double) item->opacity) / 255.0); - - } else { // outline; draw a rect instead - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff); - - { Inkscape::DrawingContext::Save save(ct); - ct.transform(image->ctm); - ct.newPath(); - - Geom::Rect r = nr_arena_image_rect (image); - Geom::Point c00 = r.corner(0); - Geom::Point c01 = r.corner(3); - Geom::Point c11 = r.corner(2); - Geom::Point c10 = r.corner(1); - - ct.moveTo(c00); - // the box - ct.lineTo(c10); - ct.lineTo(c11); - ct.lineTo(c01); - ct.lineTo(c00); - // the diagonals - ct.lineTo(c11); - ct.moveTo(c10); - ct.lineTo(c01); - } - - ct.setLineWidth(0.5); - ct.setSource(rgba); - ct.stroke(); - } - return item->state; -} - -/** Calculates the closest distance from p to the segment a1-a2*/ -double -distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2) -{ - // calculate sides of the triangle and their squares - double d1 = Geom::L2(p - a1); - double d1_2 = d1 * d1; - double d2 = Geom::L2(p - a2); - double d2_2 = d2 * d2; - double a = Geom::L2(a1 - a2); - double a_2 = a * a; - - // if one of the angles at the base is > 90, return the corresponding side - if (d1_2 + a_2 <= d2_2) return d1; - if (d2_2 + a_2 <= d1_2) return d2; - - // otherwise calculate the height to the base - double peri = (a + d1 + d2)/2; - return (2*sqrt(peri * (peri - a) * (peri - d1) * (peri - d2))/a); -} - -static NRArenaItem * -nr_arena_image_pick( NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/ ) -{ - NRArenaImage *image = NR_ARENA_IMAGE (item); - - if (!image->pixbuf) return NULL; - - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - if (outline) { - Geom::Rect r = nr_arena_image_rect (image); - - Geom::Point c00 = r.corner(0); - Geom::Point c01 = r.corner(3); - Geom::Point c11 = r.corner(2); - Geom::Point c10 = r.corner(1); - - // frame - if (distance_to_segment (p, c00, c10) < delta) return item; - if (distance_to_segment (p, c10, c11) < delta) return item; - if (distance_to_segment (p, c11, c01) < delta) return item; - if (distance_to_segment (p, c01, c00) < delta) return item; - - // diagonals - if (distance_to_segment (p, c00, c11) < delta) return item; - if (distance_to_segment (p, c10, c01) < delta) return item; - - return NULL; - - } else { - - unsigned char *const pixels = gdk_pixbuf_get_pixels(image->pixbuf); - int const width = gdk_pixbuf_get_width(image->pixbuf); - int const height = gdk_pixbuf_get_height(image->pixbuf); - int const rowstride = gdk_pixbuf_get_rowstride(image->pixbuf); - - Geom::Point tp = p * image->ctm.inverse(); - Geom::Rect r = nr_arena_image_rect(image); - - if (!r.contains(tp)) - return NULL; - - double vw = width * image->sx; - double vh = height * image->sy; - int ix = floor((tp[Geom::X] - image->ox) / vw * width); - int iy = floor((tp[Geom::Y] - image->oy) / vh * height); - - if ((ix < 0) || (iy < 0) || (ix >= width) || (iy >= height)) - return NULL; - - unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4; - // is the alpha not transparent? - return (pix_ptr[3] > 0) ? item : NULL; - } -} - -Geom::Rect -nr_arena_image_rect (NRArenaImage *image) -{ - Geom::Rect r = image->clipbox; - - if (image->pixbuf) { - double pw = gdk_pixbuf_get_width(image->pixbuf); - double ph = gdk_pixbuf_get_height(image->pixbuf); - double vw = pw * image->sx; - double vh = ph * image->sy; - Geom::Point p(image->ox, image->oy); - Geom::Point wh(vw, vh); - Geom::Rect view(p, p+wh); - Geom::OptRect res = r & view; - r = res ? *res : r; - } - - return r; -} - -/* Utility */ - -void -nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1 - if (pb != NULL) { - g_object_ref (pb); - } - if (image->pixbuf != NULL) { - g_object_unref(image->pixbuf); - cairo_surface_destroy(image->surface); - } - image->pixbuf = pb; - image->surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - image->clipbox = clip; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - image->ox = origin[Geom::X]; - image->oy = origin[Geom::Y]; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - image->sx = sx; - image->sy = sy; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style) -{ - g_return_if_fail(image != NULL); - g_return_if_fail(NR_IS_ARENA_IMAGE(image)); - - if (style) sp_style_ref(style); - if (image->style) sp_style_unref(image->style); - image->style = style; - - //if image has a filter - if (style->filter.set && style->getFilter()) { - if (!image->filter) { - int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter())); - image->filter = new Inkscape::Filters::Filter(primitives); - } - sp_filter_build_renderer(SP_FILTER(style->getFilter()), image->filter); - } else { - //no filter set for this image - delete image->filter; - image->filter = NULL; - } - - if (style && style->enable_background.set - && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { - image->background_new = true; - } - - nr_arena_item_request_update(image, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-image.h b/src/display/nr-arena-image.h deleted file mode 100644 index 6fa9223dd..000000000 --- a/src/display/nr-arena-image.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __NR_ARENA_IMAGE_H__ -#define __NR_ARENA_IMAGE_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include -#include <2geom/rect.h> -#include "nr-arena-item.h" -#include "style.h" - -#define NR_TYPE_ARENA_IMAGE (nr_arena_image_get_type ()) -#define NR_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_IMAGE, NRArenaImage)) -#define NR_IS_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_IMAGE)) - -NRType nr_arena_image_get_type (void); - -struct NRArenaImage : public NRArenaItem { - GdkPixbuf *pixbuf; - cairo_surface_t *surface; - - Geom::Affine ctm; - Geom::Rect clipbox; - double ox, oy; - double sx, sy; - - SPStyle *style; - - static NRArenaImage *create(NRArena *arena) { - NRArenaImage *obj=reinterpret_cast(nr_object_new(NR_TYPE_ARENA_IMAGE)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaImageClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb); -void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style); -void nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip); -void nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin); -void nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy); - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp deleted file mode 100644 index 264b8ab10..000000000 --- a/src/display/nr-arena-item.cpp +++ /dev/null @@ -1,932 +0,0 @@ -#define __NR_ARENA_ITEM_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#define noNR_ARENA_ITEM_VERBOSE -#define noNR_ARENA_ITEM_DEBUG_CASCADE - -#include -#include -#include - -#include "display/cairo-utils.h" -#include "display/cairo-templates.h" -#include "display/drawing-context.h" -#include "display/drawing-surface.h" -#include "display/canvas-arena.h" -#include "nr-arena.h" -#include "nr-arena-item.h" -#include "gc-core.h" -#include "helper/geom.h" - -#include "nr-filter.h" -#include "nr-arena-group.h" -#include "preferences.h" - -namespace GC = Inkscape::GC; - -static void nr_arena_item_class_init (NRArenaItemClass *klass); -static void nr_arena_item_init (NRArenaItem *item); -static void nr_arena_item_private_finalize (NRObject *object); - -static NRObjectClass *parent_class; - -NRType -nr_arena_item_get_type (void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type (NR_TYPE_OBJECT, - "NRArenaItem", - sizeof (NRArenaItemClass), - sizeof (NRArenaItem), - (void (*)(NRObjectClass *)) - nr_arena_item_class_init, - (void (*)(NRObject *)) - nr_arena_item_init); - } - return type; -} - -static void -nr_arena_item_class_init (NRArenaItemClass *klass) -{ - NRObjectClass *object_class; - - object_class = (NRObjectClass *) klass; - - parent_class = ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_item_private_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor < NRArenaItem >; -} - -static void -nr_arena_item_init (NRArenaItem *item) -{ - item->arena = NULL; - item->parent = NULL; - item->next = item->prev = NULL; - - item->key = 0; - - item->state = 0; - item->sensitive = TRUE; - item->visible = TRUE; - - memset (&item->bbox, 0, sizeof (item->bbox)); - memset (&item->drawbox, 0, sizeof (item->drawbox)); - item->transform = NULL; - item->ctm.setIdentity(); - item->opacity = 255; - item->render_opacity = FALSE; - item->render_cache = FALSE; - - item->transform = NULL; - item->clip = NULL; - item->mask = NULL; - item->cache = NULL; - item->data = NULL; - item->filter = NULL; - item->background_new = false; -} - -static void -nr_arena_item_private_finalize (NRObject *object) -{ - NRArenaItem *item = static_cast < NRArenaItem * >(object); - - item->transform = NULL; - - if (item->clip) - nr_arena_item_detach(item, item->clip); - if (item->mask) - nr_arena_item_detach(item, item->mask); - delete item->cache; - - ((NRObjectClass *) (parent_class))->finalize (object); -} - -NRArenaItem * -nr_arena_item_children (NRArenaItem *item) -{ - nr_return_val_if_fail (item != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL); - - if (NR_ARENA_ITEM_VIRTUAL (item, children)) - return NR_ARENA_ITEM_VIRTUAL (item, children) (item); - - return NULL; -} - -NRArenaItem * -nr_arena_item_last_child (NRArenaItem *item) -{ - nr_return_val_if_fail (item != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL); - - if (NR_ARENA_ITEM_VIRTUAL (item, last_child)) { - return NR_ARENA_ITEM_VIRTUAL (item, last_child) (item); - } else { - NRArenaItem *ref = nr_arena_item_children (item); - if (ref) - while (ref->next) - ref = ref->next; - return ref; - } -} - -void -nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child, - NRArenaItem *ref) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_return_if_fail (child != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (child)); - nr_return_if_fail (child->parent == NULL); - nr_return_if_fail (child->prev == NULL); - nr_return_if_fail (child->next == NULL); - nr_return_if_fail (child->arena == item->arena); - nr_return_if_fail (child != ref); - nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref)); - nr_return_if_fail (!ref || (ref->parent == item)); - - if (NR_ARENA_ITEM_VIRTUAL (item, add_child)) - NR_ARENA_ITEM_VIRTUAL (item, add_child) (item, child, ref); -} - -void -nr_arena_item_remove_child (NRArenaItem *item, NRArenaItem *child) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_return_if_fail (child != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (child)); - nr_return_if_fail (child->parent == item); - - if (NR_ARENA_ITEM_VIRTUAL (item, remove_child)) - NR_ARENA_ITEM_VIRTUAL (item, remove_child) (item, child); -} - -void -nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, - NRArenaItem *ref) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_return_if_fail (child != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (child)); - nr_return_if_fail (child->parent == item); - nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref)); - nr_return_if_fail (!ref || (ref->parent == item)); - - if (NR_ARENA_ITEM_VIRTUAL (item, set_child_position)) - NR_ARENA_ITEM_VIRTUAL (item, set_child_position) (item, child, ref); -} - -NRArenaItem * -nr_arena_item_ref (NRArenaItem *item) -{ - nr_object_ref ((NRObject *) item); - - return item; -} - -NRArenaItem * -nr_arena_item_unref (NRArenaItem *item) -{ - nr_object_unref ((NRObject *) item); - - return NULL; -} - -unsigned int -nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, - unsigned int state, unsigned int reset) -{ - NRGC childgc (gc); - bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL); - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), - NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail (!(state & NR_ARENA_ITEM_STATE_INVALID), - NR_ARENA_ITEM_STATE_INVALID); - -#ifdef NR_ARENA_ITEM_DEBUG_CASCADE - printf ("Update %s:%p %x %x %x\n", - nr_type_name_from_instance ((GTypeInstance *) item), item, state, - item->state, reset); -#endif - - /* return if in error */ - if (item->state & NR_ARENA_ITEM_STATE_INVALID) - return item->state; - /* Set reset flags according to propagation status */ - if (item->propagate) { - reset |= ~item->state; - item->propagate = FALSE; - } - /* Reset our state */ - item->state &= ~reset; - /* Return if NOP */ - if (!(~item->state & state)) - return item->state; - /* Test whether to return immediately */ - if (item->state & NR_ARENA_ITEM_STATE_BBOX) { - // we have up-to-date bbox - if (!area.intersects(outline ? item->bbox : item->drawbox)) - return item->state; - } - - /* Set up local gc */ - childgc = *gc; - if (item->transform) { - childgc.transform = (*item->transform) * childgc.transform; - } - /* Remember the transformation matrix */ - Geom::Affine ctm_change = item->ctm.inverse() * childgc.transform; - item->ctm = childgc.transform; - - /* Invoke the real method */ - // that will update bbox - item->state = NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state, reset); - if (item->state & NR_ARENA_ITEM_STATE_INVALID) - return item->state; - - /* Enlarge the drawbox to contain filter effects */ - if (item->filter && filter && item->item_bbox) { - item->drawbox = item->filter->compute_drawbox(item, *item->item_bbox); - } else { - item->drawbox = item->bbox; - } - - /* Clipping */ - if (item->clip) { - // FIXME: since here we only need bbox, consider passing - // ((state & !(NR_ARENA_ITEM_STATE_RENDER)) | NR_ARENA_ITEM_STATE_BBOX) - // instead of state, so it does not have to create rendering structures in nr_arena_shape_update - unsigned int newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset); - if (newstate & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - if (outline) { - item->bbox.unionWith(item->clip->bbox); - } else { - item->drawbox.intersectWith(item->clip->bbox); - } - } - /* Masking */ - if (item->mask) { - unsigned int newstate = nr_arena_item_invoke_update (item->mask, area, &childgc, state, reset); - if (newstate & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - if (outline) { - item->bbox.unionWith(item->mask->bbox); - } else { - // for masking, we need full drawbox of mask - item->drawbox.intersectWith(item->mask->drawbox); - } - } - - // update cache if enabled - if (item->render_cache) { - Geom::OptIntRect cl = item->arena->cache_limit; - cl.intersectWith(item->drawbox); - if (cl) { - if (item->cache) { - // this takes care of invalidation on transform - item->cache->resizeAndTransform(*cl, ctm_change); - } else { - item->cache = new Inkscape::DrawingCache(*cl); - // the cache is initially dirty - } - } else { - // disable cache for this item - not visible - delete item->cache; - item->cache = NULL; - } - } - - // now that we know drawbox, dirty the corresponding rect on canvas: - if (!NR_IS_ARENA_GROUP(item) || (item->filter && filter)) { - // unless filtered, groups do not need to render by themselves, only their members - if (state & ~NR_ARENA_ITEM_STATE_CACHE) { - nr_arena_item_request_render (item); - } - } - - return item->state; -} - -struct MaskLuminanceToAlpha { - guint32 operator()(guint32 in) { - EXTRACT_ARGB32(in, a, r, g, b) - // the operation of unpremul -> luminance-to-alpha -> multiply by alpha - // is equivalent to luminance-to-alpha on premultiplied color values - // original computation in double: r*0.2125 + g*0.7154 + b*0.0721 - guint32 ao = r*109 + g*366 + b*37; // coeffs add up to 512 - return ((ao + 256) << 15) & 0xff000000; // equivalent to ((ao + 256) / 512) << 24 - } -}; - -unsigned int -nr_arena_item_invoke_render (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, - unsigned int flags) -{ - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - bool filter = (item->arena->rendermode != Inkscape::RENDERMODE_OUTLINE && - item->arena->rendermode != Inkscape::RENDERMODE_NO_FILTERS); - - nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), - NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX, - item->state); - - /* If we are invisible, just return successfully */ - if (!item->visible) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - - if (outline) { - // intersect with bbox rather than drawbox, as we want to render things outside - // of the clipping path as well - Geom::OptIntRect carea = Geom::intersect(area, item->bbox); - if (!carea) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - - // No caching in outline mode for now; investigate if it really gives any advantage with cairo. - // Also no attempts to clip anything; just render everything: item, clip, mask - // First, render the object itself - unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - - // render clip and mask, if any - guint32 saved_rgba = item->arena->outlinecolor; // save current outline color - // render clippath as an object, using a different color - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (item->clip) { - item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips - NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, *carea, flags); - } - // render mask as an object, using a different color - if (item->mask) { - item->arena->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks - NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, *carea, flags); - } - item->arena->outlinecolor = saved_rgba; // restore outline color - - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } - - // carea is the bounding box for intermediate rendering. - Geom::OptIntRect carea = Geom::intersect(area, item->drawbox); - if (!carea) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - - // render from cache - if (item->render_cache && item->cache) { - if(item->cache->paintFromCache(ct, *carea)) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } - - // expand carea to contain the dependent area of filters. - if (item->filter && filter) { - item->filter->area_enlarge(*carea, item); - carea.intersectWith(item->drawbox); - } - - using namespace Inkscape; - - unsigned state; - unsigned retstate; - - // determine whether this shape needs intermediate rendering. - bool needs_intermediate_rendering = false; - bool &nir = needs_intermediate_rendering; - bool needs_opacity = (item->opacity != 255 && !item->render_opacity); - - // this item needs an intermediate rendering if: - nir |= (item->clip != NULL); // 1. it has a clipping path - nir |= (item->mask != NULL); // 2. it has a mask - nir |= (item->filter != NULL && filter); // 3. it has a filter - nir |= needs_opacity; // 4. it is non-opaque - - double opacity = static_cast(item->opacity) / 255.0; - - /* How the rendering is done. - * - * Clipping, masking and opacity are done by rendering them to a surface - * and then compositing the object's rendering onto it with the IN operator. - * The object itself is rendered to a group. - * - * Opacity is done by rendering the clipping path with an alpha - * value corresponding to the opacity. If there is no clipping path, - * the entire intermediate surface is painted with alpha corresponding - * to the opacity value. - */ - - // short-circuit the simple case. - if (!needs_intermediate_rendering) { - if (item->render_cache && item->cache) { - Inkscape::DrawingContext cachect(*item->cache); - cachect.rectangle(area); - cachect.clip(); - - { // 1. clear the corresponding part of cache - Inkscape::DrawingContext::Save save(cachect); - cachect.setSource(0,0,0,0); - cachect.setOperator(CAIRO_OPERATOR_SOURCE); - cachect.paint(); - } - // 2. render to cache - state = NR_ARENA_ITEM_VIRTUAL (item, render) (cachect, item, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - // 3. copy from cache to output - Inkscape::DrawingContext::Save save(ct); - ct.rectangle(*carea); - ct.clip(); - ct.setSource(item->cache); - ct.paint(); - // 4. mark as clean - item->cache->markClean(area); - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } else { - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - return item->state | NR_ARENA_ITEM_STATE_RENDER; - } - } - - DrawingSurface intermediate(*carea); - DrawingContext ict(intermediate); - - // 1. Render clipping path with alpha = opacity. - ict.setSource(0,0,0,opacity); - // Since clip can be combined with opacity, the result could be incorrect - // for overlapping clip children. To fix this we use the SOURCE operator - // instead of the default OVER. - ict.setOperator(CAIRO_OPERATOR_SOURCE); - if (item->clip) { - state = nr_arena_item_invoke_clip(ict, item->clip, *carea); // fixme: carea or area? - if (state & NR_ARENA_ITEM_STATE_INVALID) { - retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); - goto cleanup; - } - } else { - // if there is no clipping path, fill the entire surface with alpha = opacity. - ict.paint(); - } - // reset back to default - ict.setOperator(CAIRO_OPERATOR_OVER); - - // 2. Render the mask if present and compose it with the clipping path + opacity. - if (item->mask) { - ict.pushGroup(); - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); - goto cleanup; - } - cairo_surface_t *mask_s = ict.rawTarget(); - // Convert mask's luminance to alpha - ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha()); - ict.popGroupToSource(); - ict.setOperator(CAIRO_OPERATOR_IN); - ict.paint(); - ict.setOperator(CAIRO_OPERATOR_OVER); - } - - // 3. Render object itself. - ict.pushGroup(); - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, *carea, flags); - if (state & NR_ARENA_ITEM_STATE_INVALID) { - retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); - goto cleanup; - } - - // 4. Apply filter. - if (item->filter && filter) { - item->filter->render(item, ct, ict); - // Note that because the object was rendered to a group, - // the internals of the filter need to use cairo_get_group_target() - // instead of cairo_get_target(). - } - - // 5. Render object inside the composited mask + clip - ict.popGroupToSource(); - ict.setOperator(CAIRO_OPERATOR_IN); - ict.paint(); - - // 6. Paint the completed rendering onto the base context (or into cache) - if (item->render_cache && item->cache) { - DrawingContext cachect(*item->cache); - cachect.rectangle(area); - cachect.clip(); - cachect.setOperator(CAIRO_OPERATOR_SOURCE); - cachect.setSource(&intermediate); - cachect.paint(); - item->cache->markClean(area); - } - ct.setSource(&intermediate); - ct.paint(); - ct.setSource(0,0,0,0); - // the call above is to clear a ref on the intermediate surface held by ct - - retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; - - cleanup: - return retstate; -} - -unsigned int -nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area) -{ - nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), - NR_ARENA_ITEM_STATE_INVALID); - - unsigned retstate = 0; - - // don't bother if the object does not implement clipping (e.g. NRArenaImage) - if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) - return retstate; - - if (item->visible && area.intersects(item->bbox)) { - // The item used as the clipping path itself has a clipping path. - // Render this item's clipping path onto a temporary surface, then composite it - // with the item using the IN operator - if (item->clip) { - ct.pushAlphaGroup(); - { Inkscape::DrawingContext::Save save(ct); - ct.setSource(0,0,0,1); - nr_arena_item_invoke_clip(ct, item->clip, area); - } - ct.pushAlphaGroup(); - } - - // rasterize the clipping path - retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - clip (ct, item, area); - - if (item->clip) { - ct.popGroupToSource(); - ct.setOperator(CAIRO_OPERATOR_IN); - ct.paint(); - ct.popGroupToSource(); - ct.setOperator(CAIRO_OPERATOR_SOURCE); - ct.paint(); - } - } - - return retstate; -} - -NRArenaItem * -nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta, - unsigned int sticky) -{ - nr_return_val_if_fail (item != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL); - - // Sometimes there's no BBOX in item->state, reason unknown (bug 992817); I made this not an assert to remove the warning - if (!(item->state & NR_ARENA_ITEM_STATE_BBOX) - || !(item->state & NR_ARENA_ITEM_STATE_PICK)) - return NULL; - - if (!sticky && !(item->visible && item->sensitive)) - return NULL; - - if (!item->bbox) return NULL; - Geom::Rect expanded(*item->bbox); - expanded.expandBy(delta); - - if (expanded.contains(p)) { - if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick) - return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - pick (item, p, delta, sticky); - } - - return NULL; -} - -void -nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, - unsigned int propagate) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_return_if_fail (!(reset & NR_ARENA_ITEM_STATE_INVALID)); - - if (propagate && !item->propagate) - item->propagate = TRUE; - - if (item->state & reset) { - item->state &= ~reset; - if (item->parent) { - nr_arena_item_request_update (item->parent, reset, FALSE); - } else { - nr_arena_request_update (item->arena, item); - } - } -} - -void -nr_arena_item_request_render (NRArenaItem *item) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - Geom::OptIntRect dirty = outline ? item->bbox : item->drawbox; - if (!dirty) return; - - // dirty the caches of all parents - for (NRArenaItem *i = item; i; i = i->parent) { - if (i->render_cache && i->cache) { - i->cache->markDirty(*dirty); - } - } - - nr_arena_request_render_rect (item->arena, dirty); -} - -/* Public */ - -NRArenaItem * -nr_arena_item_unparent (NRArenaItem *item) -{ - nr_return_val_if_fail (item != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL); - - nr_arena_item_request_render (item); - - if (item->parent) { - nr_arena_item_remove_child (item->parent, item); - } - - return NULL; -} - -void -nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child) -{ - nr_return_if_fail (parent != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (parent)); - nr_return_if_fail (child != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (child)); - nr_return_if_fail (parent->arena == child->arena); - nr_return_if_fail (child->parent == NULL); - nr_return_if_fail (child->prev == NULL); - nr_return_if_fail (child->next == NULL); - - nr_arena_item_add_child (parent, child, nr_arena_item_last_child (parent)); -} - -void -nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const &transform) -{ - Geom::Affine const t (transform); - nr_arena_item_set_transform (item, &t); -} - -void -nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - - if (!transform && !item->transform) - return; - - const Geom::Affine *md = (item->transform) ? item->transform : &GEOM_MATRIX_IDENTITY; - const Geom::Affine *ms = (transform) ? transform : &GEOM_MATRIX_IDENTITY; - - if (!Geom::matrix_equalp(*md, *ms, NR_EPSILON)) { - // mark the area where the object was for redraw. - nr_arena_item_request_render (item); - if (!transform || transform->isIdentity()) { - /* Set to identity affine */ - item->transform = NULL; - } else { - if (!item->transform) - item->transform = new (GC::ATOMIC) Geom::Affine (); - *item->transform = *transform; - } - // when update is called, the area where the object was moved - // will be redrawn as well - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE); - } -} - -void -nr_arena_item_set_opacity (NRArenaItem *item, double opacity) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - - nr_arena_item_request_render (item); - - item->opacity = (unsigned int) (opacity * 255.9999); -} - -void -nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - - /* fixme: mess with pick/repick... */ - - item->sensitive = sensitive; -} - -void -nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - - item->visible = visible; - - nr_arena_item_request_render (item); -} - -void -nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_return_if_fail (!clip || NR_IS_ARENA_ITEM (clip)); - - if (clip != item->clip) { - nr_arena_item_request_render (item); - if (item->clip) - item->clip = nr_arena_item_detach (item, item->clip); - if (clip) - item->clip = nr_arena_item_attach (item, clip, NULL, NULL); - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE); - } -} - -void -nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_return_if_fail (!mask || NR_IS_ARENA_ITEM (mask)); - - if (mask != item->mask) { - nr_arena_item_request_render (item); - if (item->mask) - item->mask = nr_arena_item_detach (item, item->mask); - if (mask) - item->mask = nr_arena_item_attach (item, mask, NULL, NULL); - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE); - } -} - -void -nr_arena_item_set_order (NRArenaItem *item, int order) -{ - nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - - if (!item->parent) - return; - - NRArenaItem *children = nr_arena_item_children (item->parent); - - NRArenaItem *ref = NULL; - int pos = 0; - for (NRArenaItem *child = children; child != NULL; child = child->next) { - if (pos >= order) - break; - if (child != item) { - ref = child; - pos += 1; - } - } - - nr_arena_item_set_child_position (item->parent, item, ref); -} - -void -nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox) -{ - nr_return_if_fail(item != NULL); - nr_return_if_fail(NR_IS_ARENA_ITEM(item)); - - item->item_bbox = bbox; -} - -void -nr_arena_item_set_cache (NRArenaItem *item, bool cache) -{ - if (cache) { - item->render_cache = TRUE; - item->arena->cached_items.insert(item); - } else { - item->render_cache = FALSE; - item->arena->cached_items.erase(item); - } - nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -/** Returns a background image for use with filter effects. */ -NRPixBlock *nr_arena_item_get_background(NRArenaItem const * /*item*/) -{ - return NULL; -} - -/* Helpers */ - -NRArenaItem * -nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child, - NRArenaItem *prev, NRArenaItem *next) -{ - nr_return_val_if_fail (parent != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL); - nr_return_val_if_fail (child != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL); - nr_return_val_if_fail (child->parent == NULL, NULL); - nr_return_val_if_fail (child->prev == NULL, NULL); - nr_return_val_if_fail (child->next == NULL, NULL); - nr_return_val_if_fail (!prev || NR_IS_ARENA_ITEM (prev), NULL); - nr_return_val_if_fail (!prev || (prev->parent == parent), NULL); - nr_return_val_if_fail (!prev || (prev->next == next), NULL); - nr_return_val_if_fail (!next || NR_IS_ARENA_ITEM (next), NULL); - nr_return_val_if_fail (!next || (next->parent == parent), NULL); - nr_return_val_if_fail (!next || (next->prev == prev), NULL); - - child->parent = parent; - child->prev = prev; - child->next = next; - - if (prev) - prev->next = child; - if (next) - next->prev = child; - - return child; -} - -NRArenaItem * -nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child) -{ - nr_return_val_if_fail (parent != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL); - nr_return_val_if_fail (child != NULL, NULL); - nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL); - nr_return_val_if_fail (child->parent == parent, NULL); - - NRArenaItem *prev = child->prev; - NRArenaItem *next = child->next; - - child->parent = NULL; - child->prev = NULL; - child->next = NULL; - - if (prev) - prev->next = next; - if (next) - next->prev = prev; - - return next; -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h deleted file mode 100644 index 2c00c0bf3..000000000 --- a/src/display/nr-arena-item.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_DISPLAY_NR_ARENA_ITEM_H -#define SEEN_DISPLAY_NR_ARENA_ITEM_H - -#include -#include <2geom/affine.h> -#include <2geom/rect.h> -#include "libnr/nr-forward.h" -#include "libnr/nr-rect-l.h" -#include "libnr/nr-object.h" -#include "gc-soft-ptr.h" -#include "nr-arena-forward.h" - -namespace Inkscape { -class DrawingContext; -class DrawingCache; -namespace Filters { -class Filter; -} } - -#define NR_TYPE_ARENA_ITEM (nr_arena_item_get_type ()) -#define NR_ARENA_ITEM(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_ITEM, NRArenaItem)) -#define NR_IS_ARENA_ITEM(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_ITEM)) - -#define NR_ARENA_ITEM_VIRTUAL(i,m) (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (i))->m) - -/* - * NRArenaItem state flags - */ - -/* - * NR_ARENA_ITEM_STATE_INVALID - * - * If set or retuned indicates, that given object is in error. - * Calling method has to return immediately, with appropriate - * error flag. - */ - -#define NR_ARENA_ITEM_STATE_INVALID (1 << 0) - - -#define NR_ARENA_ITEM_STATE_BBOX (1 << 1) -#define NR_ARENA_ITEM_STATE_COVERAGE (1 << 2) -#define NR_ARENA_ITEM_STATE_DRAFT (1 << 3) -#define NR_ARENA_ITEM_STATE_RENDER (1 << 4) -#define NR_ARENA_ITEM_STATE_CLIP (1 << 5) -#define NR_ARENA_ITEM_STATE_MASK (1 << 6) -#define NR_ARENA_ITEM_STATE_PICK (1 << 7) -#define NR_ARENA_ITEM_STATE_IMAGE (1 << 8) -#define NR_ARENA_ITEM_STATE_CACHE (1 << 9) - -#define NR_ARENA_ITEM_STATE_NONE 0x0000 -#define NR_ARENA_ITEM_STATE_ALL 0x03fe - -#define NR_ARENA_ITEM_STATE(i,s) (NR_ARENA_ITEM (i)->state & (s)) -#define NR_ARENA_ITEM_SET_STATE(i,s) (NR_ARENA_ITEM (i)->state |= (s)) -#define NR_ARENA_ITEM_UNSET_STATE(i,s) (NR_ARENA_ITEM (i)->state &= ~(s)) - -#define NR_ARENA_ITEM_RENDER_NO_CACHE (1 << 0) -#define NR_ARENA_ITEM_RENDER_CACHE (1 << 1) - -struct NRGC { - NRGC(NRGC const *p) : parent(p) {} - NRGC const *parent; - Geom::Affine transform; -}; - -struct NRArenaItem : public NRObject { - - NRArena *arena; - Inkscape::GC::soft_ptr parent; - NRArenaItem *next; - Inkscape::GC::soft_ptr prev; - - /* Item state */ - unsigned state : 16; - /* Opacity itself */ - unsigned opacity : 8; - unsigned propagate : 1; - unsigned sensitive : 1; - unsigned visible : 1; - /* Whether items renders opacity itself */ - unsigned render_opacity : 1; - unsigned render_cache : 1; - - unsigned int key; ///< Some SPItems can have more than one NRArenaItem, - ///this value is a hack used to distinguish between them - - Geom::OptIntRect bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin - Geom::OptIntRect drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks - Geom::OptRect item_bbox; ///< Bounding box in item coordinates, required by filters - Geom::Affine *transform; ///< Incremental transform of this item, as given by the transform= attribute - Geom::Affine ctm; ///< Total transform from pixel grid to item coords - NRArenaItem *clip; ///< Clipping path - NRArenaItem *mask; ///< Mask - Inkscape::Filters::Filter *filter; ///< Filter - Inkscape::DrawingCache *cache; ///< Render cache - - void *data; ///< Anonymous data member - this is used to associate SPItems with arena items - - bool background_new; - - void init(NRArena *arena) { - this->arena = arena; - } -}; - -struct NRArenaItemClass : public NRObjectClass { - NRArenaItem * (* children) (NRArenaItem *item); - NRArenaItem * (* last_child) (NRArenaItem *item); - void (* add_child) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - void (* remove_child) (NRArenaItem *item, NRArenaItem *child); - void (* set_child_position) (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - - unsigned int (* update) (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); - unsigned int (* render) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); - unsigned int (* clip) (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); - NRArenaItem * (* pick) (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); -}; - -#define NR_ARENA_ITEM_ARENA(ai) (((NRArenaItem *) (ai))->arena) - -NRType nr_arena_item_get_type (void); - -NRArenaItem *nr_arena_item_ref (NRArenaItem *item); -NRArenaItem *nr_arena_item_unref (NRArenaItem *item); - -NRArenaItem *nr_arena_item_children (NRArenaItem *item); -NRArenaItem *nr_arena_item_last_child (NRArenaItem *item); -void nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -void nr_arena_item_remove_child (NRArenaItem *item, NRArenaItem *child); -void nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - -/* - * Invoke update to given state, if item is inside area - * - * area == NULL is infinite - * gc is PARENT gc for invoke, CHILD gc in corresponding virtual method - * state - requested to state (bitwise or of requested flags) - * reset - reset to state (bitwise or of flags to reset) - */ - -unsigned int nr_arena_item_invoke_update (NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, unsigned int state, unsigned int reset); - -unsigned int nr_arena_item_invoke_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); - -unsigned int nr_arena_item_invoke_clip (Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); - -void nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, unsigned int propagate); -void nr_arena_item_request_render (NRArenaItem *item); - -/* Public */ - -NRArenaItem *nr_arena_item_unparent (NRArenaItem *item); - -void nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child); - -void nr_arena_item_set_transform(NRArenaItem *item, Geom::Affine const &transform); -void nr_arena_item_set_transform(NRArenaItem *item, Geom::Affine const *transform); -void nr_arena_item_set_opacity (NRArenaItem *item, double opacity); -void nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive); -void nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible); -void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip); -void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask); -void nr_arena_item_set_order (NRArenaItem *item, int order); -void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect const &bbox); -void nr_arena_item_set_cache (NRArenaItem *item, bool cache); - -NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item); - -/* Helpers */ - -NRArenaItem *nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child, NRArenaItem *prev, NRArenaItem *next); -NRArenaItem *nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child); - -#define NR_ARENA_ITEM_SET_DATA(i,v) (((NRArenaItem *) (i))->data = (v)) -#define NR_ARENA_ITEM_GET_DATA(i) (((NRArenaItem *) (i))->data) - -#define NR_ARENA_ITEM_SET_KEY(i,k) (((NRArenaItem *) (i))->key = (k)) -#define NR_ARENA_ITEM_GET_KEY(i) (((NRArenaItem *) (i))->key) - -#endif /* !SEEN_DISPLAY_NR_ARENA_ITEM_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp deleted file mode 100644 index ff985550c..000000000 --- a/src/display/nr-arena-shape.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include -#include -#include -#include - -#include <2geom/curves.h> -#include <2geom/pathvector.h> -#include <2geom/svg-path.h> -#include <2geom/svg-path-parser.h> -#include "display/cairo-utils.h" -#include "display/canvas-arena.h" -#include "display/canvas-bpath.h" -#include "display/curve.h" -#include "display/drawing-context.h" -#include "display/nr-arena.h" -#include "display/nr-arena-shape.h" -#include "display/nr-filter.h" -#include "helper/geom-curves.h" -#include "helper/geom.h" -#include "libnr/nr-convert2geom.h" -#include "preferences.h" -#include "sp-filter.h" -#include "sp-filter-reference.h" -#include "style.h" -#include "svg/svg.h" - -static void nr_arena_shape_class_init(NRArenaShapeClass *klass); -static void nr_arena_shape_init(NRArenaShape *shape); -static void nr_arena_shape_finalize(NRObject *object); - -static NRArenaItem *nr_arena_shape_children(NRArenaItem *item); -static void nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); -static void nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child); -static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref); - -static guint nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset); -static unsigned int nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags); -static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area); -static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int sticky); - -static NRArenaItemClass *shape_parent_class; - -NRType -nr_arena_shape_get_type(void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type(NR_TYPE_ARENA_ITEM, - "NRArenaShape", - sizeof(NRArenaShapeClass), - sizeof(NRArenaShape), - (void (*)(NRObjectClass *)) nr_arena_shape_class_init, - (void (*)(NRObject *)) nr_arena_shape_init); - } - return type; -} - -static void -nr_arena_shape_class_init(NRArenaShapeClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - shape_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_shape_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor; - - item_class->children = nr_arena_shape_children; - item_class->add_child = nr_arena_shape_add_child; - item_class->set_child_position = nr_arena_shape_set_child_position; - item_class->remove_child = nr_arena_shape_remove_child; - item_class->update = nr_arena_shape_update; - item_class->render = nr_arena_shape_render; - item_class->clip = nr_arena_shape_clip; - item_class->pick = nr_arena_shape_pick; -} - -/** - * Initializes the arena shape, setting all parameters to null, 0, false, - * or other defaults - */ -static void -nr_arena_shape_init(NRArenaShape *shape) -{ - shape->curve = NULL; - shape->style = NULL; - shape->markers = NULL; - shape->last_pick = NULL; - shape->repick_after = 0; -} - -static void -nr_arena_shape_finalize(NRObject *object) -{ - NRArenaShape *shape = (NRArenaShape *) object; - - if (shape->style) sp_style_unref(shape->style); - if (shape->curve) shape->curve->unref(); - shape->last_pick = NULL; - - ((NRObjectClass *) shape_parent_class)->finalize(object); -} - -/** - * Retrieves the markers from the item - */ -static NRArenaItem * -nr_arena_shape_children(NRArenaItem *item) -{ - NRArenaShape *shape = (NRArenaShape *) item; - - return shape->markers; -} - -/** - * Attaches child to item, and if ref is not NULL, sets it and ref->next as - * the prev and next items. If ref is NULL, then it sets the item's markers - * as the next items. - */ -static void -nr_arena_shape_add_child(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref) -{ - NRArenaShape *shape = (NRArenaShape *) item; - - if (!ref) { - shape->markers = nr_arena_item_attach(item, child, NULL, shape->markers); - } else { - ref->next = nr_arena_item_attach(item, child, ref, ref->next); - } - - nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -/** - * Removes child from the shape. If there are no prev items in - * the child, it sets items' markers to the next item in the child. - */ -static void -nr_arena_shape_remove_child(NRArenaItem *item, NRArenaItem *child) -{ - NRArenaShape *shape = (NRArenaShape *) item; - - if (child->prev) { - nr_arena_item_detach(item, child); - } else { - shape->markers = nr_arena_item_detach(item, child); - } - - nr_arena_item_request_update(item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -/** - * Detaches child from item, and if there are no previous items in child, it - * sets item's markers to the child. It then attaches the child back onto the item. - * If ref is null, it sets the markers to be the next item, otherwise it uses - * the next/prev items in ref. - */ -static void -nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref) -{ - NRArenaShape *shape = (NRArenaShape *) item; - - if (child->prev) { - nr_arena_item_detach(item, child); - } else { - shape->markers = nr_arena_item_detach(item, child); - } - - if (!ref) { - shape->markers = nr_arena_item_attach(item, child, NULL, shape->markers); - } else { - ref->next = nr_arena_item_attach(item, child, ref, ref->next); - } - - nr_arena_item_request_render(child); -} - -/** - * Updates the arena shape 'item' and all of its children, including the markers. - */ -static guint -nr_arena_shape_update(NRArenaItem *item, Geom::IntRect const &area, NRGC *gc, guint state, guint reset) -{ - Geom::OptRect boundingbox; - - NRArenaShape *shape = NR_ARENA_SHAPE(item); - - unsigned int beststate = NR_ARENA_ITEM_STATE_ALL; - - // update markers - unsigned int newstate; - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - newstate = nr_arena_item_invoke_update(child, area, gc, state, reset); - beststate = beststate & newstate; - } - - if (!(state & NR_ARENA_ITEM_STATE_RENDER)) { - /* We do not have to create rendering structures */ - if (state & NR_ARENA_ITEM_STATE_BBOX) { - if (shape->curve) { - boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); - if (boundingbox) { - item->bbox = boundingbox->roundOutwards(); - } else { - item->bbox = Geom::OptIntRect(); - } - } - if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - item->bbox.unionWith(child->bbox); - } - } - } - return (state | item->state); - } - - boundingbox = Geom::OptRect(); - - bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - // clear Cairo data to force update - shape->nrstyle.update(); - - if (shape->curve) { - boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); - - if (boundingbox && (shape->nrstyle.stroke.type != NRStyle::PAINT_NONE || outline)) { - float width, scale; - scale = gc->transform.descrim(); - width = MAX(0.125, shape->nrstyle.stroke_width * scale); - if ( fabs(shape->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true - boundingbox->expandBy(width); - } - // those pesky miters, now - float miterMax = width * shape->nrstyle.miter_limit; - if ( miterMax > 0.01 ) { - // grunt mode. we should compute the various miters instead - // (one for each point on the curve) - boundingbox->expandBy(miterMax); - } - } - } - - item->bbox = boundingbox ? boundingbox->roundOutwards() : Geom::OptIntRect(); - - if (!shape->curve || - !shape->style || - shape->curve->is_empty() || - (( shape->nrstyle.fill.type != NRStyle::PAINT_NONE ) && - ( shape->nrstyle.stroke.type != NRStyle::PAINT_NONE && !outline) )) - { - //item->bbox = shape->approx_bbox; - return NR_ARENA_ITEM_STATE_ALL; - } - - if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - item->bbox.unionWith(child->bbox); - } - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -// cairo outline rendering: -static unsigned int -cairo_arena_shape_render_outline(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - - guint32 rgba = NR_ARENA_ITEM(shape)->arena->outlinecolor; - - { Inkscape::DrawingContext::Save save(ct); - ct.transform(shape->ctm); - ct.path(shape->curve->get_pathvector()); - } - { Inkscape::DrawingContext::Save save(ct); - ct.setSource(rgba); - ct.setLineWidth(0.5); - ct.setTolerance(1.25); - ct.stroke(); - } - - return item->state; -} - -/** - * Renders the item. Markers are just composed into the parent buffer. - */ -static unsigned int -nr_arena_shape_render(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &area, unsigned int flags) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - - if (!shape->curve) return item->state; - if (!shape->style) return item->state; - - // skip if not within bounding box - if (!area.intersects(item->bbox)) { - return item->state; - } - - bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - if (outline) { - // cairo outline rendering - unsigned int ret = cairo_arena_shape_render_outline (ct, item, area); - if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } else { - bool has_stroke, has_fill; - // we assume the context has no path - Inkscape::DrawingContext::Save save(ct); - ct.transform(shape->ctm); - - // update fill and stroke paints. - // this cannot be done during nr_arena_shape_update, because we need a Cairo context - // to render svg:pattern - has_fill = shape->nrstyle.prepareFill(ct, shape->paintbox); - has_stroke = shape->nrstyle.prepareStroke(ct, shape->paintbox); - has_stroke &= (shape->nrstyle.stroke_width != 0); - - if (has_fill || has_stroke) { - // TODO: remove segments outside of bbox when no dashes present - ct.path(shape->curve->get_pathvector()); - if (has_fill) { - shape->nrstyle.applyFill(ct); - ct.fillPreserve(); - } - if (has_stroke) { - shape->nrstyle.applyStroke(ct); - ct.strokePreserve(); - } - ct.newPath(); // clear path - } // has fill or stroke pattern - } - - // marker rendering - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - unsigned int ret = nr_arena_item_invoke_render(ct, child, area, flags); - if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } - - return item->state; -} - - -static guint nr_arena_shape_clip(Inkscape::DrawingContext &ct, NRArenaItem *item, Geom::IntRect const &/*area*/) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - if (!shape->curve) { - return item->state; - } - - Inkscape::DrawingContext::Save save(ct); - // handle clip-rule - if (shape->style) { - if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); - } else { - ct.setFillRule(CAIRO_FILL_RULE_WINDING); - } - } - ct.transform(shape->ctm); - ct.path(shape->curve->get_pathvector()); - ct.fill(); - - return item->state; -} - -static NRArenaItem * -nr_arena_shape_pick(NRArenaItem *item, Geom::Point const &p, double delta, unsigned int /*sticky*/) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - - if (shape->repick_after > 0) - shape->repick_after--; - - if (shape->repick_after > 0) // we are a slow, huge path. skip this pick, returning what was returned last time - return shape->last_pick; - - if (!shape->curve) return NULL; - if (!shape->style) return NULL; - - bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - if (SP_SCALE24_TO_FLOAT(shape->style->opacity.value) == 0 && !outline) - // fully transparent, no pick unless outline mode - return NULL; - - GTimeVal tstart, tfinish; - g_get_current_time (&tstart); - - double width; - if (outline) { - width = 0.5; - } else if (shape->nrstyle.stroke.type != NRStyle::PAINT_NONE && shape->nrstyle.stroke.opacity > 1e-3) { - float const scale = shape->ctm.descrim(); - width = MAX(0.125, shape->nrstyle.stroke_width * scale) / 2; - } else { - width = 0; - } - - double dist = Geom::infinity(); - int wind = 0; - bool needfill = (shape->nrstyle.fill.type != NRStyle::PAINT_NONE - && shape->nrstyle.fill.opacity > 1e-3 && !outline); - - if (item->arena->canvasarena) { - Geom::Rect viewbox = item->arena->canvasarena->item.canvas->getViewbox(); - viewbox.expandBy (width); - pathv_matrix_point_bbox_wind_distance(shape->curve->get_pathvector(), shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox); - } else { - pathv_matrix_point_bbox_wind_distance(shape->curve->get_pathvector(), shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL); - } - - g_get_current_time (&tfinish); - glong this_pick = (tfinish.tv_sec - tstart.tv_sec) * 1000000 + (tfinish.tv_usec - tstart.tv_usec); - //g_print ("pick time %lu\n", this_pick); - - if (this_pick > 10000) { // slow picking, remember to skip several new picks - shape->repick_after = this_pick / 5000; - } - - // covered by fill? - if (needfill) { - if (!shape->style->fill_rule.computed) { - if (wind != 0) { - shape->last_pick = item; - return item; - } - } else { - if (wind & 0x1) { - shape->last_pick = item; - return item; - } - } - } - - // close to the edge, as defined by strokewidth and delta? - // this ignores dashing (as if the stroke is solid) and always works as if caps are round - if (needfill || width > 0) { // if either fill or stroke visible, - if ((dist - width) < delta) { - shape->last_pick = item; - return item; - } - } - - // if not picked on the shape itself, try its markers - for (NRArenaItem *child = shape->markers; child != NULL; child = child->next) { - NRArenaItem *ret = nr_arena_item_invoke_pick(child, p, delta, 0); - if (ret) { - shape->last_pick = item; - return item; - } - } - - shape->last_pick = NULL; - return NULL; -} - -/** - * - * Requests a render of the shape, then if the shape is already a curve it - * unrefs the old curve; if the new curve is valid it creates a copy of the - * curve and adds it to the shape. Finally, it requests an update of the - * arena for the shape. - */ -void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve, bool /*justTrans*/) -{ - g_return_if_fail(shape != NULL); - g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); - - nr_arena_item_request_render(NR_ARENA_ITEM(shape)); - - if (shape->curve) { - shape->curve->unref(); - shape->curve = NULL; - } - - if (curve) { - shape->curve = curve; - curve->ref(); - } - - nr_arena_item_request_update(NR_ARENA_ITEM(shape), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -/** nr_arena_shape_set_style - * - * Unrefs any existing style and ref's to the given one, then requests an update of the arena - */ -void -nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style) -{ - g_return_if_fail(shape != NULL); - g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); - g_return_if_fail(style != NULL); - - sp_style_ref(style); - if (shape->style) sp_style_unref(shape->style); - shape->style = style; - - shape->nrstyle.set(style); - - //if shape has a filter - if (style->filter.set && style->getFilter()) { - if (!shape->filter) { - int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter())); - shape->filter = new Inkscape::Filters::Filter(primitives); - } - sp_filter_build_renderer(SP_FILTER(style->getFilter()), shape->filter); - } else { - //no filter set for this shape - delete shape->filter; - shape->filter = NULL; - } - - nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox) -{ - g_return_if_fail(shape != NULL); - g_return_if_fail(NR_IS_ARENA_SHAPE(shape)); - g_return_if_fail(pbox != NULL); - - shape->paintbox = pbox->upgrade_2geom(); - - nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void NRArenaShape::setPaintBox(Geom::Rect const &pbox) -{ - paintbox = pbox; - - nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h deleted file mode 100644 index 317cff7fb..000000000 --- a/src/display/nr-arena-shape.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef __NR_ARENA_SHAPE_H__ -#define __NR_ARENA_SHAPE_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#define NR_TYPE_ARENA_SHAPE (nr_arena_shape_get_type ()) -#define NR_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_SHAPE, NRArenaShape)) -#define NR_IS_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_SHAPE)) - -#include -#include "display/display-forward.h" -#include "forward.h" -#include "nr-arena-item.h" -#include "nr-style.h" -#include "libnr/nr-rect.h" - -NRType nr_arena_shape_get_type (void); - -struct NRArenaShape : public NRArenaItem { - /* Shape data */ - SPCurve *curve; - SPStyle *style; - NRStyle nrstyle; - Geom::OptRect paintbox; - - /* Markers */ - NRArenaItem *markers; - - NRArenaItem *last_pick; - guint repick_after; - - static NRArenaShape *create(NRArena *arena) { - NRArenaShape *obj=reinterpret_cast(nr_object_new(NR_TYPE_ARENA_SHAPE)); - obj->init(arena); - obj->key = 0; - return obj; - } - - void setPaintBox(Geom::Rect const &pbox); -}; - -struct NRArenaShapeClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve, bool justTrans); -void nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style); -void nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox); - - -#endif /* !__NR_ARENA_SHAPE_H__ */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index 735d44e9e..b3e962201 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -12,13 +12,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "nr-arena-item.h" -#include "nr-arena.h" -#include "nr-filter-gaussian.h" -#include "nr-filter-types.h" +#include "display/drawing-item.h" +#include "display/nr-arena.h" +#include "display/nr-filter-gaussian.h" +#include "display/nr-filter-types.h" #include "preferences.h" #include "color.h" #include "libnr/nr-rect.h" +#include "libnr/nr-rect-l.h" static void nr_arena_class_init (NRArenaClass *klass); static void nr_arena_init (NRArena *arena); @@ -58,7 +59,7 @@ nr_arena_init (NRArena *arena) arena->delta = 0; // to be set by desktop from prefs arena->renderoffscreen = false; // use render values from preferences otherwise render exact arena->rendermode = Inkscape::RENDERMODE_NORMAL; // default is normal render - arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; // default is normal color + arena->colormode = Inkscape::COLORMODE_NORMAL; // default is normal color arena->blurquality = BLUR_QUALITY_NORMAL; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_NORMAL; arena->outlinecolor = 0xff; // black; to be set by desktop from bg color @@ -72,14 +73,14 @@ nr_arena_finalize (NRObject *object) } void -nr_arena_request_update (NRArena *arena, NRArenaItem *item) +nr_arena_request_update (NRArena *arena, Inkscape::DrawingItem *item) { NRActiveObject *aobject = (NRActiveObject *) arena; nr_return_if_fail (arena != NULL); nr_return_if_fail (NR_IS_ARENA (arena)); nr_return_if_fail (item != NULL); - nr_return_if_fail (NR_IS_ARENA_ITEM (item)); + // setup render parameter if (arena->renderoffscreen == false) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -89,7 +90,7 @@ nr_arena_request_update (NRArena *arena, NRArenaItem *item) arena->blurquality = BLUR_QUALITY_BEST; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; arena->rendermode = Inkscape::RENDERMODE_NORMAL; - arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; + arena->colormode = Inkscape::COLORMODE_NORMAL; } if (aobject->callbacks) { @@ -121,7 +122,7 @@ nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area) arena->blurquality = BLUR_QUALITY_BEST; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; arena->rendermode = Inkscape::RENDERMODE_NORMAL; - arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; + arena->colormode = Inkscape::COLORMODE_NORMAL; } NRRectL nr_area(*area); if (aobject->callbacks) { @@ -155,10 +156,10 @@ void nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit) { arena->cache_limit = cache_limit; - for (std::set::iterator i = arena->cached_items.begin(); + for (std::set::iterator i = arena->cached_items.begin(); i != arena->cached_items.end(); ++i) { - nr_arena_item_request_update(*i, NR_ARENA_ITEM_STATE_CACHE, FALSE); + (*i)->_markForUpdate(Inkscape::DrawingItem::STATE_CACHE, false); } } diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index 5d078e19d..a444ed505 100644 --- a/src/display/nr-arena.h +++ b/src/display/nr-arena.h @@ -13,9 +13,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include #include - +#include +#include <2geom/rect.h> #include "display/rendermode.h" +#include "libnr/nr-forward.h" +#include "libnr/nr-object.h" +#include "display/display-forward.h" G_BEGIN_DECLS @@ -27,19 +32,13 @@ G_END_DECLS #define NR_ARENA(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA, NRArena)) #define NR_IS_ARENA(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA)) -#include -#include <2geom/rect.h> -#include -#include -#include "nr-arena-forward.h" - class SPPainter; NRType nr_arena_get_type (void); struct NRArenaEventVector { NRObjectEventVector parent; - void (* request_update) (NRArena *arena, NRArenaItem *item, void *data); + void (* request_update) (NRArena *arena, Inkscape::DrawingItem *item, void *data); void (* request_render) (NRArena *arena, NRRectL *area, void *data); }; @@ -51,20 +50,22 @@ struct NRArena : public NRActiveObject { double delta; bool renderoffscreen; // if true then rendering must be exact Inkscape::RenderMode rendermode; - Inkscape::ColorRenderMode colorrendermode; + Inkscape::ColorMode colormode; int blurquality; // will be updated during update from preferences int filterquality; // will be updated during update from preferences Geom::OptIntRect cache_limit; - std::set cached_items; + std::set cached_items; guint32 outlinecolor; SPCanvasArena *canvasarena; // may be NULL is this arena is not the screen but used for export etc. + + sigc::signal item_deleted; }; struct NRArenaClass : public NRActiveObjectClass { }; -void nr_arena_request_update (NRArena *arena, NRArenaItem *item); +void nr_arena_request_update (NRArena *arena, Inkscape::DrawingItem *item); void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area); void nr_arena_set_renderoffscreen (NRArena *arena); void nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index eaed2a8bd..039e56bb0 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -16,7 +16,6 @@ #include "display/cairo-templates.h" #include "display/cairo-utils.h" #include "display/nr-3dutils.h" -#include "display/nr-arena-item.h" #include "display/nr-filter-diffuselighting.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 01d2eca64..55cd02697 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -15,7 +15,7 @@ #include "display/cairo-utils.h" #include "display/drawing-context.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "display/nr-filter.h" #include "display/nr-filter-image.h" #include "display/nr-filter-units.h" @@ -70,7 +70,7 @@ void FilterImage::render_cairo(FilterSlot &slot) // TODO: do not recreate the rendering tree every time // TODO: the entire thing is a hack, we should give filter primitives an "update" method - // like the one for NRArenaItems + // like the one for DrawingItems document->ensureUpToDate(); NRArena* arena = NRArena::create(); @@ -78,7 +78,7 @@ void FilterImage::render_cairo(FilterSlot &slot) if (!optarea) return; unsigned const key = SPItem::display_key_new(1); - NRArenaItem* ai = SVGElem->invoke_show(arena, key, SP_ITEM_SHOW_DISPLAY); + DrawingItem *ai = SVGElem->invoke_show(arena, key, SP_ITEM_SHOW_DISPLAY); if (!ai) { g_warning("feImage renderer: error creating NRArenaItem for SVG Element"); @@ -104,15 +104,12 @@ void FilterImage::render_cairo(FilterSlot &slot) ct.translate(render_rect.min()); // Update to renderable state - NRGC gc(NULL); - Geom::Affine t = Geom::identity(); - nr_arena_item_set_transform(ai, &t); - gc.transform.setIdentity(); - nr_arena_item_invoke_update(ai, render_rect, &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render(ct, ai, render_rect, NR_ARENA_ITEM_RENDER_NO_CACHE); + UpdateContext ctx; + ai->setTransform(Geom::identity()); + ai->update(render_rect, ctx, DrawingItem::STATE_ALL, 0); + ai->render(ct, render_rect, DrawingItem::RENDER_BYPASS_CACHE); SVGElem->invoke_hide(key); + //delete ai; // should be deleted by hide() above nr_object_unref((NRObject*) arena); slot.set(_output, out); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 494d77749..d2f992859 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -17,7 +17,6 @@ #include <2geom/transforms.h> #include "display/cairo-utils.h" #include "display/drawing-context.h" -#include "display/nr-arena-item.h" #include "display/nr-filter-types.h" #include "display/nr-filter-gaussian.h" #include "display/nr-filter-slot.h" @@ -26,7 +25,7 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(NRArenaItem *item, DrawingContext &bgct, +FilterSlot::FilterSlot(DrawingItem *item, DrawingContext &bgct, DrawingContext &graphic, FilterUnits const &u) : _item(item) , _source_graphic(graphic.rawTarget()) diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 6a86ded8c..1e7c3a5a6 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -19,17 +19,16 @@ #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" -struct NRArenaItem; - namespace Inkscape { class DrawingContext; +class DrawingItem; namespace Filters { class FilterSlot { public: /** Creates a new FilterSlot object. */ - FilterSlot(NRArenaItem *item, DrawingContext &bgct, + FilterSlot(DrawingItem *item, DrawingContext &bgct, DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); @@ -73,7 +72,7 @@ public: private: typedef std::map SlotMap; SlotMap _slots; - NRArenaItem *_item; + DrawingItem *_item; //Geom::Rect _source_bbox; ///< bounding box of source graphic surface //Geom::Rect _intermediate_bbox; ///< bounding box of intermediate surfaces diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 25ef80c17..abd102452 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -39,7 +39,7 @@ #include "display/nr-filter-turbulence.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "display/drawing-context.h" #include <2geom/affine.h> #include <2geom/rect.h> @@ -97,7 +97,7 @@ Filter::~Filter() } -int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic) +int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic @@ -108,14 +108,14 @@ int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext return 1; } - FilterQuality const filterquality = (FilterQuality)item->arena->filterquality; - int const blurquality = item->arena->blurquality; + FilterQuality const filterquality = (FilterQuality)item->drawing()->filterquality; + int const blurquality = item->drawing()->blurquality; - Geom::Affine trans = item->ctm; + Geom::Affine trans = item->ctm(); Geom::Rect item_bbox; { - Geom::OptRect maybe_bbox = item->item_bbox; + Geom::OptRect maybe_bbox = item->itemBounds(); if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return 1; @@ -161,7 +161,7 @@ int Filter::render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext } } - FilterSlot slot(const_cast(item), bgct, graphic, units); + FilterSlot slot(const_cast(item), bgct, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -188,10 +188,10 @@ void Filter::set_primitive_units(SPFilterUnits unit) { _primitive_units = unit; } -void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { +void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item) const { NRRectL b(bbox); for (unsigned i = 0 ; i < _primitive.size() ; i++) { - if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm); + if (_primitive[i]) _primitive[i]->area_enlarge(b, item->ctm()); } bbox = *b.upgrade_2geom(); @@ -208,7 +208,7 @@ void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { } Geom::Rect item_bbox; - Geom::OptRect maybe_bbox = item->item_bbox; + Geom::OptRect maybe_bbox = item->itemBounds(); if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return; @@ -216,9 +216,9 @@ void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { item_bbox = *maybe_bbox; std::pair res_low - = _filter_resolution(item_bbox, item->ctm, filterquality); + = _filter_resolution(item_bbox, item->ctm(), filterquality); //std::pair res_full - // = _filter_resolution(item_bbox, item->ctm, FILTER_QUALITY_BEST); + // = _filter_resolution(item_bbox, item->ctm(), FILTER_QUALITY_BEST); double pixels_per_block = fmax(item_bbox.width() / res_low.first, item_bbox.height() / res_low.second); bbox.x0 -= (int)pixels_per_block; @@ -228,10 +228,10 @@ void Filter::area_enlarge(Geom::IntRect &bbox, NRArenaItem const *item) const { */ } -Geom::IntRect Filter::compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox) { +Geom::IntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox) { Geom::Rect enlarged = filter_effect_area(item_bbox); - enlarged *= item->ctm; + enlarged *= item->ctm(); Geom::IntRect ret(enlarged.roundOutwards()); return ret; diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 5cebf3ad3..31705f53b 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -21,21 +21,20 @@ #include "sp-filter-units.h" #include "gc-managed.h" -struct NRArenaItem; - namespace Inkscape { class DrawingContext; +class DrawingItem; namespace Filters { -class Filter : public Inkscape::GC::Managed<> { +class Filter { public: /** Given background state from @a bgct and an intermediate rendering from the surface * backing @a graphic, modify the contents of the surface backing @a graphic to represent * the results of filter rendering. @a bgarea and @a area specify bounding boxes * of both surfaces in world coordinates; Cairo contexts are assumed to be in default state * (0,0 = surface origin, no path, OVER operator) */ - int render(NRArenaItem const *item, DrawingContext &bgct, DrawingContext &graphic); + int render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic); /** * Creates a new filter primitive under this filter object. @@ -151,13 +150,13 @@ public: * to be rendered so that after filtering, the original area is * drawn correctly. */ - void area_enlarge(Geom::IntRect &area, NRArenaItem const *item) const; + void area_enlarge(Geom::IntRect &area, Inkscape::DrawingItem const *item) const; /** * Given an item bounding box (in user coords), this function enlarges it * to contain the filter effects region and transforms it to screen * coordinates */ - Geom::IntRect compute_drawbox(NRArenaItem const *item, Geom::Rect const &item_bbox); + Geom::IntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in diff --git a/src/display/rendermode.h b/src/display/rendermode.h index 8fc022bfb..cbd35de73 100644 --- a/src/display/rendermode.h +++ b/src/display/rendermode.h @@ -15,10 +15,10 @@ enum RenderMode { RENDERMODE_OUTLINE }; -enum ColorRenderMode { - COLORRENDERMODE_NORMAL, - COLORRENDERMODE_GRAYSCALE, - COLORRENDERMODE_PRINT_COLORS_PREVIEW +enum ColorMode { + COLORMODE_NORMAL, + COLORMODE_GRAYSCALE, + COLORMODE_PRINT_COLORS_PREVIEW }; } diff --git a/src/document.cpp b/src/document.cpp index 5bcf1bf40..64f4ea92a 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -44,7 +44,7 @@ #include "desktop.h" #include "dir-util.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "document-private.h" #include "helper/units.h" #include "inkscape-private.h" @@ -1113,8 +1113,8 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro for ( SPObject *o = group->firstChild() ; o && !bottomMost; o = o->getNext() ) { if ( SP_IS_ITEM(o) ) { SPItem *item = SP_ITEM(o); - NRArenaItem *arenaitem = item->get_arenaitem(dkey); - if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL + Inkscape::DrawingItem *arenaitem = item->get_arenaitem(dkey); + if (arenaitem && arenaitem->pick(p, delta, 1) != NULL && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { if (g_slist_find((GSList *) list, item) != NULL) { bottomMost = item; @@ -1167,10 +1167,10 @@ SPItem *find_item_at_point(unsigned int dkey, SPGroup *group, Geom::Point const } } else { SPItem *child = SP_ITEM(o); - NRArenaItem *arenaitem = child->get_arenaitem(dkey); + Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); // seen remembers the last (topmost) of items pickable at this point - if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL + if (arenaitem && arenaitem->pick(p, delta, 1) != NULL && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { seen = child; } @@ -1201,10 +1201,10 @@ SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Point const } if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) { SPItem *child = SP_ITEM(o); - NRArenaItem *arenaitem = child->get_arenaitem(dkey); + Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); // seen remembers the last (topmost) of groups pickable at this point - if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL) { + if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) { seen = child; } } diff --git a/src/extension/internal/cairo-png-out.cpp b/src/extension/internal/cairo-png-out.cpp index f741c9f39..4b551e730 100644 --- a/src/extension/internal/cairo-png-out.cpp +++ b/src/extension/internal/cairo-png-out.cpp @@ -28,7 +28,6 @@ #include "extension/db.h" #include "extension/output.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "display/curve.h" #include "display/canvas-bpath.h" @@ -61,7 +60,7 @@ png_render_document_to_file(SPDocument *doc, gchar const *filename) SPItem *base = doc->getRoot(); NRArena *arena = NRArena::create(); unsigned dkey = SPItem::display_key_new(1); - NRArenaItem *root = base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); + base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); /* Create renderer and context */ renderer = new CairoRenderer(); diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 7fdfaf8df..7e5324e57 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -30,7 +30,6 @@ #include "extension/db.h" #include "extension/output.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "display/curve.h" #include "display/canvas-bpath.h" diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 22b68b0ca..c7cba09bb 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -33,8 +33,7 @@ #include #include "display/nr-arena.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena-group.h" +#include "display/display-forward.h" #include "display/curve.h" #include "display/canvas-bpath.h" #include "display/cairo-utils.h" @@ -91,14 +90,14 @@ struct SPClipPathView { SPClipPathView *next; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; NRRect bbox; }; struct SPMaskView { SPMaskView *next; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; NRRect bbox; }; diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 5d7c82bff..5be9e15c3 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -30,7 +30,6 @@ #include "extension/db.h" #include "extension/output.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "display/curve.h" #include "display/canvas-bpath.h" diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 7eb7881dc..76fc5073f 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -37,8 +37,7 @@ #include #include "display/nr-arena.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena-group.h" +#include "display/display-forward.h" #include "display/curve.h" #include "display/canvas-bpath.h" #include "display/cairo-utils.h" @@ -88,14 +87,14 @@ struct SPClipPathView { SPClipPathView *next; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; NRRect bbox; }; struct SPMaskView { SPMaskView *next; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; NRRect bbox; }; diff --git a/src/extension/internal/latex-pstricks-out.cpp b/src/extension/internal/latex-pstricks-out.cpp index 376db7ee3..000280158 100644 --- a/src/extension/internal/latex-pstricks-out.cpp +++ b/src/extension/internal/latex-pstricks-out.cpp @@ -19,7 +19,7 @@ #include "extension/print.h" #include "extension/db.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/display-forward.h" #include "sp-root.h" @@ -73,7 +73,7 @@ void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, /* Release arena */ (mod->base)->invoke_hide (mod->dkey); mod->base = NULL; - mod->root = NULL; + mod->root = NULL; // should have been deleted by invoke_hide nr_object_unref ((NRObject *) mod->arena); mod->arena = NULL; /* end */ diff --git a/src/extension/print.h b/src/extension/print.h index d5218aed8..b3c686d26 100644 --- a/src/extension/print.h +++ b/src/extension/print.h @@ -13,7 +13,7 @@ #include "extension.h" -#include "display/nr-arena-forward.h" +#include "display/display-forward.h" #include "forward.h" #include "sp-item.h" namespace Inkscape { @@ -22,10 +22,10 @@ namespace Extension { class Print : public Extension { public: /* TODO: These are public for the short term, but this should be fixed */ - SPItem *base; /**< TODO: Document these */ - NRArena *arena; /**< TODO: Document these */ - NRArenaItem *root; /**< TODO: Document these */ - unsigned int dkey; /**< TODO: Document these */ + SPItem *base; + NRArena *arena; + Inkscape::DrawingItem *root; + unsigned int dkey; public: Print (Inkscape::XML::Node * in_repr, diff --git a/src/flood-context.cpp b/src/flood-context.cpp index 84c97b096..a71333a4f 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -20,54 +20,53 @@ #include "config.h" #endif +#include <2geom/pathvector.h> #include #include #include +#include -#include "macros.h" -#include "display/sp-canvas.h" -#include "document.h" -#include "sp-namedview.h" -#include "sp-object.h" -#include "sp-rect.h" -#include "selection.h" -#include "desktop-handles.h" +#include "color.h" +#include "context-fns.h" #include "desktop.h" +#include "desktop-handles.h" #include "desktop-style.h" -#include "message-stack.h" -#include "message-context.h" -#include "pixmaps/cursor-paintbucket.xpm" +#include "display/cairo-utils.h" +#include "display/canvas-arena.h" +#include "display/drawing-context.h" +#include "display/drawing-image.h" +#include "display/drawing-item.h" +#include "display/nr-arena.h" +#include "display/sp-canvas.h" +#include "document.h" #include "flood-context.h" -#include "sp-metrics.h" -#include +#include "livarot/Path.h" +#include "livarot/Shape.h" +#include "macros.h" +#include "message-context.h" +#include "message-stack.h" #include "object-edit.h" -#include "xml/repr.h" -#include "xml/node-event-vector.h" #include "preferences.h" -#include "context-fns.h" #include "rubberband.h" +#include "selection.h" #include "shape-editor.h" - -#include "display/nr-arena-item.h" -#include "display/nr-arena.h" -#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" #include "sp-defs.h" -#include "sp-path.h" +#include "sp-item.h" #include "splivarot.h" -#include "livarot/Path.h" -#include "livarot/Shape.h" +#include "sp-metrics.h" +#include "sp-namedview.h" +#include "sp-object.h" +#include "sp-path.h" +#include "sp-rect.h" +#include "sp-root.h" #include "svg/svg.h" -#include "color.h" - -#include "trace/trace.h" #include "trace/imagemap.h" #include "trace/potrace/inkscape-potrace.h" +#include "trace/trace.h" +#include "xml/node-event-vector.h" +#include "xml/repr.h" + +#include "pixmaps/cursor-paintbucket.xpm" using Inkscape::DocumentUndo; @@ -812,15 +811,12 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even Geom::Affine affine = scale * Geom::Translate(-origin * scale); /* Create ArenaItems and set transform */ - NRArenaItem *root = document->getRoot()->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); - nr_arena_item_set_transform(NR_ARENA_ITEM(root), affine); - - NRGC gc(NULL); - gc.transform.setIdentity(); + Inkscape::DrawingItem *root = document->getRoot()->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); + root->setTransform(affine); + Inkscape::UpdateContext ctx; 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); + root->update(final_bbox, ctx, Inkscape::DrawingItem::STATE_ALL, 0); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); guchar *px = g_new(guchar, stride * height); @@ -842,7 +838,7 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even ct.paint(); ct.setOperator(CAIRO_OPERATOR_OVER); - nr_arena_item_invoke_render(ct, root, final_bbox, NR_ARENA_ITEM_RENDER_NO_CACHE ); + root->render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_flush(s); cairo_surface_destroy(s); diff --git a/src/helper/Makefile_insert b/src/helper/Makefile_insert index 2ccec8d16..7110c2025 100644 --- a/src/helper/Makefile_insert +++ b/src/helper/Makefile_insert @@ -18,7 +18,6 @@ ink_common_sources += \ helper/recthull.h \ helper/sp-marshal.cpp \ helper/sp-marshal.h \ - helper/stlport.h \ helper/unit-menu.cpp \ helper/unit-menu.h \ helper/unit-tracker.cpp \ diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index c845da011..959007450 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -24,7 +24,7 @@ #include "helper/png-write.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "display/nr-arena.h" #include "document.h" #include "sp-item.h" @@ -111,43 +111,40 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, { if (width == 0 || height == 0) return NULL; - GdkPixbuf* pixbuf = NULL; - /* Create new arena for offscreen rendering*/ - NRArena *arena = NRArena::create(); - nr_arena_set_renderoffscreen(arena); - unsigned dkey = SPItem::display_key_new(1); + GdkPixbuf* pixbuf = NULL; + /* Create new arena for offscreen rendering*/ + NRArena *arena = NRArena::create(); + nr_arena_set_renderoffscreen(arena); + unsigned dkey = SPItem::display_key_new(1); - doc->ensureUpToDate(); + doc->ensureUpToDate(); - Geom::Rect screen=Geom::Rect(Geom::Point(x0,y0), Geom::Point(x1, y1)); + Geom::Rect screen=Geom::Rect(Geom::Point(x0,y0), Geom::Point(x1, y1)); - double padding = 1.0; + double padding = 1.0; - Geom::Point origin(screen.min()[Geom::X], - doc->getHeight() - screen[Geom::Y].extent() - screen.min()[Geom::Y]); + Geom::Point origin(screen.min()[Geom::X], + doc->getHeight() - screen[Geom::Y].extent() - screen.min()[Geom::Y]); - origin[Geom::X] = origin[Geom::X] + (screen[Geom::X].extent() * ((1 - padding) / 2)); - origin[Geom::Y] = origin[Geom::Y] + (screen[Geom::Y].extent() * ((1 - padding) / 2)); + origin[Geom::X] = origin[Geom::X] + (screen[Geom::X].extent() * ((1 - padding) / 2)); + origin[Geom::Y] = origin[Geom::Y] + (screen[Geom::Y].extent() * ((1 - padding) / 2)); - Geom::Scale scale( (xdpi / PX_PER_IN), (ydpi / PX_PER_IN)); - Geom::Affine affine = scale * Geom::Translate(-origin * scale); + Geom::Scale scale( (xdpi / PX_PER_IN), (ydpi / PX_PER_IN)); + Geom::Affine affine = scale * Geom::Translate(-origin * scale); - /* Create ArenaItems and set transform */ - NRArenaItem *root = doc->getRoot()->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); - nr_arena_item_set_transform(NR_ARENA_ITEM(root), affine); + /* Create ArenaItems and set transform */ + Inkscape::DrawingItem *root = doc->getRoot()->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); + root->setTransform(affine); + Inkscape::UpdateContext ctx; - NRGC gc(NULL); - gc.transform.setIdentity(); - - // We show all and then hide all items we don't want, instead of showing only requested items, - // because that would not work if the shown item references something in defs - if (items_only) { - hide_other_items_recursively(doc->getRoot(), items_only, dkey); - } + // We show all and then hide all items we don't want, instead of showing only requested items, + // because that would not work if the shown item references something in defs + if (items_only) { + hide_other_items_recursively(doc->getRoot(), items_only, dkey); + } 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); + root->update(final_bbox, ctx, Inkscape::DrawingItem::STATE_ALL, 0); cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); @@ -155,7 +152,7 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, Inkscape::DrawingContext ct(surface, Geom::Point(0,0)); // render items - nr_arena_item_invoke_render(ct, root, final_bbox, NR_ARENA_ITEM_RENDER_NO_CACHE ); + root->render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_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 d2983806a..7812969a0 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -24,7 +24,7 @@ #include "png-write.h" #include "io/sys.h" #include "display/drawing-context.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "display/nr-arena.h" #include "document.h" #include "sp-item.h" @@ -51,7 +51,7 @@ static unsigned int const MAX_STRIPE_SIZE = 1024*1024; struct SPEBP { unsigned long int width, height, sheight; guint32 background; - NRArenaItem *root; // the root arena item to show; it is assumed that all unneeded items are hidden + Inkscape::DrawingItem *root; // the root arena item to show; it is assumed that all unneeded items are hidden guchar *px; unsigned (*status)(float, void *); void *data; @@ -326,11 +326,8 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v 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_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); + Inkscape::UpdateContext ctx; + ebp->root->update(bbox, ctx, Inkscape::DrawingItem::STATE_ALL, 0); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ebp->width); unsigned char *px = g_new(guchar, num_rows * stride); @@ -344,7 +341,7 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v ct.setOperator(CAIRO_OPERATOR_OVER); /* Render */ - nr_arena_item_invoke_render(ct, ebp->root, bbox, 0); + ebp->root->render(ct, bbox, 0); cairo_surface_destroy(s); *to_free = px; @@ -462,7 +459,7 @@ sp_export_png_file(SPDocument *doc, gchar const *filename, // Create ArenaItems and set transform ebp.root = doc->getRoot()->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); - nr_arena_item_set_transform(NR_ARENA_ITEM(ebp.root), affine); + ebp.root->setTransform(affine); // We show all and then hide all items we don't want, instead of showing only requested items, // because that would not work if the shown item references something in defs diff --git a/src/interface.cpp b/src/interface.cpp index 25153097d..a981424fa 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -646,7 +646,7 @@ update_view_menu(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view"); SPDesktop *dt = static_cast(view); Inkscape::RenderMode mode = dt->getMode(); - Inkscape::ColorRenderMode colormode = dt->getColorMode(); + Inkscape::ColorMode colormode = dt->getColorMode(); bool new_state = false; if (!strcmp(action->id, "ViewModeNormal")) { @@ -656,11 +656,11 @@ update_view_menu(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat } else if (!strcmp(action->id, "ViewModeOutline")) { new_state = mode == Inkscape::RENDERMODE_OUTLINE; } else if (!strcmp(action->id, "ViewColorModeNormal")) { - new_state = colormode == Inkscape::COLORRENDERMODE_NORMAL; + new_state = colormode == Inkscape::COLORMODE_NORMAL; } else if (!strcmp(action->id, "ViewColorModeGrayscale")) { - new_state = colormode == Inkscape::COLORRENDERMODE_GRAYSCALE; + new_state = colormode == Inkscape::COLORMODE_GRAYSCALE; } else if (!strcmp(action->id, "ViewColorModePrintColorsPreview")) { - new_state = colormode == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW; + new_state = colormode == Inkscape::COLORMODE_PRINT_COLORS_PREVIEW; } else { g_warning("update_view_menu does not handle this verb"); } diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index 610f92582..a72fa0180 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -10,7 +10,7 @@ */ #include #include "Layout-TNG.h" -#include "display/nr-arena-glyphs.h" +#include "display/drawing-text.h" #include "style.h" #include "print.h" #include "extension/print.h" @@ -81,28 +81,27 @@ void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) con } } -void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const +void Layout::show(DrawingGroup *in_arena, NRRect const *paintbox) const { int glyph_index = 0; for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) { if (_input_stream[_spans[span_index].in_input_stream_item]->Type() != TEXT_SOURCE) continue; InputStreamTextSource const *text_source = static_cast(_input_stream[_spans[span_index].in_input_stream_item]); - NRArenaGlyphsGroup *nr_group = NRArenaGlyphsGroup::create(in_arena->arena); - nr_arena_item_add_child(in_arena, nr_group, NULL); - nr_arena_item_unref(nr_group); - nr_arena_glyphs_group_set_style(nr_group, text_source->style); + DrawingText *nr_text = new DrawingText(in_arena->drawing()); + nr_text->setStyle(text_source->style); + while (glyph_index < (int)_glyphs.size() && _characters[_glyphs[glyph_index].in_character].in_span == span_index) { if (_characters[_glyphs[glyph_index].in_character].in_glyph != -1) { Geom::Affine glyph_matrix; _getGlyphTransformMatrix(glyph_index, &glyph_matrix); - nr_arena_glyphs_group_add_component(nr_group, _spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix); + nr_text->addComponent(_spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix); } glyph_index++; } - nr_arena_glyphs_group_set_paintbox(NR_ARENA_GLYPHS_GROUP(nr_group), paintbox); + nr_text->setPaintBox(paintbox ? paintbox->upgrade_2geom() : Geom::OptRect()); + in_arena->prependChild(nr_text); } - nr_arena_item_request_update(NR_ARENA_ITEM(in_arena), NR_ARENA_ITEM_STATE_ALL, FALSE); } void Layout::getBoundingBox(NRRect *bounding_box, Geom::Affine const &transform, int start, int length) const diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index 6ab02c0e3..25f80e9e9 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -37,7 +37,6 @@ using Inkscape::Extension::Internal::CairoRenderContext; class SPStyle; class Shape; -class NRArenaGroup; class SPPrintContext; class SVGLength; class Path; @@ -46,6 +45,8 @@ class font_instance; typedef struct _PangoFontDescription PangoFontDescription; namespace Inkscape { +class DrawingGroup; + namespace Text { /** \brief Generates the layout for either wrapped or non-wrapped text and stores the result @@ -327,7 +328,7 @@ public: \param in_arena The arena to add the glyphs group to \param paintbox The current rendering tile */ - void show(NRArenaGroup *in_arena, NRRect const *paintbox) const; + void show(DrawingGroup *in_arena, NRRect const *paintbox) const; /** Calculates the smallest rectangle completely enclosing all the glyphs. diff --git a/src/marker.cpp b/src/marker.cpp index d3fa83ed6..11a270e73 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -21,7 +21,7 @@ #include <2geom/affine.h> #include <2geom/transforms.h> #include "svg/svg.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "xml/repr.h" #include "attributes.h" #include "marker.h" @@ -31,7 +31,7 @@ struct SPMarkerView { SPMarkerView *next; unsigned int key; - std::vector items; + std::vector items; }; static void sp_marker_class_init (SPMarkerClass *klass); @@ -43,7 +43,7 @@ static void sp_marker_set (SPObject *object, unsigned int key, const gchar *valu static void sp_marker_update (SPObject *object, SPCtx *ctx, guint flags); static Inkscape::XML::Node *sp_marker_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static NRArenaItem *sp_marker_private_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_marker_private_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_marker_private_hide (SPItem *item, unsigned int key); static void sp_marker_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_marker_print (SPItem *item, SPPrintContext *ctx); @@ -448,8 +448,8 @@ static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) for (SPMarkerView *v = marker->views; v != NULL; v = v->next) { for (unsigned i = 0 ; i < v->items.size() ; i++) { if (v->items[i]) { - Geom::Affine tmp = marker->c2p; - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->items[i]), &tmp); + Inkscape::DrawingGroup *g = dynamic_cast(v->items[i]); + g->setChildTransform(marker->c2p); } } } @@ -522,7 +522,7 @@ sp_marker_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::X /** * This routine is disabled to break propagation. */ -static NRArenaItem * +static Inkscape::DrawingItem * sp_marker_private_show (SPItem */*item*/, NRArena */*arena*/, unsigned int /*key*/, unsigned int /*flags*/) { /* Break propagation */ @@ -560,14 +560,14 @@ sp_marker_print (SPItem */*item*/, SPPrintContext */*ctx*/) /** * Removes any SPMarkerViews that a marker has with a specific key. - * Set up the NRArenaItem array's size in the specified SPMarker's SPMarkerView. + * Set up the DrawingItem array's size in the specified SPMarker's SPMarkerView. * This is called from sp_shape_update() for shapes that have markers. It * removes the old view of the marker and establishes a new one, registering * it with the marker's list of views for future updates. * * \param marker Marker to create views in. * \param key Key to give each SPMarkerView. - * \param size Number of NRArenaItems to put in the SPMarkerView. + * \param size Number of DrawingItems to put in the SPMarkerView. */ void sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size) @@ -601,8 +601,8 @@ sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size) * Shows an instance of a marker. This is called during sp_shape_update_marker_view() * show and transform a child item in the arena for all views with the given key. */ -NRArenaItem * -sp_marker_show_instance ( SPMarker *marker, NRArenaItem *parent, +Inkscape::DrawingItem * +sp_marker_show_instance ( SPMarker *marker, Inkscape::DrawingItem *parent, unsigned int key, unsigned int pos, Geom::Affine const &base, float linewidth) { @@ -621,14 +621,13 @@ sp_marker_show_instance ( SPMarker *marker, NRArenaItem *parent, if (!v->items[pos]) { /* Parent class ::show method */ v->items[pos] = ((SPItemClass *) parent_class)->show ((SPItem *) marker, - parent->arena, key, + parent->drawing(), key, SP_ITEM_REFERENCE_FLAGS); if (v->items[pos]) { /* fixme: Position (Lauris) */ - nr_arena_item_add_child (parent, v->items[pos], NULL); - /* nr_arena_item_unref (v->items[pos]); */ - Geom::Affine tmp = marker->c2p; - nr_arena_group_set_child_transform((NRArenaGroup *) v->items[pos], &tmp); + parent->prependChild(v->items[pos]); + Inkscape::DrawingGroup *g = dynamic_cast(v->items[pos]); + if (g) g->setChildTransform(marker->c2p); } } if (v->items[pos]) { @@ -643,8 +642,7 @@ sp_marker_show_instance ( SPMarker *marker, NRArenaItem *parent, if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { m = Geom::Scale(linewidth) * m; } - - nr_arena_item_set_transform(v->items[pos], m); + v->items[pos]->setTransform(m); } return v->items[pos]; } @@ -695,7 +693,7 @@ sp_marker_view_remove (SPMarker *marker, SPMarkerView *view, unsigned int destro if (destroyitems) { for (i = 0; i < view->items.size(); i++) { /* We have to walk through the whole array because there may be hidden items */ - if (view->items[i]) nr_arena_item_unref (view->items[i]); + delete view->items[i]; } } view->items.clear(); diff --git a/src/marker.h b/src/marker.h index 09461b3a1..eb907e2fb 100644 --- a/src/marker.h +++ b/src/marker.h @@ -85,7 +85,7 @@ protected: }; void sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size); -NRArenaItem *sp_marker_show_instance (SPMarker *marker, NRArenaItem *parent, +Inkscape::DrawingItem *sp_marker_show_instance (SPMarker *marker, Inkscape::DrawingItem *parent, unsigned int key, unsigned int pos, Geom::Affine const &base, float linewidth); void sp_marker_hide (SPMarker *marker, unsigned int key); diff --git a/src/print.cpp b/src/print.cpp index 1ee58a3e6..29c5b0ed2 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -15,6 +15,8 @@ # include "config.h" #endif +#include "display/nr-arena.h" +#include "display/drawing-item.h" #include "inkscape.h" #include "desktop.h" #include "sp-item.h" @@ -80,9 +82,6 @@ unsigned int sp_print_text(SPPrintContext *ctx, char const *text, Geom::Point p, return ctx->module->text(text, p, style); } -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" - /* UI */ void @@ -92,19 +91,11 @@ sp_print_document(Gtk::Window& parentWindow, SPDocument *doc) // Build arena SPItem *base = doc->getRoot(); - NRArena *arena = NRArena::create(); - unsigned int dkey = SPItem::display_key_new(1); - // TODO investigate why we are grabbing root and then ignoring it. - NRArenaItem *root = base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); // Run print dialog Inkscape::UI::Dialog::Print printop(doc,base); Gtk::PrintOperationResult res = printop.run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, parentWindow); (void)res; // TODO handle this - - // Release arena - base->invoke_hide(dkey); - nr_object_unref((NRObject *) arena); } void @@ -138,8 +129,8 @@ sp_print_document_to_file(SPDocument *doc, gchar const *filename) /* Release arena */ (mod->base)->invoke_hide(mod->dkey); mod->base = NULL; - mod->root = NULL; nr_object_unref((NRObject *) mod->arena); + mod->root = NULL; // should be deleted by invoke_hide mod->arena = NULL; /* end */ diff --git a/src/print.h b/src/print.h index caea6ae3a..6bdbe4b82 100644 --- a/src/print.h +++ b/src/print.h @@ -17,6 +17,7 @@ #include "forward.h" #include "extension/extension-forward.h" +struct NRRect; struct SPPrintContext { Inkscape::Extension::Print *module; }; diff --git a/src/select-context.cpp b/src/select-context.cpp index 143fb1ae2..b3e38bf7b 100644 --- a/src/select-context.cpp +++ b/src/select-context.cpp @@ -43,7 +43,7 @@ #include "seltrans.h" #include "box3d.h" #include "display/sp-canvas.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" using Inkscape::DocumentUndo; @@ -414,7 +414,7 @@ sp_select_context_cycle_through_items(SPSelectContext *sc, Inkscape::Selection * if (!sc->cycling_cur_item) return; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; SPItem *item = SP_ITEM(sc->cycling_cur_item->data); @@ -422,7 +422,7 @@ sp_select_context_cycle_through_items(SPSelectContext *sc, Inkscape::Selection * if (!g_list_find(sc->cycling_items_selected_before, item) && selection->includes(item)) selection->remove(item); arenaitem = item->get_arenaitem(desktop->dkey); - nr_arena_item_set_opacity (arenaitem, 0.3); + arenaitem->setOpacity(0.3); // Find next item and activate it GList *next; @@ -438,7 +438,7 @@ sp_select_context_cycle_through_items(SPSelectContext *sc, Inkscape::Selection * sc->cycling_cur_item = next; item = SP_ITEM(sc->cycling_cur_item->data); arenaitem = item->get_arenaitem(desktop->dkey); - nr_arena_item_set_opacity (arenaitem, 1.0); + arenaitem->setOpacity(1.0); if (shift_pressed) selection->add(item); @@ -788,10 +788,10 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) g_assert(sc->cycling_cur_item != NULL || sc->cycling_items == NULL); } else { // ... otherwise reset opacities for outdated items ... - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; for(GList *l = sc->cycling_items_cmp; l != NULL; l = l->next) { arenaitem = SP_ITEM(l->data)->get_arenaitem(desktop->dkey); - nr_arena_item_set_opacity (arenaitem, 1.0); + arenaitem->setOpacity(1.0); //if (!shift_pressed && !g_list_find(sc->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) if (!g_list_find(sc->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) selection->remove(SP_ITEM(l->data)); @@ -810,7 +810,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) for(GList *l = sc->cycling_items; l != NULL; l = l->next) { item = SP_ITEM(l->data); arenaitem = item->get_arenaitem(desktop->dkey); - nr_arena_item_set_opacity (arenaitem, 0.3); + arenaitem->setOpacity(0.3); if (selection->includes(item)) { // already selected items are stored separately, too sc->cycling_items_selected_before = g_list_append(sc->cycling_items_selected_before, item); @@ -1085,10 +1085,10 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (alt) { // TODO: Should we have a variable like is_cycling or is it harmless to run this piece of code each time? // quit cycle-selection and reset opacities SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; for (GList *l = sc->cycling_items; l != NULL; l = g_list_next(l)) { arenaitem = SP_ITEM(l->data)->get_arenaitem(desktop->dkey); - nr_arena_item_set_opacity (arenaitem, 1.0); + arenaitem->setOpacity(1.0); } g_list_free(sc->cycling_items); g_list_free(sc->cycling_items_selected_before); diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 48e466628..14c206828 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -16,7 +16,7 @@ #include #include "display/nr-arena.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "xml/repr.h" #include "enums.h" @@ -24,6 +24,7 @@ #include "document.h" #include "document-private.h" #include "sp-item.h" +#include "style.h" #include <2geom/transforms.h> @@ -32,11 +33,11 @@ struct SPClipPathView { SPClipPathView *next; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; NRRect bbox; }; -SPClipPathView *sp_clippath_view_new_prepend(SPClipPathView *list, unsigned int key, NRArenaItem *arenaitem); +SPClipPathView *sp_clippath_view_new_prepend(SPClipPathView *list, unsigned int key, Inkscape::DrawingItem *arenaitem); SPClipPathView *sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view); SPObjectGroupClass * SPClipPathClass::static_parent_class = 0; @@ -155,11 +156,11 @@ void SPClipPath::childAdded(SPObject *object, Inkscape::XML::Node *child, Inksca if (SP_IS_ITEM(ochild)) { SPClipPath *cp = SP_CLIPPATH(object); for (SPClipPathView *v = cp->display; v != NULL; v = v->next) { - NRArenaItem *ac = SP_ITEM(ochild)->invoke_show( NR_ARENA_ITEM_ARENA(v->arenaitem), + Inkscape::DrawingItem *ac = SP_ITEM(ochild)->invoke_show( v->arenaitem->drawing(), v->key, SP_ITEM_REFERENCE_FLAGS); if (ac) { - nr_arena_item_add_child(v->arenaitem, ac, NULL); + v->arenaitem->prependChild(ac); } } } @@ -191,13 +192,14 @@ void SPClipPath::update(SPObject *object, SPCtx *ctx, guint flags) SPClipPath *cp = SP_CLIPPATH(object); for (SPClipPathView *v = cp->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { Geom::Affine t(Geom::Scale(v->bbox.x1 - v->bbox.x0, v->bbox.y1 - v->bbox.y0)); t[4] = v->bbox.x0; t[5] = v->bbox.y0; - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), &t); + g->setChildTransform(t); } else { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), NULL); + g->setChildTransform(Geom::identity()); } } } @@ -240,20 +242,20 @@ Inkscape::XML::Node *SPClipPath::write(SPObject *object, Inkscape::XML::Document return repr; } -NRArenaItem *SPClipPath::show(NRArena *arena, unsigned int key) +Inkscape::DrawingItem *SPClipPath::show(NRArena *arena, unsigned int key) { g_return_val_if_fail(arena != NULL, NULL); g_return_val_if_fail(NR_IS_ARENA(arena), NULL); - NRArenaItem *ai = NRArenaGroup::create(arena); + Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(arena); display = sp_clippath_view_new_prepend(display, key, ai); for ( SPObject *child = firstChild() ; child ; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - NRArenaItem *ac = SP_ITEM(child)->invoke_show(arena, key, SP_ITEM_REFERENCE_FLAGS); + Inkscape::DrawingItem *ac = SP_ITEM(child)->invoke_show(arena, key, SP_ITEM_REFERENCE_FLAGS); if (ac) { /* The order is not important in clippath */ - nr_arena_item_add_child(ai, ac, NULL); + ai->appendChild(ac); } } } @@ -262,9 +264,9 @@ NRArenaItem *SPClipPath::show(NRArena *arena, unsigned int key) Geom::Affine t(Geom::Scale(display->bbox.x1 - display->bbox.x0, display->bbox.y1 - display->bbox.y0)); t[4] = display->bbox.x0; t[5] = display->bbox.y0; - nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), &t); + ai->setChildTransform(t); } - nr_arena_group_set_style(NR_ARENA_GROUP(ai), this->style); + ai->setStyle(this->style); return ai; } @@ -329,13 +331,13 @@ void SPClipPath::getBBox(NRRect *bbox, Geom::Affine const &transform, unsigned c /* ClipPath views */ SPClipPathView * -sp_clippath_view_new_prepend(SPClipPathView *list, unsigned int key, NRArenaItem *arenaitem) +sp_clippath_view_new_prepend(SPClipPathView *list, unsigned int key, Inkscape::DrawingItem *arenaitem) { SPClipPathView *new_path_view = g_new(SPClipPathView, 1); new_path_view->next = list; new_path_view->key = key; - new_path_view->arenaitem = nr_arena_item_ref(arenaitem); + new_path_view->arenaitem = arenaitem; new_path_view->bbox.x0 = new_path_view->bbox.x1 = 0.0; new_path_view->bbox.y0 = new_path_view->bbox.y1 = 0.0; @@ -354,7 +356,7 @@ sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view) prev->next = view->next; } - nr_arena_item_unref(view->arenaitem); + delete view->arenaitem; g_free(view); return list; diff --git a/src/sp-clippath.h b/src/sp-clippath.h index d3c650ca6..d163e0709 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -23,7 +23,7 @@ class SPClipPathView; -#include "display/nr-arena-forward.h" +#include "display/display-forward.h" #include "libnr/nr-forward.h" #include "sp-object-group.h" #include "uri-references.h" @@ -40,7 +40,7 @@ public: static const gchar *create(GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); static GType sp_clippath_get_type(void); - NRArenaItem *show(NRArena *arena, unsigned int key); + Inkscape::DrawingItem *show(NRArena *arena, unsigned int key); void hide(unsigned int key); void setBBox(unsigned int key, NRRect *bbox); diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index 87266464c..cbdc8684b 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -31,7 +31,7 @@ #include "livarot/Shape.h" -#include "display/nr-arena-glyphs.h" +#include "display/drawing-text.h" static void sp_flowtext_class_init(SPFlowtextClass *klass); @@ -50,7 +50,7 @@ static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Affine cons static void sp_flowtext_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_flowtext_description(SPItem *item); static void sp_flowtext_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); -static NRArenaItem *sp_flowtext_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); +static Inkscape::DrawingItem *sp_flowtext_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); static void sp_flowtext_hide(SPItem *item, unsigned key); static SPItemClass *parent_class; @@ -179,10 +179,11 @@ static void sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) NRRect paintbox; group->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView *v = group->display; v != NULL; v = v->next) { - group->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + group->_clearFlow(g); + g->setStyle(object->style); // pass the bbox of the flowtext object as paintbox (used for paintserver fills) - group->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); + group->layout.show(g, &paintbox); } } @@ -200,9 +201,10 @@ static void sp_flowtext_modified(SPObject *object, guint flags) NRRect paintbox; text->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView* v = text->display; v != NULL; v = v->next) { - text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); - text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + text->_clearFlow(g); + g->setStyle(object->style); + text->layout.show(g, &paintbox); } } @@ -406,14 +408,13 @@ static void sp_flowtext_snappoints(SPItem const *item, std::vectorstyle); + Inkscape::DrawingGroup *flowed = new Inkscape::DrawingGroup(arena); + flowed->setPickChildren(false); + flowed->setStyle(group->style); // pass the bbox of the flowtext object as paintbox (used for paintserver fills) NRRect paintbox; @@ -541,17 +542,9 @@ void SPFlowtext::rebuildLayout() //g_print(layout.dumpAsText().c_str()); } -void SPFlowtext::_clearFlow(NRArenaGroup *in_arena) +void SPFlowtext::_clearFlow(Inkscape::DrawingGroup *in_arena) { - nr_arena_item_request_render(NR_ARENA_ITEM(in_arena)); - for (NRArenaItem *child = in_arena->children; child != NULL; ) { - NRArenaItem *nchild = child->next; - - nr_arena_glyphs_group_clear(NR_ARENA_GLYPHS_GROUP(child)); - nr_arena_item_remove_child(NR_ARENA_ITEM(in_arena), child); - - child = nchild; - } + in_arena->clearChildren(); } Inkscape::XML::Node *SPFlowtext::getAsText() diff --git a/src/sp-flowtext.h b/src/sp-flowtext.h index 3b0ce178a..d06105c30 100644 --- a/src/sp-flowtext.h +++ b/src/sp-flowtext.h @@ -6,7 +6,7 @@ #include "sp-item.h" -#include "display/nr-arena-forward.h" +#include "display/display-forward.h" #include <2geom/forward.h> #include "libnrtype/Layout-TNG.h" @@ -32,7 +32,7 @@ struct SPFlowtext : public SPItem { Inkscape::Text::Layout layout; /** discards the NRArena objects representing this text. */ - void _clearFlow(NRArenaGroup* in_arena); + void _clearFlow(Inkscape::DrawingGroup* in_arena); double par_indent; diff --git a/src/sp-image.cpp b/src/sp-image.cpp index c9647c939..3a1280aa0 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -28,7 +28,7 @@ #include <2geom/transforms.h> #include -#include "display/nr-arena-image.h" +#include "display/drawing-image.h" #include "display/cairo-utils.h" #include "display/curve.h" //Added for preserveAspectRatio support -- EAF @@ -84,14 +84,14 @@ static void sp_image_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const & static void sp_image_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_image_description (SPItem * item); static void sp_image_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); -static NRArenaItem *sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static Geom::Affine sp_image_set_transform (SPItem *item, Geom::Affine const &xform); static void sp_image_set_curve(SPImage *image); static GdkPixbuf *sp_image_repr_read_image( time_t& modTime, gchar*& pixPath, const gchar *href, const gchar *absref, const gchar *base ); static GdkPixbuf *sp_image_pixbuf_force_rgba (GdkPixbuf * pixbuf); -static void sp_image_update_arenaitem (SPImage *img, NRArenaImage *ai); +static void sp_image_update_arenaitem (SPImage *img, Inkscape::DrawingImage *ai); static void sp_image_update_canvas_image (SPImage *image); static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data); static GdkPixbuf * sp_image_repr_read_b64 (const gchar * uri_data); @@ -1018,7 +1018,8 @@ static void sp_image_modified( SPObject *object, unsigned int flags ) if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = image->display; v != NULL; v = v->next) { - nr_arena_image_set_style (NR_ARENA_IMAGE (v->arenaitem), object->style); + Inkscape::DrawingImage *img = dynamic_cast(v->arenaitem); + img->setStyle(object->style); } } } @@ -1148,12 +1149,12 @@ static gchar *sp_image_description( SPItem *item ) return ret; } -static NRArenaItem *sp_image_show( SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/ ) +static Inkscape::DrawingItem *sp_image_show( SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/ ) { SPImage * image = SP_IMAGE(item); - NRArenaItem *ai = NRArenaImage::create(arena); + Inkscape::DrawingImage *ai = new Inkscape::DrawingImage(arena); - sp_image_update_arenaitem(image, NR_ARENA_IMAGE(ai)); + sp_image_update_arenaitem(image, ai); return ai; } @@ -1264,13 +1265,13 @@ static GdkPixbuf *sp_image_pixbuf_force_rgba( GdkPixbuf * pixbuf ) /* We assert that realpixbuf is either NULL or identical size to pixbuf */ static void -sp_image_update_arenaitem (SPImage *image, NRArenaImage *ai) +sp_image_update_arenaitem (SPImage *image, Inkscape::DrawingImage *ai) { - nr_arena_image_set_style(ai, SP_OBJECT(image)->style); - nr_arena_image_set_argb32_pixbuf(ai, image->pixbuf); - nr_arena_image_set_origin(ai, Geom::Point(image->ox, image->oy)); - nr_arena_image_set_scale(ai, image->sx, image->sy); - nr_arena_image_set_clipbox(ai, image->clipbox); + ai->setStyle(SP_OBJECT(image)->style); + ai->setARGB32Pixbuf(image->pixbuf); + ai->setOrigin(Geom::Point(image->ox, image->oy)); + ai->setScale(image->sx, image->sy); + ai->setClipbox(image->clipbox); } static void sp_image_update_canvas_image(SPImage *image) @@ -1278,7 +1279,7 @@ static void sp_image_update_canvas_image(SPImage *image) SPItem *item = SP_ITEM(image); for (SPItemView *v = item->display; v != NULL; v = v->next) { - sp_image_update_arenaitem(image, NR_ARENA_IMAGE(v->arenaitem)); + sp_image_update_arenaitem(image, dynamic_cast(v->arenaitem)); } } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 491b2a62a..c27319c83 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -22,7 +22,7 @@ #include #include -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "display/curve.h" #include "xml/repr.h" #include "svg/svg.h" @@ -68,7 +68,7 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value); static void sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_group_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_group_description (SPItem * item); -static NRArenaItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_group_hide (SPItem * item, unsigned int key); static void sp_group_snappoints (SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); @@ -312,7 +312,7 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value) { } } -static NRArenaItem * +static Inkscape::DrawingItem * sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) { return SP_GROUP(item)->group->show(arena, key, flags); @@ -562,9 +562,9 @@ void SPGroup::_updateLayerMode(unsigned int display_key) { SPItemView *view; for ( view = this->display ; view ; view = view->next ) { if ( !display_key || view->key == display_key ) { - NRArenaGroup *arena_group=NR_ARENA_GROUP(view->arenaitem); - if (arena_group) { - nr_arena_group_set_transparent(arena_group, effectiveLayerMode(view->key) == SPGroup::LAYER); + Inkscape::DrawingGroup *g = dynamic_cast(view->arenaitem); + if (g) { + g->setPickChildren(effectiveLayerMode(view->key) == SPGroup::LAYER); } } } @@ -596,13 +596,13 @@ void CGroup::onChildAdded(Inkscape::XML::Node *child) { if ( SP_IS_ITEM(ochild) ) { /* TODO: this should be moved into SPItem somehow */ SPItemView *v; - NRArenaItem *ac; + Inkscape::DrawingItem *ac; for (v = _group->display; v != NULL; v = v->next) { - ac = SP_ITEM (ochild)->invoke_show (NR_ARENA_ITEM_ARENA (v->arenaitem), v->key, v->flags); + ac = SP_ITEM (ochild)->invoke_show (v->arenaitem->drawing(), v->key, v->flags); if (ac) { - nr_arena_item_append_child (v->arenaitem, ac); + v->arenaitem->appendChild(ac); } } } @@ -611,16 +611,16 @@ void CGroup::onChildAdded(Inkscape::XML::Node *child) { if ( ochild && SP_IS_ITEM(ochild) ) { /* TODO: this should be moved into SPItem somehow */ SPItemView *v; - NRArenaItem *ac; + Inkscape::DrawingItem *ac; unsigned position = SP_ITEM(ochild)->pos_in_parent(); for (v = _group->display; v != NULL; v = v->next) { - ac = SP_ITEM (ochild)->invoke_show (NR_ARENA_ITEM_ARENA (v->arenaitem), v->key, v->flags); + ac = SP_ITEM (ochild)->invoke_show (v->arenaitem->drawing(), v->key, v->flags); if (ac) { - nr_arena_item_add_child (v->arenaitem, ac, NULL); - nr_arena_item_set_order (ac, position); + v->arenaitem->prependChild(ac); + ac->setZOrder(position); } } } @@ -646,10 +646,11 @@ void CGroup::onUpdate(SPCtx *ctx, unsigned int flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - SPObject *object = _group; - for (SPItemView *v = _group->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); - } + SPObject *object = _group; + for (SPItemView *v = _group->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *group = dynamic_cast(v->arenaitem); + group->setStyle(object->style); + } } GSList *l = g_slist_reverse(_group->childList(true, SPObject::ActionUpdate)); @@ -677,10 +678,11 @@ void CGroup::onModified(guint flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - SPObject *object = _group; - for (SPItemView *v = _group->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); - } + SPObject *object = _group; + for (SPItemView *v = _group->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *group = dynamic_cast(v->arenaitem); + group->setStyle(object->style); + } } GSList *l = g_slist_reverse(_group->childList(true)); @@ -742,24 +744,20 @@ gchar *CGroup::getDescription() { len), len); } -NRArenaItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) { - NRArenaItem *ai; +Inkscape::DrawingItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) { + Inkscape::DrawingGroup *ai; SPObject *object = _group; - ai = NRArenaGroup::create(arena); - - nr_arena_group_set_transparent(NR_ARENA_GROUP (ai), - _group->effectiveLayerMode(key) == - SPGroup::LAYER); - nr_arena_group_set_style(NR_ARENA_GROUP(ai), object->style); + ai = new Inkscape::DrawingGroup(arena); + ai->setPickChildren(_group->effectiveLayerMode(key) == SPGroup::LAYER); + ai->setStyle(object->style); _showChildren(arena, ai, key, flags); return ai; } -void CGroup::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) { - NRArenaItem *ac = NULL; - NRArenaItem *ar = NULL; +void CGroup::_showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { + Inkscape::DrawingItem *ac = NULL; SPItem * child = NULL; GSList *l = g_slist_reverse(_group->childList(false, SPObject::ActionShow)); while (l) { @@ -767,10 +765,7 @@ void CGroup::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, u if (SP_IS_ITEM (o)) { child = SP_ITEM (o); ac = child->invoke_show (arena, key, flags); - if (ac) { - nr_arena_item_add_child (ai, ac, ar); - ar = ac; - } + ai->appendChild(ac); } l = g_slist_remove (l, o); } @@ -801,7 +796,7 @@ void CGroup::onOrderChanged (Inkscape::XML::Node *child, Inkscape::XML::Node *, SPItemView *v; unsigned position = SP_ITEM(ochild)->pos_in_parent(); for ( v = SP_ITEM (ochild)->display ; v != NULL ; v = v->next ) { - nr_arena_item_set_order (v->arenaitem, position); + v->arenaitem->setZOrder(position); } } diff --git a/src/sp-item-group.h b/src/sp-item-group.h index e2aeb8bc5..88586a6b0 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -73,13 +73,13 @@ public: virtual void onPrint(SPPrintContext *ctx); virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); virtual gchar *getDescription(); - virtual NRArenaItem *show (NRArena *arena, unsigned int key, unsigned int flags); + virtual Inkscape::DrawingItem *show (NRArena *arena, unsigned int key, unsigned int flags); virtual void hide (unsigned int key); gint getItemCount(); protected: - virtual void _showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags); + virtual void _showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); SPGroup *_group; }; diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 946c94353..9ab924423 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -30,7 +30,7 @@ #include "svg/svg.h" #include "print.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-item.h" #include "attributes.h" #include "document.h" #include "uri.h" @@ -145,14 +145,10 @@ void SPItem::init() { display = NULL; clip_ref = new SPClipPathReference(this); - sigc::signal cs1 = clip_ref->changedSignal(); - sigc::slot2 sl1 = sigc::bind(sigc::ptr_fun(clip_ref_changed), this); - _clip_ref_connection = cs1.connect(sl1); + clip_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(clip_ref_changed), this)); mask_ref = new SPMaskReference(this); - sigc::signal cs2 = mask_ref->changedSignal(); - sigc::slot2 sl2=sigc::bind(sigc::ptr_fun(mask_ref_changed), this); - _mask_ref_connection = cs2.connect(sl2); + mask_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(mask_ref_changed), this)); avoidRef = new SPAvoidRef(this); @@ -204,10 +200,10 @@ bool SPItem::isHidden(unsigned display_key) const { for ( SPItemView *view(display) ; view ; view = view->next ) { if ( view->key == display_key ) { g_assert(view->arenaitem != NULL); - for ( NRArenaItem *arenaitem = view->arenaitem ; - arenaitem ; arenaitem = arenaitem->parent ) + for ( Inkscape::DrawingItem *arenaitem = view->arenaitem ; + arenaitem ; arenaitem = arenaitem->parent() ) { - if (!arenaitem->visible) { + if (!arenaitem->visible()) { return true; } } @@ -394,35 +390,22 @@ void SPItem::sp_item_release(SPObject *object) { SPItem *item = (SPItem *) object; - item->_clip_ref_connection.disconnect(); - item->_mask_ref_connection.disconnect(); - // Note: do this here before the clip_ref is deleted, since calling // ensureUpToDate() for triggered routing may reference // the deleted clip_ref. - if (item->avoidRef) { - delete item->avoidRef; - item->avoidRef = NULL; - } - - if (item->clip_ref) { - item->clip_ref->detach(); - delete item->clip_ref; - item->clip_ref = NULL; - } + delete item->avoidRef; - if (item->mask_ref) { - item->mask_ref->detach(); - delete item->mask_ref; - item->mask_ref = NULL; - } + // we do NOT disconnect from the changed signal of those before deletion. + // The destructor will call *_ref_changed with NULL as the new value, + // which will cause the hide() function to be called. + delete item->clip_ref; + delete item->mask_ref; if (((SPObjectClass *) (SPItemClass::static_parent_class))->release) { ((SPObjectClass *) SPItemClass::static_parent_class)->release(object); } while (item->display) { - nr_arena_item_unparent(item->display->arenaitem); item->display = sp_item_view_list_remove(item->display, item->display); } @@ -478,7 +461,7 @@ void SPItem::sp_item_set(SPObject *object, unsigned key, gchar const *value) case SP_ATTR_SODIPODI_INSENSITIVE: item->sensitive = !value; for (SPItemView *v = item->display; v != NULL; v = v->next) { - nr_arena_item_set_sensitive(v->arenaitem, item->sensitive); + v->arenaitem->setSensitive(item->sensitive); } break; case SP_ATTR_CONNECTOR_AVOID: @@ -529,23 +512,22 @@ void SPItem::clip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item) SPItemView *v; /* Hide clippath */ for (v = item->display; v != NULL; v = v->next) { - SP_CLIPPATH(old_clip)->hide(NR_ARENA_ITEM_GET_KEY(v->arenaitem)); - nr_arena_item_set_clip(v->arenaitem, NULL); + SP_CLIPPATH(old_clip)->hide(v->arenaitem->key()); + v->arenaitem->setClip(NULL); } } if (SP_IS_CLIPPATH(clip)) { NRRect bbox; item->invoke_bbox( &bbox, Geom::identity(), TRUE); for (SPItemView *v = item->display; v != NULL; v = v->next) { - if (!v->arenaitem->key) { - NR_ARENA_ITEM_SET_KEY(v->arenaitem, SPItem::display_key_new(3)); + if (!v->arenaitem->key()) { + v->arenaitem->setKey(SPItem::display_key_new(3)); } - NRArenaItem *ai = SP_CLIPPATH(clip)->show( - NR_ARENA_ITEM_ARENA(v->arenaitem), - NR_ARENA_ITEM_GET_KEY(v->arenaitem)); - nr_arena_item_set_clip(v->arenaitem, ai); - nr_arena_item_unref(ai); - SP_CLIPPATH(clip)->setBBox(NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox); + Inkscape::DrawingItem *ai = SP_CLIPPATH(clip)->show( + v->arenaitem->drawing(), + v->arenaitem->key()); + v->arenaitem->setClip(ai); + SP_CLIPPATH(clip)->setBBox(v->arenaitem->key(), &bbox); clip->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } @@ -556,23 +538,22 @@ void SPItem::mask_ref_changed(SPObject *old_mask, SPObject *mask, SPItem *item) if (old_mask) { /* Hide mask */ for (SPItemView *v = item->display; v != NULL; v = v->next) { - sp_mask_hide(SP_MASK(old_mask), NR_ARENA_ITEM_GET_KEY(v->arenaitem)); - nr_arena_item_set_mask(v->arenaitem, NULL); + sp_mask_hide(SP_MASK(old_mask), v->arenaitem->key()); + v->arenaitem->setMask(NULL); } } if (SP_IS_MASK(mask)) { NRRect bbox; item->invoke_bbox( &bbox, Geom::identity(), TRUE); for (SPItemView *v = item->display; v != NULL; v = v->next) { - if (!v->arenaitem->key) { - NR_ARENA_ITEM_SET_KEY(v->arenaitem, SPItem::display_key_new(3)); + if (!v->arenaitem->key()) { + v->arenaitem->setKey(SPItem::display_key_new(3)); } - NRArenaItem *ai = sp_mask_show(SP_MASK(mask), - NR_ARENA_ITEM_ARENA(v->arenaitem), - NR_ARENA_ITEM_GET_KEY(v->arenaitem)); - nr_arena_item_set_mask(v->arenaitem, ai); - nr_arena_item_unref(ai); - sp_mask_set_bbox(SP_MASK(mask), NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox); + Inkscape::DrawingItem *ai = sp_mask_show(SP_MASK(mask), + v->arenaitem->drawing(), + v->arenaitem->key()); + v->arenaitem->setMask(ai); + sp_mask_set_bbox(SP_MASK(mask), v->arenaitem->key(), &bbox); mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } @@ -589,7 +570,7 @@ void SPItem::sp_item_update(SPObject *object, SPCtx *ctx, guint flags) if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) { if (flags & SP_OBJECT_MODIFIED_FLAG) { for (SPItemView *v = item->display; v != NULL; v = v->next) { - nr_arena_item_set_transform(v->arenaitem, item->transform); + v->arenaitem->setTransform(item->transform); } } @@ -601,20 +582,20 @@ void SPItem::sp_item_update(SPObject *object, SPCtx *ctx, guint flags) item->invoke_bbox( &bbox, Geom::identity(), TRUE); if (clip_path) { for (SPItemView *v = item->display; v != NULL; v = v->next) { - clip_path->setBBox(NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox); + clip_path->setBBox(v->arenaitem->key(), &bbox); } } if (mask) { for (SPItemView *v = item->display; v != NULL; v = v->next) { - sp_mask_set_bbox(mask, NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox); + sp_mask_set_bbox(mask, v->arenaitem->key(), &bbox); } } } if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = item->display; v != NULL; v = v->next) { - nr_arena_item_set_opacity(v->arenaitem, SP_SCALE24_TO_FLOAT(object->style->opacity.value)); - nr_arena_item_set_visible(v->arenaitem, !item->isHidden()); + v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(object->style->opacity.value)); + v->arenaitem->setVisible(!item->isHidden()); } } } @@ -627,7 +608,7 @@ void SPItem::sp_item_update(SPObject *object, SPCtx *ctx, guint flags) SPItemView *itemview = item->display; do { if (itemview->arenaitem) - nr_arena_item_set_item_bbox(itemview->arenaitem, item_bbox); + itemview->arenaitem->setItemBounds(item_bbox); } while ( (itemview = itemview->next) ); } @@ -1036,34 +1017,33 @@ unsigned SPItem::display_key_new(unsigned numkeys) return dkey - numkeys; } -NRArenaItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigned flags) +Inkscape::DrawingItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigned flags) { g_assert(arena != NULL); g_assert(NR_IS_ARENA(arena)); - NRArenaItem *ai = NULL; + Inkscape::DrawingItem *ai = NULL; if (((SPItemClass *) G_OBJECT_GET_CLASS(this))->show) { ai = ((SPItemClass *) G_OBJECT_GET_CLASS(this))->show(this, arena, key, flags); } if (ai != NULL) { display = sp_item_view_new_prepend(display, this, flags, key, ai); - nr_arena_item_set_transform(ai, transform); - nr_arena_item_set_opacity(ai, SP_SCALE24_TO_FLOAT(style->opacity.value)); - nr_arena_item_set_visible(ai, !isHidden()); - nr_arena_item_set_sensitive(ai, sensitive); + ai->setTransform(transform); + ai->setOpacity(SP_SCALE24_TO_FLOAT(style->opacity.value)); + ai->setVisible(!isHidden()); + ai->setSensitive(sensitive); if (clip_ref->getObject()) { SPClipPath *cp = clip_ref->getObject(); - if (!display->arenaitem->key) { - NR_ARENA_ITEM_SET_KEY(display->arenaitem, display_key_new(3)); + if (!display->arenaitem->key()) { + display->arenaitem->setKey(display_key_new(3)); } - int clip_key = NR_ARENA_ITEM_GET_KEY(display->arenaitem); + int clip_key = display->arenaitem->key(); // Show and set clip - NRArenaItem *ac = cp->show(arena, clip_key); - nr_arena_item_set_clip(ai, ac); - nr_arena_item_unref(ac); + Inkscape::DrawingItem *ac = cp->show(arena, clip_key); + ai->setClip(ac); // Update bbox, in case the clip uses bbox units NRRect bbox; @@ -1074,15 +1054,14 @@ NRArenaItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigned flags) if (mask_ref->getObject()) { SPMask *mask = mask_ref->getObject(); - if (!display->arenaitem->key) { - NR_ARENA_ITEM_SET_KEY(display->arenaitem, display_key_new(3)); + if (!display->arenaitem->key()) { + display->arenaitem->setKey(display_key_new(3)); } - int mask_key = NR_ARENA_ITEM_GET_KEY(display->arenaitem); + int mask_key = display->arenaitem->key(); // Show and set mask - NRArenaItem *ac = sp_mask_show(mask, arena, mask_key); - nr_arena_item_set_mask(ai, ac); - nr_arena_item_unref(ac); + Inkscape::DrawingItem *ac = sp_mask_show(mask, arena, mask_key); + ai->setMask(ac); // Update bbox, in case the mask uses bbox units NRRect bbox; @@ -1090,10 +1069,10 @@ NRArenaItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigned flags) sp_mask_set_bbox(SP_MASK(mask), mask_key, &bbox); mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } - NR_ARENA_ITEM_SET_DATA(ai, this); + ai->setData(this); Geom::OptRect item_bbox; invoke_bbox( item_bbox, Geom::identity(), TRUE, SPItem::GEOMETRIC_BBOX); - nr_arena_item_set_item_bbox(ai, item_bbox); + ai->setItemBounds(item_bbox); } return ai; @@ -1111,20 +1090,19 @@ void SPItem::invoke_hide(unsigned key) SPItemView *next = v->next; if (v->key == key) { if (clip_ref->getObject()) { - (clip_ref->getObject())->hide(NR_ARENA_ITEM_GET_KEY(v->arenaitem)); - nr_arena_item_set_clip(v->arenaitem, NULL); + (clip_ref->getObject())->hide(v->arenaitem->key()); + v->arenaitem->setClip(NULL); } if (mask_ref->getObject()) { - sp_mask_hide(mask_ref->getObject(), NR_ARENA_ITEM_GET_KEY(v->arenaitem)); - nr_arena_item_set_mask(v->arenaitem, NULL); + sp_mask_hide(mask_ref->getObject(), v->arenaitem->key()); + v->arenaitem->setMask(NULL); } if (!ref) { display = v->next; } else { ref->next = v->next; } - nr_arena_item_unparent(v->arenaitem); - nr_arena_item_unref(v->arenaitem); + delete v->arenaitem; g_free(v); } else { ref = v; @@ -1501,27 +1479,27 @@ Geom::Affine SPItem::dt2i_affine() const /* Item views */ -SPItemView *SPItem::sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, NRArenaItem *arenaitem) +SPItemView *SPItem::sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, Inkscape::DrawingItem *drawing_item) { g_assert(item != NULL); g_assert(SP_IS_ITEM(item)); - g_assert(arenaitem != NULL); - g_assert(NR_IS_ARENA_ITEM(arenaitem)); + g_assert(drawing_item != NULL); SPItemView *new_view = g_new(SPItemView, 1); new_view->next = list; new_view->flags = flags; new_view->key = key; - new_view->arenaitem = arenaitem; + new_view->arenaitem = drawing_item; return new_view; } SPItemView *SPItem::sp_item_view_list_remove(SPItemView *list, SPItemView *view) { + SPItemView *ret = list; if (view == list) { - list = list->next; + ret = list->next; } else { SPItemView *prev; prev = list; @@ -1529,17 +1507,17 @@ SPItemView *SPItem::sp_item_view_list_remove(SPItemView *list, SPItemView *view) prev->next = view->next; } - nr_arena_item_unref(view->arenaitem); + delete view->arenaitem; g_free(view); - return list; + return ret; } /** * Return the arenaitem corresponding to the given item in the display * with the given key */ -NRArenaItem *SPItem::get_arenaitem(unsigned key) +Inkscape::DrawingItem *SPItem::get_arenaitem(unsigned key) { for ( SPItemView *iv = display ; iv ; iv = iv->next ) { if ( iv->key == key ) { diff --git a/src/sp-item.h b/src/sp-item.h index 0065a9c0e..f8cc948bb 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -20,7 +20,7 @@ */ #include -#include "display/nr-arena-forward.h" +#include "display/display-forward.h" #include "sp-object.h" #include <2geom/affine.h> #include @@ -66,7 +66,7 @@ public: SPItemView *next; unsigned int flags; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; }; /* flags */ @@ -169,9 +169,6 @@ public: Geom::OptRect getBounds(Geom::Affine const &transform, BBoxType type=APPROXIMATE_BBOX, unsigned int dkey=0) const; - sigc::connection _clip_ref_connection; - sigc::connection _mask_ref_connection; - sigc::connection connectTransformed(sigc::slot slot) { return _transformed_signal.connect(slot); } @@ -184,7 +181,7 @@ public: gchar *description(); void invoke_print(SPPrintContext *ctx); static unsigned int display_key_new(unsigned int numkeys); - NRArenaItem *invoke_show(NRArena *arena, unsigned int key, unsigned int flags); + Inkscape::DrawingItem *invoke_show(NRArena *arena, unsigned int key, unsigned int flags); void invoke_hide(unsigned int key); void getSnappoints(std::vector &p, Inkscape::SnapPreferences const *snapprefs=0) const; void adjust_pattern(/* Geom::Affine const &premul, */ Geom::Affine const &postmul, bool set = false); @@ -197,7 +194,7 @@ public: void set_item_transform(Geom::Affine const &transform_matrix); void convert_item_to_guides(); gint emitEvent (SPEvent &event); - NRArenaItem *get_arenaitem(unsigned int key); + Inkscape::DrawingItem *get_arenaitem(unsigned int key); void getBboxDesktop(NRRect *bbox, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) __attribute__ ((deprecated)); Geom::OptRect getBboxDesktop(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX); Geom::Affine i2doc_affine() const; @@ -226,7 +223,7 @@ private: static gchar *sp_item_private_description(SPItem *item); static void sp_item_private_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); - static SPItemView *sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, NRArenaItem *arenaitem); + static SPItemView *sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, Inkscape::DrawingItem *arenaitem); static SPItemView *sp_item_view_list_remove(SPItemView *list, SPItemView *view); static void clip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item); static void mask_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item); @@ -249,7 +246,7 @@ public: /** Give short description of item (for status display) */ gchar * (* description) (SPItem * item); - NRArenaItem * (* show) (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); + Inkscape::DrawingItem * (* show) (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); void (* hide) (SPItem *item, unsigned int key); /** Write to an iterator the points that should be considered for snapping diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index 38599188f..f23be6fc5 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -16,7 +16,7 @@ #include <2geom/transforms.h> #include "display/nr-arena.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "xml/repr.h" #include "enums.h" @@ -30,7 +30,7 @@ struct SPMaskView { SPMaskView *next; unsigned int key; - NRArenaItem *arenaitem; + Inkscape::DrawingItem *arenaitem; NRRect bbox; }; @@ -45,7 +45,7 @@ static void sp_mask_update (SPObject *object, SPCtx *ctx, guint flags); static void sp_mask_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_mask_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -SPMaskView *sp_mask_view_new_prepend (SPMaskView *list, unsigned int key, NRArenaItem *arenaitem); +SPMaskView *sp_mask_view_new_prepend (SPMaskView *list, unsigned int key, Inkscape::DrawingItem *arenaitem); SPMaskView *sp_mask_view_list_remove (SPMaskView *list, SPMaskView *view); static SPObjectGroupClass *parent_class; @@ -179,11 +179,11 @@ sp_mask_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML if (SP_IS_ITEM (ochild)) { SPMask *cp = SP_MASK (object); for (SPMaskView *v = cp->display; v != NULL; v = v->next) { - NRArenaItem *ac = SP_ITEM (ochild)->invoke_show ( NR_ARENA_ITEM_ARENA (v->arenaitem), + Inkscape::DrawingItem *ac = SP_ITEM (ochild)->invoke_show ( v->arenaitem->drawing(), v->key, SP_ITEM_REFERENCE_FLAGS); if (ac) { - nr_arena_item_add_child (v->arenaitem, ac, NULL); + v->arenaitem->prependChild(ac); } } } @@ -215,13 +215,14 @@ static void sp_mask_update(SPObject *object, SPCtx *ctx, guint flags) SPMask *mask = SP_MASK(object); for (SPMaskView *v = mask->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { Geom::Affine t(Geom::Scale(v->bbox.x1 - v->bbox.x0, v->bbox.y1 - v->bbox.y0)); t[4] = v->bbox.x0; t[5] = v->bbox.y0; - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), &t); + g->setChildTransform(t); } else { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), NULL); + g->setChildTransform(Geom::identity()); } } } @@ -296,22 +297,21 @@ sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTr return mask_id; } -NRArenaItem *sp_mask_show(SPMask *mask, NRArena *arena, unsigned int key) +Inkscape::DrawingItem *sp_mask_show(SPMask *mask, NRArena *arena, unsigned int key) { g_return_val_if_fail (mask != NULL, NULL); g_return_val_if_fail (SP_IS_MASK (mask), NULL); g_return_val_if_fail (arena != NULL, NULL); g_return_val_if_fail (NR_IS_ARENA (arena), NULL); - NRArenaItem *ai = NRArenaGroup::create(arena); + Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(arena); mask->display = sp_mask_view_new_prepend (mask->display, key, ai); for ( SPObject *child = mask->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - NRArenaItem *ac = SP_ITEM (child)->invoke_show (arena, key, SP_ITEM_REFERENCE_FLAGS); + Inkscape::DrawingItem *ac = SP_ITEM (child)->invoke_show (arena, key, SP_ITEM_REFERENCE_FLAGS); if (ac) { - /* The order is not important in mask */ - nr_arena_item_add_child (ai, ac, NULL); + ai->prependChild(ac); } } } @@ -320,7 +320,7 @@ NRArenaItem *sp_mask_show(SPMask *mask, NRArena *arena, unsigned int key) Geom::Affine t(Geom::Scale(mask->display->bbox.x1 - mask->display->bbox.x0, mask->display->bbox.y1 - mask->display->bbox.y0)); t[4] = mask->display->bbox.x0; t[5] = mask->display->bbox.y0; - nr_arena_group_set_child_transform (NR_ARENA_GROUP (ai), &t); + ai->setChildTransform(t); } return ai; @@ -367,13 +367,13 @@ sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox) /* Mask views */ SPMaskView * -sp_mask_view_new_prepend (SPMaskView *list, unsigned int key, NRArenaItem *arenaitem) +sp_mask_view_new_prepend (SPMaskView *list, unsigned int key, Inkscape::DrawingItem *arenaitem) { SPMaskView *new_mask_view = g_new (SPMaskView, 1); new_mask_view->next = list; new_mask_view->key = key; - new_mask_view->arenaitem = nr_arena_item_ref(arenaitem); + new_mask_view->arenaitem = arenaitem; new_mask_view->bbox.x0 = new_mask_view->bbox.x1 = 0.0; new_mask_view->bbox.y0 = new_mask_view->bbox.y1 = 0.0; @@ -392,7 +392,7 @@ sp_mask_view_list_remove (SPMaskView *list, SPMaskView *view) prev->next = view->next; } - nr_arena_item_unref (view->arenaitem); + delete view->arenaitem; g_free (view); return list; diff --git a/src/sp-mask.h b/src/sp-mask.h index 5a98ac8c5..e7a4723cf 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -23,7 +23,7 @@ class SPMask; class SPMaskClass; class SPMaskView; -#include "display/nr-arena-forward.h" +#include "display/display-forward.h" #include "libnr/nr-forward.h" #include "sp-object-group.h" #include "uri-references.h" @@ -90,7 +90,7 @@ protected: } }; -NRArenaItem *sp_mask_show (SPMask *mask, NRArena *arena, unsigned int key); +Inkscape::DrawingItem *sp_mask_show (SPMask *mask, NRArena *arena, unsigned int key); void sp_mask_hide (SPMask *mask, unsigned int key); void sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox); diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 3a3d01ebd..805a93267 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -25,10 +25,11 @@ #include "display/drawing-context.h" #include "display/drawing-surface.h" #include "display/nr-arena.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "attributes.h" #include "document-private.h" #include "uri.h" +#include "style.h" #include "sp-pattern.h" #include "xml/repr.h" #include "display/grayscale.h" @@ -632,15 +633,15 @@ sp_pattern_create_pattern(SPPaintServer *ps, /* Create arena */ NRArena *arena = NRArena::create(); unsigned int dkey = SPItem::display_key_new (1); - NRArenaGroup *root = NRArenaGroup::create(arena); + Inkscape::DrawingGroup *root = new Inkscape::DrawingGroup(arena); for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext() ) { if (SP_IS_ITEM (child)) { // for each item in pattern, show it on our arena, add to the group, // and connect to the release signal in case the item gets deleted - NRArenaItem *cai; + Inkscape::DrawingItem *cai; cai = SP_ITEM(child)->invoke_show (arena, dkey, SP_ITEM_SHOW_DISPLAY); - nr_arena_item_append_child (root, cai); + root->appendChild(cai); } } @@ -689,17 +690,17 @@ sp_pattern_create_pattern(SPPaintServer *ps, } // TODO: make sure there are no leaks. - NRGC gc(NULL); - gc.transform = vb2ps; - 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); + Inkscape::UpdateContext ctx; + ctx.ctm = vb2ps; + root->update(Geom::IntRect::infinite(), ctx, Inkscape::DrawingItem::STATE_ALL, 0); + root->render(ct, one_tile, 0); for (SPObject *child = shown->firstChild() ; child != NULL; child = child->getNext() ) { if (SP_IS_ITEM (child)) { SP_ITEM(child)->invoke_hide(dkey); } } - nr_object_unref(root); nr_object_unref(arena); + delete root; if (needs_opacity) { ct.popGroupToSource(); // pop raw pattern diff --git a/src/sp-root.cpp b/src/sp-root.cpp index 918bd3295..bbb12f5d3 100644 --- a/src/sp-root.cpp +++ b/src/sp-root.cpp @@ -22,7 +22,7 @@ #include <2geom/transforms.h> #include "svg/svg.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "attributes.h" #include "print.h" #include "document.h" @@ -46,7 +46,7 @@ static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_root_modified(SPObject *object, guint flags); static Inkscape::XML::Node *sp_root_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static NRArenaItem *sp_root_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_root_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_root_print(SPItem *item, SPPrintContext *ctx); static SPGroupClass *parent_class; @@ -540,7 +540,8 @@ static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags) /* As last step set additional transform of arena group */ for (SPItemView *v = root->display; v != NULL; v = v->next) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), root->c2p); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + g->setChildTransform(root->c2p); } } @@ -609,16 +610,17 @@ sp_root_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: /** * Displays the SPRoot item on the NRArena. */ -static NRArenaItem * +static Inkscape::DrawingItem * sp_root_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) { SPRoot *root = SP_ROOT(item); - NRArenaItem *ai; + Inkscape::DrawingItem *ai; if (((SPItemClass *) (parent_class))->show) { ai = ((SPItemClass *) (parent_class))->show(item, arena, key, flags); if (ai) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), root->c2p); + Inkscape::DrawingGroup *g = dynamic_cast(ai); + g->setChildTransform(root->c2p); } } else { ai = NULL; diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index beec860be..1512898f5 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -30,7 +30,7 @@ #include #include "macros.h" -#include "display/nr-arena-shape.h" +#include "display/drawing-shape.h" #include "display/curve.h" #include "print.h" #include "document.h" @@ -182,7 +182,7 @@ void SPShape::sp_shape_release(SPObject *object) for (i = 0; i < SP_MARKER_LOC_QTY; i++) { if (shape->marker[i]) { for (v = item->display; v != NULL; v = v->next) { - sp_marker_hide ((SPMarker *) shape->marker[i], NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i); + sp_marker_hide ((SPMarker *) shape->marker[i], v->arenaitem->key() + i); } shape->release_connect[i].disconnect(); shape->modified_connect[i].disconnect(); @@ -247,7 +247,8 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) double const aw = 1.0 / ictx->i2vp.descrim(); style->stroke_width.computed = style->stroke_width.value * aw; for (SPItemView *v = ((SPItem *) (shape))->display; v != NULL; v = v->next) { - nr_arena_shape_set_style ((NRArenaShape *) v->arenaitem, style); + Inkscape::DrawingShape *sh = dynamic_cast(v->arenaitem); + sh->setStyle(style); } } } @@ -257,12 +258,12 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) /* But on the other hand - how can we know that parent does not tie style and transform */ Geom::OptRect paintbox = SP_ITEM(object)->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX); for (SPItemView *v = shape->display; v != NULL; v = v->next) { - NRArenaShape * const s = NR_ARENA_SHAPE(v->arenaitem); + Inkscape::DrawingShape *sh = dynamic_cast(v->arenaitem); if (flags & SP_OBJECT_MODIFIED_FLAG) { - nr_arena_shape_set_path(s, shape->curve, (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)); + sh->setPath(shape->curve); } if (paintbox) { - s->setPaintBox(*paintbox); + sh->setPaintBox(*paintbox); } } } @@ -270,13 +271,13 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) if (shape->hasMarkers ()) { /* Dimension marker views */ for (SPItemView *v = shape->display; v != NULL; v = v->next) { - if (!v->arenaitem->key) { - NR_ARENA_ITEM_SET_KEY (v->arenaitem, SPItem::display_key_new (SP_MARKER_LOC_QTY)); + if (!v->arenaitem->key()) { + v->arenaitem->setKey(SPItem::display_key_new (SP_MARKER_LOC_QTY)); } for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) { if (shape->marker[i]) { sp_marker_show_dimension ((SPMarker *) shape->marker[i], - NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i, + v->arenaitem->key() + i, shape->numberOfMarkers (i)); } } @@ -375,7 +376,7 @@ Geom::Affine sp_shape_marker_get_transform_at_end(Geom::Curve const & c) * * @todo figure out what to do when both 'marker' and for instance 'marker-end' are set. */ -void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) +void SPShape::sp_shape_update_marker_view(SPShape *shape, Inkscape::DrawingItem *ai) { SPStyle *style = ((SPObject *) shape)->style; @@ -395,7 +396,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( shape->marker[i] ) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, - NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m, + ai->key() + i, counter[i], m, style->stroke_width.computed); counter[i]++; } @@ -413,7 +414,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID if ( shape->marker[i] ) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, - NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m, + ai->key() + i, counter[i], m, style->stroke_width.computed); counter[i]++; } @@ -433,7 +434,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID if (shape->marker[i]) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, - NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m, + ai->key() + i, counter[i], m, style->stroke_width.computed); counter[i]++; } @@ -450,7 +451,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID if (shape->marker[i]) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, - NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m, + ai->key() + i, counter[i], m, style->stroke_width.computed); counter[i]++; } @@ -474,7 +475,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END if (shape->marker[i]) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, - NR_ARENA_ITEM_GET_KEY(ai) + i, counter[i], m, + ai->key() + i, counter[i], m, style->stroke_width.computed); counter[i]++; } @@ -495,7 +496,8 @@ void SPShape::sp_shape_modified(SPObject *object, unsigned int flags) if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = shape->display; v != NULL; v = v->next) { - nr_arena_shape_set_style (NR_ARENA_SHAPE (v->arenaitem), object->style); + Inkscape::DrawingShape *sh = dynamic_cast(v->arenaitem); + sh->setStyle(object->style); } } } @@ -850,15 +852,14 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) /** * Sets style, path, and paintbox. Updates marker views, including dimensions. */ -NRArenaItem * SPShape::sp_shape_show(SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/) +Inkscape::DrawingItem * SPShape::sp_shape_show(SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/) { SPObject *object = item; SPShape *shape = SP_SHAPE(item); - NRArenaItem *arenaitem = NRArenaShape::create(arena); - NRArenaShape * const s = NR_ARENA_SHAPE(arenaitem); - nr_arena_shape_set_style(s, object->style); - nr_arena_shape_set_path(s, shape->curve, false); + Inkscape::DrawingShape *s = new Inkscape::DrawingShape(arena); + s->setStyle(object->style); + s->setPath(shape->curve); Geom::OptRect paintbox = item->getBounds(Geom::identity()); if (paintbox) { s->setPaintBox(*paintbox); @@ -876,23 +877,23 @@ NRArenaItem * SPShape::sp_shape_show(SPItem *item, NRArena *arena, unsigned int if (shape->hasMarkers ()) { /* provide key and dimension the marker views */ - if (!arenaitem->key) { - NR_ARENA_ITEM_SET_KEY (arenaitem, SPItem::display_key_new (SP_MARKER_LOC_QTY)); + if (!s->key()) { + s->setKey(SPItem::display_key_new (SP_MARKER_LOC_QTY)); } for (int i = 0; i < SP_MARKER_LOC_QTY; i++) { if (shape->marker[i]) { sp_marker_show_dimension ((SPMarker *) shape->marker[i], - NR_ARENA_ITEM_GET_KEY (arenaitem) + i, + s->key() + i, shape->numberOfMarkers (i)); } } /* Update marker views */ - sp_shape_update_marker_view (shape, arenaitem); + sp_shape_update_marker_view (shape, s); } - return arenaitem; + return s; } /** @@ -911,7 +912,7 @@ void SPShape::sp_shape_hide(SPItem *item, unsigned int key) for (v = item->display; v != NULL; v = v->next) { if (key == v->key) { sp_marker_hide ((SPMarker *) shape->marker[i], - NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i); + v->arenaitem->key() + i); } } } @@ -1013,9 +1014,9 @@ sp_shape_marker_release (SPObject *marker, SPShape *shape) SPItemView *v; /* Hide marker */ for (v = item->display; v != NULL; v = v->next) { - sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i); + sp_marker_hide ((SPMarker *) (shape->marker[i]), v->arenaitem->key() + i); /* fixme: Do we need explicit remove here? (Lauris) */ - /* nr_arena_item_set_mask (v->arenaitem, NULL); */ + /* v->arenaitem->setMask(NULL); */ } /* Detach marker */ shape->release_connect[i].disconnect(); @@ -1064,9 +1065,9 @@ sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value) /* Hide marker */ for (v = item->display; v != NULL; v = v->next) { sp_marker_hide ((SPMarker *) (shape->marker[key]), - NR_ARENA_ITEM_GET_KEY (v->arenaitem) + key); + v->arenaitem->key() + key); /* fixme: Do we need explicit remove here? (Lauris) */ - /* nr_arena_item_set_mask (v->arenaitem, NULL); */ + /* v->arenaitem->setMask(NULL); */ } /* Unref marker */ diff --git a/src/sp-shape.h b/src/sp-shape.h index b91850d1f..4da2d5a2d 100644 --- a/src/sp-shape.h +++ b/src/sp-shape.h @@ -67,11 +67,11 @@ private: static Inkscape::XML::Node *sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); - static NRArenaItem *sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); + static Inkscape::DrawingItem *sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_shape_hide (SPItem *item, unsigned int key); static void sp_shape_snappoints (SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); - static void sp_shape_update_marker_view (SPShape *shape, NRArenaItem *ai); + static void sp_shape_update_marker_view (SPShape *shape, Inkscape::DrawingItem *ai); diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index eb30f2644..bb1495387 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -19,7 +19,7 @@ #include #include "sp-switch.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "conditions.h" #include @@ -157,20 +157,18 @@ void CSwitch::_releaseLastItem(SPObject *obj) _cached_item = NULL; } -void CSwitch::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) { +void CSwitch::_showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { SPObject *evaluated_child = _evaluateFirst(); - NRArenaItem *ar = NULL; GSList *l = _childList(false, SPObject::ActionShow); while (l) { SPObject *o = SP_OBJECT (l->data); if (SP_IS_ITEM (o)) { SPItem * child = SP_ITEM(o); child->setEvaluated(o == evaluated_child); - NRArenaItem *ac = child->invoke_show (arena, key, flags); + Inkscape::DrawingItem *ac = child->invoke_show (arena, key, flags); if (ac) { - nr_arena_item_add_child (ai, ac, ar); - ar = ac; + ai->appendChild(ac); } } l = g_slist_remove (l, o); diff --git a/src/sp-switch.h b/src/sp-switch.h index 310655a23..7b108947d 100644 --- a/src/sp-switch.h +++ b/src/sp-switch.h @@ -42,7 +42,7 @@ public: protected: virtual GSList *_childList(bool add_ref, SPObject::Action action); - virtual void _showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags); + virtual void _showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); SPObject *_evaluateFirst(); void _reevaluate(bool add_to_arena = false); diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp index 91218c986..1f35a0ee1 100644 --- a/src/sp-symbol.cpp +++ b/src/sp-symbol.cpp @@ -19,7 +19,7 @@ #include #include <2geom/transforms.h> -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "xml/repr.h" #include "attributes.h" #include "print.h" @@ -37,7 +37,7 @@ static void sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags); static void sp_symbol_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_symbol_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static NRArenaItem *sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_symbol_hide (SPItem *item, unsigned int key); static void sp_symbol_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_symbol_print (SPItem *item, SPPrintContext *ctx); @@ -327,7 +327,8 @@ static void sp_symbol_update(SPObject *object, SPCtx *ctx, guint flags) // As last step set additional transform of arena group for (SPItemView *v = symbol->display; v != NULL; v = v->next) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), symbol->c2p); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + g->setChildTransform(symbol->c2p); } } else { // No-op @@ -367,17 +368,18 @@ static Inkscape::XML::Node *sp_symbol_write(SPObject *object, Inkscape::XML::Doc return repr; } -static NRArenaItem *sp_symbol_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) +static Inkscape::DrawingItem *sp_symbol_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) { SPSymbol *symbol = SP_SYMBOL(item); - NRArenaItem *ai = 0; + Inkscape::DrawingItem *ai = 0; if (symbol->cloned) { // Cloned is actually renderable if (((SPItemClass *) (parent_class))->show) { ai = ((SPItemClass *) (parent_class))->show (item, arena, key, flags); - if (ai) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), symbol->c2p); + Inkscape::DrawingGroup *g = dynamic_cast(ai); + if (g) { + g->setChildTransform(symbol->c2p); } } } diff --git a/src/sp-text.cpp b/src/sp-text.cpp index 89ca4ace4..ed848c646 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -35,7 +35,7 @@ #include #include "svg/svg.h" #include "svg/stringstream.h" -#include "display/nr-arena-glyphs.h" +#include "display/drawing-text.h" #include "attributes.h" #include "document.h" #include "desktop-handles.h" @@ -72,7 +72,7 @@ static void sp_text_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_text_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); -static NRArenaItem *sp_text_show (SPItem *item, NRArena *arena, unsigned key, unsigned flags); +static Inkscape::DrawingItem *sp_text_show (SPItem *item, NRArena *arena, unsigned key, unsigned flags); static void sp_text_hide (SPItem *item, unsigned key); static char *sp_text_description (SPItem *item); static void sp_text_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); @@ -251,10 +251,11 @@ static void sp_text_update(SPObject *object, SPCtx *ctx, guint flags) NRRect paintbox; text->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView* v = text->display; v != NULL; v = v->next) { - text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + text->_clearFlow(g); + g->setStyle(object->style); // pass the bbox of the text object as paintbox (used for paintserver fills) - text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); + text->layout.show(g, &paintbox); } } } @@ -270,8 +271,8 @@ static void sp_text_modified(SPObject *object, guint flags) cflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } - // FIXME: all that we need to do here is nr_arena_glyphs_[group_]set_style, to set the changed - // style, but there's no easy way to access the arena glyphs or glyph groups corresponding to a + // FIXME: all that we need to do here is to call setStyle, to set the changed + // style, but there's no easy way to access the drawing glyphs or texts corresponding to a // text object. Therefore we do here the same as in _update, that is, destroy all arena items // and create new ones. This is probably quite wasteful. if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) { @@ -279,9 +280,10 @@ static void sp_text_modified(SPObject *object, guint flags) NRRect paintbox; text->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView* v = text->display; v != NULL; v = v->next) { - text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); - text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + text->_clearFlow(g); + g->setStyle(object->style); + text->layout.show(g, &paintbox); } } @@ -383,15 +385,14 @@ sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, un } -static NRArenaItem * +static Inkscape::DrawingItem * sp_text_show(SPItem *item, NRArena *arena, unsigned /* key*/, unsigned /*flags*/) { SPText *group = (SPText *) item; - NRArenaGroup *flowed = NRArenaGroup::create(arena); - nr_arena_group_set_transparent (flowed, FALSE); - - nr_arena_group_set_style(flowed, group->style); + Inkscape::DrawingGroup *flowed = new Inkscape::DrawingGroup(arena); + flowed->setPickChildren(false); + flowed->setStyle(group->style); // pass the bbox of the text object as paintbox (used for paintserver fills) NRRect paintbox; @@ -662,17 +663,9 @@ void SPText::_adjustCoordsRecursive(SPItem *item, Geom::Affine const &m, double } -void SPText::_clearFlow(NRArenaGroup *in_arena) +void SPText::_clearFlow(Inkscape::DrawingGroup *in_arena) { - nr_arena_item_request_render (in_arena); - for (NRArenaItem *child = in_arena->children; child != NULL; ) { - NRArenaItem *nchild = child->next; - - nr_arena_glyphs_group_clear(NR_ARENA_GLYPHS_GROUP(child)); - nr_arena_item_remove_child (in_arena, child); - - child=nchild; - } + in_arena->clearChildren(); } diff --git a/src/sp-text.h b/src/sp-text.h index cd103aa2a..f865713c7 100644 --- a/src/sp-text.h +++ b/src/sp-text.h @@ -57,7 +57,7 @@ struct SPText : public SPItem { static void _adjustFontsizeRecursive(SPItem *item, double ex, bool is_root = true); /** discards the NRArena objects representing this text. */ - void _clearFlow(NRArenaGroup *in_arena); + void _clearFlow(Inkscape::DrawingGroup *in_arena); private: /** Recursively walks the xml tree adding tags and their contents. The diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp index b301add7f..dcf46f6ac 100644 --- a/src/sp-tref.cpp +++ b/src/sp-tref.cpp @@ -32,7 +32,6 @@ #include "text-editing.h" #include "uri.h" -#include "display/nr-arena-group.h" #include "xml/node.h" #include "xml/repr.h" diff --git a/src/sp-use.cpp b/src/sp-use.cpp index a05b28a5f..2f83679de 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -22,7 +22,7 @@ #include <2geom/transforms.h> #include -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "attributes.h" #include "document.h" #include "sp-object-repr.h" @@ -53,7 +53,7 @@ static void sp_use_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &tr static void sp_use_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); static void sp_use_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_use_description(SPItem *item); -static NRArenaItem *sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); +static Inkscape::DrawingItem *sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); static void sp_use_hide(SPItem *item, unsigned key); static void sp_use_href_changed(SPObject *old_ref, SPObject *ref, SPUse *use); @@ -346,23 +346,23 @@ sp_use_description(SPItem *item) } } -static NRArenaItem * +static Inkscape::DrawingItem * sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags) { SPUse *use = SP_USE(item); - NRArenaItem *ai = NRArenaGroup::create(arena); - nr_arena_group_set_transparent(NR_ARENA_GROUP(ai), FALSE); - nr_arena_group_set_style(NR_ARENA_GROUP(ai), item->style); + Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(arena); + ai->setPickChildren(false); + ai->setStyle(item->style); if (use->child) { - NRArenaItem *ac = SP_ITEM(use->child)->invoke_show(arena, key, flags); + Inkscape::DrawingItem *ac = SP_ITEM(use->child)->invoke_show(arena, key, flags); if (ac) { - nr_arena_item_add_child(ai, ac, NULL); + ai->prependChild(ac); } Geom::Translate t(use->x.computed, use->y.computed); - nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), Geom::Affine(t)); + ai->setChildTransform(t); } return ai; @@ -540,10 +540,10 @@ sp_use_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUse *use) (use->child)->invoke_build(use->document, childrepr, TRUE); for (SPItemView *v = item->display; v != NULL; v = v->next) { - NRArenaItem *ai; - ai = SP_ITEM(use->child)->invoke_show(NR_ARENA_ITEM_ARENA(v->arenaitem), v->key, v->flags); + Inkscape::DrawingItem *ai; + ai = SP_ITEM(use->child)->invoke_show(v->arenaitem->drawing(), v->key, v->flags); if (ai) { - nr_arena_item_add_child(v->arenaitem, ai, NULL); + v->arenaitem->prependChild(ai); } } @@ -592,7 +592,8 @@ sp_use_update(SPObject *object, SPCtx *ctx, unsigned flags) if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = SP_ITEM(object)->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + g->setStyle(object->style); } } @@ -633,8 +634,9 @@ sp_use_update(SPObject *object, SPCtx *ctx, unsigned flags) /* As last step set additional transform of arena group */ for (SPItemView *v = item->display; v != NULL; v = v->next) { + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); Geom::Affine t(Geom::Translate(use->x.computed, use->y.computed)); - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), t); + g->setChildTransform(t); } } @@ -650,7 +652,8 @@ sp_use_modified(SPObject *object, guint flags) if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = SP_ITEM(object)->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); + Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); + g->setStyle(object->style); } } diff --git a/src/svg-view.cpp b/src/svg-view.cpp index 2f1a20b82..3221ce146 100644 --- a/src/svg-view.cpp +++ b/src/svg-view.cpp @@ -15,6 +15,7 @@ #include <2geom/transforms.h> #include "display/canvas-arena.h" +#include "display/drawing-group.h" #include "document.h" #include "sp-item.h" #include "svg-view.h" @@ -129,13 +130,13 @@ SPSVGView::mouseout() */ /// \todo fixme. static gint -arena_handler (SPCanvasArena */*arena*/, NRArenaItem *ai, GdkEvent *event, SPSVGView *svgview) +arena_handler (SPCanvasArena */*arena*/, Inkscape::DrawingItem *ai, GdkEvent *event, SPSVGView *svgview) { static gdouble x, y; static gboolean active = FALSE; SPEvent spev; - SPItem *spitem = (ai) ? (SPItem*)NR_ARENA_ITEM_GET_DATA (ai) : 0; + SPItem *spitem = (ai) ? (SPItem*) ai->data() : 0; switch (event->type) { case GDK_BUTTON_PRESS: @@ -202,13 +203,13 @@ SPSVGView::setDocument (SPDocument *document) View::setDocument (document); if (document) { - NRArenaItem *ai = document->getRoot()->invoke_show( + Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( SP_CANVAS_ARENA (_drawing)->arena, _dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - nr_arena_item_add_child (SP_CANVAS_ARENA (_drawing)->root, ai, NULL); + SP_CANVAS_ARENA (_drawing)->root->prependChild(ai); } doRescale (!_rescale); diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index ef75d8b23..7093ff683 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -12,8 +12,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ - - #include "trace/potrace/inkscape-potrace.h" #include "inkscape.h" @@ -32,22 +30,13 @@ #include <2geom/transforms.h> #include "display/nr-arena.h" -#include "display/nr-arena-shape.h" +#include "display/drawing-shape.h" #include "siox.h" #include "imagemap-gdk.h" - - -namespace Inkscape -{ - -namespace Trace -{ - - - - +namespace Inkscape { +namespace Trace { /** * Get the selected image. Also check for any SPItems over it, in @@ -247,12 +236,12 @@ Tracer::sioxProcessImage(SPImage *img, return Glib::RefPtr(NULL); } - NRArenaItem *aImg = img->get_arenaitem(desktop->dkey); + Inkscape::DrawingItem *aImg = img->get_arenaitem(desktop->dkey); //g_message("img: %d %d %d %d\n", aImg->bbox.x0, aImg->bbox.y0, // aImg->bbox.x1, aImg->bbox.y1); - double width = aImg->bbox->width(); - double height = aImg->bbox->height(); + double width = aImg->geometricBounds()->width(); + double height = aImg->geometricBounds()->height(); double iwidth = simage.getWidth(); double iheight = simage.getHeight(); @@ -260,12 +249,12 @@ Tracer::sioxProcessImage(SPImage *img, double iwscale = width / iwidth; double ihscale = height / iheight; - std::vector arenaItems; + std::vector arenaItems; std::vector::iterator iter; for (iter = sioxShapes.begin() ; iter!=sioxShapes.end() ; iter++) { SPItem *item = *iter; - NRArenaItem *aItem = item->get_arenaitem(desktop->dkey); + Inkscape::DrawingItem *aItem = item->get_arenaitem(desktop->dkey); arenaItems.push_back(aItem); } @@ -278,25 +267,22 @@ Tracer::sioxProcessImage(SPImage *img, for (int row=0 ; rowbbox->top() + ihscale * (double) row; + double ypos = aImg->geometricBounds()->top() + ihscale * (double) row; for (int col=0 ; colbbox->left() + iwscale * (double)col; + double xpos = aImg->geometricBounds()->left() + iwscale * (double)col; Geom::Point point(xpos, ypos); - if (aImg->transform) - point *= *aImg->transform; + point *= aImg->transform(); //point *= imgMat; //point = desktop->doc2dt(point); //g_message("x:%f y:%f\n", point[0], point[1]); bool weHaveAHit = false; - std::vector::iterator aIter; + std::vector::iterator aIter; for (aIter = arenaItems.begin() ; aIter!=arenaItems.end() ; aIter++) { - NRArenaItem *arenaItem = *aIter; - NRArenaItemClass *arenaClass = - (NRArenaItemClass *) NR_OBJECT_GET_CLASS (arenaItem); - if (arenaClass->pick(arenaItem, point, 1.0f, 1)) + Inkscape::DrawingItem *arenaItem = *aIter; + if (arenaItem->pick(point, 1.0f, 1)) { weHaveAHit = true; break; @@ -338,17 +324,6 @@ Tracer::sioxProcessImage(SPImage *img, //result.writePPM("siox2.ppm"); - /* Free Arena and ArenaItem */ - /* - std::vector::iterator aIter; - for (aIter = arenaItems.begin() ; aIter!=arenaItems.end() ; aIter++) - { - NRArenaItem *arenaItem = *aIter; - nr_arena_item_unref(arenaItem); - } - nr_object_unref((NRObject *) arena); - */ - Glib::RefPtr newPixbuf = Glib::wrap(result.getGdkPixbuf()); //g_message("siox: done"); diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index 67ec701cb..ae5355c58 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -29,23 +29,19 @@ #include "document-private.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" +#include "display/drawing-item.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "ui/cache/svg_preview_cache.h" -GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize) { - NRGC gc(NULL); - +GdkPixbuf* render_pixbuf(Inkscape::DrawingItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize) +{ Geom::Affine t(Geom::Scale(scale_factor, scale_factor)); - nr_arena_item_set_transform(root, t); - gc.transform.setIdentity(); + root->setTransform(Geom::Scale(scale_factor)); 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 ); + root->update(ibox); /* Find visible area */ int width = ibox.width(); @@ -63,8 +59,7 @@ GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rec CAIRO_FORMAT_ARGB32, psize, psize); Inkscape::DrawingContext ct(s, area.min()); - nr_arena_item_invoke_render(ct, root, area, - NR_ARENA_ITEM_RENDER_NO_CACHE ); + root->render(ct, area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_flush(s); GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), @@ -111,7 +106,7 @@ void SvgPreview::set_preview_in_cache(const Glib::ustring& key, GdkPixbuf* px) { _pixmap_cache[key] = px; } -GdkPixbuf* SvgPreview::get_preview(const gchar* uri, const gchar* id, NRArenaItem */*root*/, +GdkPixbuf* SvgPreview::get_preview(const gchar* uri, const gchar* id, Inkscape::DrawingItem */*root*/, double /*scale_factor*/, unsigned int psize) { // First try looking up the cached preview in the cache map Glib::ustring key = cache_key(uri, id, psize); diff --git a/src/ui/cache/svg_preview_cache.h b/src/ui/cache/svg_preview_cache.h index 0fac94782..b9fa6f627 100644 --- a/src/ui/cache/svg_preview_cache.h +++ b/src/ui/cache/svg_preview_cache.h @@ -1,17 +1,22 @@ -#ifndef __SVG_PREVIEW_CACHE_H__ -#define __SVG_PREVIEW_CACHE_H__ - -/** \file - * SPIcon: Generic icon widget +/** @file + * @brief Preview cache */ /* * Copyright (C) 2007 Bryce W. Harrington - * * Released under GNU GPL, read the file 'COPYING' for more information - * */ -GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize); +#ifndef SEEN_INKSCAPE_UI_SVG_PREVIEW_CACHE_H +#define SEEN_INKSCAPE_UI_SVG_PREVIEW_CACHE_H + +#include +#include +#include +#include <2geom/rect.h> + +#include "display/display-forward.h" + +GdkPixbuf* render_pixbuf(Inkscape::DrawingItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize); namespace Inkscape { namespace UI { @@ -28,7 +33,7 @@ class SvgPreview { Glib::ustring cache_key(gchar const *uri, gchar const *name, unsigned psize) const; GdkPixbuf* get_preview_from_cache(const Glib::ustring& key); void set_preview_in_cache(const Glib::ustring& key, GdkPixbuf* px); - GdkPixbuf* get_preview(const gchar* uri, const gchar* id, NRArenaItem *root, double scale_factor, unsigned int psize); + GdkPixbuf* get_preview(const gchar* uri, const gchar* id, Inkscape::DrawingItem *root, double scale_factor, unsigned int psize); }; }; // namespace Cache diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index 38ec6d1be..a6d76eb13 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -38,7 +38,7 @@ extern "C" { // takes doc, root, icon, and icon name to produce pixels guchar * -sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, +sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, const gchar *name, unsigned int psize, unsigned &stride); } @@ -438,7 +438,7 @@ void IconPreviewPanel::renderPreview( SPObject* obj ) g_message("%s setting up to render '%s' as the icon", getTimestr().c_str(), id ); #endif // ICON_VERBOSE - NRArenaItem *root = NULL; + Inkscape::DrawingItem *root = NULL; /* Create new arena */ NRArena *arena = NRArena::create(); diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 7958a9d07..af329f3fc 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -641,10 +641,10 @@ SPDesktopWidget::updateTitle(gchar const* uri) gchar const *colormodename = ""; gchar const *colormodenamecomma = ""; - if (this->desktop->getColorMode() == Inkscape::COLORRENDERMODE_GRAYSCALE) { + if (this->desktop->getColorMode() == Inkscape::COLORMODE_GRAYSCALE) { colormodename = grayscalename; colormodenamecomma = grayscalenamecomma; - } else if (this->desktop->getColorMode() == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW) { + } else if (this->desktop->getColorMode() == Inkscape::COLORMODE_PRINT_COLORS_PREVIEW) { colormodename = printcolorsname; colormodenamecomma = printcolorsnamecomma; } diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index c6823e2d8..fea825444 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -32,8 +32,8 @@ #include "sp-item.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" +#include "display/drawing-item.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "io/sys.h" #include "sp-root.h" @@ -1090,7 +1090,7 @@ static Geom::IntRect round_rect(Geom::Rect const &r) // takes doc, root, icon, and icon name to produce pixels extern "C" guchar * -sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, +sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, gchar const *name, unsigned psize, unsigned &stride) { @@ -1113,14 +1113,10 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, /* This is in document coordinates, i.e. pixels */ if ( dbox ) { - NRGC gc(NULL); /* Update to renderable state */ 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, Geom::IntRect::infinite(), &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); + root->setTransform(Geom::Scale(sf)); + root->update(); /* Item integer bbox in points */ // NOTE: previously, each rect coordinate was rounded using floor(c + 0.5) Geom::IntRect ibox = round_rect(*dbox); @@ -1145,11 +1141,8 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, } sf = (double)psize / (double)block; - nr_arena_item_set_transform(root, (Geom::Affine)Geom::Scale(sf, sf)); - gc.transform.setIdentity(); - nr_arena_item_invoke_update( root, Geom::IntRect::infinite(), &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); + root->setTransform(Geom::Scale(sf)); + root->update(); ibox = round_rect(*dbox * Geom::Scale(sf)); if ( dump ) { @@ -1192,8 +1185,7 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, CAIRO_FORMAT_ARGB32, psize, psize, stride); Inkscape::DrawingContext ct(s, ua.min()); - nr_arena_item_invoke_render(ct, root, ua, - NR_ARENA_ITEM_RENDER_NO_CACHE ); + root->render(ct, ua, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_destroy(s); // convert to GdkPixbuf format @@ -1214,9 +1206,9 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, class SVGDocCache { public: - SVGDocCache( SPDocument *doc, NRArenaItem *root ) : doc(doc), root(root) {} + SVGDocCache( SPDocument *doc, Inkscape::DrawingItem *root ) : doc(doc), root(root) {} SPDocument *doc; - NRArenaItem *root; + Inkscape::DrawingItem *root; }; static std::map doc_cache; @@ -1294,7 +1286,7 @@ guchar *IconImpl::load_svg_pixels(std::list const &names, // fixme: Memory manage root if needed (Lauris) // This needs to be fixed indeed; this leads to a memory leak of a few megabytes these days // because shapes are being rendered which are not being freed - NRArenaItem *root = doc->getRoot()->invoke_show( arena, visionkey, SP_ITEM_SHOW_DISPLAY ); + Inkscape::DrawingItem *root = doc->getRoot()->invoke_show( arena, visionkey, SP_ITEM_SHOW_DISPLAY ); // store into the cache info = new SVGDocCache(doc, root); diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 8b5582163..4f6466ce8 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -28,8 +28,8 @@ #include "desktop-style.h" #include "dialogs/dialog-events.h" #include "display/canvas-bpath.h" // for SP_STROKE_LINEJOIN_* +#include "display/display-forward.h" #include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "document-private.h" #include "gradient-chemistry.h" #include "helper/stock-items.h" @@ -153,7 +153,8 @@ sp_stroke_radio_button(Gtk::RadioButton *tb, char const *icon, static Gtk::Image * sp_marker_prev_new(unsigned psize, gchar const *mname, SPDocument *source, SPDocument *sandbox, - gchar const *menu_id, NRArena const * /*arena*/, unsigned /*visionkey*/, NRArenaItem *root) + gchar const *menu_id, NRArena const * /*arena*/, unsigned /*visionkey*/, + Inkscape::DrawingItem *root) { // Retrieve the marker named 'mname' from the source SVG document SPObject const *marker = source->getObjectById(mname); @@ -250,7 +251,7 @@ sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPD // Do this here, outside of loop, to speed up preview generation: NRArena const *arena = NRArena::create(); unsigned const visionkey = SPItem::display_key_new(1); - NRArenaItem *root = sandbox->getRoot()->invoke_show((NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY); + Inkscape::DrawingItem *root = sandbox->getRoot()->invoke_show((NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY); for (; marker_list != NULL; marker_list = marker_list->next) { Inkscape::XML::Node *repr = reinterpret_cast(marker_list->data)->getRepr(); -- cgit v1.2.3 From 42c8636a2c5814746c41f1452ffa7df99cf21367 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 15:38:28 +0200 Subject: Document things figured out during the rewriting (bzr r10347.1.22) --- src/display/drawing-group.cpp | 11 ++++- src/display/drawing-image.cpp | 2 +- src/display/drawing-image.h | 2 +- src/display/drawing-item.cpp | 99 +++++++++++++++++++++++++++++++++++++++++-- src/display/drawing-item.h | 2 +- src/display/drawing-shape.cpp | 6 +-- src/display/drawing-shape.h | 2 +- src/display/drawing-text.cpp | 4 +- src/display/drawing-text.h | 4 +- 9 files changed, 115 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index 2d40f0a83..feaa7622a 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -31,6 +31,9 @@ DrawingGroup::~DrawingGroup() sp_style_unref(_style); } +/** @brief Set whether the group returns children from pick calls. + * Previously this feature was called "transparent groups". + */ void DrawingGroup::setPickChildren(bool p) { @@ -43,6 +46,10 @@ DrawingGroup::setStyle(SPStyle *style) _setStyleCommon(_style, style); } +/** @brief Set additional transform for the group. + * This is applied after the normal transform and mainly useful for + * markers, clipping paths, etc. + */ void DrawingGroup::setChildTransform(Geom::Affine const &new_trans) { @@ -105,10 +112,10 @@ DrawingGroup::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingGroup::_pickItem(Geom::Point const &p, double delta) +DrawingGroup::_pickItem(Geom::Point const &p, double delta, bool sticky) { for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - DrawingItem *picked = i->pick(p, delta, false); + DrawingItem *picked = i->pick(p, delta, sticky); if (picked) { return _pick_children ? picked : this; } diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index ea6f6ce3c..879809cfa 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -196,7 +196,7 @@ distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point co } DrawingItem * -DrawingImage::_pickItem(Geom::Point const &p, double delta) +DrawingImage::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { if (!_pixbuf) return NULL; diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index 570c10360..d66395aab 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -38,7 +38,7 @@ protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); GdkPixbuf *_pixbuf; cairo_surface_t *_surface; diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 318ff28e7..caed08e6f 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -22,6 +22,26 @@ namespace Inkscape { +/** @class DrawingItem + * @brief SVG drawing item for display. + * + * This was previously known as NRArenaItem. It represents the renderable + * portion of the SVG document. Typically this is created by the SP tree, + * in particular the show() virtual function. + * + * @section ObjectLifetime Object Lifetime + * Deleting a DrawingItem will cause all of its children to be deleted as well. + * This can lead to nasty surprises if you hold references to things + * which are children of what is being deleted. Therefore, in the SP tree, + * you always need to delete the item views of children before deleting + * the view of the parent. Do not call delete on things returned from show() + * - this will cause dangling pointers inside the SPItem and lead to a crash. + * Use the corresponing hide() method. + * + * Outside of the SP tree you should not use any references after the root node + * has been deleted. + */ + DrawingItem::DrawingItem(Drawing *drawing) : _drawing(drawing) , _parent(NULL) @@ -84,9 +104,8 @@ DrawingItem::~DrawingItem() DrawingItem * DrawingItem::parent() const { - //if (_clip_child || _mask_child) - // return NULL; - + // initially I wanted to return NULL if we are a clip or mask child, + // but the previous behavior was just to return the parent return _parent; } @@ -106,6 +125,7 @@ DrawingItem::prependChild(DrawingItem *item) _markForUpdate(STATE_ALL, false); } +/// Delete all regular children of this item (not mask or clip). void DrawingItem::clearChildren() { @@ -118,6 +138,7 @@ DrawingItem::clearChildren() _children.clear_and_dispose(DeleteDisposer()); } +/// Set the incremental transform for this item void DrawingItem::setTransform(Geom::Affine const &new_trans) { @@ -153,12 +174,14 @@ DrawingItem::setVisible(bool v) _markForRendering(); } +/// This is currently unused void DrawingItem::setSensitive(bool s) { _sensitive = s; } +/// Enable / disable storing the rendering in memory. void DrawingItem::setCached(bool c) { @@ -197,6 +220,8 @@ DrawingItem::setMask(DrawingItem *item) _markForUpdate(STATE_ALL, true); } +/// Move this item to the given place in the Z order of siblings. +/// Does nothing if the item has no parent. void DrawingItem::setZOrder(unsigned z) { @@ -217,6 +242,27 @@ DrawingItem::setItemBounds(Geom::OptRect const &bounds) _item_bbox = bounds; } +/** @brief Update derived data before operations. + * The purpose of this call is to recompute internal data which depends + * on the attributes of the object, but is not directly settable by the user. + * Precomputing this data speeds up later rendering, because some items + * can be omitted. + * + * Currently this method handles updating the visual and geometric bounding boxes + * in pixels, storing the total transformation from item space to the screen + * and cache invalidation. + * + * @param area Area to which the update should be restricted. Only takes effect + * if the bounding box is known. + * @param ctx A structure to store cascading state. + * @param flags Which internal data should be recomputed. This can be any combination + * of StateFlags. + * @param reset State fields that should be reset before processing them. This is + * a means to force a recomputation of internal data even if the item + * considers it up to date. Mainly for internal use, such as + * propagating bunding box recomputation to children when the item's + * transform changes. + */ void DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { @@ -315,6 +361,15 @@ struct MaskLuminanceToAlpha { } }; +/** @brief Rasterize items. + * This method submits the drawing opeartions required to draw this item + * to the supplied DrawingContext, restricting drawing the the specified area. + * + * This method does some common tasks and calls the item-specific rendering + * function, _renderItem(), to render e.g. paths or bitmaps. + * + * @param flags Rendering options. This deals mainly with cache control. + */ void DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { @@ -490,6 +545,13 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig _drawing->outlinecolor = saved_rgba; // restore outline color } +/** @brief Rasterize the clipping path. + * This method submits drawing operations required to draw a basic filled shape + * of the item to the supplied drawing context. Rendering is limited to the + * given area. The rendering of the clipped object is composited into + * the result of this call using the IN operator. See the implementation + * of render() for details. + */ void DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area) { @@ -523,6 +585,16 @@ DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area) } } +/** @brief Get the item under the specified point. + * Searches the tree for the first item in the Z-order which is closer than + * @a delta to the given point. The pick should be visual - for example + * an object with a thick stroke should pick on the entire area of the stroke. + * @param p Search point + * @param delta Maximum allowed distance from the point + * @param sticky Whether the pick should ignore visibility and sensitivity. + * When false, only visible and sensitive objects are considered. + * When true, invisible and insensitive objects can also be picked. + */ DrawingItem * DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) { @@ -544,6 +616,11 @@ DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) return NULL; } +/** Marks the current visual bounding box of the item for redrawing. + * This is called whenever the object changes its visible appearance. + * For some cases (such as setting opacity) this is enough, but for others + * _markForUpdate() also needs to be called. + */ void DrawingItem::_markForRendering() { @@ -561,10 +638,24 @@ DrawingItem::_markForRendering() nr_arena_request_render_rect (_drawing, dirty); } +/** @brief Marks the item as needing a recomputation of internal data. + * + * This mechanism avoids traversing the entire rendering tree (which could be vast) + * on every trivial state changed in any item. Only items marked as needing + * an update (having some bits in their _state unset) will be traversed + * during the update call. + * + * The _propagate variable is another optimization. We use it to specify that + * all children should also have the corresponding flags unset before checking + * whether they need to be traversed. This way there is one less traversal + * of the tree. Without this we would need to unset state bits in all children. + * With _propagate we do this during the update call, when we have to traverse + * the tree anyway. + */ void DrawingItem::_markForUpdate(unsigned flags, bool propagate) { - // here we can't simply assign because a previous markForUpdate call + // we can't simply assign because a previous markForUpdate call // could have had propagate=true even if this one has propagate=false if (propagate) _propagate = true; diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index b34ddf0e4..87b9ba048 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -109,7 +109,7 @@ protected: unsigned flags, unsigned reset) { return 0; } virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta) { return NULL; } + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky) { return NULL; } virtual bool _canClip() { return false; } Drawing *_drawing; diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index 1a56eea9b..602aa2515 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -232,13 +232,13 @@ DrawingShape::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingShape::_pickItem(Geom::Point const &p, double delta) +DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { if (_repick_after > 0) --_repick_after; - if (_repick_after > 0) // we are a slow, huge path. skip this pick, returning what was returned last time - return _last_pick; + if (_repick_after > 0) // we are a slow, huge path + return _last_pick; // skip this pick, returning what was returned last time if (!_curve) return NULL; if (!_style) return NULL; diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 7fd16374e..4b7b75e2a 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -36,7 +36,7 @@ protected: unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); virtual bool _canClip(); SPCurve *_curve; diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 784888bd7..e03a91b39 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -102,7 +102,7 @@ DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, } DrawingItem * -DrawingGlyphs::_pickItem(Geom::Point const &p, double delta) +DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { if (!_font || !_bbox) return NULL; @@ -248,7 +248,7 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingText::_pickItem(Geom::Point const &p, double delta) +DrawingText::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { DrawingItem *picked = DrawingGroup::_pickItem(p, delta); if (picked) return this; diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 58fecc067..f95a5073c 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -32,7 +32,7 @@ public: protected: unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); Geom::Affine *_glyph_transform; font_instance *_font; @@ -59,7 +59,7 @@ protected: unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); virtual bool _canClip(); Geom::OptRect _paintbox; -- cgit v1.2.3 From d44b95520c721d25c79287788bcc51865810051d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 15:40:27 +0200 Subject: Plug a giant gaping memory leak in Gaussian blur filter (bzr r10347.1.23) --- src/display/nr-filter-gaussian.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 3a6b425e1..a777d76a4 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -643,6 +643,13 @@ void FilterGaussian::render_cairo(FilterSlot &slot) } } + // free the temporary data + if ( use_IIR_x || use_IIR_y ) { + for(int i = 0; i < threads; ++i) { + delete[] tmpdata[i]; + } + } + cairo_surface_mark_dirty(downsampled); if (resampling) { cairo_surface_t *upsampled = cairo_surface_create_similar(downsampled, cairo_surface_get_content(downsampled), -- cgit v1.2.3 From 456dddb2670686427c60497702e86648635ce42e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 15:45:04 +0200 Subject: Fix compilation (oops). (bzr r10347.1.24) --- src/display/drawing-group.h | 2 +- src/display/drawing-item.cpp | 2 +- src/display/drawing-item.h | 2 +- src/display/drawing-text.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h index f7d6a2be3..072944b6c 100644 --- a/src/display/drawing-group.h +++ b/src/display/drawing-group.h @@ -36,7 +36,7 @@ protected: unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); virtual bool _canClip(); SPStyle *_style; diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index caed08e6f..53639f765 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -611,7 +611,7 @@ DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) expanded.expandBy(delta); if (expanded.contains(p)) { - return _pickItem(p, delta); + return _pickItem(p, delta, sticky); } return NULL; } diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 87b9ba048..f26c65df5 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -109,7 +109,7 @@ protected: unsigned flags, unsigned reset) { return 0; } virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky) { return NULL; } + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky = false) { return NULL; } virtual bool _canClip() { return false; } Drawing *_drawing; diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index e03a91b39..5fc732779 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -248,9 +248,9 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingText::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) +DrawingText::_pickItem(Geom::Point const &p, double delta, bool sticky) { - DrawingItem *picked = DrawingGroup::_pickItem(p, delta); + DrawingItem *picked = DrawingGroup::_pickItem(p, delta, sticky); if (picked) return this; return NULL; } -- cgit v1.2.3 From 75976ea07dba9b97186667524d0a76603de416af Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 7 Aug 2011 12:53:12 +0200 Subject: Rewrite NRArena -> Inkscape::Drawing. Call render and update methods on the Drawing rather than on the root DrawingItem. (bzr r10347.1.25) --- src/desktop.cpp | 21 +-- src/dialogs/clonetiler.cpp | 30 ++-- src/display/Makefile_insert | 4 +- src/display/canvas-arena.cpp | 82 +++++---- src/display/canvas-arena.h | 4 +- src/display/display-forward.h | 15 +- src/display/drawing-group.cpp | 6 +- src/display/drawing-group.h | 2 +- src/display/drawing-image.cpp | 8 +- src/display/drawing-image.h | 2 +- src/display/drawing-item.cpp | 42 ++--- src/display/drawing-item.h | 41 ++--- src/display/drawing-shape.cpp | 16 +- src/display/drawing-shape.h | 2 +- src/display/drawing-text.cpp | 10 +- src/display/drawing-text.h | 4 +- src/display/drawing.cpp | 159 +++++++++++++++++ src/display/drawing.h | 103 +++++++++++ src/display/nr-arena.cpp | 198 ---------------------- src/display/nr-arena.h | 75 -------- src/display/nr-filter-image.cpp | 19 +-- src/display/nr-filter.cpp | 6 +- src/extension/internal/cairo-png-out.cpp | 10 +- src/extension/internal/cairo-ps-out.cpp | 9 +- src/extension/internal/cairo-render-context.cpp | 8 +- src/extension/internal/cairo-renderer-pdf-out.cpp | 10 +- src/extension/internal/cairo-renderer.cpp | 1 - src/extension/internal/emf-win32-inout.cpp | 13 +- src/extension/internal/latex-pstricks-out.cpp | 12 +- src/extension/print.cpp | 23 ++- src/extension/print.h | 2 +- src/flood-context.cpp | 31 ++-- src/helper/pixbuf-ops.cpp | 19 +-- src/helper/png-write.cpp | 24 ++- src/marker.cpp | 10 +- src/print.cpp | 13 +- src/sp-clippath.cpp | 11 +- src/sp-clippath.h | 2 +- src/sp-flowtext.cpp | 6 +- src/sp-flowtext.h | 2 +- src/sp-image.cpp | 6 +- src/sp-item-group.cpp | 16 +- src/sp-item-group.h | 4 +- src/sp-item.cpp | 14 +- src/sp-item.h | 4 +- src/sp-mask.cpp | 10 +- src/sp-mask.h | 2 +- src/sp-pattern.cpp | 24 +-- src/sp-root.cpp | 10 +- src/sp-shape.cpp | 8 +- src/sp-shape.h | 2 +- src/sp-switch.cpp | 6 +- src/sp-switch.h | 2 +- src/sp-symbol.cpp | 8 +- src/sp-text.cpp | 8 +- src/sp-text.h | 2 +- src/sp-use.cpp | 8 +- src/svg-view.cpp | 4 +- src/text-context.h | 1 - src/trace/trace.cpp | 2 +- src/ui/cache/svg_preview_cache.cpp | 10 +- src/ui/cache/svg_preview_cache.h | 2 +- src/ui/dialog/filedialogimpl-win32.cpp | 4 +- src/ui/dialog/icon-preview.cpp | 21 +-- src/ui/view/view.h | 2 +- src/widgets/desktop-widget.cpp | 1 - src/widgets/icon.cpp | 49 +++--- src/widgets/stroke-style.cpp | 14 +- 68 files changed, 619 insertions(+), 680 deletions(-) create mode 100644 src/display/drawing.cpp create mode 100644 src/display/drawing.h delete mode 100644 src/display/nr-arena.cpp delete mode 100644 src/display/nr-arena.h (limited to 'src') diff --git a/src/desktop.cpp b/src/desktop.cpp index cceee9499..7a71862d3 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -72,7 +72,7 @@ #include "display/canvas-temporary-item-list.h" #include "display/drawing-group.h" #include "display/gnome-canvas-acetate.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/snap-indicator.h" #include "display/sodipodi-ctrlrect.h" #include "display/sp-canvas-group.h" @@ -230,7 +230,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid drawing = sp_canvas_item_new (main, SP_TYPE_CANVAS_ARENA, NULL); g_signal_connect (G_OBJECT (drawing), "arena_event", G_CALLBACK (_arena_handler), this); - SP_CANVAS_ARENA (drawing)->arena->delta = prefs->getDouble("/options/cursortolerance/value", 1.0); // default is 1 px + SP_CANVAS_ARENA (drawing)->drawing.delta = prefs->getDouble("/options/cursortolerance/value", 1.0); // default is 1 px if (prefs->getBool("/options/startmode/outline")) { // Start in outline mode @@ -287,11 +287,11 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( - SP_CANVAS_ARENA (drawing)->arena, + SP_CANVAS_ARENA (drawing)->drawing, dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - SP_CANVAS_ARENA (drawing)->root->prependChild(ai); + SP_CANVAS_ARENA (drawing)->drawing.root()->prependChild(ai); } namedview->show(this); @@ -404,6 +404,7 @@ void SPDesktop::destroy() if (drawing) { doc()->getRoot()->invoke_hide(dkey); + g_object_unref(drawing); drawing = NULL; } @@ -455,14 +456,14 @@ SPDesktop::remove_temporary_canvasitem (Inkscape::Display::TemporaryItem * tempi } void SPDesktop::_setDisplayMode(Inkscape::RenderMode mode) { - SP_CANVAS_ARENA (drawing)->arena->rendermode = mode; + SP_CANVAS_ARENA (drawing)->drawing.setRenderMode(mode); canvas->rendermode = mode; _display_mode = mode; sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw _widget->setTitle( sp_desktop_document(this)->getName() ); } void SPDesktop::_setDisplayColorMode(Inkscape::ColorMode mode) { - SP_CANVAS_ARENA (drawing)->arena->colormode = mode; + SP_CANVAS_ARENA (drawing)->drawing.setColorMode(mode); canvas->colorrendermode = mode; _display_color_mode = mode; sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw @@ -1570,11 +1571,11 @@ SPDesktop::setDocument (SPDocument *doc) number = namedview->getViewCount(); ai = doc->getRoot()->invoke_show( - SP_CANVAS_ARENA (drawing)->arena, + SP_CANVAS_ARENA (drawing)->drawing, dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - SP_CANVAS_ARENA (drawing)->root->prependChild(ai); + SP_CANVAS_ARENA (drawing)->drawing.root()->prependChild(ai); } namedview->show(this); /* Ugly hack */ @@ -1788,9 +1789,9 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop) SP_RGBA32_G_U(nv->pagecolor) + SP_RGBA32_B_U(nv->pagecolor)) >= 384) { // the background color is light or transparent, use black outline - SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs->getInt("/options/wireframecolors/onlight", 0xff); + SP_CANVAS_ARENA (desktop->drawing)->drawing.outlinecolor = prefs->getInt("/options/wireframecolors/onlight", 0xff); } else { // use white outline - SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs->getInt("/options/wireframecolors/ondark", 0xffffffff); + SP_CANVAS_ARENA (desktop->drawing)->drawing.outlinecolor = prefs->getInt("/options/wireframecolors/ondark", 0xffffffff); } } } diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index 2b08a307a..109b235d0 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -25,8 +25,8 @@ #include "desktop-handles.h" #include "dialog-events.h" #include "display/cairo-utils.h" +#include "display/drawing.h" #include "display/drawing-context.h" -#include "display/nr-arena.h" #include "display/drawing-item.h" #include "document.h" #include "filter-chemistry.h" @@ -832,15 +832,14 @@ static bool clonetiler_is_a_clone_of(SPObject *tile, SPObject *obj) return result; } -static NRArena const *trace_arena = NULL; +static Inkscape::Drawing *trace_drawing = NULL; static unsigned trace_visionkey; -static Inkscape::DrawingItem *trace_root; static gdouble trace_zoom; -static SPDocument *trace_doc; +static SPDocument *trace_doc = NULL; static void clonetiler_trace_hide_tiled_clones_recursively(SPObject *from) { - if (!trace_arena) + if (!trace_drawing) return; for (SPObject *o = from->firstChild(); o != NULL; o = o->next) { @@ -852,13 +851,11 @@ static void clonetiler_trace_hide_tiled_clones_recursively(SPObject *from) static void clonetiler_trace_setup(SPDocument *doc, gdouble zoom, SPItem *original) { - // FIXME MEMORY LEAK: the stuff here is never freed - - trace_arena = NRArena::create(); + trace_drawing = new Inkscape::Drawing(); /* Create ArenaItem and set transform */ trace_visionkey = SPItem::display_key_new(1); trace_doc = doc; - trace_root = trace_doc->getRoot()->invoke_show((NRArena *) trace_arena, trace_visionkey, SP_ITEM_SHOW_DISPLAY); + trace_drawing->setRoot(trace_doc->getRoot()->invoke_show(*trace_drawing, trace_visionkey, SP_ITEM_SHOW_DISPLAY)); // hide the (current) original and any tiled clones, we only want to pick the background original->invoke_hide(trace_visionkey); @@ -872,12 +869,12 @@ static void clonetiler_trace_setup(SPDocument *doc, gdouble zoom, SPItem *origin static guint32 clonetiler_trace_pick(Geom::Rect box) { - if (!trace_arena) { + if (!trace_drawing) { return 0; } - trace_root->setTransform(Geom::Scale(trace_zoom)); - trace_root->update(); + trace_drawing->root()->setTransform(Geom::Scale(trace_zoom)); + trace_drawing->update(); /* Item integer bbox in points */ Geom::IntRect ibox = (box * Geom::Scale(trace_zoom)).roundOutwards(); @@ -886,7 +883,7 @@ static guint32 clonetiler_trace_pick(Geom::Rect box) cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ibox.width(), ibox.height()); Inkscape::DrawingContext ct(s, ibox.min()); /* Render */ - trace_root->render(ct, ibox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); + trace_drawing->render(ct, ibox); double R = 0, G = 0, B = 0, A = 0; ink_cairo_surface_average_color(s, R, G, B, A); cairo_surface_destroy(s); @@ -898,10 +895,9 @@ static void clonetiler_trace_finish() { if (trace_doc) { trace_doc->getRoot()->invoke_hide(trace_visionkey); - } - if (trace_arena) { - ((NRObject *) trace_arena)->unreference(); - trace_arena = NULL; + delete trace_drawing; + trace_doc = NULL; + trace_drawing = NULL; } } diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index 1c51f19a0..1c7a21dae 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -23,6 +23,8 @@ ink_common_sources += \ display/canvas-text.h \ display/curve.cpp \ display/curve.h \ + display/drawing.cpp \ + display/drawing.h \ display/drawing-context.cpp \ display/drawing-context.h \ display/drawing-group.cpp \ @@ -45,8 +47,6 @@ ink_common_sources += \ display/guideline.h \ display/nr-3dutils.cpp \ display/nr-3dutils.h \ - display/nr-arena.h \ - display/nr-arena.cpp \ display/nr-arena-forward.h \ display/nr-filter-blend.cpp \ display/nr-filter-blend.h \ diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 81416fefb..6026ebd3f 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -15,7 +15,6 @@ #include "display/display-forward.h" #include "display/sp-canvas-util.h" #include "helper/sp-marshal.h" -#include "display/nr-arena.h" #include "display/canvas-arena.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" @@ -43,14 +42,8 @@ static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event); static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event); -static void sp_canvas_arena_request_update (NRArena *arena, DrawingItem *item, void *data); -static void sp_canvas_arena_request_render (NRArena *arena, NRRectL *area, void *data); - -NRArenaEventVector carenaev = { - {NULL}, - sp_canvas_arena_request_update, - sp_canvas_arena_request_render -}; +static void sp_canvas_arena_request_update (SPCanvasArena *ca, DrawingItem *item); +static void sp_canvas_arena_request_render (SPCanvasArena *ca, Geom::IntRect const &area); static SPCanvasItemClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; @@ -108,21 +101,27 @@ sp_canvas_arena_init (SPCanvasArena *arena) { arena->sticky = FALSE; - arena->arena = NRArena::create(); - nr_object_ref(arena->arena); - arena->arena->canvasarena = arena; - arena->arena->item_deleted.connect( + new (&arena->drawing) Inkscape::Drawing(arena); + + Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing); + root->setPickChildren(true); + root->setCached(true); + arena->drawing.setRoot(root); + + arena->drawing.signal_request_update.connect( + sigc::bind<0>( + sigc::ptr_fun(&sp_canvas_arena_request_update), + arena)); + arena->drawing.signal_request_render.connect( + sigc::bind<0>( + sigc::ptr_fun(&sp_canvas_arena_request_render), + arena)); + arena->drawing.signal_item_deleted.connect( sigc::bind<0>( sigc::ptr_fun(&sp_canvas_arena_item_deleted), arena)); - arena->root = new DrawingGroup(arena->arena); - arena->root->setPickChildren(true); - arena->root->setCached(true); - arena->active = NULL; - - nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena); } static void @@ -130,11 +129,7 @@ sp_canvas_arena_destroy (GtkObject *object) { SPCanvasArena *arena = SP_CANVAS_ARENA (object); - delete arena->root; - - nr_active_object_remove_listener_by_data ((NRActiveObject *) arena->arena, arena); - nr_object_unref ((NRObject *) arena->arena); - arena->arena = NULL; + arena->drawing.~Drawing(); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -151,9 +146,9 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned arena->ctx.ctm = affine; unsigned reset = flags & SP_CANVAS_UPDATE_AFFINE ? DrawingItem::STATE_ALL : 0; - arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, reset); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, reset); - Geom::OptIntRect b = arena->root->visualBounds(); + Geom::OptIntRect b = arena->drawing.root()->visualBounds(); if (b) { item->x1 = b->left() - 1; item->y1 = b->top() - 1; @@ -163,7 +158,7 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned if (arena->cursor) { /* Mess with enter/leave notifiers */ - DrawingItem *new_arena = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); + DrawingItem *new_arena = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = GTK_WIDGET (item->canvas)->window; @@ -205,8 +200,8 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) Inkscape::DrawingContext ct(buf->ct, r->min()); - arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, 0); - arena->root->render(ct, *r, 0); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx); + arena->drawing.render(ct, *r); } static double @@ -214,8 +209,8 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ { SPCanvasArena *arena = SP_CANVAS_ARENA (item); - arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); - DrawingItem *picked = arena->root->pick(p, arena->arena->delta, arena->sticky); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK); + DrawingItem *picked = arena->drawing.pick(p, arena->drawing.delta, arena->sticky); arena->picked = picked; @@ -235,7 +230,7 @@ sp_canvas_arena_viewbox_changed (SPCanvasItem *item, Geom::IntRect const &new_ar Geom::IntRect expanded = new_area; Geom::IntPoint expansion(new_area.width()/2, new_area.height()/2); expanded.expandBy(expansion); - nr_arena_set_cache_limit(arena->arena, expanded); + arena->drawing.setCacheLimit(expanded); } static gint @@ -260,8 +255,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->crossing.x, event->crossing.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); - arena->active = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + arena->active = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky); ret = sp_canvas_arena_send_event (arena, event); } break; @@ -279,8 +274,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->motion.x, event->motion.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - arena->root->update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); - new_arena = arena->root->pick(arena->c, arena->arena->delta, arena->sticky); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK); + new_arena = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = event->motion.window; @@ -324,16 +319,16 @@ sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event) } static void -sp_canvas_arena_request_update (NRArena */*arena*/, DrawingItem */*item*/, void *data) +sp_canvas_arena_request_update (SPCanvasArena *ca, DrawingItem */*item*/) { - sp_canvas_item_request_update (SP_CANVAS_ITEM (data)); + sp_canvas_item_request_update (SP_CANVAS_ITEM (ca)); } static void -sp_canvas_arena_request_render (NRArena */*arena*/, NRRectL *area, void *data) +sp_canvas_arena_request_render (SPCanvasArena *ca, Geom::IntRect const &area) { - if (!area) return; - sp_canvas_request_redraw (SP_CANVAS_ITEM (data)->canvas, area->x0, area->y0, area->x1, area->y1); + SPCanvas *canvas = SP_CANVAS_ITEM (ca)->canvas; + sp_canvas_request_redraw (canvas, area.left(), area.top(), area.right(), area.bottom()); } void @@ -365,11 +360,10 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, NRR Geom::OptIntRect area = r.upgrade_2geom(); if (!area) return; Inkscape::DrawingContext ct(surface, area->min()); - ca->root->update(Geom::IntRect::infinite(), ca->ctx, DrawingItem::STATE_ALL, 0); - ca->root->render(ct, *area, 0); + ca->drawing.update(Geom::IntRect::infinite(), ca->ctx); + ca->drawing.render(ct, *area); } - /* Local Variables: mode:c++ diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index e63a524f2..6c65bb0e5 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -16,6 +16,7 @@ #include #include <2geom/rect.h> #include "display/display-forward.h" +#include "display/drawing.h" #include "display/drawing-item.h" #include "display/sp-canvas.h" #include "display/sp-canvas-item.h" @@ -38,8 +39,7 @@ struct _SPCanvasArena { guint sticky : 1; Geom::Point c; // what is this? - NRArena *arena; - Inkscape::DrawingGroup *root; + Inkscape::Drawing drawing; Inkscape::UpdateContext ctx; Inkscape::DrawingItem *active; diff --git a/src/display/display-forward.h b/src/display/display-forward.h index d7e7d72ab..7dccb76ef 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -10,23 +10,30 @@ typedef struct _SPCanvasItemClass SPCanvasItemClass; struct SPCanvasGroup; struct SPCanvasGroupClass; class SPCurve; - -class NRArena; +typedef struct _SPCanvasArena SPCanvasArena; namespace Inkscape { -class DrawingContext; -class DrawingSurface; +class Drawing; class DrawingItem; class DrawingGroup; class DrawingImage; class DrawingShape; class DrawingGlyphs; class DrawingText; +class UpdateContext; + +class DrawingContext; +class DrawingSurface; +class DrawingCache; namespace Display { class TemporaryItem; class TemporaryItemList; } + +namespace Filters { + class Filter; +} } #endif /* !SEEN_DISPLAY_DISPLAY_FORWARD_H */ diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index feaa7622a..38ab73ca2 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -10,16 +10,16 @@ */ #include "display/cairo-utils.h" +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-item.h" #include "display/drawing-group.h" #include "libnr/nr-values.h" -#include "nr-arena.h" #include "style.h" namespace Inkscape { -DrawingGroup::DrawingGroup(Drawing *drawing) +DrawingGroup::DrawingGroup(Drawing &drawing) : DrawingItem(drawing) , _style(NULL) , _child_transform(NULL) @@ -75,7 +75,7 @@ unsigned DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { unsigned beststate = STATE_ALL; - bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { UpdateContext child_ctx(ctx); diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h index 072944b6c..7b0645bf4 100644 --- a/src/display/drawing-group.h +++ b/src/display/drawing-group.h @@ -22,7 +22,7 @@ class DrawingGroup : public DrawingItem { public: - DrawingGroup(Drawing *drawing); + DrawingGroup(Drawing &drawing); ~DrawingGroup(); bool pickChildren() { return _pick_children; } diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 879809cfa..64601354d 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -10,15 +10,15 @@ */ #include "display/cairo-utils.h" +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-image.h" -#include "nr-arena.h" #include "preferences.h" #include "style.h" namespace Inkscape { -DrawingImage::DrawingImage(Drawing *drawing) +DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) , _surface(NULL) @@ -115,7 +115,7 @@ DrawingImage::_updateItem(Geom::IntRect const &, UpdateContext const &, unsigned void DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { - bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); if (!outline) { if (!_pixbuf) return; @@ -200,7 +200,7 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { if (!_pixbuf) return NULL; - bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); if (outline) { Geom::Rect r = bounds(); diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index d66395aab..de8591221 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -24,7 +24,7 @@ class DrawingImage : public DrawingItem { public: - DrawingImage(Drawing *drawing); + DrawingImage(Drawing &drawing); ~DrawingImage(); void setARGB32Pixbuf(GdkPixbuf *pb); diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 53639f765..47f6c55a1 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -11,11 +11,11 @@ #include "display/cairo-utils.h" #include "display/cairo-templates.h" +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-item.h" #include "display/drawing-group.h" #include "display/drawing-surface.h" -#include "nr-arena.h" #include "nr-filter.h" #include "preferences.h" #include "style.h" @@ -42,7 +42,7 @@ namespace Inkscape { * has been deleted. */ -DrawingItem::DrawingItem(Drawing *drawing) +DrawingItem::DrawingItem(Drawing &drawing) : _drawing(drawing) , _parent(NULL) , _key(0) @@ -61,21 +61,21 @@ DrawingItem::DrawingItem(Drawing *drawing) // , _renders_opacity(0) , _clip_child(0) , _mask_child(0) + , _drawing_root(0) , _pick_children(0) { - nr_object_ref(_drawing); } DrawingItem::~DrawingItem() { - _drawing->item_deleted.emit(this); + _drawing.signal_item_deleted.emit(this); //if (!_children.empty()) { // g_warning("Removing item with children"); //} // remove from the set of cached items if (_cached) { - _drawing->cached_items.erase(this); + _drawing._cached_items.erase(this); } // remove this item from parent's children list // due to the effect of clearChildren(), this only happens for the top-level deleted item @@ -92,13 +92,14 @@ DrawingItem::~DrawingItem() _parent->_children.erase(ithis); } _parent->_markForUpdate(STATE_ALL, false); + } else if (_drawing_root) { + _drawing._root = NULL; } clearChildren(); delete _transform; delete _clip; delete _mask; delete _filter; - nr_object_unref(_drawing); } DrawingItem * @@ -187,9 +188,9 @@ DrawingItem::setCached(bool c) { _cached = c; if (c) { - _drawing->cached_items.insert(this); + _drawing._cached_items.insert(this); } else { - _drawing->cached_items.erase(this); + _drawing._cached_items.erase(this); } _markForUpdate(STATE_CACHE, false); } @@ -266,8 +267,8 @@ DrawingItem::setItemBounds(Geom::OptRect const &bounds) void DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { - bool render_filters = (_drawing->rendermode == Inkscape::RENDERMODE_NORMAL); - bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + bool render_filters = _drawing.renderFilters(); + bool outline = _drawing.outline(); // Set reset flags according to propagation status if (_propagate) { @@ -324,7 +325,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne // update cache if enabled if (_cached) { - Geom::OptIntRect cl = _drawing->cache_limit; + Geom::OptIntRect cl = _drawing.cacheLimit(); cl.intersectWith(_drawbox); if (cl) { if (_cache) { @@ -373,8 +374,8 @@ struct MaskLuminanceToAlpha { void DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { - bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); - bool render_filters = (_drawing->rendermode == Inkscape::RENDERMODE_NORMAL); + bool outline = _drawing.outline(); + bool render_filters = _drawing.renderFilters(); /* If we are invisible, just return successfully */ if (!_visible) return; @@ -530,19 +531,19 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig _renderItem(ct, *carea, flags); // render clip and mask, if any - guint32 saved_rgba = _drawing->outlinecolor; // save current outline color + guint32 saved_rgba = _drawing.outlinecolor; // save current outline color // render clippath as an object, using a different color Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (_clip) { - _drawing->outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips + _drawing.outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips _clip->render(ct, *carea, flags); } // render mask as an object, using a different color if (_mask) { - _drawing->outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks + _drawing.outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks _mask->render(ct, *carea, flags); } - _drawing->outlinecolor = saved_rgba; // restore outline color + _drawing.outlinecolor = saved_rgba; // restore outline color } /** @brief Rasterize the clipping path. @@ -624,7 +625,7 @@ DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) void DrawingItem::_markForRendering() { - bool outline = (_drawing->rendermode == Inkscape::RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); Geom::OptIntRect dirty = outline ? _bbox : _drawbox; if (!dirty) return; @@ -634,8 +635,7 @@ DrawingItem::_markForRendering() i->_cache->markDirty(*dirty); } } - - nr_arena_request_render_rect (_drawing, dirty); + _drawing.signal_request_render.emit(*dirty); } /** @brief Marks the item as needing a recomputation of internal data. @@ -665,7 +665,7 @@ DrawingItem::_markForUpdate(unsigned flags, bool propagate) if (_parent) { _parent->_markForUpdate(flags, false); } else { - nr_arena_request_update (_drawing, this); + _drawing.signal_request_update.emit(this); } } } diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index f26c65df5..ba0c42695 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -13,22 +13,16 @@ #define SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H #include +#include #include #include <2geom/rect.h> #include <2geom/affine.h> +#include "display/display-forward.h" -class NRArena; class SPStyle; -void nr_arena_set_cache_limit(NRArena *, Geom::OptIntRect const &); namespace Inkscape { -typedef ::NRArena Drawing; -class DrawingContext; -class DrawingCache; -class DrawingItem; -namespace Filters { class Filter; } - struct UpdateContext { Geom::Affine ctm; }; @@ -39,10 +33,8 @@ class InvalidItemException : public std::exception { } }; -typedef boost::intrusive::list_base_hook<> ChildrenListHook; - class DrawingItem - : public ChildrenListHook + : boost::noncopyable { public: enum RenderFlags { @@ -59,9 +51,8 @@ public: STATE_RENDER = (1<<4), // can be rendered STATE_ALL = (1<<5)-1 }; - typedef boost::intrusive::list ChildrenList; - DrawingItem(Drawing *drawing); + DrawingItem(Drawing &drawing); virtual ~DrawingItem(); Geom::OptIntRect geometricBounds() const { return _bbox; } @@ -69,7 +60,7 @@ public: Geom::OptRect itemBounds() const { return _item_bbox; } Geom::Affine ctm() const { return _ctm; } Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } - Drawing *drawing() const { return _drawing; } + Drawing &drawing() const { return _drawing; } DrawingItem *parent() const; void appendChild(DrawingItem *item); @@ -112,11 +103,21 @@ protected: virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky = false) { return NULL; } virtual bool _canClip() { return false; } - Drawing *_drawing; + // member variables start here + + Drawing &_drawing; DrawingItem *_parent; + + typedef boost::intrusive::list_member_hook<> ListHook; + ListHook _child_hook; + + typedef boost::intrusive::list< + DrawingItem, + boost::intrusive::member_hook + > ChildrenList; ChildrenList _children; - unsigned _key; ///< Some SPItems can have more than one NRArenaItem; + unsigned _key; ///< Some SPItems can have more than one DrawingItem; /// this value is a hack used to distinguish between them float _opacity; @@ -140,12 +141,14 @@ protected: //unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity unsigned _clip_child : 1; ///< If set, this is not a child of _parent, but a clipping path unsigned _mask_child : 1; ///< If set, this is not a child of _parent, but a mask + unsigned _drawing_root : 1; ///< If set, this is the root item of Drawing unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(), /// otherwise the group is returned - // temporary hacks until I rewrite NRArena to Inkscape::Drawing - friend class NRArena; - friend void ::nr_arena_set_cache_limit(NRArena *, Geom::OptIntRect const &); + friend class Drawing; + +private: + DrawingItem(DrawingItem const &); }; struct DeleteDisposer { diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index 602aa2515..1e41bf5dd 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -19,10 +19,10 @@ #include "display/canvas-arena.h" #include "display/canvas-bpath.h" #include "display/curve.h" +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-group.h" #include "display/drawing-shape.h" -#include "display/nr-arena.h" #include "helper/geom-curves.h" #include "helper/geom.h" #include "libnr/nr-convert2geom.h" @@ -32,7 +32,7 @@ namespace Inkscape { -DrawingShape::DrawingShape(Drawing *drawing) +DrawingShape::DrawingShape(Drawing &drawing) : DrawingItem(drawing) , _curve(NULL) , _style(NULL) @@ -112,7 +112,7 @@ DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u } boundingbox = Geom::OptRect(); - bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); // clear Cairo data to force update _nrstyle.update(); @@ -163,10 +163,10 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne if (!_curve || !_style) return; if (!area.intersects(_bbox)) return; // skip if not within bounding box - bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); if (outline) { - guint32 rgba = _drawing->outlinecolor; + guint32 rgba = _drawing.outlinecolor; { Inkscape::DrawingContext::Save save(ct); ct.transform(_ctm); @@ -243,7 +243,7 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) if (!_curve) return NULL; if (!_style) return NULL; - bool outline = (_drawing->rendermode == RENDERMODE_OUTLINE); + bool outline = _drawing.outline(); if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline) // fully transparent, no pick unless outline mode @@ -267,8 +267,8 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) bool needfill = (_nrstyle.fill.type != NRStyle::PAINT_NONE && _nrstyle.fill.opacity > 1e-3 && !outline); - if (_drawing->canvasarena) { - Geom::Rect viewbox = _drawing->canvasarena->item.canvas->getViewbox(); + if (_drawing.arena()) { + Geom::Rect viewbox = _drawing.arena()->item.canvas->getViewbox(); viewbox.expandBy (width); pathv_matrix_point_bbox_wind_distance(_curve->get_pathvector(), _ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox); } else { diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 4b7b75e2a..153dcd54e 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -24,7 +24,7 @@ class DrawingShape : public DrawingItem { public: - DrawingShape(Drawing *drawing); + DrawingShape(Drawing &drawing); ~DrawingShape(); void setPath(SPCurve *curve); diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 5fc732779..2f0881c49 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -11,17 +11,17 @@ #include "display/cairo-utils.h" #include "display/canvas-bpath.h" // for SPWindRule (WTF!) +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-surface.h" #include "display/drawing-text.h" -#include "display/nr-arena.h" #include "helper/geom.h" #include "libnrtype/font-instance.h" #include "style.h" namespace Inkscape { -DrawingGlyphs::DrawingGlyphs(Drawing *drawing) +DrawingGlyphs::DrawingGlyphs(Drawing &drawing) : DrawingItem(drawing) , _glyph_transform(NULL) , _font(NULL) @@ -115,7 +115,7 @@ DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) -DrawingText::DrawingText(Drawing *drawing) +DrawingText::DrawingText(Drawing &drawing) : DrawingGroup(drawing) {} @@ -164,9 +164,9 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un void DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { - if (_drawing->rendermode == RENDERMODE_OUTLINE) { + if (_drawing.outline()) { DrawingContext::Save save(ct); - guint32 rgba = _drawing->outlinecolor; + guint32 rgba = _drawing.outlinecolor; ct.setSource(rgba); ct.setTolerance(1.25); // low quality, but good enough for outline mode ct.newPath(); diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index f95a5073c..671f8f64e 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -24,7 +24,7 @@ class DrawingGlyphs : public DrawingItem { public: - DrawingGlyphs(Drawing *drawing); + DrawingGlyphs(Drawing &drawing); ~DrawingGlyphs(); void setGlyph(font_instance *font, int glyph, Geom::Affine const &trans); @@ -46,7 +46,7 @@ class DrawingText : public DrawingGroup { public: - DrawingText(Drawing *drawing); + DrawingText(Drawing &drawing); ~DrawingText(); void clear(); diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp new file mode 100644 index 000000000..22bd84587 --- /dev/null +++ b/src/display/drawing.cpp @@ -0,0 +1,159 @@ +/** + * @file + * @brief SVG drawing for display + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/drawing.h" +#include "nr-filter-gaussian.h" +#include "nr-filter-types.h" + +namespace Inkscape { + +Drawing::Drawing(SPCanvasArena *arena) + : _root(NULL) + , outlinecolor(0x000000ff) + , delta(0) + , _exact(false) + , _rendermode(RENDERMODE_NORMAL) + , _colormode(COLORMODE_NORMAL) + , _blur_quality(BLUR_QUALITY_BEST) + , _filter_quality(Filters::FILTER_QUALITY_BEST) + , _canvasarena(arena) +{ + +} + +Drawing::~Drawing() +{ + delete _root; +} + +void +Drawing::setRoot(DrawingItem *item) +{ + delete _root; + _root = item; + _root->_drawing_root = true; +} + +RenderMode +Drawing::renderMode() const +{ + return _exact ? RENDERMODE_NORMAL : _rendermode; +} +ColorMode +Drawing::colorMode() const +{ + return (outline() || _exact) ? COLORMODE_NORMAL : _colormode; +} +bool +Drawing::outline() const +{ + return renderMode() == RENDERMODE_OUTLINE; +} +bool +Drawing::renderFilters() const +{ + return renderMode() == RENDERMODE_NORMAL; +} +int +Drawing::blurQuality() const +{ + if (renderMode() == RENDERMODE_NORMAL) { + return _exact ? BLUR_QUALITY_BEST : _blur_quality; + } else { + return BLUR_QUALITY_WORST; + } +} +int +Drawing::filterQuality() const +{ + if (renderMode() == RENDERMODE_NORMAL) { + return _exact ? Filters::FILTER_QUALITY_BEST : _filter_quality; + } else { + return Filters::FILTER_QUALITY_WORST; + } +} + +void +Drawing::setRenderMode(RenderMode mode) +{ + _rendermode = mode; +} +void +Drawing::setColorMode(ColorMode mode) +{ + _colormode = mode; +} +void +Drawing::setBlurQuality(int q) +{ + _blur_quality = q; +} +void +Drawing::setFilterQuality(int q) +{ + _filter_quality = q; +} +void +Drawing::setExact(bool e) +{ + _exact = e; +} + +Geom::OptIntRect const & +Drawing::cacheLimit() const +{ + return _cache_limit; +} +void +Drawing::setCacheLimit(Geom::OptIntRect const &r) +{ + _cache_limit = r; + for (std::set::iterator i = _cached_items.begin(); + i != _cached_items.end(); ++i) + { + (*i)->_markForUpdate(DrawingItem::STATE_CACHE, false); + } +} + +void +Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + // TODO add autocache + if (!_root) return; + _root->update(area, ctx, flags, reset); +} + +void +Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (!_root) return; + _root->render(ct, area, flags); +} + +DrawingItem * +Drawing::pick(Geom::Point const &p, double delta, bool sticky) +{ + if (!_root) return NULL; + return _root->pick(p, delta, sticky); +} + +} // 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.h b/src/display/drawing.h new file mode 100644 index 000000000..4560d277d --- /dev/null +++ b/src/display/drawing.h @@ -0,0 +1,103 @@ +/** + * @file + * @brief SVG drawing for display + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_H + +#include +#include +#include +#include <2geom/rect.h> +#include "display/display-forward.h" +#include "display/drawing-item.h" +#include "display/rendermode.h" + +namespace Inkscape { + +struct OutlineColors { + guint32 paths; + guint32 clippaths; + guint32 masks; + guint32 images; +}; + +class Drawing + : boost::noncopyable +{ +public: + Drawing(SPCanvasArena *arena = NULL); + ~Drawing(); + + DrawingItem *root() { return _root; } + SPCanvasArena *arena() { return _canvasarena; } + void setRoot(DrawingItem *item); + + RenderMode renderMode() const; + ColorMode colorMode() const; + bool outline() const; + bool renderFilters() const; + int blurQuality() const; + int filterQuality() const; + void setRenderMode(RenderMode mode); + void setColorMode(ColorMode mode); + void setBlurQuality(int q); + void setFilterQuality(int q); + void setExact(bool e); + + Geom::OptIntRect const &cacheLimit() const; + void setCacheLimit(Geom::OptIntRect const &r); + + OutlineColors const &colors() const { return _colors; } + + void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0); + void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); + DrawingItem *pick(Geom::Point const &p, double delta, bool sticky); + + sigc::signal signal_request_update; + sigc::signal signal_request_render; + sigc::signal signal_item_deleted; + +private: + DrawingItem *_root; + std::set _cached_items; +public: + // TODO: remove these temporarily public members + guint32 outlinecolor; + double delta; +private: + bool _exact; // if true then rendering must be exact + RenderMode _rendermode; + ColorMode _colormode; + int _blur_quality; + int _filter_quality; + Geom::OptIntRect _cache_limit; + + OutlineColors _colors; + + SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen but used for export etc. + + friend class DrawingItem; +}; + +} // end namespace Inkscape + +#endif // !SEEN_INKSCAPE_DRAWING_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp deleted file mode 100644 index b3e962201..000000000 --- a/src/display/nr-arena.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#define __NR_ARENA_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "display/drawing-item.h" -#include "display/nr-arena.h" -#include "display/nr-filter-gaussian.h" -#include "display/nr-filter-types.h" -#include "preferences.h" -#include "color.h" -#include "libnr/nr-rect.h" -#include "libnr/nr-rect-l.h" - -static void nr_arena_class_init (NRArenaClass *klass); -static void nr_arena_init (NRArena *arena); -static void nr_arena_finalize (NRObject *object); - -static NRActiveObjectClass *parent_class; - -NRType -nr_arena_get_type (void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type (NR_TYPE_ACTIVE_OBJECT, - "NRArena", - sizeof (NRArenaClass), - sizeof (NRArena), - (void (*) (NRObjectClass *)) nr_arena_class_init, - (void (*) (NRObject *)) nr_arena_init); - } - return type; -} - -static void -nr_arena_class_init (NRArenaClass *klass) -{ - NRObjectClass *object_class = (NRObjectClass *) klass; - - parent_class = (NRActiveObjectClass *) (((NRObjectClass *) klass)->parent); - - object_class->finalize = nr_arena_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor; -} - -static void -nr_arena_init (NRArena *arena) -{ - arena->delta = 0; // to be set by desktop from prefs - arena->renderoffscreen = false; // use render values from preferences otherwise render exact - arena->rendermode = Inkscape::RENDERMODE_NORMAL; // default is normal render - arena->colormode = Inkscape::COLORMODE_NORMAL; // default is normal color - arena->blurquality = BLUR_QUALITY_NORMAL; - arena->filterquality = Inkscape::Filters::FILTER_QUALITY_NORMAL; - arena->outlinecolor = 0xff; // black; to be set by desktop from bg color - arena->canvasarena = NULL; -} - -static void -nr_arena_finalize (NRObject *object) -{ - ((NRObjectClass *) (parent_class))->finalize (object); -} - -void -nr_arena_request_update (NRArena *arena, Inkscape::DrawingItem *item) -{ - NRActiveObject *aobject = (NRActiveObject *) arena; - - nr_return_if_fail (arena != NULL); - nr_return_if_fail (NR_IS_ARENA (arena)); - nr_return_if_fail (item != NULL); - - // setup render parameter - if (arena->renderoffscreen == false) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - arena->blurquality = prefs->getInt("/options/blurquality/value", 0); - arena->filterquality = prefs->getInt("/options/filterquality/value", 0); - } else { - arena->blurquality = BLUR_QUALITY_BEST; - arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; - arena->rendermode = Inkscape::RENDERMODE_NORMAL; - arena->colormode = Inkscape::COLORMODE_NORMAL; - } - - 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_update) { - avector->request_update (arena, item, listener->data); - } - } - } -} - -void -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)); - if (!area) return; - - // setup render parameter - if (arena->renderoffscreen == false) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - arena->blurquality = prefs->getInt("/options/blurquality/value", 0); - arena->filterquality = prefs->getInt("/options/filterquality/value", 0); - } else { - arena->blurquality = BLUR_QUALITY_BEST; - arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; - arena->rendermode = Inkscape::RENDERMODE_NORMAL; - arena->colormode = Inkscape::COLORMODE_NORMAL; - } - 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, &nr_area, listener->data); - } - } - } -} - -/** - set arena to offscreen mode - rendering will be exact - @param arena NRArena object -*/ -void -nr_arena_set_renderoffscreen (NRArena *arena) -{ - nr_return_if_fail (arena != NULL); - nr_return_if_fail (NR_IS_ARENA (arena)); - - // the real assignment to the quality indicators is in the update function - arena->renderoffscreen = true; - -} - -void -nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit) -{ - arena->cache_limit = cache_limit; - for (std::set::iterator i = arena->cached_items.begin(); - i != arena->cached_items.end(); ++i) - { - (*i)->_markForUpdate(Inkscape::DrawingItem::STATE_CACHE, false); - } -} - -#define FLOAT_TO_UINT8(f) (int(f*255)) -#define RGBA_R(v) ((v) >> 24) -#define RGBA_G(v) (((v) >> 16) & 0xff) -#define RGBA_B(v) (((v) >> 8) & 0xff) -#define RGBA_A(v) ((v) & 0xff) - -void nr_arena_separate_color_plates(guint32* rgba){ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool render_cyan = prefs->getBool("/options/printcolorspreview/cyan", true); - bool render_magenta = prefs->getBool("/options/printcolorspreview/magenta", true); - bool render_yellow = prefs->getBool("/options/printcolorspreview/yellow", true); - bool render_black = prefs->getBool("/options/printcolorspreview/black", true); - - float rgb_v[3]; - float cmyk_v[4]; - sp_color_rgb_to_cmyk_floatv (cmyk_v, RGBA_R(*rgba)/256.0, RGBA_G(*rgba)/256.0, RGBA_B(*rgba)/256.0); - sp_color_cmyk_to_rgb_floatv (rgb_v, render_cyan ? cmyk_v[0] : 0, - render_magenta ? cmyk_v[1] : 0, - render_yellow ? cmyk_v[2] : 0, - render_black ? cmyk_v[3] : 0); - *rgba = (FLOAT_TO_UINT8(rgb_v[0])<<24) + (FLOAT_TO_UINT8(rgb_v[1])<<16) + (FLOAT_TO_UINT8(rgb_v[2])<<8) + 0xff; -} - -/* - 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.h b/src/display/nr-arena.h deleted file mode 100644 index a444ed505..000000000 --- a/src/display/nr-arena.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __NR_ARENA_H__ -#define __NR_ARENA_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include -#include -#include -#include <2geom/rect.h> -#include "display/rendermode.h" -#include "libnr/nr-forward.h" -#include "libnr/nr-object.h" -#include "display/display-forward.h" - -G_BEGIN_DECLS - -typedef struct _SPCanvasArena SPCanvasArena; - -G_END_DECLS - -#define NR_TYPE_ARENA (nr_arena_get_type ()) -#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)) - -class SPPainter; - -NRType nr_arena_get_type (void); - -struct NRArenaEventVector { - NRObjectEventVector parent; - void (* request_update) (NRArena *arena, Inkscape::DrawingItem *item, void *data); - void (* request_render) (NRArena *arena, NRRectL *area, void *data); -}; - -struct NRArena : public NRActiveObject { - static NRArena *create() { - return reinterpret_cast(nr_object_new(NR_TYPE_ARENA)); - } - - double delta; - bool renderoffscreen; // if true then rendering must be exact - Inkscape::RenderMode rendermode; - Inkscape::ColorMode colormode; - int blurquality; // will be updated during update from preferences - int filterquality; // will be updated during update from preferences - Geom::OptIntRect cache_limit; - std::set cached_items; - - guint32 outlinecolor; - SPCanvasArena *canvasarena; // may be NULL is this arena is not the screen but used for export etc. - - sigc::signal item_deleted; -}; - -struct NRArenaClass : public NRActiveObjectClass { -}; - -void nr_arena_request_update (NRArena *arena, Inkscape::DrawingItem *item); -void nr_arena_request_render_rect (NRArena *arena, Geom::OptIntRect const &area); -void nr_arena_set_renderoffscreen (NRArena *arena); -void nr_arena_set_cache_limit (NRArena *arena, Geom::OptIntRect const &cache_limit); - -void nr_arena_separate_color_plates(guint32* rgba); - -#endif diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 55cd02697..b176cdcef 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -14,7 +14,7 @@ #include "sp-item.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-item.h" #include "display/nr-filter.h" #include "display/nr-filter-image.h" @@ -73,18 +73,17 @@ void FilterImage::render_cairo(FilterSlot &slot) // like the one for DrawingItems document->ensureUpToDate(); - NRArena* arena = NRArena::create(); + Drawing drawing; Geom::OptRect optarea = SVGElem->getBounds(Geom::identity()); if (!optarea) return; unsigned const key = SPItem::display_key_new(1); - DrawingItem *ai = SVGElem->invoke_show(arena, key, SP_ITEM_SHOW_DISPLAY); - + DrawingItem *ai = SVGElem->invoke_show(drawing, key, SP_ITEM_SHOW_DISPLAY); if (!ai) { - g_warning("feImage renderer: error creating NRArenaItem for SVG Element"); - nr_object_unref((NRObject *) arena); + g_warning("feImage renderer: error creating DrawingItem for SVG Element"); return; } + drawing.setRoot(ai); Geom::Rect area = *optarea; Geom::Affine pu2pb = slot.get_units().get_matrix_primitiveunits2pb(); @@ -104,13 +103,9 @@ void FilterImage::render_cairo(FilterSlot &slot) ct.translate(render_rect.min()); // Update to renderable state - UpdateContext ctx; - ai->setTransform(Geom::identity()); - ai->update(render_rect, ctx, DrawingItem::STATE_ALL, 0); - ai->render(ct, render_rect, DrawingItem::RENDER_BYPASS_CACHE); + drawing.update(render_rect); + drawing.render(ct, render_rect); SVGElem->invoke_hide(key); - //delete ai; // should be deleted by hide() above - nr_object_unref((NRObject*) arena); slot.set(_output, out); cairo_surface_destroy(out); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index abd102452..e84e6f0c2 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -38,7 +38,7 @@ #include "display/nr-filter-tile.h" #include "display/nr-filter-turbulence.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-item.h" #include "display/drawing-context.h" #include <2geom/affine.h> @@ -108,8 +108,8 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, Draw return 1; } - FilterQuality const filterquality = (FilterQuality)item->drawing()->filterquality; - int const blurquality = item->drawing()->blurquality; + FilterQuality const filterquality = (FilterQuality)item->drawing().filterQuality(); + int const blurquality = item->drawing().blurQuality(); Geom::Affine trans = item->ctm(); diff --git a/src/extension/internal/cairo-png-out.cpp b/src/extension/internal/cairo-png-out.cpp index 4b551e730..678a46095 100644 --- a/src/extension/internal/cairo-png-out.cpp +++ b/src/extension/internal/cairo-png-out.cpp @@ -27,7 +27,7 @@ #include "extension/print.h" #include "extension/db.h" #include "extension/output.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/curve.h" #include "display/canvas-bpath.h" @@ -56,11 +56,11 @@ png_render_document_to_file(SPDocument *doc, gchar const *filename) doc->ensureUpToDate(); /* Start */ - // Create new arena + SPItem *base = doc->getRoot(); - NRArena *arena = NRArena::create(); + Inkscape::Drawing drawing; unsigned dkey = SPItem::display_key_new(1); - base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); + base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY); /* Create renderer and context */ renderer = new CairoRenderer(); @@ -75,9 +75,7 @@ png_render_document_to_file(SPDocument *doc, gchar const *filename) } renderer->destroyContext(ctx); - /* Release arena */ base->invoke_hide(dkey); - nr_object_unref((NRObject *) arena); /* end */ delete renderer; diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 7e5324e57..9cc3a4ce3 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -29,7 +29,7 @@ #include "extension/print.h" #include "extension/db.h" #include "extension/output.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/curve.h" #include "display/canvas-bpath.h" @@ -85,10 +85,9 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l if (!base) return false; - /* Create new arena */ - NRArena *arena = NRArena::create(); + Inkscape::Drawing drawing; unsigned dkey = SPItem::display_key_new(1); - base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); + base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY); /* Create renderer and context */ CairoRenderer *renderer = new CairoRenderer(); @@ -110,9 +109,7 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l } } - /* Release arena */ base->invoke_hide(dkey); - nr_object_unref((NRObject *) arena); renderer->destroyContext(ctx); delete renderer; diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index c7cba09bb..c3a8a790b 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -32,7 +32,7 @@ #include #include -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/display-forward.h" #include "display/curve.h" #include "display/canvas-bpath.h" @@ -1092,8 +1092,8 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver pattern_ctx->setTransform(&pcs2dev); pattern_ctx->pushState(); - // create arena and group - NRArena *arena = NRArena::create(); + // create drawing and group + Inkscape::Drawing drawing; unsigned dkey = SPItem::display_key_new(1); // show items and render them @@ -1101,7 +1101,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children for ( SPObject *child = pat_i->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - SP_ITEM (child)->invoke_show (arena, dkey, SP_ITEM_REFERENCE_FLAGS); + SP_ITEM (child)->invoke_show (drawing, dkey, SP_ITEM_REFERENCE_FLAGS); _renderer->renderItem(pattern_ctx, SP_ITEM (child)); } } diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 5be9e15c3..7ea5718f7 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -29,7 +29,7 @@ #include "extension/print.h" #include "extension/db.h" #include "extension/output.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/curve.h" #include "display/canvas-bpath.h" @@ -81,10 +81,10 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int } /* Create new arena */ - NRArena *arena = NRArena::create(); - nr_arena_set_renderoffscreen (arena); + Inkscape::Drawing drawing; + drawing.setExact(true); unsigned dkey = SPItem::display_key_new(1); - base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); + base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY); /* Create renderer and context */ CairoRenderer *renderer = new CairoRenderer(); @@ -105,9 +105,7 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int } } - /* Release arena */ base->invoke_hide(dkey); - nr_object_unref((NRObject *) arena); renderer->destroyContext(ctx); delete renderer; diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 76fc5073f..5e7fb991a 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -36,7 +36,6 @@ #include #include -#include "display/nr-arena.h" #include "display/display-forward.h" #include "display/curve.h" #include "display/canvas-bpath.h" diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp index 646b33507..aadfce86f 100644 --- a/src/extension/internal/emf-win32-inout.cpp +++ b/src/extension/internal/emf-win32-inout.cpp @@ -36,8 +36,8 @@ #include "extension/print.h" #include "extension/db.h" #include "extension/output.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing.h" +#include "display/drawing-item.h" #include "unit-constants.h" #include "clear-n_.h" @@ -106,9 +106,10 @@ emf_print_document_to_file(SPDocument *doc, gchar const *filename) /* fixme: This has to go into module constructor somehow */ /* Create new arena */ mod->base = doc->getRoot(); - mod->arena = NRArena::create(); + Inkscape::Drawing drawing; mod->dkey = SPItem::display_key_new(1); - mod->root = mod->base->invoke_show(mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY); + mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(mod->root); /* Print document */ ret = mod->begin(doc); if (ret) { @@ -120,9 +121,7 @@ emf_print_document_to_file(SPDocument *doc, gchar const *filename) /* Release arena */ mod->base->invoke_hide(mod->dkey); mod->base = NULL; - mod->root = NULL; - nr_object_unref((NRObject *) mod->arena); - mod->arena = NULL; + mod->root = NULL; // deleted by invoke_hide /* end */ mod->set_param_string("destination", oldoutput); diff --git a/src/extension/internal/latex-pstricks-out.cpp b/src/extension/internal/latex-pstricks-out.cpp index 000280158..3a16268e6 100644 --- a/src/extension/internal/latex-pstricks-out.cpp +++ b/src/extension/internal/latex-pstricks-out.cpp @@ -18,8 +18,8 @@ #include "extension/system.h" #include "extension/print.h" #include "extension/db.h" -#include "display/nr-arena.h" #include "display/display-forward.h" +#include "display/drawing.h" #include "sp-root.h" @@ -61,21 +61,19 @@ void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, /* Start */ context.module = mod; /* fixme: This has to go into module constructor somehow */ - // Create new arena mod->base = doc->getRoot(); - mod->arena = NRArena::create(); + Inkscape::Drawing drawing; mod->dkey = SPItem::display_key_new (1); - mod->root = (mod->base)->invoke_show (mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY); + mod->root = (mod->base)->invoke_show (drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(mod->root); /* Print document */ ret = mod->begin (doc); (mod->base)->invoke_print (&context); ret = mod->finish (); - /* Release arena */ + /* Release things */ (mod->base)->invoke_hide (mod->dkey); mod->base = NULL; mod->root = NULL; // should have been deleted by invoke_hide - nr_object_unref ((NRObject *) mod->arena); - mod->arena = NULL; /* end */ mod->set_param_string("destination", oldoutput); diff --git a/src/extension/print.cpp b/src/extension/print.cpp index ad8c4c38d..f2dbb0b9b 100644 --- a/src/extension/print.cpp +++ b/src/extension/print.cpp @@ -15,25 +15,22 @@ namespace Inkscape { namespace Extension { -Print::Print (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp) : Extension(in_repr, in_imp) +Print::Print (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp) + : Extension(in_repr, in_imp) + , base(NULL) + , drawing(NULL) + , root(NULL) + , dkey(0) { - base = NULL; - arena = NULL; - root = NULL; - dkey = 0; - - return; } Print::~Print (void) -{ - return; -} +{} bool Print::check (void) { - return Extension::check(); + return Extension::check(); } unsigned int @@ -108,14 +105,14 @@ Print::text (const char* text, Geom::Point p, const SPStyle* style) bool Print::textToPath (void) { - return imp->textToPath(this); + return imp->textToPath(this); } //whether embed font in print output (EPS especially) bool Print::fontEmbedded (void) { - return imp->fontEmbedded(this); + return imp->fontEmbedded(this); } } } /* namespace Inkscape, Extension */ diff --git a/src/extension/print.h b/src/extension/print.h index b3c686d26..c2276126b 100644 --- a/src/extension/print.h +++ b/src/extension/print.h @@ -23,7 +23,7 @@ class Print : public Extension { public: /* TODO: These are public for the short term, but this should be fixed */ SPItem *base; - NRArena *arena; + Inkscape::Drawing *drawing; Inkscape::DrawingItem *root; unsigned int dkey; diff --git a/src/flood-context.cpp b/src/flood-context.cpp index a71333a4f..8603f8b66 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -32,11 +32,10 @@ #include "desktop-handles.h" #include "desktop-style.h" #include "display/cairo-utils.h" -#include "display/canvas-arena.h" #include "display/drawing-context.h" #include "display/drawing-image.h" #include "display/drawing-item.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/sp-canvas.h" #include "document.h" #include "flood-context.h" @@ -777,10 +776,6 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even SPDesktop *desktop = event_context->desktop; SPDocument *document = sp_desktop_document(desktop); - /* Create new arena */ - NRArena *arena = NRArena::create(); - unsigned dkey = SPItem::display_key_new(1); - document->ensureUpToDate(); Geom::OptRect bbox = document->getRoot()->getBounds(Geom::identity()); @@ -809,20 +804,22 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even Geom::Scale scale(zoom_scale, zoom_scale); Geom::Affine affine = scale * Geom::Translate(-origin * scale); - - /* Create ArenaItems and set transform */ - Inkscape::DrawingItem *root = document->getRoot()->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); - root->setTransform(affine); - - Inkscape::UpdateContext ctx; - Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height); - root->update(final_bbox, ctx, Inkscape::DrawingItem::STATE_ALL, 0); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); guchar *px = g_new(guchar, stride * height); guint32 bgcolor, dtc; - { // this block limits the lifetime of DrawingContext + { // this block limits the lifetime of Drawing and DrawingContext + /* Create DrawingItems and set transform */ + unsigned dkey = SPItem::display_key_new(1); + Inkscape::Drawing drawing; + Inkscape::DrawingItem *root = document->getRoot()->invoke_show( drawing, dkey, SP_ITEM_SHOW_DISPLAY); + root->setTransform(affine); + drawing.setRoot(root); + + Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height); + drawing.update(final_bbox); + 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)); @@ -838,15 +835,13 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even ct.paint(); ct.setOperator(CAIRO_OPERATOR_OVER); - root->render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); + drawing.render(ct, final_bbox); cairo_surface_flush(s); cairo_surface_destroy(s); // Hide items document->getRoot()->invoke_hide(dkey); - - nr_object_unref((NRObject *) arena); } guchar *trace_px = g_new(guchar, width * height); diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index 959007450..3f987dc01 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -23,9 +23,9 @@ #include "interface.h" #include "helper/png-write.h" #include "display/cairo-utils.h" +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-item.h" -#include "display/nr-arena.h" #include "document.h" #include "sp-item.h" #include "sp-root.h" @@ -112,9 +112,9 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, if (width == 0 || height == 0) return NULL; GdkPixbuf* pixbuf = NULL; - /* Create new arena for offscreen rendering*/ - NRArena *arena = NRArena::create(); - nr_arena_set_renderoffscreen(arena); + /* Create new drawing for offscreen rendering*/ + Inkscape::Drawing drawing; + drawing.setExact(true); unsigned dkey = SPItem::display_key_new(1); doc->ensureUpToDate(); @@ -133,9 +133,9 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, Geom::Affine affine = scale * Geom::Translate(-origin * scale); /* Create ArenaItems and set transform */ - Inkscape::DrawingItem *root = doc->getRoot()->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); + Inkscape::DrawingItem *root = doc->getRoot()->invoke_show( drawing, dkey, SP_ITEM_SHOW_DISPLAY); root->setTransform(affine); - Inkscape::UpdateContext ctx; + drawing.setRoot(root); // We show all and then hide all items we don't want, instead of showing only requested items, // because that would not work if the shown item references something in defs @@ -144,7 +144,7 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, } Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height); - root->update(final_bbox, ctx, Inkscape::DrawingItem::STATE_ALL, 0); + drawing.update(final_bbox); cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); @@ -152,7 +152,7 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, Inkscape::DrawingContext ct(surface, Geom::Point(0,0)); // render items - root->render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); + drawing.render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(surface), GDK_COLORSPACE_RGB, TRUE, @@ -167,8 +167,7 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, g_warning("sp_generate_internal_bitmap: not enough memory to create pixel buffer. Need %lld.", size); cairo_surface_destroy(surface); } - doc->getRoot()->invoke_hide(dkey); - nr_object_unref((NRObject *) arena); + doc->getRoot()->invoke_hide(dkey); // gdk_pixbuf_save (pixbuf, "C:\\temp\\internal.jpg", "jpeg", NULL, "quality","100", NULL); diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 7812969a0..24da697c1 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -23,9 +23,9 @@ #include #include "png-write.h" #include "io/sys.h" +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-item.h" -#include "display/nr-arena.h" #include "document.h" #include "sp-item.h" #include "sp-root.h" @@ -51,7 +51,7 @@ static unsigned int const MAX_STRIPE_SIZE = 1024*1024; struct SPEBP { unsigned long int width, height, sheight; guint32 background; - Inkscape::DrawingItem *root; // the root arena item to show; it is assumed that all unneeded items are hidden + Inkscape::Drawing *drawing; // it is assumed that all unneeded items are hidden guchar *px; unsigned (*status)(float, void *); void *data; @@ -326,8 +326,7 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v Geom::IntRect bbox = Geom::IntRect::from_xywh(0, row, ebp->width, num_rows); /* Update to renderable state */ - Inkscape::UpdateContext ctx; - ebp->root->update(bbox, ctx, Inkscape::DrawingItem::STATE_ALL, 0); + ebp->drawing->update(bbox); int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ebp->width); unsigned char *px = g_new(guchar, num_rows * stride); @@ -341,7 +340,7 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v ct.setOperator(CAIRO_OPERATOR_OVER); /* Render */ - ebp->root->render(ct, bbox, 0); + ebp->drawing->render(ct, bbox); cairo_surface_destroy(s); *to_free = px; @@ -451,15 +450,15 @@ sp_export_png_file(SPDocument *doc, gchar const *filename, ebp.height = height; ebp.background = bgcolor; - /* Create new arena */ - NRArena *const arena = NRArena::create(); - // export with maximum blur rendering quality - nr_arena_set_renderoffscreen(arena); + /* Create new drawing */ + Inkscape::Drawing drawing; + drawing.setExact(true); // export with maximum blur rendering quality unsigned const dkey = SPItem::display_key_new(1); // Create ArenaItems and set transform - ebp.root = doc->getRoot()->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY); - ebp.root->setTransform(affine); + drawing.setRoot(doc->getRoot()->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY)); + drawing.root()->setTransform(affine); + ebp.drawing = &drawing; // We show all and then hide all items we don't want, instead of showing only requested items, // because that would not work if the shown item references something in defs @@ -483,9 +482,6 @@ sp_export_png_file(SPDocument *doc, gchar const *filename, // Hide items, this releases arenaitem doc->getRoot()->invoke_hide(dkey); - /* Free arena */ - nr_object_unref((NRObject *) arena); - return write_status; } diff --git a/src/marker.cpp b/src/marker.cpp index 11a270e73..c8fa9218d 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -43,7 +43,7 @@ static void sp_marker_set (SPObject *object, unsigned int key, const gchar *valu static void sp_marker_update (SPObject *object, SPCtx *ctx, guint flags); static Inkscape::XML::Node *sp_marker_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static Inkscape::DrawingItem *sp_marker_private_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_marker_private_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_marker_private_hide (SPItem *item, unsigned int key); static void sp_marker_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_marker_print (SPItem *item, SPPrintContext *ctx); @@ -168,7 +168,7 @@ sp_marker_release (SPObject *object) marker = (SPMarker *) object; while (marker->views) { - /* Destroy all NRArenaitems etc. */ + /* Destroy all DrawingItems etc. */ /* Parent class ::hide method */ ((SPItemClass *) parent_class)->hide ((SPItem *) marker, marker->views->key); sp_marker_view_remove (marker, marker->views, TRUE); @@ -444,7 +444,7 @@ static void sp_marker_update(SPObject *object, SPCtx *ctx, guint flags) ((SPObjectClass *) (parent_class))->update (object, (SPCtx *) &rctx, flags); } - // As last step set additional transform of arena group + // As last step set additional transform of drawing group for (SPMarkerView *v = marker->views; v != NULL; v = v->next) { for (unsigned i = 0 ; i < v->items.size() ; i++) { if (v->items[i]) { @@ -523,7 +523,7 @@ sp_marker_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::X * This routine is disabled to break propagation. */ static Inkscape::DrawingItem * -sp_marker_private_show (SPItem */*item*/, NRArena */*arena*/, unsigned int /*key*/, unsigned int /*flags*/) +sp_marker_private_show (SPItem */*item*/, Inkscape::Drawing &/*drawing*/, unsigned int /*key*/, unsigned int /*flags*/) { /* Break propagation */ return NULL; @@ -599,7 +599,7 @@ sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size) /** * Shows an instance of a marker. This is called during sp_shape_update_marker_view() - * show and transform a child item in the arena for all views with the given key. + * show and transform a child item in the drawing for all views with the given key. */ Inkscape::DrawingItem * sp_marker_show_instance ( SPMarker *marker, Inkscape::DrawingItem *parent, diff --git a/src/print.cpp b/src/print.cpp index 29c5b0ed2..2eadf0fa9 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -15,7 +15,7 @@ # include "config.h" #endif -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-item.h" #include "inkscape.h" #include "desktop.h" @@ -117,21 +117,20 @@ sp_print_document_to_file(SPDocument *doc, gchar const *filename) /* Start */ context.module = mod; /* fixme: This has to go into module constructor somehow */ - /* Create new arena */ + /* Create new drawing */ mod->base = doc->getRoot(); - mod->arena = NRArena::create(); + Inkscape::Drawing drawing; mod->dkey = SPItem::display_key_new(1); - mod->root = (mod->base)->invoke_show(mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY); + mod->root = (mod->base)->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(mod->root); /* Print document */ ret = mod->begin(doc); (mod->base)->invoke_print(&context); ret = mod->finish(); - /* Release arena */ + /* Release drawing items */ (mod->base)->invoke_hide(mod->dkey); mod->base = NULL; - nr_object_unref((NRObject *) mod->arena); mod->root = NULL; // should be deleted by invoke_hide - mod->arena = NULL; /* end */ mod->set_param_string("destination", oldoutput); diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 14c206828..0b3320e59 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -15,7 +15,7 @@ #include #include -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-group.h" #include "xml/repr.h" @@ -242,17 +242,14 @@ Inkscape::XML::Node *SPClipPath::write(SPObject *object, Inkscape::XML::Document return repr; } -Inkscape::DrawingItem *SPClipPath::show(NRArena *arena, unsigned int key) +Inkscape::DrawingItem *SPClipPath::show(Inkscape::Drawing &drawing, unsigned int key) { - g_return_val_if_fail(arena != NULL, NULL); - g_return_val_if_fail(NR_IS_ARENA(arena), NULL); - - Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(arena); + Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(drawing); display = sp_clippath_view_new_prepend(display, key, ai); for ( SPObject *child = firstChild() ; child ; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - Inkscape::DrawingItem *ac = SP_ITEM(child)->invoke_show(arena, key, SP_ITEM_REFERENCE_FLAGS); + Inkscape::DrawingItem *ac = SP_ITEM(child)->invoke_show(drawing, key, SP_ITEM_REFERENCE_FLAGS); if (ac) { /* The order is not important in clippath */ ai->appendChild(ac); diff --git a/src/sp-clippath.h b/src/sp-clippath.h index d163e0709..11817eb77 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -40,7 +40,7 @@ public: static const gchar *create(GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); static GType sp_clippath_get_type(void); - Inkscape::DrawingItem *show(NRArena *arena, unsigned int key); + Inkscape::DrawingItem *show(Inkscape::Drawing &drawing, unsigned int key); void hide(unsigned int key); void setBBox(unsigned int key, NRRect *bbox); diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index cbdc8684b..710f799a5 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -50,7 +50,7 @@ static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Affine cons static void sp_flowtext_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_flowtext_description(SPItem *item); static void sp_flowtext_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); -static Inkscape::DrawingItem *sp_flowtext_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); +static Inkscape::DrawingItem *sp_flowtext_show(SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags); static void sp_flowtext_hide(SPItem *item, unsigned key); static SPItemClass *parent_class; @@ -409,10 +409,10 @@ static void sp_flowtext_snappoints(SPItem const *item, std::vectorsetPickChildren(false); flowed->setStyle(group->style); diff --git a/src/sp-flowtext.h b/src/sp-flowtext.h index d06105c30..de41ba47f 100644 --- a/src/sp-flowtext.h +++ b/src/sp-flowtext.h @@ -31,7 +31,7 @@ struct SPFlowtext : public SPItem { //semiprivate: (need to be accessed by the C-style functions still) Inkscape::Text::Layout layout; - /** discards the NRArena objects representing this text. */ + /** discards the drawing objects representing this text. */ void _clearFlow(Inkscape::DrawingGroup* in_arena); double par_indent; diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 3a1280aa0..225cccfca 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -84,7 +84,7 @@ static void sp_image_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const & static void sp_image_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_image_description (SPItem * item); static void sp_image_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); -static Inkscape::DrawingItem *sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_image_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static Geom::Affine sp_image_set_transform (SPItem *item, Geom::Affine const &xform); static void sp_image_set_curve(SPImage *image); @@ -1149,10 +1149,10 @@ static gchar *sp_image_description( SPItem *item ) return ret; } -static Inkscape::DrawingItem *sp_image_show( SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/ ) +static Inkscape::DrawingItem *sp_image_show( SPItem *item, Inkscape::Drawing &drawing, unsigned int /*key*/, unsigned int /*flags*/ ) { SPImage * image = SP_IMAGE(item); - Inkscape::DrawingImage *ai = new Inkscape::DrawingImage(arena); + Inkscape::DrawingImage *ai = new Inkscape::DrawingImage(drawing); sp_image_update_arenaitem(image, ai); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index c27319c83..f8ab0460a 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -68,7 +68,7 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value); static void sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_group_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_group_description (SPItem * item); -static Inkscape::DrawingItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_group_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_group_hide (SPItem * item, unsigned int key); static void sp_group_snappoints (SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); @@ -313,9 +313,9 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value) { } static Inkscape::DrawingItem * -sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) +sp_group_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { - return SP_GROUP(item)->group->show(arena, key, flags); + return SP_GROUP(item)->group->show(drawing, key, flags); } static void @@ -744,19 +744,19 @@ gchar *CGroup::getDescription() { len), len); } -Inkscape::DrawingItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) { +Inkscape::DrawingItem *CGroup::show (Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { Inkscape::DrawingGroup *ai; SPObject *object = _group; - ai = new Inkscape::DrawingGroup(arena); + ai = new Inkscape::DrawingGroup(drawing); ai->setPickChildren(_group->effectiveLayerMode(key) == SPGroup::LAYER); ai->setStyle(object->style); - _showChildren(arena, ai, key, flags); + _showChildren(drawing, ai, key, flags); return ai; } -void CGroup::_showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { +void CGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { Inkscape::DrawingItem *ac = NULL; SPItem * child = NULL; GSList *l = g_slist_reverse(_group->childList(false, SPObject::ActionShow)); @@ -764,7 +764,7 @@ void CGroup::_showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned SPObject *o = SP_OBJECT (l->data); if (SP_IS_ITEM (o)) { child = SP_ITEM (o); - ac = child->invoke_show (arena, key, flags); + ac = child->invoke_show (drawing, key, flags); ai->appendChild(ac); } l = g_slist_remove (l, o); diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 88586a6b0..99f375e44 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -73,13 +73,13 @@ public: virtual void onPrint(SPPrintContext *ctx); virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); virtual gchar *getDescription(); - virtual Inkscape::DrawingItem *show (NRArena *arena, unsigned int key, unsigned int flags); + virtual Inkscape::DrawingItem *show (Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); virtual void hide (unsigned int key); gint getItemCount(); protected: - virtual void _showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); + virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); SPGroup *_group; }; diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 9ab924423..bd3802dd3 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -29,7 +29,6 @@ #include "sp-item.h" #include "svg/svg.h" #include "print.h" -#include "display/nr-arena.h" #include "display/drawing-item.h" #include "attributes.h" #include "document.h" @@ -513,7 +512,6 @@ void SPItem::clip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item) /* Hide clippath */ for (v = item->display; v != NULL; v = v->next) { SP_CLIPPATH(old_clip)->hide(v->arenaitem->key()); - v->arenaitem->setClip(NULL); } } if (SP_IS_CLIPPATH(clip)) { @@ -539,7 +537,6 @@ void SPItem::mask_ref_changed(SPObject *old_mask, SPObject *mask, SPItem *item) /* Hide mask */ for (SPItemView *v = item->display; v != NULL; v = v->next) { sp_mask_hide(SP_MASK(old_mask), v->arenaitem->key()); - v->arenaitem->setMask(NULL); } } if (SP_IS_MASK(mask)) { @@ -1017,14 +1014,11 @@ unsigned SPItem::display_key_new(unsigned numkeys) return dkey - numkeys; } -Inkscape::DrawingItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigned flags) +Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned key, unsigned flags) { - g_assert(arena != NULL); - g_assert(NR_IS_ARENA(arena)); - Inkscape::DrawingItem *ai = NULL; if (((SPItemClass *) G_OBJECT_GET_CLASS(this))->show) { - ai = ((SPItemClass *) G_OBJECT_GET_CLASS(this))->show(this, arena, key, flags); + ai = ((SPItemClass *) G_OBJECT_GET_CLASS(this))->show(this, drawing, key, flags); } if (ai != NULL) { @@ -1042,7 +1036,7 @@ Inkscape::DrawingItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigne int clip_key = display->arenaitem->key(); // Show and set clip - Inkscape::DrawingItem *ac = cp->show(arena, clip_key); + Inkscape::DrawingItem *ac = cp->show(drawing, clip_key); ai->setClip(ac); // Update bbox, in case the clip uses bbox units @@ -1060,7 +1054,7 @@ Inkscape::DrawingItem *SPItem::invoke_show(NRArena *arena, unsigned key, unsigne int mask_key = display->arenaitem->key(); // Show and set mask - Inkscape::DrawingItem *ac = sp_mask_show(mask, arena, mask_key); + Inkscape::DrawingItem *ac = sp_mask_show(mask, drawing, mask_key); ai->setMask(ac); // Update bbox, in case the mask uses bbox units diff --git a/src/sp-item.h b/src/sp-item.h index f8cc948bb..633deb508 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -181,7 +181,7 @@ public: gchar *description(); void invoke_print(SPPrintContext *ctx); static unsigned int display_key_new(unsigned int numkeys); - Inkscape::DrawingItem *invoke_show(NRArena *arena, unsigned int key, unsigned int flags); + Inkscape::DrawingItem *invoke_show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); void invoke_hide(unsigned int key); void getSnappoints(std::vector &p, Inkscape::SnapPreferences const *snapprefs=0) const; void adjust_pattern(/* Geom::Affine const &premul, */ Geom::Affine const &postmul, bool set = false); @@ -246,7 +246,7 @@ public: /** Give short description of item (for status display) */ gchar * (* description) (SPItem * item); - Inkscape::DrawingItem * (* show) (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); + Inkscape::DrawingItem * (* show) (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); void (* hide) (SPItem *item, unsigned int key); /** Write to an iterator the points that should be considered for snapping diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index f23be6fc5..f23172a17 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -15,7 +15,7 @@ #include #include <2geom/transforms.h> -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-group.h" #include "xml/repr.h" @@ -297,19 +297,17 @@ sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTr return mask_id; } -Inkscape::DrawingItem *sp_mask_show(SPMask *mask, NRArena *arena, unsigned int key) +Inkscape::DrawingItem *sp_mask_show(SPMask *mask, Inkscape::Drawing &drawing, unsigned int key) { g_return_val_if_fail (mask != NULL, NULL); g_return_val_if_fail (SP_IS_MASK (mask), NULL); - g_return_val_if_fail (arena != NULL, NULL); - g_return_val_if_fail (NR_IS_ARENA (arena), NULL); - Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(arena); + Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(drawing); mask->display = sp_mask_view_new_prepend (mask->display, key, ai); for ( SPObject *child = mask->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - Inkscape::DrawingItem *ac = SP_ITEM (child)->invoke_show (arena, key, SP_ITEM_REFERENCE_FLAGS); + Inkscape::DrawingItem *ac = SP_ITEM (child)->invoke_show (drawing, key, SP_ITEM_REFERENCE_FLAGS); if (ac) { ai->prependChild(ac); } diff --git a/src/sp-mask.h b/src/sp-mask.h index e7a4723cf..b1048e6be 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -90,7 +90,7 @@ protected: } }; -Inkscape::DrawingItem *sp_mask_show (SPMask *mask, NRArena *arena, unsigned int key); +Inkscape::DrawingItem *sp_mask_show (SPMask *mask, Inkscape::Drawing &drawing, unsigned int key); void sp_mask_hide (SPMask *mask, unsigned int key); void sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox); diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 805a93267..9aefdf6ff 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -24,7 +24,7 @@ #include "display/cairo-utils.h" #include "display/drawing-context.h" #include "display/drawing-surface.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-group.h" #include "attributes.h" #include "document-private.h" @@ -630,17 +630,18 @@ sp_pattern_create_pattern(SPPaintServer *ps, return cairo_pattern_create_rgba(0,0,0,0); } - /* Create arena */ - NRArena *arena = NRArena::create(); + /* Create drawing for rendering */ + Inkscape::Drawing drawing; unsigned int dkey = SPItem::display_key_new (1); - Inkscape::DrawingGroup *root = new Inkscape::DrawingGroup(arena); + Inkscape::DrawingGroup *root = new Inkscape::DrawingGroup(drawing); + drawing.setRoot(root); for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext() ) { if (SP_IS_ITEM (child)) { - // for each item in pattern, show it on our arena, add to the group, + // for each item in pattern, show it on our drawing, add to the group, // and connect to the release signal in case the item gets deleted Inkscape::DrawingItem *cai; - cai = SP_ITEM(child)->invoke_show (arena, dkey, SP_ITEM_SHOW_DISPLAY); + cai = SP_ITEM(child)->invoke_show (drawing, dkey, SP_ITEM_SHOW_DISPLAY); root->appendChild(cai); } } @@ -676,7 +677,10 @@ 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.1); + // TODO: this is lame. instead of using descrim(), we should extract + // the scaling component from the complete matrix and use it + // to find the optimum tile size for rendering + Geom::Point c(pattern_tile.dimensions()*vb2ps.descrim()*ps2user.descrim()*full.descrim()*1.1); c[Geom::X] = ceil(c[Geom::X]); c[Geom::Y] = ceil(c[Geom::Y]); @@ -692,15 +696,13 @@ sp_pattern_create_pattern(SPPaintServer *ps, // TODO: make sure there are no leaks. Inkscape::UpdateContext ctx; ctx.ctm = vb2ps; - root->update(Geom::IntRect::infinite(), ctx, Inkscape::DrawingItem::STATE_ALL, 0); - root->render(ct, one_tile, 0); + drawing.update(Geom::IntRect::infinite(), ctx); + drawing.render(ct, one_tile); for (SPObject *child = shown->firstChild() ; child != NULL; child = child->getNext() ) { if (SP_IS_ITEM (child)) { SP_ITEM(child)->invoke_hide(dkey); } } - nr_object_unref(arena); - delete root; if (needs_opacity) { ct.popGroupToSource(); // pop raw pattern diff --git a/src/sp-root.cpp b/src/sp-root.cpp index bbb12f5d3..a6df580d3 100644 --- a/src/sp-root.cpp +++ b/src/sp-root.cpp @@ -46,7 +46,7 @@ static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_root_modified(SPObject *object, guint flags); static Inkscape::XML::Node *sp_root_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static Inkscape::DrawingItem *sp_root_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_root_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_root_print(SPItem *item, SPPrintContext *ctx); static SPGroupClass *parent_class; @@ -538,7 +538,7 @@ static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags) if (((SPObjectClass *) (parent_class))->update) ((SPObjectClass *) (parent_class))->update(object, (SPCtx *) &rctx, flags); - /* As last step set additional transform of arena group */ + /* As last step set additional transform of drawing group */ for (SPItemView *v = root->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); g->setChildTransform(root->c2p); @@ -608,16 +608,16 @@ sp_root_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: } /** - * Displays the SPRoot item on the NRArena. + * Displays the SPRoot item on the drawing. */ static Inkscape::DrawingItem * -sp_root_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) +sp_root_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { SPRoot *root = SP_ROOT(item); Inkscape::DrawingItem *ai; if (((SPItemClass *) (parent_class))->show) { - ai = ((SPItemClass *) (parent_class))->show(item, arena, key, flags); + ai = ((SPItemClass *) (parent_class))->show(item, drawing, key, flags); if (ai) { Inkscape::DrawingGroup *g = dynamic_cast(ai); g->setChildTransform(root->c2p); diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 1512898f5..eff0665af 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -852,12 +852,12 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) /** * Sets style, path, and paintbox. Updates marker views, including dimensions. */ -Inkscape::DrawingItem * SPShape::sp_shape_show(SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/) +Inkscape::DrawingItem * SPShape::sp_shape_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int /*key*/, unsigned int /*flags*/) { SPObject *object = item; SPShape *shape = SP_SHAPE(item); - Inkscape::DrawingShape *s = new Inkscape::DrawingShape(arena); + Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); s->setStyle(object->style); s->setPath(shape->curve); Geom::OptRect paintbox = item->getBounds(Geom::identity()); @@ -1015,8 +1015,6 @@ sp_shape_marker_release (SPObject *marker, SPShape *shape) /* Hide marker */ for (v = item->display; v != NULL; v = v->next) { sp_marker_hide ((SPMarker *) (shape->marker[i]), v->arenaitem->key() + i); - /* fixme: Do we need explicit remove here? (Lauris) */ - /* v->arenaitem->setMask(NULL); */ } /* Detach marker */ shape->release_connect[i].disconnect(); @@ -1066,8 +1064,6 @@ sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value) for (v = item->display; v != NULL; v = v->next) { sp_marker_hide ((SPMarker *) (shape->marker[key]), v->arenaitem->key() + key); - /* fixme: Do we need explicit remove here? (Lauris) */ - /* v->arenaitem->setMask(NULL); */ } /* Unref marker */ diff --git a/src/sp-shape.h b/src/sp-shape.h index 4da2d5a2d..355d8e7cc 100644 --- a/src/sp-shape.h +++ b/src/sp-shape.h @@ -67,7 +67,7 @@ private: static Inkscape::XML::Node *sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); - static Inkscape::DrawingItem *sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); + static Inkscape::DrawingItem *sp_shape_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_shape_hide (SPItem *item, unsigned int key); static void sp_shape_snappoints (SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index bb1495387..500e43c9c 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -117,7 +117,7 @@ void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inks _reevaluate(); } -void CSwitch::_reevaluate(bool /*add_to_arena*/) { +void CSwitch::_reevaluate(bool /*add_to_drawing*/) { SPObject *evaluated_child = _evaluateFirst(); if (!evaluated_child || _cached_item == evaluated_child) { return; @@ -157,7 +157,7 @@ void CSwitch::_releaseLastItem(SPObject *obj) _cached_item = NULL; } -void CSwitch::_showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { +void CSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { SPObject *evaluated_child = _evaluateFirst(); GSList *l = _childList(false, SPObject::ActionShow); @@ -166,7 +166,7 @@ void CSwitch::_showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned if (SP_IS_ITEM (o)) { SPItem * child = SP_ITEM(o); child->setEvaluated(o == evaluated_child); - Inkscape::DrawingItem *ac = child->invoke_show (arena, key, flags); + Inkscape::DrawingItem *ac = child->invoke_show (drawing, key, flags); if (ac) { ai->appendChild(ac); } diff --git a/src/sp-switch.h b/src/sp-switch.h index 7b108947d..8eafe6e7b 100644 --- a/src/sp-switch.h +++ b/src/sp-switch.h @@ -42,7 +42,7 @@ public: protected: virtual GSList *_childList(bool add_ref, SPObject::Action action); - virtual void _showChildren (NRArena *arena, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); + virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); SPObject *_evaluateFirst(); void _reevaluate(bool add_to_arena = false); diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp index 1f35a0ee1..bee28f8e3 100644 --- a/src/sp-symbol.cpp +++ b/src/sp-symbol.cpp @@ -37,7 +37,7 @@ static void sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags); static void sp_symbol_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_symbol_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static Inkscape::DrawingItem *sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); +static Inkscape::DrawingItem *sp_symbol_show (SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_symbol_hide (SPItem *item, unsigned int key); static void sp_symbol_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_symbol_print (SPItem *item, SPPrintContext *ctx); @@ -325,7 +325,7 @@ static void sp_symbol_update(SPObject *object, SPCtx *ctx, guint flags) ((SPObjectClass *) (parent_class))->update (object, (SPCtx *) &rctx, flags); } - // As last step set additional transform of arena group + // As last step set additional transform of drawing group for (SPItemView *v = symbol->display; v != NULL; v = v->next) { Inkscape::DrawingGroup *g = dynamic_cast(v->arenaitem); g->setChildTransform(symbol->c2p); @@ -368,7 +368,7 @@ static Inkscape::XML::Node *sp_symbol_write(SPObject *object, Inkscape::XML::Doc return repr; } -static Inkscape::DrawingItem *sp_symbol_show(SPItem *item, NRArena *arena, unsigned int key, unsigned int flags) +static Inkscape::DrawingItem *sp_symbol_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { SPSymbol *symbol = SP_SYMBOL(item); Inkscape::DrawingItem *ai = 0; @@ -376,7 +376,7 @@ static Inkscape::DrawingItem *sp_symbol_show(SPItem *item, NRArena *arena, unsig if (symbol->cloned) { // Cloned is actually renderable if (((SPItemClass *) (parent_class))->show) { - ai = ((SPItemClass *) (parent_class))->show (item, arena, key, flags); + ai = ((SPItemClass *) (parent_class))->show (item, drawing, key, flags); Inkscape::DrawingGroup *g = dynamic_cast(ai); if (g) { g->setChildTransform(symbol->c2p); diff --git a/src/sp-text.cpp b/src/sp-text.cpp index ed848c646..34722ce5d 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -72,7 +72,7 @@ static void sp_text_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_text_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); -static Inkscape::DrawingItem *sp_text_show (SPItem *item, NRArena *arena, unsigned key, unsigned flags); +static Inkscape::DrawingItem *sp_text_show (SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags); static void sp_text_hide (SPItem *item, unsigned key); static char *sp_text_description (SPItem *item); static void sp_text_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); @@ -273,7 +273,7 @@ static void sp_text_modified(SPObject *object, guint flags) // FIXME: all that we need to do here is to call setStyle, to set the changed // style, but there's no easy way to access the drawing glyphs or texts corresponding to a - // text object. Therefore we do here the same as in _update, that is, destroy all arena items + // text object. Therefore we do here the same as in _update, that is, destroy all items // and create new ones. This is probably quite wasteful. if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) { SPText *text = SP_TEXT (object); @@ -386,11 +386,11 @@ sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, un static Inkscape::DrawingItem * -sp_text_show(SPItem *item, NRArena *arena, unsigned /* key*/, unsigned /*flags*/) +sp_text_show(SPItem *item, Inkscape::Drawing &drawing, unsigned /* key*/, unsigned /*flags*/) { SPText *group = (SPText *) item; - Inkscape::DrawingGroup *flowed = new Inkscape::DrawingGroup(arena); + Inkscape::DrawingGroup *flowed = new Inkscape::DrawingGroup(drawing); flowed->setPickChildren(false); flowed->setStyle(group->style); diff --git a/src/sp-text.h b/src/sp-text.h index f865713c7..e426c425b 100644 --- a/src/sp-text.h +++ b/src/sp-text.h @@ -56,7 +56,7 @@ struct SPText : public SPItem { static void _adjustCoordsRecursive(SPItem *item, Geom::Affine const &m, double ex, bool is_root = true); static void _adjustFontsizeRecursive(SPItem *item, double ex, bool is_root = true); - /** discards the NRArena objects representing this text. */ + /** discards the drawing objects representing this text. */ void _clearFlow(Inkscape::DrawingGroup *in_arena); private: diff --git a/src/sp-use.cpp b/src/sp-use.cpp index 2f83679de..89df9130d 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -53,7 +53,7 @@ static void sp_use_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &tr static void sp_use_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); static void sp_use_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_use_description(SPItem *item); -static Inkscape::DrawingItem *sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); +static Inkscape::DrawingItem *sp_use_show(SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags); static void sp_use_hide(SPItem *item, unsigned key); static void sp_use_href_changed(SPObject *old_ref, SPObject *ref, SPUse *use); @@ -347,16 +347,16 @@ sp_use_description(SPItem *item) } static Inkscape::DrawingItem * -sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags) +sp_use_show(SPItem *item, Inkscape::Drawing &drawing, unsigned key, unsigned flags) { SPUse *use = SP_USE(item); - Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(arena); + Inkscape::DrawingGroup *ai = new Inkscape::DrawingGroup(drawing); ai->setPickChildren(false); ai->setStyle(item->style); if (use->child) { - Inkscape::DrawingItem *ac = SP_ITEM(use->child)->invoke_show(arena, key, flags); + Inkscape::DrawingItem *ac = SP_ITEM(use->child)->invoke_show(drawing, key, flags); if (ac) { ai->prependChild(ac); } diff --git a/src/svg-view.cpp b/src/svg-view.cpp index 3221ce146..8773dfab7 100644 --- a/src/svg-view.cpp +++ b/src/svg-view.cpp @@ -204,12 +204,12 @@ SPSVGView::setDocument (SPDocument *document) if (document) { Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( - SP_CANVAS_ARENA (_drawing)->arena, + SP_CANVAS_ARENA (_drawing)->drawing, _dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - SP_CANVAS_ARENA (_drawing)->root->prependChild(ai); + SP_CANVAS_ARENA (_drawing)->drawing.root()->prependChild(ai); } doRescale (!_rescale); diff --git a/src/text-context.h b/src/text-context.h index a140c2f08..50a738ca0 100644 --- a/src/text-context.h +++ b/src/text-context.h @@ -31,7 +31,6 @@ class SPTextContext; class SPTextContextClass; -class SPCanvasArena; struct SPTextContext : public SPEventContext { diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 7093ff683..7c47dc442 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -29,7 +29,7 @@ #include "sp-image.h" #include <2geom/transforms.h> -#include "display/nr-arena.h" +#include "display/drawing.h" #include "display/drawing-shape.h" #include "siox.h" diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index ae5355c58..912bc1a40 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -30,18 +30,18 @@ #include "display/cairo-utils.h" #include "display/drawing-context.h" #include "display/drawing-item.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "ui/cache/svg_preview_cache.h" -GdkPixbuf* render_pixbuf(Inkscape::DrawingItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize) +GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, const Geom::Rect& dbox, unsigned psize) { Geom::Affine t(Geom::Scale(scale_factor, scale_factor)); - root->setTransform(Geom::Scale(scale_factor)); + drawing.root()->setTransform(Geom::Scale(scale_factor)); Geom::IntRect ibox = (dbox * Geom::Scale(scale_factor)).roundOutwards(); - root->update(ibox); + drawing.update(ibox); /* Find visible area */ int width = ibox.width(); @@ -59,7 +59,7 @@ GdkPixbuf* render_pixbuf(Inkscape::DrawingItem* root, double scale_factor, const CAIRO_FORMAT_ARGB32, psize, psize); Inkscape::DrawingContext ct(s, area.min()); - root->render(ct, area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); + drawing.render(ct, area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_flush(s); GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), diff --git a/src/ui/cache/svg_preview_cache.h b/src/ui/cache/svg_preview_cache.h index b9fa6f627..2318307e2 100644 --- a/src/ui/cache/svg_preview_cache.h +++ b/src/ui/cache/svg_preview_cache.h @@ -16,7 +16,7 @@ #include "display/display-forward.h" -GdkPixbuf* render_pixbuf(Inkscape::DrawingItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize); +GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, double scale_factor, const Geom::Rect& dbox, unsigned psize); namespace Inkscape { namespace UI { diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index bb800f9ca..4f4093a99 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -34,8 +34,8 @@ #include "extension/output.h" #include "extension/db.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena.h" +//#include "display/drawing-item.h" +//#include "display/drawing.h" #include "sp-item.h" #include "display/canvas-arena.h" diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index a6d76eb13..9865c0cdb 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -16,6 +16,7 @@ # include #endif +#include #include #include #include @@ -25,7 +26,7 @@ #include "desktop.h" #include "desktop-handles.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "document.h" #include "inkscape.h" #include "preferences.h" @@ -36,9 +37,10 @@ #include "icon-preview.h" extern "C" { -// takes doc, root, icon, and icon name to produce pixels +// takes doc, drawing, icon, and icon name to produce pixels +// this is defined in widgets/icon.cpp guchar * -sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, +sp_icon_doc_icon( SPDocument *doc, Inkscape::Drawing &drawing, const gchar *name, unsigned int psize, unsigned &stride); } @@ -438,20 +440,16 @@ void IconPreviewPanel::renderPreview( SPObject* obj ) g_message("%s setting up to render '%s' as the icon", getTimestr().c_str(), id ); #endif // ICON_VERBOSE - Inkscape::DrawingItem *root = NULL; + Inkscape::Drawing drawing; - /* Create new arena */ - NRArena *arena = NRArena::create(); - - /* Create ArenaItem and set transform */ + /* Create drawing items and set transform */ unsigned int visionkey = SPItem::display_key_new(1); - - root = doc->getRoot()->invoke_show( arena, visionkey, SP_ITEM_SHOW_DISPLAY ); + drawing.setRoot(doc->getRoot()->invoke_show( drawing, visionkey, SP_ITEM_SHOW_DISPLAY )); for ( int i = 0; i < numEntries; i++ ) { unsigned unused; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, sizes[i]); - guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i], unused); + guchar * px = sp_icon_doc_icon( doc, drawing, id, sizes[i], unused); // g_message( " size %d %s", sizes[i], (px ? "worked" : "failed") ); if ( px ) { memcpy( pixMem[i], px, sizes[i] * stride ); @@ -465,7 +463,6 @@ void IconPreviewPanel::renderPreview( SPObject* obj ) updateMagnify(); doc->getRoot()->invoke_hide(visionkey); - nr_object_unref((NRObject *) arena); renderTimer->stop(); minDelay = std::max( 0.1, renderTimer->elapsed() * 3.0 ); #if ICON_VERBOSE diff --git a/src/ui/view/view.h b/src/ui/view/view.h index 13499a2e4..db6061434 100644 --- a/src/ui/view/view.h +++ b/src/ui/view/view.h @@ -65,7 +65,7 @@ namespace Inkscape { /** * View is an abstract base class of all UI document views. This * includes both the editing window and the SVG preview, but does not - * include the non-UI RGBA buffer-based NRArena nor the XML editor or + * include the non-UI RGBA buffer-based Inkscape::Drawing nor the XML editor or * similar views. The View base class has very little functionality of * its own. */ diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index af329f3fc..08f0eadfb 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -36,7 +36,6 @@ #include "desktop-widget.h" #include "display/sp-canvas.h" #include "display/canvas-arena.h" -#include "display/nr-arena.h" #include "document.h" #include "ege-color-prof-tracker.h" #include "ege-select-one-action.h" diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index fea825444..a57b56b5c 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -33,7 +33,7 @@ #include "display/cairo-utils.h" #include "display/drawing-context.h" #include "display/drawing-item.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "io/sys.h" #include "sp-root.h" @@ -1088,9 +1088,9 @@ static Geom::IntRect round_rect(Geom::Rect const &r) return ret; } -// takes doc, root, icon, and icon name to produce pixels +// takes doc, drawing, icon, and icon name to produce pixels extern "C" guchar * -sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, +sp_icon_doc_icon( SPDocument *doc, Inkscape::Drawing &drawing, gchar const *name, unsigned psize, unsigned &stride) { @@ -1115,8 +1115,8 @@ sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, if ( dbox ) { /* Update to renderable state */ double sf = 1.0; - root->setTransform(Geom::Scale(sf)); - root->update(); + drawing.root()->setTransform(Geom::Scale(sf)); + drawing.update(); /* Item integer bbox in points */ // NOTE: previously, each rect coordinate was rounded using floor(c + 0.5) Geom::IntRect ibox = round_rect(*dbox); @@ -1141,8 +1141,8 @@ sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, } sf = (double)psize / (double)block; - root->setTransform(Geom::Scale(sf)); - root->update(); + drawing.root()->setTransform(Geom::Scale(sf)); + drawing.update(); ibox = round_rect(*dbox * Geom::Scale(sf)); if ( dump ) { @@ -1185,7 +1185,7 @@ sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, CAIRO_FORMAT_ARGB32, psize, psize, stride); Inkscape::DrawingContext ct(s, ua.min()); - root->render(ct, ua, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); + drawing.render(ct, ua); cairo_surface_destroy(s); // convert to GdkPixbuf format @@ -1206,9 +1206,21 @@ sp_icon_doc_icon( SPDocument *doc, Inkscape::DrawingItem *root, class SVGDocCache { public: - SVGDocCache( SPDocument *doc, Inkscape::DrawingItem *root ) : doc(doc), root(root) {} + SVGDocCache( SPDocument *doc ) + : doc(doc) + , visionkey(SPItem::display_key_new(1)) + { + doc->doRef(); + doc->ensureUpToDate(); + drawing.setRoot(doc->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY )); + } + ~SVGDocCache() { + doc->getRoot()->invoke_hide(visionkey); + doc->doUnref(); + } SPDocument *doc; - Inkscape::DrawingItem *root; + Inkscape::Drawing drawing; + unsigned visionkey; }; static std::map doc_cache; @@ -1275,27 +1287,14 @@ guchar *IconImpl::load_svg_pixels(std::list const &names, if ( dump ) { g_message("Loaded icon file %s", doc_filename); } - // prep the document - doc->ensureUpToDate(); - - // Create new arena - NRArena *arena = NRArena::create(); - - // Create ArenaItem and set transform - unsigned visionkey = SPItem::display_key_new(1); - // fixme: Memory manage root if needed (Lauris) - // This needs to be fixed indeed; this leads to a memory leak of a few megabytes these days - // because shapes are being rendered which are not being freed - Inkscape::DrawingItem *root = doc->getRoot()->invoke_show( arena, visionkey, SP_ITEM_SHOW_DISPLAY ); - // store into the cache - info = new SVGDocCache(doc, root); + info = new SVGDocCache(doc); doc_cache[key] = info; } } if (info) { for (std::list::const_iterator it = names.begin(); !px && (it != names.end()); ++it ) { - px = sp_icon_doc_icon( info->doc, info->root, it->c_str(), psize, stride ); + px = sp_icon_doc_icon( info->doc, info->drawing, it->c_str(), psize, stride ); } } } diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 4f6466ce8..8d9b9b429 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -29,7 +29,7 @@ #include "dialogs/dialog-events.h" #include "display/canvas-bpath.h" // for SP_STROKE_LINEJOIN_* #include "display/display-forward.h" -#include "display/nr-arena.h" +#include "display/drawing.h" #include "document-private.h" #include "gradient-chemistry.h" #include "helper/stock-items.h" @@ -153,8 +153,7 @@ sp_stroke_radio_button(Gtk::RadioButton *tb, char const *icon, static Gtk::Image * sp_marker_prev_new(unsigned psize, gchar const *mname, SPDocument *source, SPDocument *sandbox, - gchar const *menu_id, NRArena const * /*arena*/, unsigned /*visionkey*/, - Inkscape::DrawingItem *root) + gchar const *menu_id, Inkscape::Drawing &drawing, unsigned /*visionkey*/) { // Retrieve the marker named 'mname' from the source SVG document SPObject const *marker = source->getObjectById(mname); @@ -209,7 +208,7 @@ sp_marker_prev_new(unsigned psize, gchar const *mname, Glib::RefPtr pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); if (!pixbuf) { - pixbuf = Glib::wrap(render_pixbuf(root, sf, *dbox, psize)); + pixbuf = Glib::wrap(render_pixbuf(drawing, sf, *dbox, psize)); svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); } @@ -249,9 +248,9 @@ static void sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPDocument *sandbox, gchar const *menu_id) { // Do this here, outside of loop, to speed up preview generation: - NRArena const *arena = NRArena::create(); + Inkscape::Drawing drawing; unsigned const visionkey = SPItem::display_key_new(1); - Inkscape::DrawingItem *root = sandbox->getRoot()->invoke_show((NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); for (; marker_list != NULL; marker_list = marker_list->next) { Inkscape::XML::Node *repr = reinterpret_cast(marker_list->data)->getRepr(); @@ -272,7 +271,7 @@ sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPD // generate preview - Gtk::Image *prv = sp_marker_prev_new (22, markid, source, sandbox, menu_id, arena, visionkey, root); + Gtk::Image *prv = sp_marker_prev_new (22, markid, source, sandbox, menu_id, drawing, visionkey); prv->show(); hb->pack_start(*prv, false, false, 6); @@ -290,7 +289,6 @@ sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPD } sandbox->getRoot()->invoke_hide(visionkey); - nr_object_unref((NRObject *) arena); } /** -- cgit v1.2.3 From f336c94939e9740501835b2584ad9a3160ac6d51 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 9 Aug 2011 03:14:07 +0200 Subject: Initial autocache work (bzr r10347.1.26) --- src/display/canvas-arena.cpp | 2 +- src/display/drawing-item.cpp | 146 ++++++++++++++++++++++----- src/display/drawing-item.h | 22 +++- src/display/drawing-surface.cpp | 47 ++++++--- src/display/drawing-surface.h | 5 +- src/display/drawing.cpp | 45 +++++++-- src/display/drawing.h | 29 ++++-- src/display/nr-filter-blend.cpp | 5 + src/display/nr-filter-blend.h | 1 + src/display/nr-filter-colormatrix.cpp | 5 + src/display/nr-filter-colormatrix.h | 1 + src/display/nr-filter-component-transfer.cpp | 5 + src/display/nr-filter-component-transfer.h | 1 + src/display/nr-filter-composite.cpp | 5 + src/display/nr-filter-composite.h | 1 + src/display/nr-filter-convolve-matrix.cpp | 5 + src/display/nr-filter-convolve-matrix.h | 1 + src/display/nr-filter-diffuselighting.cpp | 5 + src/display/nr-filter-diffuselighting.h | 1 + src/display/nr-filter-displacement-map.cpp | 5 + src/display/nr-filter-displacement-map.h | 6 +- src/display/nr-filter-flood.cpp | 7 ++ src/display/nr-filter-flood.h | 5 +- src/display/nr-filter-gaussian.cpp | 7 ++ src/display/nr-filter-gaussian.h | 1 + src/display/nr-filter-image.cpp | 6 ++ src/display/nr-filter-image.h | 2 + src/display/nr-filter-merge.cpp | 5 + src/display/nr-filter-merge.h | 1 + src/display/nr-filter-morphology.cpp | 7 ++ src/display/nr-filter-morphology.h | 2 + src/display/nr-filter-offset.cpp | 5 + src/display/nr-filter-offset.h | 1 + src/display/nr-filter-primitive.cpp | 4 - src/display/nr-filter-primitive.h | 32 +----- src/display/nr-filter-specularlighting.cpp | 135 +------------------------ src/display/nr-filter-specularlighting.h | 2 + src/display/nr-filter-tile.cpp | 5 + src/display/nr-filter-tile.h | 1 + src/display/nr-filter-turbulence.cpp | 5 + src/display/nr-filter-turbulence.h | 1 + src/display/nr-filter.cpp | 12 +++ src/display/nr-filter.h | 3 + 43 files changed, 367 insertions(+), 225 deletions(-) (limited to 'src') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 6026ebd3f..b254a55c8 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -105,7 +105,7 @@ sp_canvas_arena_init (SPCanvasArena *arena) Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing); root->setPickChildren(true); - root->setCached(true); + root->setCached(true, true); arena->drawing.setRoot(root); arena->drawing.signal_request_update.connect( diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 47f6c55a1..3f409b8ee 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -9,6 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include #include "display/cairo-utils.h" #include "display/cairo-templates.h" #include "display/drawing.h" @@ -29,7 +30,7 @@ namespace Inkscape { * portion of the SVG document. Typically this is created by the SP tree, * in particular the show() virtual function. * - * @section ObjectLifetime Object Lifetime + * @section ObjectLifetime Object lifetime * Deleting a DrawingItem will cause all of its children to be deleted as well. * This can lead to nasty surprises if you hold references to things * which are children of what is being deleted. Therefore, in the SP tree, @@ -38,7 +39,7 @@ namespace Inkscape { * - this will cause dangling pointers inside the SPItem and lead to a crash. * Use the corresponing hide() method. * - * Outside of the SP tree you should not use any references after the root node + * Outside of the SP tree, you should not use any references after the root node * has been deleted. */ @@ -57,6 +58,8 @@ DrawingItem::DrawingItem(Drawing &drawing) , _visible(true) , _sensitive(true) , _cached(0) + , _cached_persistent(0) + , _has_cache_iterator(0) , _propagate(0) // , _renders_opacity(0) , _clip_child(0) @@ -77,6 +80,9 @@ DrawingItem::~DrawingItem() if (_cached) { _drawing._cached_items.erase(this); } + if (_has_cache_iterator) { + _drawing._candidate_items.erase(_cache_iterator); + } // remove this item from parent's children list // due to the effect of clearChildren(), this only happens for the top-level deleted item if (_parent) { @@ -182,17 +188,27 @@ DrawingItem::setSensitive(bool s) _sensitive = s; } -/// Enable / disable storing the rendering in memory. +/** @brief Enable / disable storing the rendering in memory. + * Calling setCached(false, true) will also remove the persistent status + */ void -DrawingItem::setCached(bool c) +DrawingItem::setCached(bool cached, bool persistent) { - _cached = c; - if (c) { + static const char *cache_env = getenv("_INKSCAPE_DISABLE_CACHE"); + if (cache_env) return; + + if (_cached_persistent && !persistent) + return; + + _cached = cached; + _cached_persistent = persistent ? cached : false; + if (cached) { _drawing._cached_items.insert(this); } else { _drawing._cached_items.erase(this); + delete _cache; + _cache = NULL; } - _markForUpdate(STATE_CACHE, false); } void @@ -277,7 +293,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } _state &= ~reset; // reset state of this item - if ((~_state & flags) == 0) return; // nothing to do + if ((~_state & flags) == 0) return; // nothing to do // TODO this might be wrong if (_state & STATE_BBOX) { @@ -323,20 +339,40 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } } - // update cache if enabled - if (_cached) { - Geom::OptIntRect cl = _drawing.cacheLimit(); - cl.intersectWith(_drawbox); - if (cl) { - if (_cache) { - // this takes care of invalidation on transform - _cache->resizeAndTransform(*cl, ctm_change); - } else { - _cache = new Inkscape::DrawingCache(*cl); - // the cache is initially dirty - } + // Update cache score for this item + if (_has_cache_iterator) { + // remove old score information + _drawing._candidate_items.erase(_cache_iterator); + _has_cache_iterator = false; + } + double score = _cacheScore(); + if (score >= _drawing._cache_score_threshold) { + CacheRecord cr; + cr.score = score; + // if _cacheRect() is empty, a negative score will be returnedfrom _cacheScore(), + // so this will not execute (cache score threshold must be positive) + cr.cache_size = _cacheRect()->area() * 4; + cr.item = this; + _drawing._candidate_items.push_back(cr); + _cache_iterator = --_drawing._candidate_items.end(); + _has_cache_iterator = true; + } + + /* Update cache if enabled. + * General note: here we only tell the cache how it has to transform + * during the render phase. The transformation is deferred because + * after the update the item can have its caching turned off, + * e.g. because its filter was removed. This way we avoid tempoerarily + * using more memory than the cache budget */ + if (_cache) { + Geom::OptIntRect cl = _cacheRect(); + if (_visible && cl) { // never create cache for invisible items + // this takes care of invalidation on transform + _cache->scheduleTransform(*cl, ctm_change); } else { - // disable cache for this item - not visible + // Destroy cache for this item - outside of canvas or invisible. + // The opposite transition (invisible -> visible or object + // entering the canvas) is handled during the render phase delete _cache; _cache = NULL; } @@ -377,9 +413,10 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag bool outline = _drawing.outline(); bool render_filters = _drawing.renderFilters(); - /* If we are invisible, just return successfully */ + // If we are invisible, return immediately if (!_visible) return; + // TODO convert outline rendering to a separate virtual function if (outline) { _renderOutline(ct, area, flags); return; @@ -389,10 +426,25 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag Geom::OptIntRect carea = Geom::intersect(area, _drawbox); if (!carea) return; - // render from cache - if (_cached && _cache) { - if (_cache->paintFromCache(ct, *carea)) - return; + // render from cache if possible + if (_cached) { + if (_cache) { + _cache->prepare(); + if (_cache->paintFromCache(ct, *carea)) + return; + } else { + // There is no cache. This could be because caching of this item + // was just turned on after the last update phase, or because + // we are outside of the canvas. + Geom::OptIntRect cl = _drawing.cacheLimit(); + cl.intersectWith(_drawbox); + if (cl) { + _cache = new DrawingCache(*cl); + } + } + } else { + // if our caching was turned off after the last update, it was already + // deleted in setCached() } // expand carea to contain the dependent area of filters. @@ -695,6 +747,48 @@ DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style) && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { _background_new = true; }*/ + + // TODO: STATE_ALL unsets too much + _markForUpdate(STATE_ALL, false); +} + +double +DrawingItem::_cacheScore() +{ + Geom::OptIntRect cache_rect = _cacheRect(); + if (!cache_rect) return -1.0; + + // a crude first approximation: + // the basic score is the number of pixels in the drawbox + double score = cache_rect->area(); + // this is multiplied by the filter complexity and its expansion + if (_filter &&_drawing.renderFilters()) { + score *= _filter->complexity(_ctm); + Geom::IntRect ref_area = Geom::IntRect::from_xywh(0, 0, 16, 16); + Geom::IntRect test_area = ref_area; + Geom::IntRect limit_area(0, INT_MIN, 16, INT_MAX); + _filter->area_enlarge(test_area, this); + // area_enlarge never shrinks the rect, so the result of intersection below + // must be non-empty + score *= double((test_area & limit_area)->area()) / ref_area.area(); + } + // if the object is clipped, add 1/2 of its bbox pixels + if (_clip && _clip->_bbox) { + score += _clip->_bbox->area() * 0.5; + } + // if masked, add mask score + if (_mask) { + score += _mask->_cacheScore(); + } + g_message("caching score: %f", score); + return score; +} + +Geom::OptIntRect +DrawingItem::_cacheRect() +{ + Geom::OptIntRect r = _drawbox & _drawing.cacheLimit(); + return r; } } // end namespace Inkscape diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index ba0c42695..b934570f2 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -12,7 +12,9 @@ #ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H #define SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H +#include #include +#include #include #include #include <2geom/rect.h> @@ -27,6 +29,18 @@ struct UpdateContext { Geom::Affine ctm; }; +struct CacheRecord + : boost::totally_ordered +{ + bool operator<(CacheRecord const &other) const { return score < other.score; } + bool operator==(CacheRecord const &other) const { return score == other.score; } + operator DrawingItem *() const { return item; } + double score; + size_t cache_size; + DrawingItem *item; +}; +typedef std::list CacheList; + class InvalidItemException : public std::exception { virtual const char *what() const throw() { return "Invalid item in drawing"; @@ -72,7 +86,7 @@ public: bool sensitive() const { return _sensitive; } void setSensitive(bool v); bool cached() const { return _cached; } - void setCached(bool c); + void setCached(bool c, bool persistent = false); void setOpacity(float opacity); void setTransform(Geom::Affine const &trans); @@ -96,6 +110,8 @@ protected: void _markForUpdate(unsigned state, bool propagate); void _markForRendering(); void _setStyleCommon(SPStyle *&_style, SPStyle *style); + double _cacheScore(); + Geom::OptIntRect _cacheRect(); virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { return 0; } virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} @@ -133,10 +149,14 @@ protected: void *_user_data; ///< Used to associate DrawingItems with SPItems that created them DrawingCache *_cache; + CacheList::iterator _cache_iterator; + unsigned _state : 8; unsigned _visible : 1; unsigned _sensitive : 1; ///< Whether this item responds to events unsigned _cached : 1; ///< Whether the rendering is stored for reuse + unsigned _cached_persistent : 1; ///< If set, will always be cached regardless of score + unsigned _has_cache_iterator : 1; ///< If set, _cache_list_pos is valid unsigned _propagate : 1; ///< Whether to call update for all children on next update //unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity unsigned _clip_child : 1; ///< If set, this is not a child of _parent, but a clipping path diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 28bdc1f3c..1faa3151e 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -9,6 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include #include "display/drawing-surface.h" #include "display/drawing-context.h" #include "display/cairo-utils.h" @@ -165,6 +166,7 @@ DrawingSurface::pixelArea() const DrawingCache::DrawingCache(Geom::IntRect const &area) : DrawingSurface(area) , _clean_region(cairo_region_create()) + , _pending_area(area) {} DrawingCache::~DrawingCache() @@ -196,28 +198,41 @@ DrawingCache::isClean(Geom::IntRect const &area) const return false; } } + +/// Call this during the update phase to schedule a transformation of the cache. +void +DrawingCache::scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans) +{ + if (new_area.hasZeroArea() && trans.isIdentity()) return; + _pending_area = new_area; + _pending_transform *= trans; +} + +/// Transforms the cache according to the transform specified during the update phase. +/// Call this during render phase, before painting. void -DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine const &trans) +DrawingCache::prepare() { Geom::IntRect old_area = pixelArea(); - bool is_identity = false; - bool is_integer_translation = false; - if (trans.isIdentity()) { - is_identity = true; - if (new_area == old_area) return; + bool is_identity = _pending_transform.isIdentity(); + if (is_identity) { + if (_pending_area == old_area) return; } - if (!is_identity && trans.isTranslation()) { - Geom::IntPoint t = trans.translation().round(); - if (Geom::are_near(Geom::Point(t), trans.translation())) { + + bool is_integer_translation = false; + if (!is_identity && _pending_transform.isTranslation()) { + Geom::IntPoint t = _pending_transform.translation().round(); + if (Geom::are_near(Geom::Point(t), _pending_transform.translation())) { // integer translation or identity with change of area is_integer_translation = true; cairo_region_translate(_clean_region, t[X], t[Y]); - if (old_area + t == new_area) { + if (old_area + t == _pending_area) { // if the areas match, the only thing to do // is to ensure that the clean area is not too large - cairo_rectangle_int_t limit = _convertRect(new_area); + cairo_rectangle_int_t limit = _convertRect(_pending_area); cairo_region_intersect_rectangle(_clean_region, &limit); _origin += t; + _pending_transform.setIdentity(); return; } } @@ -226,12 +241,12 @@ DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine con Geom::IntPoint old_origin = old_area.min(); cairo_surface_t *old_surface = _surface; _surface = NULL; - _pixels = new_area.dimensions(); - _origin = new_area.min(); + _pixels = _pending_area.dimensions(); + _origin = _pending_area.min(); cairo_t *ct = createRawContext(); if (!is_identity) { - ink_cairo_transform(ct, trans); + ink_cairo_transform(ct, _pending_transform); } cairo_set_source_surface(ct, old_surface, old_origin[X], old_origin[Y]); cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); @@ -245,9 +260,11 @@ DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine con cairo_region_destroy(_clean_region); _clean_region = cairo_region_create(); } else { - cairo_rectangle_int_t limit = _convertRect(new_area); + cairo_rectangle_int_t limit = _convertRect(_pending_area); cairo_region_intersect_rectangle(_clean_region, &limit); } + std::cout << _pending_transform << old_area << _pending_area << std::endl; + _pending_transform.setIdentity(); } /** @brief Paints the clean area from cache and returns the remaining part */ diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index f279d771b..fd46d66ba 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -64,11 +64,14 @@ public: void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite()); void markClean(Geom::IntRect const &area = Geom::IntRect::infinite()); bool isClean(Geom::IntRect const &area) const; - void resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); + void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); + void prepare(); bool paintFromCache(DrawingContext &ct, Geom::IntRect const &area); protected: cairo_region_t *_clean_region; + Geom::IntRect _pending_area; + Geom::Affine _pending_transform; private: static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r); }; diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index 22bd84587..5881c84ed 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -9,6 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include #include "display/drawing.h" #include "nr-filter-gaussian.h" #include "nr-filter-types.h" @@ -24,6 +25,8 @@ Drawing::Drawing(SPCanvasArena *arena) , _colormode(COLORMODE_NORMAL) , _blur_quality(BLUR_QUALITY_BEST) , _filter_quality(Filters::FILTER_QUALITY_BEST) + , _cache_score_threshold(50000.0) + , _cache_budget(128 << 20) // 128 MiB , _canvasarena(arena) { @@ -126,23 +129,51 @@ Drawing::setCacheLimit(Geom::OptIntRect const &r) void Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { - // TODO add autocache - if (!_root) return; - _root->update(area, ctx, flags, reset); + if (_root) { + _root->update(area, ctx, flags, reset); + } + // process the updated cache scores + // we cache the objects with the highest score until the budget is exhausted + _candidate_items.sort(std::greater()); + size_t used = 0; + CandidateList::iterator i; + for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) { + if (used + i->cache_size > _cache_budget) break; + used += i->cache_size; + } + + std::set to_cache; + for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) { + i->item->setCached(true); + to_cache.insert(i->item); + } + // Everything which is now in _cached_items but not in to_cache must be uncached + // Note that calling setCached on an item modifies _cached_items + // TODO: find a way to avoid the set copy + std::set to_uncache; + std::set_difference(_cached_items.begin(), _cached_items.end(), + to_cache.begin(), to_cache.end(), + std::inserter(to_uncache, to_uncache.end())); + for (std::set::iterator j = to_uncache.begin(); j != to_uncache.end(); ++j) { + (*j)->setCached(false); + } } void Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { - if (!_root) return; - _root->render(ct, area, flags); + if (_root) { + _root->render(ct, area, flags); + } } DrawingItem * Drawing::pick(Geom::Point const &p, double delta, bool sticky) { - if (!_root) return NULL; - return _root->pick(p, delta, sticky); + if (_root) { + return _root->pick(p, delta, sticky); + } + return NULL; } } // end namespace Inkscape diff --git a/src/display/drawing.h b/src/display/drawing.h index 4560d277d..a8e70bbe6 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -13,6 +13,7 @@ #define SEEN_INKSCAPE_DISPLAY_DRAWING_H #include +#include #include #include #include <2geom/rect.h> @@ -22,17 +23,17 @@ namespace Inkscape { -struct OutlineColors { - guint32 paths; - guint32 clippaths; - guint32 masks; - guint32 images; -}; - class Drawing : boost::noncopyable { public: + struct OutlineColors { + guint32 paths; + guint32 clippaths; + guint32 masks; + guint32 images; + }; + Drawing(SPCanvasArena *arena = NULL); ~Drawing(); @@ -66,8 +67,13 @@ public: sigc::signal signal_item_deleted; private: + void _reportCacheScore(CacheRecord const &); + + typedef std::list CandidateList; + DrawingItem *_root; - std::set _cached_items; + std::set _cached_items; // modified by DrawingItem::setCached() + CacheList _candidate_items; public: // TODO: remove these temporarily public members guint32 outlinecolor; @@ -80,9 +86,12 @@ private: int _filter_quality; Geom::OptIntRect _cache_limit; - OutlineColors _colors; + double _cache_score_threshold; ///< do not consider objects for caching below this score + size_t _cache_budget; ///< maximum allowed size of cache - SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen but used for export etc. + OutlineColors _colors; + SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen + // but used for export etc. friend class DrawingItem; }; diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index 3cec479fa..99a142b44 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -196,6 +196,11 @@ bool FilterBlend::can_handle_affine(Geom::Affine const &) return true; } +double FilterBlend::complexity(Geom::Affine const &) +{ + return 1.1; +} + void FilterBlend::set_input(int slot) { _input = slot; } diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 64b3c9284..5f71d468d 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -39,6 +39,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual bool can_handle_affine(Geom::Affine const &); + virtual double complexity(Geom::Affine const &ctm); virtual void set_input(int slot); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp index 7eb2fa2e9..6fa34bf0b 100644 --- a/src/display/nr-filter-colormatrix.cpp +++ b/src/display/nr-filter-colormatrix.cpp @@ -192,6 +192,11 @@ void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*tr { } +double FilterColorMatrix::complexity(Geom::Affine const &) +{ + return 2.0; +} + void FilterColorMatrix::set_type(FilterColorMatrixType t){ type = t; } diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h index df851e0aa..5864a010e 100644 --- a/src/display/nr-filter-colormatrix.h +++ b/src/display/nr-filter-colormatrix.h @@ -38,6 +38,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual bool can_handle_affine(Geom::Affine const &); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); virtual void set_type(FilterColorMatrixType type); virtual void set_value(gdouble value); diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp index 80bc07df8..887352f62 100644 --- a/src/display/nr-filter-component-transfer.cpp +++ b/src/display/nr-filter-component-transfer.cpp @@ -308,6 +308,11 @@ void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Affine const { } +double FilterComponentTransfer::complexity(Geom::Affine const &) +{ + return 2.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-component-transfer.h b/src/display/nr-filter-component-transfer.h index 89bc61403..6d65ae6d1 100644 --- a/src/display/nr-filter-component-transfer.h +++ b/src/display/nr-filter-component-transfer.h @@ -38,6 +38,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual bool can_handle_affine(Geom::Affine const &); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); FilterComponentTransferType type[4]; std::vector tableValues[4]; diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index 694ccaec5..b25ecdf2c 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -139,6 +139,11 @@ void FilterComposite::set_arithmetic(double k1, double k2, double k3, double k4) this->k4 = k4; } +double FilterComposite::complexity(Geom::Affine const &) +{ + return 1.1; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-composite.h b/src/display/nr-filter-composite.h index 930898830..95579cc0e 100644 --- a/src/display/nr-filter-composite.h +++ b/src/display/nr-filter-composite.h @@ -28,6 +28,7 @@ public: virtual void render_cairo(FilterSlot &); virtual bool can_handle_affine(Geom::Affine const &); + virtual double complexity(Geom::Affine const &ctm); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index 06e28b074..469baf346 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -212,6 +212,11 @@ void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Affine const &/*tra area.y1 += orderY - targetY - 1; } +double FilterConvolveMatrix::complexity(Geom::Affine const &) +{ + return kernelMatrix.size(); +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-convolve-matrix.h b/src/display/nr-filter-convolve-matrix.h index d13738260..8b7fc35d1 100644 --- a/src/display/nr-filter-convolve-matrix.h +++ b/src/display/nr-filter-convolve-matrix.h @@ -36,6 +36,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); void set_targetY(int coord); void set_targetX(int coord); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index 039e56bb0..14144ace5 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -171,6 +171,11 @@ void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*t area.y1 += 1; } +double FilterDiffuseLighting::complexity(Geom::Affine const &) +{ + return 9.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h index 6e39242f6..bb3ceccb3 100644 --- a/src/display/nr-filter-diffuselighting.h +++ b/src/display/nr-filter-diffuselighting.h @@ -33,6 +33,7 @@ public: virtual ~FilterDiffuseLighting(); virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); union { SPFeDistantLight *distant; diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index 15200223b..75e310339 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -140,6 +140,11 @@ void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Affine const &tran area.y1 += (int)(scaley)+2; } +double FilterDisplacementMap::complexity(Geom::Affine const &) +{ + return 3.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-displacement-map.h b/src/display/nr-filter-displacement-map.h index aec4b7eb6..393a904c1 100644 --- a/src/display/nr-filter-displacement-map.h +++ b/src/display/nr-filter-displacement-map.h @@ -27,12 +27,14 @@ public: static FilterPrimitive *create(); virtual ~FilterDisplacementMap(); + virtual void render_cairo(FilterSlot &slot); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); + virtual void set_input(int slot); virtual void set_input(int input, int slot); virtual void set_scale(double s); virtual void set_channel_selector(int s, FilterDisplacementMapChannelSelector channel); - virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); private: double scale; diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp index a015d3f1f..5716c1bc5 100644 --- a/src/display/nr-filter-flood.cpp +++ b/src/display/nr-filter-flood.cpp @@ -86,6 +86,13 @@ void FilterFlood::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } +double FilterFlood::complexity(Geom::Affine const &) +{ + // flood is actually less expensive than normal rendering, + // but when flood is processed, the object has already been rendered + return 1.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h index 6db90d439..c87bf6d8f 100644 --- a/src/display/nr-filter-flood.h +++ b/src/display/nr-filter-flood.h @@ -27,10 +27,13 @@ public: virtual void render_cairo(FilterSlot &slot); virtual bool can_handle_affine(Geom::Affine const &); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); + virtual void set_opacity(double o); virtual void set_color(guint32 c); virtual void set_icc(SVGICCColor *icc_color); - virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + private: double opacity; guint32 color; diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index a777d76a4..988a8479e 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -691,6 +691,13 @@ bool FilterGaussian::can_handle_affine(Geom::Affine const &) return false; } +double FilterGaussian::complexity(Geom::Affine const &trans) +{ + int area_x = _effect_area_scr(_deviation_x * trans.expansionX()); + int area_y = _effect_area_scr(_deviation_y * trans.expansionY()); + return 2.0 * area_x * area_y; +} + void FilterGaussian::set_deviation(double deviation) { if(IS_FINITE(deviation) && deviation >= 0) { diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h index 811502016..f52bea01e 100644 --- a/src/display/nr-filter-gaussian.h +++ b/src/display/nr-filter-gaussian.h @@ -37,6 +37,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &m); virtual bool can_handle_affine(Geom::Affine const &m); + virtual double complexity(Geom::Affine const &ctm); /** * Set the standard deviation value for gaussian blur. Deviation along diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index b176cdcef..a22d23548 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -196,6 +196,12 @@ bool FilterImage::can_handle_affine(Geom::Affine const &) return true; } +double FilterImage::complexity(Geom::Affine const &) +{ + // TODO: right now we cannot actually measure this in any meaningful way. + return 1.1; +} + void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index 0651109ec..5af0b3338 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -29,6 +29,8 @@ public: virtual void render_cairo(FilterSlot &slot); virtual bool can_handle_affine(Geom::Affine const &); + virtual double complexity(Geom::Affine const &ctm); + void set_document( SPDocument *document ); void set_href(const gchar *href); void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height); diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp index 51d3975cb..6042da018 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -67,6 +67,11 @@ bool FilterMerge::can_handle_affine(Geom::Affine const &) return true; } +double FilterMerge::complexity(Geom::Affine const &) +{ + return 1.02; +} + void FilterMerge::set_input(int slot) { _input_image[0] = slot; } diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h index 263fc8026..cedab9086 100644 --- a/src/display/nr-filter-merge.h +++ b/src/display/nr-filter-merge.h @@ -26,6 +26,7 @@ public: virtual void render_cairo(FilterSlot &); virtual bool can_handle_affine(Geom::Affine const &); + virtual double complexity(Geom::Affine const &ctm); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index c79667d3e..9e43d01f3 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -158,6 +158,13 @@ void FilterMorphology::area_enlarge(NRRectL &area, Geom::Affine const &trans) area.y1 += enlarge_y; } +double FilterMorphology::complexity(Geom::Affine const &trans) +{ + int enlarge_x = ceil(xradius * trans.expansionX()); + int enlarge_y = ceil(yradius * trans.expansionY()); + return enlarge_x * enlarge_y; +} + void FilterMorphology::set_operator(FilterMorphologyOperator &o){ Operator = o; } diff --git a/src/display/nr-filter-morphology.h b/src/display/nr-filter-morphology.h index 5924085d9..512eca83c 100644 --- a/src/display/nr-filter-morphology.h +++ b/src/display/nr-filter-morphology.h @@ -33,6 +33,8 @@ public: virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); + void set_operator(FilterMorphologyOperator &o); void set_xradius(double x); void set_yradius(double y); diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp index 3b0f83841..db8b6d92a 100644 --- a/src/display/nr-filter-offset.cpp +++ b/src/display/nr-filter-offset.cpp @@ -85,6 +85,11 @@ void FilterOffset::area_enlarge(NRRectL &area, Geom::Affine const &trans) } } +double FilterOffset::complexity(Geom::Affine const &) +{ + return 1.02; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-offset.h b/src/display/nr-filter-offset.h index 09c57f803..841be6008 100644 --- a/src/display/nr-filter-offset.h +++ b/src/display/nr-filter-offset.h @@ -29,6 +29,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); virtual bool can_handle_affine(Geom::Affine const &); + virtual double complexity(Geom::Affine const &ctm); void set_dx(double amount); void set_dy(double amount); diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 539e3e952..0a445b9e6 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -161,10 +161,6 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) return area; } -FilterTraits FilterPrimitive::get_input_traits() { - return TRAIT_ANYTHING; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h index ebecb91ec..259a25e7e 100644 --- a/src/display/nr-filter-primitive.h +++ b/src/display/nr-filter-primitive.h @@ -22,24 +22,6 @@ namespace Filters { class FilterSlot; class FilterUnits; -/* - * Different filter effects need different types of inputs. This is what - * traits are used for: one can specify, what special restrictions - * there are for inputs. - * - * Example: gaussian blur requires that x- and y-axis of input image - * are paraller to blurred object's x- and y-axis, respectively. - * Otherwise blur wouldn't rotate with the object. - * - * Values here should be powers of two, so these can be used as bitfield. - * That is: any combination ef existing traits can be specified. (excluding - * TRAIT_ANYTHING, which is alias for no traits defined) - */ -enum FilterTraits { - TRAIT_ANYTHING = 0, - TRAIT_PARALLER = 1 -}; - class FilterPrimitive { public: FilterPrimitive(); @@ -81,6 +63,10 @@ public: */ virtual void set_output(int slot); + // returns cache score factor, reflecting the cost of rendering this filter + // this should return how many times slower this primitive is that normal rendering + virtual double complexity(Geom::Affine const &/*ctm*/) { return 1.0; } + /** * Sets the filter primitive subregion. Passing an unset length * (length._set == false) WILL change the parameter as it is @@ -103,14 +89,6 @@ public: */ Geom::Rect filter_primitive_area(FilterUnits const &units); - /** - * Queries the filter, which traits it needs from its input buffers. - * At the time of writing this, only one trait was needed, having - * user coordinate system and input pixelblock coordinates paraller to - * each other. - */ - virtual FilterTraits get_input_traits(); - /** @brief Indicate whether the filter primitive can handle the given affine. * * Results of some filter primitives depend on the coordinate system used when rendering. @@ -121,7 +99,7 @@ public: * When any filter returns false, filter rendering is performed on an intermediate surface * with edges parallel to the axes of the user coordinate system. This means * the matrices from FilterUnits will contain at most a (possibly non-uniform) scale - * and a translation. When all primitives of the filter return false, the rendering is + * and a translation. When all primitives of the filter return true, the rendering is * performed in display coordinate space and no intermediate surface is used. */ virtual bool can_handle_affine(Geom::Affine const &) { return false; } diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp index 2e5f69d65..c28fd485a 100644 --- a/src/display/nr-filter-specularlighting.cpp +++ b/src/display/nr-filter-specularlighting.cpp @@ -174,136 +174,6 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -/* -int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feSpecularLighting (in=%d)", _input); - return 1; - } - - NRPixBlock *out = new NRPixBlock; - - //Fvector *L = NULL; //vector to the light - - int w = in->area.x1 - in->area.x0; - int h = in->area.y1 - in->area.y0; - int x0 = in->area.x0; - int y0 = in->area.y0; - int i, j; - //As long as FilterRes and kernel unit is not supported we hardcode the - //default value - int dx = 1; //TODO setup - int dy = 1; //TODO setup - //surface scale - Geom::Affine trans = units.get_matrix_primitiveunits2pb(); - gdouble ss = surfaceScale * trans[0]; - gdouble ks = specularConstant; //diffuse lighting constant - NR::Fvector L, N, LC, H; - gdouble inter; - - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - unsigned char *data_i = NR_PIXBLOCK_PX (in); - unsigned char *data_o = NR_PIXBLOCK_PX (out); - //No light, nothing to do - switch (light_type) { - case DISTANT_LIGHT: - //the light vector is constant - { - DistantLight *dl = new DistantLight(light.distant, lighting_color); - dl->light_vector(L); - dl->light_components(LC); - NR::normalized_sum(H, L, NR::EYE_VECTOR); - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - COMPUTE_INTER(inter, N, H, ks, specularExponent); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); // CLAMP includes rounding! - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]); - ++j; - } - out->empty = FALSE; - delete dl; - } - break; - case POINT_LIGHT: - { - PointLight *pl = new PointLight(light.point, lighting_color, trans); - pl->light_components(LC); - //TODO we need a reference to the filter to determine primitiveUnits - //if objectBoundingBox is used, use a different matrix for light_vector - // UPDATE: trans is now correct matrix from primitiveUnits to - // pixblock coordinates - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - pl->light_vector(L, - i % w + x0, - i / w + y0, - ss * (double) data_i[4*i+3]/ 255); - NR::normalized_sum(H, L, NR::EYE_VECTOR); - COMPUTE_INTER(inter, N, H, ks, specularExponent); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]); - ++j; - } - out->empty = FALSE; - delete pl; - } - break; - case SPOT_LIGHT: - { - SpotLight *sl = new SpotLight(light.spot, lighting_color, trans); - //TODO we need a reference to the filter to determine primitiveUnits - //if objectBoundingBox is used, use a different matrix for light_vector - // UPDATE: trans is now correct matrix from primitiveUnits to - // pixblock coordinates - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - sl->light_vector(L, - i % w + x0, - i / w + y0, - ss * (double) data_i[4*i+3]/ 255); - sl->light_components(LC, L); - NR::normalized_sum(H, L, NR::EYE_VECTOR); - COMPUTE_INTER(inter, N, H, ks, specularExponent); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]); - ++j; - } - out->empty = FALSE; - delete sl; - } - break; - //else unknown light source, doing nothing - case NO_LIGHT: - default: - { - if (light_type != NO_LIGHT) - g_warning("unknown light source %d", light_type); - out->empty = false; - } - } - - //finishing - slot.set(_output, out); - //nr_pixblock_release(in); - //delete in; - return 0; -}*/ - void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*trans*/) { // TODO: support kernelUnitLength @@ -314,6 +184,11 @@ void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const & /* area.y1 += 1; } +double FilterSpecularLighting::complexity(Geom::Affine const &) +{ + return 9.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h index 2fcb02588..8471b70b0 100644 --- a/src/display/nr-filter-specularlighting.h +++ b/src/display/nr-filter-specularlighting.h @@ -31,8 +31,10 @@ public: FilterSpecularLighting(); static FilterPrimitive *create(); virtual ~FilterSpecularLighting(); + virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); union { SPFeDistantLight *distant; diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp index b88386638..4aadde2aa 100644 --- a/src/display/nr-filter-tile.cpp +++ b/src/display/nr-filter-tile.cpp @@ -45,6 +45,11 @@ void FilterTile::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } +double FilterTile::complexity(Geom::Affine const &) +{ + return 1.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h index 5c0a3e553..37e257f79 100644 --- a/src/display/nr-filter-tile.h +++ b/src/display/nr-filter-tile.h @@ -27,6 +27,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual double complexity(Geom::Affine const &ctm); }; } /* namespace Filters */ diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index 60d5ce872..f065ded11 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -388,6 +388,11 @@ void FilterTurbulence::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } +double FilterTurbulence::complexity(Geom::Affine const &) +{ + return 5.0; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h index 8d3639543..9f824ef48 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -45,6 +45,7 @@ public: virtual ~FilterTurbulence(); virtual void render_cairo(FilterSlot &slot); + virtual double complexity(Geom::Affine const &ctm); void set_baseFrequency(int axis, double freq); void set_numOctaves(int num); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index e84e6f0c2..df6b6222b 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -282,6 +282,18 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) return area; } +double Filter::complexity(Geom::Affine const &ctm) +{ + double factor; + for (unsigned i = 0 ; i < _primitive.size() ; i++) { + if (_primitive[i]) { + double f = _primitive[i]->complexity(ctm); + factor += (f - 1.0); + } + } + return factor; +} + /* Constructor table holds pointers to static methods returning filter * primitives. This table is indexed with FilterPrimitiveType, so that * for example method in _constructor[NR_FILTER_GAUSSIANBLUR] diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 31705f53b..7d31e10ce 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -164,6 +164,9 @@ public: */ Geom::Rect filter_effect_area(Geom::Rect const &bbox); + // returns cache score factor + double complexity(Geom::Affine const &ctm); + /** Creates a new filter with space for one filter element */ Filter(); /** -- cgit v1.2.3 From 16c067ffe728e848bd555b1607d766ccd4162ac5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 9 Aug 2011 06:02:34 +0200 Subject: Turn off debug message spam (bzr r10347.1.27) --- src/display/drawing-item.cpp | 2 +- src/display/drawing-surface.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 3f409b8ee..e86e222e2 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -780,7 +780,7 @@ DrawingItem::_cacheScore() if (_mask) { score += _mask->_cacheScore(); } - g_message("caching score: %f", score); + //g_message("caching score: %f", score); return score; } diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 1faa3151e..39a622fe7 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +//#include #include "display/drawing-surface.h" #include "display/drawing-context.h" #include "display/cairo-utils.h" @@ -263,7 +263,7 @@ DrawingCache::prepare() cairo_rectangle_int_t limit = _convertRect(_pending_area); cairo_region_intersect_rectangle(_clean_region, &limit); } - std::cout << _pending_transform << old_area << _pending_area << std::endl; + //std::cout << _pending_transform << old_area << _pending_area << std::endl; _pending_transform.setIdentity(); } -- cgit v1.2.3 From 74b91362758052e0f03bb819663a4606f08e4c69 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 9 Aug 2011 07:51:45 +0200 Subject: Use cache even if only part of the redraw region is clean (bzr r10347.1.28) --- src/display/drawing-context.h | 3 ++ src/display/drawing-item.cpp | 38 ++++++++++++---------- src/display/drawing-surface.cpp | 71 ++++++++++++++++++++++++++++------------- src/display/drawing-surface.h | 4 +-- 4 files changed, 75 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index 8d2e7d68a..4ada79057 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -64,6 +64,9 @@ public: void rectangle(Geom::Rect const &r) { cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); } + void rectangle(Geom::IntRect 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); diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index e86e222e2..113bf9c33 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -422,7 +422,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag return; } - // carea is the bounding box for intermediate rendering. + // carea is the area to paint Geom::OptIntRect carea = Geom::intersect(area, _drawbox); if (!carea) return; @@ -430,8 +430,8 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag if (_cached) { if (_cache) { _cache->prepare(); - if (_cache->paintFromCache(ct, *carea)) - return; + _cache->paintFromCache(ct, carea); + if (!carea) return; } else { // There is no cache. This could be because caching of this item // was just turned on after the last update phase, or because @@ -447,12 +447,6 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // deleted in setCached() } - // expand carea to contain the dependent area of filters. - if (_filter && render_filters) { - _filter->area_enlarge(*carea, this); - carea.intersectWith(_drawbox); - } - // determine whether this shape needs intermediate rendering. bool needs_intermediate_rendering = false; bool &nir = needs_intermediate_rendering; @@ -480,7 +474,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag if (!needs_intermediate_rendering) { if (_cached && _cache) { Inkscape::DrawingContext cachect(*_cache); - cachect.rectangle(area); + cachect.rectangle(*carea); cachect.clip(); { // 1. clear the corresponding part of cache @@ -498,7 +492,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag ct.setSource(_cache); ct.paint(); // 4. mark as clean - _cache->markClean(area); + _cache->markClean(*carea); return; } else { _renderItem(ct, *carea, flags); @@ -506,7 +500,19 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag } } - DrawingSurface intermediate(*carea); + // iarea is the bounding box for intermediate rendering + // Note 1: pixels inside iarea but outside carea might be invalid + // (incomplete filter dependence region). + // Note 2: We only need to render carea of clip and mask, but + // iarea of the object. + Geom::OptIntRect iarea = carea; + // expand carea to contain the dependent area of filters. + if (_filter && render_filters) { + _filter->area_enlarge(*iarea, this); + iarea.intersectWith(_drawbox); + } + + DrawingSurface intermediate(*iarea); DrawingContext ict(intermediate); // 1. Render clipping path with alpha = opacity. @@ -537,9 +543,9 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag ict.setOperator(CAIRO_OPERATOR_OVER); } - // 3. Render object itself. + // 3. Render object itself ict.pushGroup(); - _renderItem(ict, *carea, flags); + _renderItem(ict, *iarea, flags); // 4. Apply filter. if (_filter && render_filters) { @@ -557,12 +563,12 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // 6. Paint the completed rendering onto the base context (or into cache) if (_cached && _cache) { DrawingContext cachect(*_cache); - cachect.rectangle(area); + cachect.rectangle(*carea); cachect.clip(); cachect.setOperator(CAIRO_OPERATOR_SOURCE); cachect.setSource(&intermediate); cachect.paint(); - _cache->markClean(area); + _cache->markClean(*carea); } ct.setSource(&intermediate); ct.paint(); diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 39a622fe7..43cf50b88 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -188,16 +188,6 @@ DrawingCache::markClean(Geom::IntRect const &area) cairo_rectangle_int_t clean = _convertRect(*r); cairo_region_union_rectangle(_clean_region, &clean); } -bool -DrawingCache::isClean(Geom::IntRect const &area) const -{ - cairo_rectangle_int_t test = _convertRect(area); - if (cairo_region_contains_rectangle(_clean_region, &test) == CAIRO_REGION_OVERLAP_IN) { - return true; - } else { - return false; - } -} /// Call this during the update phase to schedule a transformation of the cache. void @@ -267,20 +257,46 @@ DrawingCache::prepare() _pending_transform.setIdentity(); } -/** @brief Paints the clean area from cache and returns the remaining part */ -bool -DrawingCache::paintFromCache(DrawingContext &ct, Geom::IntRect const &area) +/** @brief Paints the clean area from cache and modifies the @a area + * parameter to the bounds of the region that must be repainted. */ +void +DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area) { - if (!isClean(area)) - return false; - - Inkscape::DrawingContext::Save save(ct); - ct.rectangle(area); - ct.clip(); - ct.setSource(this); - ct.paint(); - - return true; + if (!area) return; + + // We subtract the clean region from the area, then get the bounds + // of the resulting region. This is the area that needs to be repainted + // by the item. + // Then we subtract the area that needs to be repainted from the + // original area and paint the resulting region from cache. + cairo_rectangle_int_t area_c = _convertRect(*area); + cairo_region_t *dirty_region = cairo_region_create_rectangle(&area_c); + cairo_region_t *cache_region = cairo_region_copy(dirty_region); + cairo_region_subtract(dirty_region, _clean_region); + + if (cairo_region_is_empty(dirty_region)) { + area = Geom::OptIntRect(); + } else { + cairo_rectangle_int_t to_repaint; + cairo_region_get_extents(dirty_region, &to_repaint); + *area = _convertRect(to_repaint); + cairo_region_subtract_rectangle(cache_region, &to_repaint); + } + cairo_region_destroy(dirty_region); + + if (!cairo_region_is_empty(cache_region)) { + Inkscape::DrawingContext::Save save(ct); + int nr = cairo_region_num_rectangles(cache_region); + cairo_rectangle_int_t tmp; + for (int i = 0; i < nr; ++i) { + cairo_region_get_rectangle(cache_region, i, &tmp); + ct.rectangle(_convertRect(tmp)); + } + ct.clip(); + ct.setSource(this); + ct.paint(); + } + cairo_region_destroy(cache_region); } cairo_rectangle_int_t @@ -294,6 +310,15 @@ DrawingCache::_convertRect(Geom::IntRect const &area) return ret; } +Geom::IntRect +DrawingCache::_convertRect(cairo_rectangle_int_t const &r) +{ + Geom::IntRect ret = Geom::IntRect::from_xywh( + r.x, r.y, + r.width, r.height); + return ret; +} + } // end namespace Inkscape /* diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index fd46d66ba..f3af33002 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -63,10 +63,9 @@ public: void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite()); void markClean(Geom::IntRect const &area = Geom::IntRect::infinite()); - bool isClean(Geom::IntRect const &area) const; void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); void prepare(); - bool paintFromCache(DrawingContext &ct, Geom::IntRect const &area); + void paintFromCache(DrawingContext &ct, Geom::OptIntRect &area); protected: cairo_region_t *_clean_region; @@ -74,6 +73,7 @@ protected: Geom::Affine _pending_transform; private: static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r); + static Geom::IntRect _convertRect(cairo_rectangle_int_t const &r); }; } // end namespace Inkscape -- cgit v1.2.3 From 52d06f53a4efef7c6880e34cad9de0c770fc13ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 9 Aug 2011 10:01:41 +0200 Subject: Fix invalidation on scrolling (bzr r10347.1.29) --- src/display/drawing-item.cpp | 21 +++++++++++++-------- src/display/drawing-surface.cpp | 6 +----- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 113bf9c33..8da59bbe2 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -296,7 +296,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if ((~_state & flags) == 0) return; // nothing to do // TODO this might be wrong - if (_state & STATE_BBOX) { + if (_state & (outline ? STATE_BBOX : STATE_DRAWBOX)) { // we have up-to-date bbox if (!area.intersects(outline ? _bbox : _drawbox)) return; } @@ -310,6 +310,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne _ctm = child_ctx.ctm; // update _bbox + unsigned old_state = _state; _state = _updateItem(area, child_ctx, flags, reset); // compute drawbox @@ -349,7 +350,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (score >= _drawing._cache_score_threshold) { CacheRecord cr; cr.score = score; - // if _cacheRect() is empty, a negative score will be returnedfrom _cacheScore(), + // if _cacheRect() is empty, a negative score will be returned from _cacheScore(), // so this will not execute (cache score threshold must be positive) cr.cache_size = _cacheRect()->area() * 4; cr.item = this; @@ -381,7 +382,8 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne // now that we know drawbox, dirty the corresponding rect on canvas // unless filtered, groups do not need to render by themselves, only their members if (!is_drawing_group(this) || (_filter && render_filters)) { - if (flags & ~STATE_CACHE) { + // mark for rendering if the item becomes renderable + if ((old_state ^ _state) & STATE_RENDER) { _markForRendering(); } } @@ -501,7 +503,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag } // iarea is the bounding box for intermediate rendering - // Note 1: pixels inside iarea but outside carea might be invalid + // Note 1: Pixels inside iarea but outside carea are invalid // (incomplete filter dependence region). // Note 2: We only need to render carea of clip and mask, but // iarea of the object. @@ -665,11 +667,14 @@ DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) if (!sticky && !(_visible && _sensitive)) return NULL; - if (!_bbox) return NULL; - Geom::Rect expanded(*_bbox); - expanded.expandBy(delta); + // some part of the shape might be hidden by clipping + // TODO add Geom::OptRect(Geom::OptIntRect const &) constructor + Geom::OptIntRect expanded_i = _bbox & _drawbox; + Geom::OptRect expanded = expanded_i ? Geom::Rect(*expanded_i) : Geom::OptRect(); + if (!expanded) return NULL; + expanded->expandBy(delta); - if (expanded.contains(p)) { + if (expanded->contains(p)) { return _pickItem(p, delta, sticky); } return NULL; diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 43cf50b88..e5564f2b3 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -193,7 +193,6 @@ DrawingCache::markClean(Geom::IntRect const &area) void DrawingCache::scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans) { - if (new_area.hasZeroArea() && trans.isIdentity()) return; _pending_area = new_area; _pending_transform *= trans; } @@ -205,15 +204,12 @@ DrawingCache::prepare() { Geom::IntRect old_area = pixelArea(); bool is_identity = _pending_transform.isIdentity(); - if (is_identity) { - if (_pending_area == old_area) return; - } + if (is_identity && _pending_area == old_area) return; // no change bool is_integer_translation = false; if (!is_identity && _pending_transform.isTranslation()) { Geom::IntPoint t = _pending_transform.translation().round(); if (Geom::are_near(Geom::Point(t), _pending_transform.translation())) { - // integer translation or identity with change of area is_integer_translation = true; cairo_region_translate(_clean_region, t[X], t[Y]); if (old_area + t == _pending_area) { -- cgit v1.2.3 From f0d6cbd77ecb7d022539e5019d2a8532f346084c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 9 Aug 2011 22:30:14 +0200 Subject: Do not leak cache objects in DrawingItem destructor (bzr r10347.1.30) --- src/display/drawing-item.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 8da59bbe2..ae3dd49ab 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -76,10 +76,8 @@ DrawingItem::~DrawingItem() // g_warning("Removing item with children"); //} - // remove from the set of cached items - if (_cached) { - _drawing._cached_items.erase(this); - } + // remove from the set of cached items and delete cache + setCached(false, true); if (_has_cache_iterator) { _drawing._candidate_items.erase(_cache_iterator); } -- cgit v1.2.3 From caa510445fc091c63e1ca0ff8f44f2e81ae0638d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 13 Aug 2011 20:30:30 +0200 Subject: More generic handling of child type in DrawingItem. Fix clip object selection bug (LP #365458). Fixed bugs: - https://launchpad.net/bugs/365458 (bzr r10347.1.31) --- src/display/drawing-group.cpp | 4 +-- src/display/drawing-group.h | 2 +- src/display/drawing-image.cpp | 2 +- src/display/drawing-image.h | 2 +- src/display/drawing-item.cpp | 83 +++++++++++++++++++++++++++++-------------- src/display/drawing-item.h | 39 ++++++++++++-------- src/display/drawing-shape.cpp | 13 +++---- src/display/drawing-shape.h | 2 +- src/display/drawing-text.cpp | 6 ++-- src/display/drawing-text.h | 4 +-- src/display/drawing.cpp | 9 +++-- src/display/drawing.h | 2 +- src/display/nr-filter.cpp | 2 +- 13 files changed, 106 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index 38ab73ca2..002a5a2d4 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -112,10 +112,10 @@ DrawingGroup::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingGroup::_pickItem(Geom::Point const &p, double delta, bool sticky) +DrawingGroup::_pickItem(Geom::Point const &p, double delta, unsigned flags) { for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - DrawingItem *picked = i->pick(p, delta, sticky); + DrawingItem *picked = i->pick(p, delta, flags); if (picked) { return _pick_children ? picked : this; } diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h index 7b0645bf4..377c0be39 100644 --- a/src/display/drawing-group.h +++ b/src/display/drawing-group.h @@ -36,7 +36,7 @@ protected: unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); SPStyle *_style; diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 64601354d..074393ab5 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -196,7 +196,7 @@ distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point co } DrawingItem * -DrawingImage::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) +DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/) { if (!_pixbuf) return NULL; diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index de8591221..9f758398b 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -38,7 +38,7 @@ protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); GdkPixbuf *_pixbuf; cairo_surface_t *_surface; diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index ae3dd49ab..ac0d1be1e 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -55,6 +55,7 @@ DrawingItem::DrawingItem(Drawing &drawing) , _user_data(NULL) , _cache(NULL) , _state(0) + , _child_type(CHILD_ORPHAN) , _visible(true) , _sensitive(true) , _cached(0) @@ -62,9 +63,6 @@ DrawingItem::DrawingItem(Drawing &drawing) , _has_cache_iterator(0) , _propagate(0) // , _renders_opacity(0) - , _clip_child(0) - , _mask_child(0) - , _drawing_root(0) , _pick_children(0) { } @@ -85,19 +83,29 @@ DrawingItem::~DrawingItem() // due to the effect of clearChildren(), this only happens for the top-level deleted item if (_parent) { _markForRendering(); + } + + switch (_child_type) { + case CHILD_NORMAL: { + ChildrenList::iterator ithis = _parent->_children.iterator_to(*this); + _parent->_children.erase(ithis); + } break; + case CHILD_CLIP: // we cannot call setClip(NULL) or setMask(NULL), // because that would be an endless loop - if (_clip_child) { - _parent->_clip = NULL; - } else if (_mask_child) { - _parent->_mask = NULL; - } else { - ChildrenList::iterator ithis = _parent->_children.iterator_to(*this); - _parent->_children.erase(ithis); - } - _parent->_markForUpdate(STATE_ALL, false); - } else if (_drawing_root) { + _parent->_clip = NULL; + break; + case CHILD_MASK: + _parent->_mask = NULL; + break; + case CHILD_ROOT: _drawing._root = NULL; + break; + default: ; + } + + if (_parent) { + _parent->_markForUpdate(STATE_ALL, false); } clearChildren(); delete _transform; @@ -118,6 +126,8 @@ void DrawingItem::appendChild(DrawingItem *item) { item->_parent = this; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_NORMAL; _children.push_back(*item); _markForUpdate(STATE_ALL, false); } @@ -126,6 +136,8 @@ void DrawingItem::prependChild(DrawingItem *item) { item->_parent = this; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_NORMAL; _children.push_front(*item); _markForUpdate(STATE_ALL, false); } @@ -139,6 +151,7 @@ DrawingItem::clearChildren() // from which they have already been removed by clear_and_dispose for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { i->_parent = NULL; + i->_child_type = CHILD_ORPHAN; } _children.clear_and_dispose(DeleteDisposer()); } @@ -217,7 +230,8 @@ DrawingItem::setClip(DrawingItem *item) _clip = item; if (item) { item->_parent = this; - item->_clip_child = true; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_CLIP; } _markForUpdate(STATE_ALL, true); } @@ -230,7 +244,8 @@ DrawingItem::setMask(DrawingItem *item) _mask = item; if (item) { item->_parent = this; - item->_mask_child = true; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_MASK; } _markForUpdate(STATE_ALL, true); } @@ -294,7 +309,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if ((~_state & flags) == 0) return; // nothing to do // TODO this might be wrong - if (_state & (outline ? STATE_BBOX : STATE_DRAWBOX)) { + if (_state & STATE_BBOX) { // we have up-to-date bbox if (!area.intersects(outline ? _bbox : _drawbox)) return; } @@ -655,25 +670,39 @@ DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area) * When true, invisible and insensitive objects can also be picked. */ DrawingItem * -DrawingItem::pick(Geom::Point const &p, double delta, bool sticky) +DrawingItem::pick(Geom::Point const &p, double delta, unsigned flags) { // Sometimes there's no BBOX in state, reason unknown (bug 992817) // I made this not an assert to remove the warning if (!(_state & STATE_BBOX) || !(_state & STATE_PICK)) return NULL; - - if (!sticky && !(_visible && _sensitive)) + // ignore invisible and insensitive items unless sticky + if (!(flags & PICK_STICKY) && !(_visible && _sensitive)) return NULL; - // some part of the shape might be hidden by clipping - // TODO add Geom::OptRect(Geom::OptIntRect const &) constructor - Geom::OptIntRect expanded_i = _bbox & _drawbox; - Geom::OptRect expanded = expanded_i ? Geom::Rect(*expanded_i) : Geom::OptRect(); - if (!expanded) return NULL; - expanded->expandBy(delta); + bool outline = _drawing.outline(); + + if (!_drawing.outline()) { + // pick inside clipping path; if NULL, it means the object is clipped away there + if (_clip) { + DrawingItem *cpick = _clip->pick(p, delta, flags | PICK_AS_CLIP); + if (!cpick) return NULL; + } + // same for mask + if (_mask) { + DrawingItem *mpick = _mask->pick(p, delta, flags); + if (!mpick) return NULL; + } + } + + Geom::OptIntRect box = (outline || (flags & PICK_AS_CLIP)) ? _bbox : _drawbox; + if (!box) return NULL; + + Geom::Rect expanded = *box; + expanded.expandBy(delta); - if (expanded->contains(p)) { - return _pickItem(p, delta, sticky); + if (expanded.contains(p)) { + return _pickItem(p, delta, flags); } return NULL; } diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index b934570f2..a50e3ef03 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -58,12 +58,16 @@ public: }; enum StateFlags { STATE_NONE = 0, - STATE_BBOX = (1<<0), // geometric bounding box is up-to-date - STATE_DRAWBOX = (1<<1), // visual bounding box is up-to-date - STATE_CACHE = (1<<2), // cache extents and clean area are up-to-date - STATE_PICK = (1<<3), // can process pick requests - STATE_RENDER = (1<<4), // can be rendered - STATE_ALL = (1<<5)-1 + STATE_BBOX = (1<<0), // bounding boxes are up-to-date + STATE_CACHE = (1<<1), // cache extents and clean area are up-to-date + STATE_PICK = (1<<2), // can process pick requests + STATE_RENDER = (1<<3), // can be rendered + STATE_ALL = (1<<4)-1 + }; + enum PickFlags { + PICK_NORMAL = 0, // normal pick + PICK_STICKY = (1<<0), // sticky pick - ignore visibility and sensitivity + PICK_AS_CLIP = (1<<2) // pick with no stroke and opaque fill regardless of item style }; DrawingItem(Drawing &drawing); @@ -103,9 +107,19 @@ public: void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = STATE_ALL, unsigned reset = 0); void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); void clip(DrawingContext &ct, Geom::IntRect const &area); - DrawingItem *pick(Geom::Point const &p, double delta, bool sticky); + DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags = 0); protected: + enum ChildType { + CHILD_ORPHAN = 0, // no parent + CHILD_NORMAL = 1, // contained in _children of parent + CHILD_CLIP = 2, // referenced by _clip member of parent + CHILD_MASK = 3, // referenced by _mask member of parent + CHILD_ROOT = 4, // root item of _drawing + CHILD_FILL_PATTERN = 5, // not yet implemented: referenced by fill pattern of parent + CHILD_STROKE_PATTERN = 6 // not yet implemented: referenced by stroke pattern of parent + }; + void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); void _markForUpdate(unsigned state, bool propagate); void _markForRendering(); @@ -116,7 +130,7 @@ protected: unsigned flags, unsigned reset) { return 0; } virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky = false) { return NULL; } + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags) { return NULL; } virtual bool _canClip() { return false; } // member variables start here @@ -152,23 +166,18 @@ protected: CacheList::iterator _cache_iterator; unsigned _state : 8; + unsigned _child_type : 3; // see ChildType enum unsigned _visible : 1; unsigned _sensitive : 1; ///< Whether this item responds to events unsigned _cached : 1; ///< Whether the rendering is stored for reuse unsigned _cached_persistent : 1; ///< If set, will always be cached regardless of score - unsigned _has_cache_iterator : 1; ///< If set, _cache_list_pos is valid + unsigned _has_cache_iterator : 1; ///< If set, _cache_iterator is valid unsigned _propagate : 1; ///< Whether to call update for all children on next update //unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity - unsigned _clip_child : 1; ///< If set, this is not a child of _parent, but a clipping path - unsigned _mask_child : 1; ///< If set, this is not a child of _parent, but a mask - unsigned _drawing_root : 1; ///< If set, this is the root item of Drawing unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(), /// otherwise the group is returned friend class Drawing; - -private: - DrawingItem(DrawingItem const &); }; struct DeleteDisposer { diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index 1e41bf5dd..b333b50f8 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -232,7 +232,7 @@ DrawingShape::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) +DrawingShape::_pickItem(Geom::Point const &p, double delta, unsigned flags) { if (_repick_after > 0) --_repick_after; @@ -264,8 +264,9 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) double dist = Geom::infinity(); int wind = 0; - bool needfill = (_nrstyle.fill.type != NRStyle::PAINT_NONE + bool needfill = (flags & PICK_AS_CLIP) || (_nrstyle.fill.type != NRStyle::PAINT_NONE && _nrstyle.fill.opacity > 1e-3 && !outline); + bool wind_evenodd = (flags & PICK_AS_CLIP) ? (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) : (_style->fill_rule.computed == SP_WIND_RULE_EVENODD); if (_drawing.arena()) { Geom::Rect viewbox = _drawing.arena()->item.canvas->getViewbox(); @@ -285,13 +286,13 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) // covered by fill? if (needfill) { - if (!_style->fill_rule.computed) { - if (wind != 0) { + if (wind_evenodd) { + if (wind & 0x1) { _last_pick = this; return this; } } else { - if (wind & 0x1) { + if (wind != 0) { _last_pick = this; return this; } @@ -309,7 +310,7 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) // if not picked on the shape itself, try its markers for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - DrawingItem *ret = i->pick(p, delta, false); + DrawingItem *ret = i->pick(p, delta, flags & ~PICK_STICKY); if (ret) { _last_pick = this; return this; diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 153dcd54e..2938d6397 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -36,7 +36,7 @@ protected: unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); SPCurve *_curve; diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 2f0881c49..21588cc4f 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -102,7 +102,7 @@ DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, } DrawingItem * -DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) +DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, unsigned /*flags*/) { if (!_font || !_bbox) return NULL; @@ -248,9 +248,9 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingText::_pickItem(Geom::Point const &p, double delta, bool sticky) +DrawingText::_pickItem(Geom::Point const &p, double delta, unsigned flags) { - DrawingItem *picked = DrawingGroup::_pickItem(p, delta, sticky); + DrawingItem *picked = DrawingGroup::_pickItem(p, delta, flags); if (picked) return this; return NULL; } diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 671f8f64e..faa33057c 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -32,7 +32,7 @@ public: protected: unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); Geom::Affine *_glyph_transform; font_instance *_font; @@ -59,7 +59,7 @@ protected: unsigned flags, unsigned reset); virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); - virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, bool sticky); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); Geom::OptRect _paintbox; diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index 5881c84ed..e1a17edf1 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -42,7 +42,10 @@ Drawing::setRoot(DrawingItem *item) { delete _root; _root = item; - _root->_drawing_root = true; + if (item) { + assert(item->_child_type == DrawingItem::CHILD_ORPHAN); + item->_child_type = DrawingItem::CHILD_ROOT; + } } RenderMode @@ -168,10 +171,10 @@ Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) } DrawingItem * -Drawing::pick(Geom::Point const &p, double delta, bool sticky) +Drawing::pick(Geom::Point const &p, double delta, unsigned flags) { if (_root) { - return _root->pick(p, delta, sticky); + return _root->pick(p, delta, flags); } return NULL; } diff --git a/src/display/drawing.h b/src/display/drawing.h index a8e70bbe6..011bf35a6 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -60,7 +60,7 @@ public: void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0); void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); - DrawingItem *pick(Geom::Point const &p, double delta, bool sticky); + DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags); sigc::signal signal_request_update; sigc::signal signal_request_render; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index df6b6222b..ef9ac5be6 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -284,7 +284,7 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) double Filter::complexity(Geom::Affine const &ctm) { - double factor; + double factor = 1.0; for (unsigned i = 0 ; i < _primitive.size() ; i++) { if (_primitive[i]) { double f = _primitive[i]->complexity(ctm); -- cgit v1.2.3 From 01913a7cb9e1f9190fd3f9d2d047cbb88b9aa4ff Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 14 Aug 2011 09:08:30 +0200 Subject: Correctly invalidate cache of objects with background-accessing filters (bzr r10347.1.32) --- src/display/drawing-item.cpp | 197 ++++++++++++++++++++++--------------- src/display/drawing-item.h | 8 +- src/display/drawing-shape.cpp | 20 ++-- src/display/nr-filter-blend.cpp | 11 +++ src/display/nr-filter-blend.h | 1 + src/display/nr-filter-flood.h | 1 + src/display/nr-filter-merge.cpp | 11 +++ src/display/nr-filter-merge.h | 1 + src/display/nr-filter-primitive.h | 9 ++ src/display/nr-filter-turbulence.h | 1 + src/display/nr-filter.cpp | 10 ++ src/display/nr-filter.h | 3 + 12 files changed, 188 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index ac0d1be1e..f28894c14 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -56,6 +56,8 @@ DrawingItem::DrawingItem(Drawing &drawing) , _cache(NULL) , _state(0) , _child_type(CHILD_ORPHAN) + , _background_new(0) + , _background_accumulate(0) , _visible(true) , _sensitive(true) , _cached(0) @@ -300,10 +302,9 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne bool outline = _drawing.outline(); // Set reset flags according to propagation status - if (_propagate) { - reset |= ~_state; - _propagate = FALSE; - } + reset |= _propagate_state; + _propagate_state = 0; + _state &= ~reset; // reset state of this item if ((~_state & flags) == 0) return; // nothing to do @@ -323,80 +324,91 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne _ctm = child_ctx.ctm; // update _bbox - unsigned old_state = _state; + unsigned to_update = _state ^ flags; _state = _updateItem(area, child_ctx, flags, reset); - // compute drawbox - if (_filter && render_filters && _item_bbox) { - _drawbox = _filter->compute_drawbox(this, *_item_bbox); - } else { - _drawbox = _bbox; - } - - // Clipping - if (_clip) { - _clip->update(area, child_ctx, flags, reset); - if (outline) { - _bbox.unionWith(_clip->_bbox); + if (to_update & STATE_BBOX) { + // compute drawbox + if (_filter && render_filters && _item_bbox) { + _drawbox = _filter->compute_drawbox(this, *_item_bbox); } else { - _drawbox.intersectWith(_clip->_bbox); + _drawbox = _bbox; } - } - // masking - if (_mask) { - _mask->update(area, child_ctx, flags, reset); - if (outline) { - _bbox.unionWith(_mask->_bbox); - } else { - // for masking, we need full drawbox of mask - _drawbox.intersectWith(_mask->_drawbox); + + // Clipping + if (_clip) { + _clip->update(area, child_ctx, flags, reset); + if (outline) { + _bbox.unionWith(_clip->_bbox); + } else { + _drawbox.intersectWith(_clip->_bbox); + } + } + // Masking + if (_mask) { + _mask->update(area, child_ctx, flags, reset); + if (outline) { + _bbox.unionWith(_mask->_bbox); + } else { + // for masking, we need full drawbox of mask + _drawbox.intersectWith(_mask->_drawbox); + } } } - // Update cache score for this item - if (_has_cache_iterator) { - // remove old score information - _drawing._candidate_items.erase(_cache_iterator); - _has_cache_iterator = false; - } - double score = _cacheScore(); - if (score >= _drawing._cache_score_threshold) { - CacheRecord cr; - cr.score = score; - // if _cacheRect() is empty, a negative score will be returned from _cacheScore(), - // so this will not execute (cache score threshold must be positive) - cr.cache_size = _cacheRect()->area() * 4; - cr.item = this; - _drawing._candidate_items.push_back(cr); - _cache_iterator = --_drawing._candidate_items.end(); - _has_cache_iterator = true; - } - - /* Update cache if enabled. - * General note: here we only tell the cache how it has to transform - * during the render phase. The transformation is deferred because - * after the update the item can have its caching turned off, - * e.g. because its filter was removed. This way we avoid tempoerarily - * using more memory than the cache budget */ - if (_cache) { - Geom::OptIntRect cl = _cacheRect(); - if (_visible && cl) { // never create cache for invisible items - // this takes care of invalidation on transform - _cache->scheduleTransform(*cl, ctm_change); - } else { - // Destroy cache for this item - outside of canvas or invisible. - // The opposite transition (invisible -> visible or object - // entering the canvas) is handled during the render phase - delete _cache; - _cache = NULL; + if (to_update & STATE_CACHE) { + // Update cache score for this item + if (_has_cache_iterator) { + // remove old score information + _drawing._candidate_items.erase(_cache_iterator); + _has_cache_iterator = false; + } + double score = _cacheScore(); + if (score >= _drawing._cache_score_threshold) { + CacheRecord cr; + cr.score = score; + // if _cacheRect() is empty, a negative score will be returned from _cacheScore(), + // so this will not execute (cache score threshold must be positive) + cr.cache_size = _cacheRect()->area() * 4; + cr.item = this; + _drawing._candidate_items.push_back(cr); + _cache_iterator = --_drawing._candidate_items.end(); + _has_cache_iterator = true; + } + + /* Update cache if enabled. + * General note: here we only tell the cache how it has to transform + * during the render phase. The transformation is deferred because + * after the update the item can have its caching turned off, + * e.g. because its filter was removed. This way we avoid tempoerarily + * using more memory than the cache budget */ + if (_cache) { + Geom::OptIntRect cl = _cacheRect(); + if (_visible && cl) { // never create cache for invisible items + // this takes care of invalidation on transform + _cache->scheduleTransform(*cl, ctm_change); + } else { + // Destroy cache for this item - outside of canvas or invisible. + // The opposite transition (invisible -> visible or object + // entering the canvas) is handled during the render phase + delete _cache; + _cache = NULL; + } } } - // now that we know drawbox, dirty the corresponding rect on canvas - // unless filtered, groups do not need to render by themselves, only their members - if (!is_drawing_group(this) || (_filter && render_filters)) { - // mark for rendering if the item becomes renderable - if ((old_state ^ _state) & STATE_RENDER) { + if (to_update & STATE_BACKGROUND) { + // Update _background_accumulate flag + // The code below correctly passes information from _background_new down the tree + _background_accumulate = _background_new; + if (_child_type == CHILD_NORMAL && _parent->_background_accumulate) + _background_accumulate = true; + } + + if (to_update & STATE_RENDER) { + // now that we know drawbox, dirty the corresponding rect on canvas + // unless filtered, groups do not need to render by themselves, only their members + if (!is_drawing_group(this) || (_filter && render_filters)) { _markForRendering(); } } @@ -720,14 +732,37 @@ DrawingItem::_markForRendering() if (!dirty) return; // dirty the caches of all parents + DrawingItem *bkg_root = NULL; + for (DrawingItem *i = this; i; i = i->_parent) { if (i->_cached && i->_cache) { i->_cache->markDirty(*dirty); } + if (i->_background_accumulate) { + bkg_root = i; + } + } + + if (bkg_root) { + bkg_root->_invalidateFilterBackground(*dirty); } _drawing.signal_request_render.emit(*dirty); } +void +DrawingItem::_invalidateFilterBackground(Geom::IntRect const &area) +{ + if (!_drawbox.intersects(area)) return; + + if (_cache && _filter && _filter->uses_background()) { + _cache->markDirty(area); + } + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->_invalidateFilterBackground(area); + } +} + /** @brief Marks the item as needing a recomputation of internal data. * * This mechanism avoids traversing the entire rendering tree (which could be vast) @@ -745,10 +780,9 @@ DrawingItem::_markForRendering() void DrawingItem::_markForUpdate(unsigned flags, bool propagate) { - // we can't simply assign because a previous markForUpdate call - // could have had propagate=true even if this one has propagate=false - if (propagate) - _propagate = true; + if (propagate) { + _propagate_state |= flags; + } if (_state & flags) { _state &= ~flags; @@ -780,16 +814,23 @@ DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style) _filter = NULL; } - /* - if (style && style->enable_background.set - && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { - _background_new = true; - }*/ + if (style && style->enable_background.set) { + if (style->enable_background.value == SP_CSS_BACKGROUND_NEW && !_background_new) { + _background_new = true; + _markForUpdate(STATE_BACKGROUND, true); + } else if (style->enable_background.value == SP_CSS_BACKGROUND_ACCUMULATE && _background_new) { + _background_new = false; + _markForUpdate(STATE_BACKGROUND, true); + } + } - // TODO: STATE_ALL unsets too much _markForUpdate(STATE_ALL, false); } +/** @brief Compute the caching score. + * + * Higher scores mean the item is more aggresively prioritized for automatic + * caching by Inkscape::Drawing. */ double DrawingItem::_cacheScore() { diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index a50e3ef03..6d142c061 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -62,7 +62,8 @@ public: STATE_CACHE = (1<<1), // cache extents and clean area are up-to-date STATE_PICK = (1<<2), // can process pick requests STATE_RENDER = (1<<3), // can be rendered - STATE_ALL = (1<<4)-1 + STATE_BACKGROUND = (1<<4), // filter background data is up to date + STATE_ALL = (1<<5)-1 }; enum PickFlags { PICK_NORMAL = 0, // normal pick @@ -123,6 +124,7 @@ protected: void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); void _markForUpdate(unsigned state, bool propagate); void _markForRendering(); + void _invalidateFilterBackground(Geom::IntRect const &area); void _setStyleCommon(SPStyle *&_style, SPStyle *style); double _cacheScore(); Geom::OptIntRect _cacheRect(); @@ -166,7 +168,11 @@ protected: CacheList::iterator _cache_iterator; unsigned _state : 8; + unsigned _propagate_state : 8; unsigned _child_type : 3; // see ChildType enum + unsigned _background_new : 1; ///< Whether enable-background: new is set for this element + unsigned _background_accumulate : 1; ///< Whether this element accumulates background + /// (has any ancestor with enable-background: new) unsigned _visible : 1; unsigned _sensitive : 1; ///< Whether this item responds to events unsigned _cached : 1; ///< Whether the rendering is stored for reuse diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index b333b50f8..1b201927f 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -244,8 +244,9 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, unsigned flags) if (!_style) return NULL; bool outline = _drawing.outline(); + bool pick_as_clip = flags & PICK_AS_CLIP; - if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline) + if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline && !pick_as_clip) // fully transparent, no pick unless outline mode return NULL; @@ -253,9 +254,14 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, unsigned flags) g_get_current_time (&tstart); double width; - if (outline) { - width = 0.5; + if (pick_as_clip) { + width = 0; // no width should be applied to clip picking + // this overrides display mode and stroke style considerations + } else if (outline) { + width = 0.5; // in outline mode, everything is stroked with the same 0.5px line width } else if (_nrstyle.stroke.type != NRStyle::PAINT_NONE && _nrstyle.stroke.opacity > 1e-3) { + // for normal picking calculate the distance corresponding top the stroke width + // FIXME BUG: this is incorrect for transformed strokes float const scale = _ctm.descrim(); width = std::max(0.125f, _nrstyle.stroke_width * scale) / 2; } else { @@ -264,10 +270,12 @@ DrawingShape::_pickItem(Geom::Point const &p, double delta, unsigned flags) double dist = Geom::infinity(); int wind = 0; - bool needfill = (flags & PICK_AS_CLIP) || (_nrstyle.fill.type != NRStyle::PAINT_NONE - && _nrstyle.fill.opacity > 1e-3 && !outline); - bool wind_evenodd = (flags & PICK_AS_CLIP) ? (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) : (_style->fill_rule.computed == SP_WIND_RULE_EVENODD); + bool needfill = pick_as_clip || (_nrstyle.fill.type != NRStyle::PAINT_NONE && + _nrstyle.fill.opacity > 1e-3 && !outline); + bool wind_evenodd = pick_as_clip ? (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) : + (_style->fill_rule.computed == SP_WIND_RULE_EVENODD); + // actual shape picking if (_drawing.arena()) { Geom::Rect viewbox = _drawing.arena()->item.canvas->getViewbox(); viewbox.expandBy (width); diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index 99a142b44..267883b4b 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -201,6 +201,17 @@ double FilterBlend::complexity(Geom::Affine const &) return 1.1; } +bool FilterBlend::uses_background() +{ + if (_input == NR_FILTER_BACKGROUNDIMAGE || _input == NR_FILTER_BACKGROUNDALPHA || + _input2 == NR_FILTER_BACKGROUNDIMAGE || _input2 == NR_FILTER_BACKGROUNDALPHA) + { + return true; + } else { + return false; + } +} + void FilterBlend::set_input(int slot) { _input = slot; } diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 5f71d468d..957d3cfc8 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -40,6 +40,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual bool can_handle_affine(Geom::Affine const &); virtual double complexity(Geom::Affine const &ctm); + virtual bool uses_background(); virtual void set_input(int slot); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h index c87bf6d8f..f744e9f48 100644 --- a/src/display/nr-filter-flood.h +++ b/src/display/nr-filter-flood.h @@ -29,6 +29,7 @@ public: virtual bool can_handle_affine(Geom::Affine const &); virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); virtual double complexity(Geom::Affine const &ctm); + virtual bool uses_background() { return false; } virtual void set_opacity(double o); virtual void set_color(guint32 c); diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp index 6042da018..28ac19a19 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -72,6 +72,17 @@ double FilterMerge::complexity(Geom::Affine const &) return 1.02; } +bool FilterMerge::uses_background() +{ + for (int i = 0; i < _input_image.size(); ++i) { + int input = _input_image[i]; + if (input == NR_FILTER_BACKGROUNDIMAGE || input == NR_FILTER_BACKGROUNDALPHA) { + return true; + } + } + return false; +} + void FilterMerge::set_input(int slot) { _input_image[0] = slot; } diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h index cedab9086..238f9a3e7 100644 --- a/src/display/nr-filter-merge.h +++ b/src/display/nr-filter-merge.h @@ -27,6 +27,7 @@ public: virtual void render_cairo(FilterSlot &); virtual bool can_handle_affine(Geom::Affine const &); virtual double complexity(Geom::Affine const &ctm); + virtual bool uses_background(); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h index 259a25e7e..501d76447 100644 --- a/src/display/nr-filter-primitive.h +++ b/src/display/nr-filter-primitive.h @@ -12,6 +12,7 @@ #define SEEN_NR_FILTER_PRIMITIVE_H #include <2geom/forward.h> +#include "display/nr-filter-types.h" #include "svg/svg-length.h" struct NRRectL; @@ -66,6 +67,14 @@ public: // returns cache score factor, reflecting the cost of rendering this filter // this should return how many times slower this primitive is that normal rendering virtual double complexity(Geom::Affine const &/*ctm*/) { return 1.0; } + + virtual bool uses_background() { + if (_input == NR_FILTER_BACKGROUNDIMAGE || _input == NR_FILTER_BACKGROUNDALPHA) { + return true; + } else { + return false; + } + } /** * Sets the filter primitive subregion. Passing an unset length diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h index 9f824ef48..0b451d355 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -46,6 +46,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual double complexity(Geom::Affine const &ctm); + virtual bool uses_background() { return false; } void set_baseFrequency(int axis, double freq); void set_numOctaves(int num); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index ef9ac5be6..ae50e641b 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -294,6 +294,16 @@ double Filter::complexity(Geom::Affine const &ctm) return factor; } +bool Filter::uses_background() +{ + for (unsigned i = 0 ; i < _primitive.size() ; i++) { + if (_primitive[i] && _primitive[i]->uses_background()) { + return true; + } + } + return false; +} + /* Constructor table holds pointers to static methods returning filter * primitives. This table is indexed with FilterPrimitiveType, so that * for example method in _constructor[NR_FILTER_GAUSSIANBLUR] diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 7d31e10ce..87a0fae94 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -167,6 +167,9 @@ public: // returns cache score factor double complexity(Geom::Affine const &ctm); + // says whether the filter accesses any of the background images + bool uses_background(); + /** Creates a new filter with space for one filter element */ Filter(); /** -- cgit v1.2.3 From 66bab1f2b80ff441643fd5fdeb5bade70fb5aa8c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 16 Aug 2011 03:40:10 +0200 Subject: Add sanity checks against singular transforms in the drawing tree. Fixes LP #825767. Fixed bugs: - https://launchpad.net/bugs/825767 (bzr r10347.1.33) --- src/display/drawing-item.cpp | 6 +++--- src/display/drawing-item.h | 2 +- src/display/drawing-text.cpp | 39 +++++++++----------------------------- src/display/drawing-text.h | 2 -- src/display/nr-filter-gaussian.cpp | 4 ++-- 5 files changed, 15 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index f28894c14..1195bc56c 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -66,8 +66,7 @@ DrawingItem::DrawingItem(Drawing &drawing) , _propagate(0) // , _renders_opacity(0) , _pick_children(0) -{ -} +{} DrawingItem::~DrawingItem() { @@ -120,7 +119,7 @@ DrawingItem * DrawingItem::parent() const { // initially I wanted to return NULL if we are a clip or mask child, - // but the previous behavior was just to return the parent + // but the previous behavior was just to return the parent regardless of child type return _parent; } @@ -442,6 +441,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // If we are invisible, return immediately if (!_visible) return; + if (_ctm.isSingular(NR_EPSILON)) return; // TODO convert outline rendering to a separate virtual function if (outline) { diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 6d142c061..abc69be02 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -112,7 +112,7 @@ public: protected: enum ChildType { - CHILD_ORPHAN = 0, // no parent + CHILD_ORPHAN = 0, // no parent - implies _parent == NULL CHILD_NORMAL = 1, // contained in _children of parent CHILD_CLIP = 2, // referenced by _clip member of parent CHILD_MASK = 3, // referenced by _mask member of parent diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 21588cc4f..5e6396df1 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -23,7 +23,6 @@ namespace Inkscape { DrawingGlyphs::DrawingGlyphs(Drawing &drawing) : DrawingItem(drawing) - , _glyph_transform(NULL) , _font(NULL) , _glyph(0) {} @@ -34,7 +33,6 @@ DrawingGlyphs::~DrawingGlyphs() _font->Unref(); _font = NULL; } - delete _glyph_transform; } void @@ -42,12 +40,7 @@ DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &tran { _markForRendering(); - if (trans.isIdentity()) { - delete _glyph_transform; // delete NULL; is safe - _glyph_transform = NULL; - } else { - _glyph_transform = new Geom::Affine(trans); - } + setTransform(trans); if (font) font->Ref(); if (_font) _font->Unref(); @@ -70,12 +63,7 @@ DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, return STATE_ALL; } - Geom::OptRect b; - Geom::Affine t = _glyph_transform ? *_glyph_transform * ctx.ctm : ctx.ctm; - _x = t[4]; - _y = t[5]; - - b = bounds_exact_transformed(*_font->PathVector(_glyph), t); + Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); if (b && ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) { float width, scale; scale = ctx.ctm.descrim(); @@ -165,21 +153,19 @@ void DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { if (_drawing.outline()) { - DrawingContext::Save save(ct); guint32 rgba = _drawing.outlinecolor; + Inkscape::DrawingContext::Save save(ct); ct.setSource(rgba); ct.setTolerance(1.25); // low quality, but good enough for outline mode - ct.newPath(); - ct.transform(_ctm); for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { DrawingGlyphs *g = dynamic_cast(&*i); if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - if (g->_glyph_transform) { - ct.transform(*g->_glyph_transform); - } + // skip glpyhs with singular transforms + if (g->_ctm.isSingular()) continue; + ct.transform(g->_ctm); ct.path(*g->_font->PathVector(g->_glyph)); ct.fill(); } @@ -189,9 +175,6 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding bool has_stroke, has_fill; - Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); - has_fill = _nrstyle.prepareFill(ct, _paintbox); has_stroke = _nrstyle.prepareStroke(ct, _paintbox); @@ -201,9 +184,8 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - if (g->_glyph_transform) { - ct.transform(*g->_glyph_transform); - } + if (g->_ctm.isSingular()) continue; + ct.transform(g->_ctm); ct.path(*g->_font->PathVector(g->_glyph)); } @@ -232,16 +214,13 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) ct.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ct.transform(_ctm); for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { DrawingGlyphs *g = dynamic_cast(&*i); if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - if (g->_glyph_transform) { - ct.transform(*g->_glyph_transform); - } + ct.transform(g->_ctm); ct.path(*g->_font->PathVector(g->_glyph)); } ct.fill(); diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index faa33057c..07962365c 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -34,10 +34,8 @@ protected: unsigned flags, unsigned reset); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); - Geom::Affine *_glyph_transform; font_instance *_font; int _glyph; - float _x, _y; friend class DrawingText; }; diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 988a8479e..19cf51772 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -511,7 +511,7 @@ gaussian_pass_IIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_su w, h, b, M, tmpdata, num_threads); break; default: - assert(false); + g_warning("gaussian_pass_IIR: unsupported image format"); }; } @@ -544,7 +544,7 @@ gaussian_pass_FIR(Geom::Dim2 d, double deviation, cairo_surface_t *src, cairo_su w, h, &kernel[0], scr_len, num_threads); break; default: - assert(false); + g_warning("gaussian_pass_FIR: unsupported image format"); }; } -- cgit v1.2.3 From dc713ea50efc5fd3f041db05ff92d31a3a54dc5b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 16 Aug 2011 06:04:53 +0200 Subject: Add user preference for rendering cache size (bzr r10347.1.34) --- src/display/canvas-arena.cpp | 19 ++++++++++++ src/display/canvas-arena.h | 2 ++ src/display/drawing.cpp | 48 ++++++++++++++++++------------ src/display/drawing.h | 3 +- src/preferences-skeleton.h | 1 + src/ui/dialog/inkscape-preferences.cpp | 54 ++++++++++++++++++---------------- src/ui/dialog/inkscape-preferences.h | 9 +++--- 7 files changed, 88 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index b254a55c8..ac2704895 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -21,6 +21,7 @@ #include "display/drawing-item.h" #include "display/drawing-group.h" #include "display/drawing-surface.h" +#include "preferences.h" using namespace Inkscape; @@ -48,6 +49,22 @@ static void sp_canvas_arena_request_render (SPCanvasArena *ca, Geom::IntRect con static SPCanvasItemClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; +struct CacheBudgetObserver : public Inkscape::Preferences::Observer { + CacheBudgetObserver(SPCanvasArena *arena) + : Inkscape::Preferences::Observer("/options/renderingcache/size") + , _arena(arena) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Inkscape::Preferences::Entry v = prefs->getEntry(observed_path); + notify(v); + prefs->addObserver(*this); + } + void notify(Preferences::Entry const &v) { + _arena->drawing.setCacheBudget((1 << 20) * v.getIntLimited(128, 0, 4096)); + } + SPCanvasArena *_arena; +}; + GType sp_canvas_arena_get_type (void) { @@ -102,6 +119,7 @@ sp_canvas_arena_init (SPCanvasArena *arena) arena->sticky = FALSE; new (&arena->drawing) Inkscape::Drawing(arena); + arena->observer = new CacheBudgetObserver(arena); Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing); root->setPickChildren(true); @@ -129,6 +147,7 @@ sp_canvas_arena_destroy (GtkObject *object) { SPCanvasArena *arena = SP_CANVAS_ARENA (object); + delete arena->observer; arena->drawing.~Drawing(); if (GTK_OBJECT_CLASS (parent_class)->destroy) diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 6c65bb0e5..463dc1bc3 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS typedef struct _SPCanvasArena SPCanvasArena; typedef struct _SPCanvasArenaClass SPCanvasArenaClass; +struct CacheBudgetObserver; struct _SPCanvasArena { SPCanvasItem item; @@ -45,6 +46,7 @@ struct _SPCanvasArena { Inkscape::DrawingItem *active; /* fixme: */ Inkscape::DrawingItem *picked; + CacheBudgetObserver *observer; double delta; }; diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index e1a17edf1..06183fed2 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -26,7 +26,7 @@ Drawing::Drawing(SPCanvasArena *arena) , _blur_quality(BLUR_QUALITY_BEST) , _filter_quality(Filters::FILTER_QUALITY_BEST) , _cache_score_threshold(50000.0) - , _cache_budget(128 << 20) // 128 MiB + , _cache_budget(0) , _canvasarena(arena) { @@ -128,6 +128,12 @@ Drawing::setCacheLimit(Geom::OptIntRect const &r) (*i)->_markForUpdate(DrawingItem::STATE_CACHE, false); } } +void +Drawing::setCacheBudget(size_t bytes) +{ + _cache_budget = bytes; + _pickItemsForCaching(); +} void Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) @@ -136,6 +142,29 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl _root->update(area, ctx, flags, reset); } // process the updated cache scores + _pickItemsForCaching(); +} + +void +Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (_root) { + _root->render(ct, area, flags); + } +} + +DrawingItem * +Drawing::pick(Geom::Point const &p, double delta, unsigned flags) +{ + if (_root) { + return _root->pick(p, delta, flags); + } + return NULL; +} + +void +Drawing::_pickItemsForCaching() +{ // we cache the objects with the highest score until the budget is exhausted _candidate_items.sort(std::greater()); size_t used = 0; @@ -162,23 +191,6 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl } } -void -Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) -{ - if (_root) { - _root->render(ct, area, flags); - } -} - -DrawingItem * -Drawing::pick(Geom::Point const &p, double delta, unsigned flags) -{ - if (_root) { - return _root->pick(p, delta, flags); - } - return NULL; -} - } // end namespace Inkscape /* diff --git a/src/display/drawing.h b/src/display/drawing.h index 011bf35a6..cfba4ebe6 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -55,6 +55,7 @@ public: Geom::OptIntRect const &cacheLimit() const; void setCacheLimit(Geom::OptIntRect const &r); + void setCacheBudget(size_t bytes); OutlineColors const &colors() const { return _colors; } @@ -67,7 +68,7 @@ public: sigc::signal signal_item_deleted; private: - void _reportCacheScore(CacheRecord const &); + void _pickItemsForCaching(); typedef std::list CandidateList; diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 16723170f..895eb7276 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -231,6 +231,7 @@ static char const preferences_skeleton[] = " \n" "\n" " \n" +" " " " " " " " diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index d11ffd565..0129f196f 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -124,7 +124,7 @@ InkscapePreferences::InkscapePreferences() initPageTransforms(); initPageClones(); initPageMasks(); - initPageFilters(); + initPageRendering(); initPageBitmaps(); initPageCMS(); initPageGrids(); @@ -739,8 +739,22 @@ void InkscapePreferences::initPageTransforms() this->AddPage(_page_transforms, _("Transforms"), PREFS_PAGE_TRANSFORMS); } -void InkscapePreferences::initPageFilters() +void InkscapePreferences::initPageRendering() { + /* show infobox */ + _show_filters_info_box.init( _("Show filter primitives infobox"), "/options/showfiltersinfobox/value", true); + _page_rendering.add_line(true, "", _show_filters_info_box, "", + _("Show icons and descriptions for the filter primitives available at the filter effects dialog")); + + /* threaded blur */ //related comments/widgets/functions should be renamed and option should be moved elsewhere when inkscape is fully multi-threaded + _filter_multi_threaded.init("/options/threading/numthreads", 1.0, 8.0, 1.0, 2.0, 4.0, true, false); + _page_rendering.add_line( false, _("Number of Threads:"), _filter_multi_threaded, _("(requires restart)"), + _("Configure number of processors/threads to use when rendering filters"), false); + + // rendering cache + _rendering_cache_size.init("/options/renderingcache/size", 0.0, 4096.0, 1.0, 32.0, 128.0, true, false); + _page_rendering.add_line( false, _("Rendering cache size:"), _rendering_cache_size, C_("mebibyte (2^20 bytes) abbreviation","MiB"), _("Set the amount of memory per drawing which can be used to store rendered parts of the drawing for later reuse; set to zero to disable caching"), false); + /* blur quality */ _blur_quality_best.init ( _("Best quality (slowest)"), "/options/blurquality/value", BLUR_QUALITY_BEST, false, 0); @@ -753,16 +767,16 @@ void InkscapePreferences::initPageFilters() _blur_quality_worst.init ( _("Lowest quality (fastest)"), "/options/blurquality/value", BLUR_QUALITY_WORST, false, &_blur_quality_best); - _page_filters.add_group_header( _("Gaussian blur quality for display")); - _page_filters.add_line( true, "", _blur_quality_best, "", + _page_rendering.add_group_header( _("Gaussian blur quality for display")); + _page_rendering.add_line( true, "", _blur_quality_best, "", _("Best quality, but display may be very slow at high zooms (bitmap export always uses best quality)")); - _page_filters.add_line( true, "", _blur_quality_better, "", + _page_rendering.add_line( true, "", _blur_quality_better, "", _("Better quality, but slower display")); - _page_filters.add_line( true, "", _blur_quality_normal, "", + _page_rendering.add_line( true, "", _blur_quality_normal, "", _("Average quality, acceptable display speed")); - _page_filters.add_line( true, "", _blur_quality_worse, "", + _page_rendering.add_line( true, "", _blur_quality_worse, "", _("Lower quality (some artifacts), but display is faster")); - _page_filters.add_line( true, "", _blur_quality_worst, "", + _page_rendering.add_line( true, "", _blur_quality_worst, "", _("Lowest quality (considerable artifacts), but display is fastest")); /* filter quality */ @@ -777,29 +791,19 @@ void InkscapePreferences::initPageFilters() _filter_quality_worst.init ( _("Lowest quality (fastest)"), "/options/filterquality/value", Inkscape::Filters::FILTER_QUALITY_WORST, false, &_filter_quality_best); - _page_filters.add_group_header( _("Filter effects quality for display")); - _page_filters.add_line( true, "", _filter_quality_best, "", + _page_rendering.add_group_header( _("Filter effects quality for display")); + _page_rendering.add_line( true, "", _filter_quality_best, "", _("Best quality, but display may be very slow at high zooms (bitmap export always uses best quality)")); - _page_filters.add_line( true, "", _filter_quality_better, "", + _page_rendering.add_line( true, "", _filter_quality_better, "", _("Better quality, but slower display")); - _page_filters.add_line( true, "", _filter_quality_normal, "", + _page_rendering.add_line( true, "", _filter_quality_normal, "", _("Average quality, acceptable display speed")); - _page_filters.add_line( true, "", _filter_quality_worse, "", + _page_rendering.add_line( true, "", _filter_quality_worse, "", _("Lower quality (some artifacts), but display is faster")); - _page_filters.add_line( true, "", _filter_quality_worst, "", + _page_rendering.add_line( true, "", _filter_quality_worst, "", _("Lowest quality (considerable artifacts), but display is fastest")); - /* show infobox */ - _show_filters_info_box.init( _("Show filter primitives infobox"), "/options/showfiltersinfobox/value", true); - _page_filters.add_line(true, "", _show_filters_info_box, "", - _("Show icons and descriptions for the filter primitives available at the filter effects dialog")); - - /* threaded blur */ //related comments/widgets/functions should be renamed and option should be moved elsewhere when inkscape is fully multi-threaded - _filter_multi_threaded.init("/options/threading/numthreads", 1.0, 8.0, 1.0, 2.0, 4.0, true, false); - _page_filters.add_line( false, _("Number of Threads:"), _filter_multi_threaded, _("(requires restart)"), - _("Configure number of processors/threads to use with rendering of gaussian blur"), false); - - this->AddPage(_page_filters, _("Filters"), PREFS_PAGE_FILTERS); + this->AddPage(_page_rendering, _("Rendering"), PREFS_PAGE_RENDERING); } diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 13851e525..d783a2df1 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -44,7 +44,7 @@ enum { PREFS_PAGE_TOOLS_SELECTOR, PREFS_PAGE_TOOLS_NODE, PREFS_PAGE_TOOLS_TWEAK, - PREFS_PAGE_TOOLS_SPRAY, + PREFS_PAGE_TOOLS_SPRAY, PREFS_PAGE_TOOLS_ZOOM, PREFS_PAGE_TOOLS_MEASURE, PREFS_PAGE_TOOLS_SHAPES, @@ -67,7 +67,7 @@ enum { PREFS_PAGE_TRANSFORMS, PREFS_PAGE_CLONES, PREFS_PAGE_MASKS, - PREFS_PAGE_FILTERS, + PREFS_PAGE_RENDERING, PREFS_PAGE_BITMAPS, PREFS_PAGE_CMS, PREFS_PAGE_GRIDS, @@ -124,7 +124,7 @@ protected: UI::Widget::DialogPage _page_clones; UI::Widget::DialogPage _page_mask; UI::Widget::DialogPage _page_transforms; - UI::Widget::DialogPage _page_filters; + UI::Widget::DialogPage _page_rendering; UI::Widget::DialogPage _page_select; UI::Widget::DialogPage _page_importexport; UI::Widget::DialogPage _page_cms; @@ -254,6 +254,7 @@ protected: UI::Widget::PrefRadioButton _filter_quality_worse; UI::Widget::PrefRadioButton _filter_quality_worst; UI::Widget::PrefCheckButton _show_filters_info_box; + UI::Widget::PrefSpinButton _rendering_cache_size; UI::Widget::PrefSpinButton _filter_multi_threaded; UI::Widget::PrefCheckButton _trans_scale_stroke; @@ -389,7 +390,7 @@ protected: void initPageClones(); void initPageMasks(); void initPageTransforms(); - void initPageFilters(); + void initPageRendering(); void initPageSelecting(); void initPageImportExport(); void initPageCMS(); -- cgit v1.2.3 From dac56109f3f34616ce6fdacf456ec9763d871322 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 16 Aug 2011 07:08:36 +0200 Subject: Fix large memory leaks in the swatches panel (bzr r10347.1.35) --- src/ege-adjustment-action.cpp | 9 +++++---- src/ege-select-one-action.cpp | 15 +++++++++++++++ src/ui/dialog/color-item.cpp | 18 +++++++++--------- src/ui/dialog/color-item.h | 3 ++- src/ui/dialog/swatches.cpp | 24 +++++++++--------------- 5 files changed, 40 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/ege-adjustment-action.cpp b/src/ege-adjustment-action.cpp index 45a44ae0c..f3009ac04 100644 --- a/src/ege-adjustment-action.cpp +++ b/src/ege-adjustment-action.cpp @@ -300,10 +300,11 @@ static void ege_adjustment_action_finalize( GObject* object ) action = EGE_ADJUSTMENT_ACTION( object ); - if ( action->private_data->format ) { - g_free( action->private_data->format ); - action->private_data->format = 0; - } + // g_free(NULL) does nothing + g_free( action->private_data->format ); + g_free( action->private_data->selfId ); + g_free( action->private_data->appearance ); + g_free( action->private_data->iconId ); egeAct_free_all_descriptions( action ); diff --git a/src/ege-select-one-action.cpp b/src/ege-select-one-action.cpp index e0130a68d..44b3dc465 100644 --- a/src/ege-select-one-action.cpp +++ b/src/ege-select-one-action.cpp @@ -52,6 +52,7 @@ enum { static void ege_select_one_action_class_init( EgeSelectOneActionClass* klass ); static void ege_select_one_action_init( EgeSelectOneAction* action ); +static void ege_select_one_action_finalize( GObject* action ); static void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec ); static void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec ); @@ -159,6 +160,7 @@ void ege_select_one_action_class_init( EgeSelectOneActionClass* klass ) gDataName = g_quark_from_string("ege-select1-action"); + objClass->finalize = ege_select_one_action_finalize; objClass->get_property = ege_select_one_action_get_property; objClass->set_property = ege_select_one_action_set_property; @@ -282,6 +284,19 @@ void ege_select_one_action_init( EgeSelectOneAction* action ) /* g_signal_connect( action, "notify", G_CALLBACK( fixup_labels ), NULL ); */ } +void ege_select_one_action_finalize( GObject* object ) +{ + EgeSelectOneAction *action = EGE_SELECT_ONE_ACTION( object ); + + g_free( action->private_data->iconProperty ); + g_free( action->private_data->appearance ); + g_free( action->private_data->selection ); + + if ( G_OBJECT_CLASS(gParentClass)->finalize ) { + (*G_OBJECT_CLASS(gParentClass)->finalize)(object); + } +} + EgeSelectOneAction* ege_select_one_action_new( const gchar *name, const gchar *label, const gchar *tooltip, diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index 598827da9..b61925855 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -460,8 +460,8 @@ void ColorItem::_updatePreviews() for ( std::vector::iterator it2 = possible.begin(); it2 != possible.end() && !found; ++it2 ) { SwatchPage* curr = *it2; index = 0; - for ( std::vector::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { - if ( this == *zz ) { + for ( boost::ptr_vector::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { + if ( this == &*zz ) { found = true; paletteName = curr->_name; break; @@ -734,12 +734,12 @@ void ColorItem::_wireMagicColors( SwatchPage *colorSet ) { if ( colorSet ) { - for ( std::vector::iterator it = colorSet->_colors.begin(); it != colorSet->_colors.end(); ++it ) + for ( boost::ptr_vector::iterator it = colorSet->_colors.begin(); it != colorSet->_colors.end(); ++it ) { - std::string::size_type pos = (*it)->def.descr.find("*{"); + std::string::size_type pos = it->def.descr.find("*{"); if ( pos != std::string::npos ) { - std::string subby = (*it)->def.descr.substr( pos + 2 ); + std::string subby = it->def.descr.substr( pos + 2 ); std::string::size_type endPos = subby.find("}*"); if ( endPos != std::string::npos ) { @@ -749,12 +749,12 @@ void ColorItem::_wireMagicColors( SwatchPage *colorSet ) if ( subby.find('E') != std::string::npos ) { - (*it)->def.setEditable( true ); + it->def.setEditable( true ); } if ( subby.find('L') != std::string::npos ) { - (*it)->_isLive = true; + it->_isLive = true; } std::string part; @@ -764,7 +764,7 @@ void ColorItem::_wireMagicColors( SwatchPage *colorSet ) if ( popVal( colorIndex, part ) ) { guint64 percent = 0; if ( popVal( percent, part ) ) { - (*it)->_linkTint( *(colorSet->_colors[colorIndex]), percent ); + it->_linkTint( colorSet->_colors[colorIndex], percent ); } } } @@ -779,7 +779,7 @@ void ColorItem::_wireMagicColors( SwatchPage *colorSet ) if ( !popVal( grayLevel, part ) ) { grayLevel = 0; } - (*it)->_linkTone( *(colorSet->_colors[colorIndex]), percent, grayLevel ); + it->_linkTone( colorSet->_colors[colorIndex], percent, grayLevel ); } } } diff --git a/src/ui/dialog/color-item.h b/src/ui/dialog/color-item.h index 9080498eb..d06082f2e 100644 --- a/src/ui/dialog/color-item.h +++ b/src/ui/dialog/color-item.h @@ -12,6 +12,7 @@ #ifndef SEEN_DIALOGS_COLOR_ITEM_H #define SEEN_DIALOGS_COLOR_ITEM_H +#include #include #include "widgets/ege-paint-def.h" @@ -33,7 +34,7 @@ public: Glib::ustring _name; int _prefWidth; - std::vector _colors; + boost::ptr_vector _colors; }; diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index ad3b79630..910d63873 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -885,7 +885,7 @@ void SwatchesPanel::_setDocument( SPDocument *document ) } static void recalcSwatchContents(SPDocument* doc, - std::vector &tmpColors, + boost::ptr_vector &tmpColors, std::map &previewMappings, std::map &gradMappings) { @@ -938,7 +938,7 @@ void SwatchesPanel::handleGradientsChange(SPDocument *document) { SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; if (docPalette) { - std::vector tmpColors; + boost::ptr_vector tmpColors; std::map tmpPrevs; std::map tmpGrads; recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); @@ -953,9 +953,6 @@ void SwatchesPanel::handleGradientsChange(SPDocument *document) } docPalette->_colors.swap(tmpColors); - for (std::vector::iterator it = tmpColors.begin(); it != tmpColors.end(); ++it) { - delete *it; - } // Figure out which SwatchesPanel instances are affected and update them. @@ -976,7 +973,7 @@ void SwatchesPanel::handleDefsModified(SPDocument *document) { SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; if (docPalette && !DocTrack::queueUpdateIfNeeded(document) ) { - std::vector tmpColors; + boost::ptr_vector tmpColors; std::map tmpPrevs; std::map tmpGrads; recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); @@ -986,8 +983,8 @@ void SwatchesPanel::handleDefsModified(SPDocument *document) } else { int cap = std::min(docPalette->_colors.size(), tmpColors.size()); for (int i = 0; i < cap; i++) { - ColorItem* newColor = tmpColors[i]; - ColorItem* oldColor = docPalette->_colors[i]; + ColorItem *newColor = &tmpColors[i]; + ColorItem *oldColor = &docPalette->_colors[i]; if ( (newColor->def.getType() != oldColor->def.getType()) || (newColor->def.getR() != oldColor->def.getR()) || (newColor->def.getG() != oldColor->def.getG()) || @@ -1006,9 +1003,6 @@ void SwatchesPanel::handleDefsModified(SPDocument *document) for (std::map::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { cairo_pattern_destroy(it->second); } - for (std::vector::iterator it = tmpColors.begin(); it != tmpColors.end(); ++it) { - delete *it; - } } } @@ -1098,8 +1092,8 @@ void SwatchesPanel::_updateFromSelection() } sp_style_unref(tmpStyle); - for ( std::vector::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) { - ColorItem* item = *it; + for ( boost::ptr_vector::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) { + ColorItem* item = &*it; bool isFill = (fillId == item->def.descr); bool isStroke = (strokeId == item->def.descr); item->setState( isFill, isStroke ); @@ -1140,8 +1134,8 @@ void SwatchesPanel::_rebuild() _holder->freezeUpdates(); // TODO restore once 'clear' works _holder->addPreview(_clear); _holder->addPreview(_remove); - for ( std::vector::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { - _holder->addPreview(*it); + for ( boost::ptr_vector::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { + _holder->addPreview(&*it); } _holder->thawUpdates(); } -- cgit v1.2.3 From a49c525365ff86ea1e22281d3a3b66d7ef0087c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 19 Aug 2011 09:33:48 +0200 Subject: Fix rendering glitches appearing when filtered, cached groups have filtered, cached children (bzr r10347.1.36) --- src/display/drawing-group.cpp | 10 +++++----- src/display/drawing-item.cpp | 20 +++++++++++--------- src/display/drawing-surface.cpp | 33 +++++++++++++++++++++++++++++---- src/display/drawing-surface.h | 1 + src/display/nr-filter-units.cpp | 4 ++-- 5 files changed, 48 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index 002a5a2d4..d9a75925e 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -57,7 +57,7 @@ DrawingGroup::setChildTransform(Geom::Affine const &new_trans) if (_child_transform) { current = *_child_transform; } - + if (!Geom::are_near(current, new_trans, NR_EPSILON)) { // mark the area where the object was for redraw. _markForRendering(); @@ -77,11 +77,11 @@ DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u unsigned beststate = STATE_ALL; bool outline = _drawing.outline(); + UpdateContext child_ctx(ctx); + if (_child_transform) { + child_ctx.ctm = *_child_transform * ctx.ctm; + } for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - UpdateContext child_ctx(ctx); - if (_child_transform) { - child_ctx.ctm = *_child_transform * ctx.ctm; - } i->update(area, child_ctx, flags, reset); } if (beststate & STATE_BBOX) { diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 1195bc56c..c517b1bb5 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -370,8 +370,8 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne // so this will not execute (cache score threshold must be positive) cr.cache_size = _cacheRect()->area() * 4; cr.item = this; - _drawing._candidate_items.push_back(cr); - _cache_iterator = --_drawing._candidate_items.end(); + _drawing._candidate_items.push_front(cr); + _cache_iterator = _drawing._candidate_items.begin(); _has_cache_iterator = true; } @@ -462,7 +462,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag } else { // There is no cache. This could be because caching of this item // was just turned on after the last update phase, or because - // we are outside of the canvas. + // we were previously outside of the canvas. Geom::OptIntRect cl = _drawing.cacheLimit(); cl.intersectWith(_drawbox); if (cl) { @@ -515,9 +515,8 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // 3. copy from cache to output Inkscape::DrawingContext::Save save(ct); ct.rectangle(*carea); - ct.clip(); ct.setSource(_cache); - ct.paint(); + ct.fill(); // 4. mark as clean _cache->markClean(*carea); return; @@ -591,14 +590,14 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag if (_cached && _cache) { DrawingContext cachect(*_cache); cachect.rectangle(*carea); - cachect.clip(); cachect.setOperator(CAIRO_OPERATOR_SOURCE); cachect.setSource(&intermediate); - cachect.paint(); + cachect.fill(); _cache->markClean(*carea); } + ct.rectangle(*carea); ct.setSource(&intermediate); - ct.paint(); + ct.fill(); ct.setSource(0,0,0,0); // the call above is to clear a ref on the intermediate surface held by ct } @@ -735,7 +734,10 @@ DrawingItem::_markForRendering() DrawingItem *bkg_root = NULL; for (DrawingItem *i = this; i; i = i->_parent) { - if (i->_cached && i->_cache) { + if (i != this && i->_filter) { + i->_filter->area_enlarge(*dirty, i); + } + if (i->_cache) { i->_cache->markDirty(*dirty); } if (i->_background_accumulate) { diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index e5564f2b3..5cbfaa3fe 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -275,26 +275,51 @@ DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area) } else { cairo_rectangle_int_t to_repaint; cairo_region_get_extents(dirty_region, &to_repaint); - *area = _convertRect(to_repaint); + area = _convertRect(to_repaint); cairo_region_subtract_rectangle(cache_region, &to_repaint); } cairo_region_destroy(dirty_region); if (!cairo_region_is_empty(cache_region)) { - Inkscape::DrawingContext::Save save(ct); int nr = cairo_region_num_rectangles(cache_region); cairo_rectangle_int_t tmp; for (int i = 0; i < nr; ++i) { cairo_region_get_rectangle(cache_region, i, &tmp); ct.rectangle(_convertRect(tmp)); } - ct.clip(); ct.setSource(this); - ct.paint(); + ct.fill(); } cairo_region_destroy(cache_region); } +// debugging utility +void +DrawingCache::_dumpCache(Geom::OptIntRect const &area) +{ + static int dumpnr = 0; + cairo_surface_t *surface = ink_cairo_surface_copy(_surface); + DrawingContext ct(surface, _origin); + if (!cairo_region_is_empty(_clean_region)) { + Inkscape::DrawingContext::Save save(ct); + int nr = cairo_region_num_rectangles(_clean_region); + cairo_rectangle_int_t tmp; + for (int i = 0; i < nr; ++i) { + cairo_region_get_rectangle(_clean_region, i, &tmp); + ct.rectangle(_convertRect(tmp)); + } + ct.setSource(0,1,0,0.1); + ct.fill(); + } + ct.rectangle(*area); + ct.setSource(1,0,0,0.1); + ct.fill(); + char *fn = g_strdup_printf("dump%d.png", dumpnr++); + cairo_surface_write_to_png(surface, fn); + cairo_surface_destroy(surface); + g_free(fn); +} + cairo_rectangle_int_t DrawingCache::_convertRect(Geom::IntRect const &area) { diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index f3af33002..e3637d402 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -72,6 +72,7 @@ protected: Geom::IntRect _pending_area; Geom::Affine _pending_transform; private: + void _dumpCache(Geom::OptIntRect const &area); static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r); static Geom::IntRect _convertRect(cairo_rectangle_int_t const &r); }; diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp index a8686545a..baf4af45d 100644 --- a/src/display/nr-filter-units.cpp +++ b/src/display/nr-filter-units.cpp @@ -71,10 +71,10 @@ Geom::Affine FilterUnits::get_matrix_user2pb() const { Geom::Affine u2pb = ctm; if (paraller_axis || !automatic_resolution) { - u2pb[0] = resolution_x / (filter_area->max()[X] - filter_area->min()[X]); + u2pb[0] = resolution_x / filter_area->width(); u2pb[1] = 0; u2pb[2] = 0; - u2pb[3] = resolution_y / (filter_area->max()[Y] - filter_area->min()[Y]); + u2pb[3] = resolution_y / filter_area->height(); u2pb[4] = ctm[4]; u2pb[5] = ctm[5]; } -- cgit v1.2.3 From 0fc028f7050c91bfdb1a50ba8cb6462b2bf03d57 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 21 Aug 2011 17:33:09 +0200 Subject: Filter background rendering now matches the SVG specification. (bzr r10347.1.37) --- src/display/drawing-group.cpp | 25 +++++++-- src/display/drawing-group.h | 5 +- src/display/drawing-image.cpp | 7 +-- src/display/drawing-image.h | 3 +- src/display/drawing-item.cpp | 112 +++++++++++++++++++++++------------------ src/display/drawing-item.h | 14 ++++-- src/display/drawing-shape.cpp | 11 ++-- src/display/drawing-shape.h | 5 +- src/display/drawing-text.cpp | 7 +-- src/display/drawing-text.h | 5 +- src/display/nr-filter-slot.cpp | 38 ++++++++------ src/display/nr-filter-slot.h | 2 +- src/display/nr-filter.cpp | 56 +++++++++------------ src/display/nr-filter.h | 6 +-- 14 files changed, 170 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index d9a75925e..a678c3feb 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -95,12 +95,29 @@ DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u return beststate; } -void -DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { - for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->render(ct, area, flags); + if (stop_at == NULL) { + // normal rendering + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->render(ct, area, flags, stop_at); + } + } else { + // background rendering + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + if (&*i == stop_at) return RENDER_OK; // do not render the stop_at item at all + if (i->isAncestorOf(stop_at)) { + // render its ancestors without masks, opacity or filters + i->render(ct, area, flags | RENDER_FILTER_BACKGROUND, stop_at); + // stop further rendering + return RENDER_OK; + } else { + i->render(ct, area, flags, stop_at); + } + } } + return RENDER_OK; } void diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h index 377c0be39..961e5b9a3 100644 --- a/src/display/drawing-group.h +++ b/src/display/drawing-group.h @@ -32,9 +32,10 @@ public: void setChildTransform(Geom::Affine const &new_trans); protected: - unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 074393ab5..fa0402699 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -112,13 +112,13 @@ DrawingImage::_updateItem(Geom::IntRect const &, UpdateContext const &, unsigned return STATE_ALL; } -void -DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { bool outline = _drawing.outline(); if (!outline) { - if (!_pixbuf) return; + if (!_pixbuf) return RENDER_OK; Inkscape::DrawingContext::Save save(ct); ct.transform(_ctm); @@ -172,6 +172,7 @@ DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne ct.setSource(rgba); ct.stroke(); } + return RENDER_OK; } /** Calculates the closest distance from p to the segment a1-a2*/ diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index 9f758398b..300d6f0b5 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -37,7 +37,8 @@ public: protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); GdkPixbuf *_pixbuf; diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index c517b1bb5..a5496e999 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -123,6 +123,16 @@ DrawingItem::parent() const return _parent; } +/// Returns true if item is among the descendants. Will return false if item == this. +bool +DrawingItem::isAncestorOf(DrawingItem *item) const +{ + for (DrawingItem *i = item->_parent; i; i = i->_parent) { + if (i == this) return true; + } + return false; +} + void DrawingItem::appendChild(DrawingItem *item) { @@ -314,6 +324,16 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (!area.intersects(outline ? _bbox : _drawbox)) return; } + // compute which elements need an update + unsigned to_update = _state ^ flags; + + // this needs to be called before we recurse into children + if (to_update & STATE_BACKGROUND) { + _background_accumulate = _background_new; + if (_child_type == CHILD_NORMAL && _parent->_background_accumulate) + _background_accumulate = true; + } + UpdateContext child_ctx(ctx); if (_transform) { child_ctx.ctm = *_transform * ctx.ctm; @@ -322,14 +342,13 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne Geom::Affine ctm_change = _ctm.inverse() * child_ctx.ctm; _ctm = child_ctx.ctm; - // update _bbox - unsigned to_update = _state ^ flags; + // update _bbox and call this function for children _state = _updateItem(area, child_ctx, flags, reset); if (to_update & STATE_BBOX) { // compute drawbox - if (_filter && render_filters && _item_bbox) { - _drawbox = _filter->compute_drawbox(this, *_item_bbox); + if (_filter && render_filters) { + _drawbox = _filter->compute_drawbox(this, _item_bbox); } else { _drawbox = _bbox; } @@ -396,14 +415,6 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } } - if (to_update & STATE_BACKGROUND) { - // Update _background_accumulate flag - // The code below correctly passes information from _background_new down the tree - _background_accumulate = _background_new; - if (_child_type == CHILD_NORMAL && _parent->_background_accumulate) - _background_accumulate = true; - } - if (to_update & STATE_RENDER) { // now that we know drawbox, dirty the corresponding rect on canvas // unless filtered, groups do not need to render by themselves, only their members @@ -433,32 +444,36 @@ struct MaskLuminanceToAlpha { * * @param flags Rendering options. This deals mainly with cache control. */ -void -DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { bool outline = _drawing.outline(); bool render_filters = _drawing.renderFilters(); + // stop_at is handled in DrawingGroup, but this check is required to handle the case + // where a filtered item with background-accessing filter has enable-background: new + if (this == stop_at) return RENDER_STOP; + // If we are invisible, return immediately - if (!_visible) return; - if (_ctm.isSingular(NR_EPSILON)) return; + if (!_visible) return RENDER_OK; + if (_ctm.isSingular(NR_EPSILON)) return RENDER_OK; // TODO convert outline rendering to a separate virtual function if (outline) { _renderOutline(ct, area, flags); - return; + return RENDER_OK; } // carea is the area to paint Geom::OptIntRect carea = Geom::intersect(area, _drawbox); - if (!carea) return; + if (!carea) return RENDER_OK; // render from cache if possible if (_cached) { if (_cache) { _cache->prepare(); _cache->paintFromCache(ct, carea); - if (!carea) return; + if (!carea) return RENDER_OK; } else { // There is no cache. This could be because caching of this item // was just turned on after the last update phase, or because @@ -484,6 +499,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag nir |= (_mask != NULL); // 2. it has a mask nir |= (_filter != NULL && render_filters); // 3. it has a filter nir |= needs_opacity; // 4. it is non-opaque + nir |= (_cache != NULL); // 5. it is cached /* How the rendering is done. * @@ -497,33 +513,12 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag * to the opacity value. */ - // short-circuit the simple case. - if (!needs_intermediate_rendering) { - if (_cached && _cache) { - Inkscape::DrawingContext cachect(*_cache); - cachect.rectangle(*carea); - cachect.clip(); - - { // 1. clear the corresponding part of cache - Inkscape::DrawingContext::Save save(cachect); - cachect.setSource(0,0,0,0); - cachect.setOperator(CAIRO_OPERATOR_SOURCE); - cachect.paint(); - } - // 2. render to cache - _renderItem(cachect, *carea, flags); - // 3. copy from cache to output - Inkscape::DrawingContext::Save save(ct); - ct.rectangle(*carea); - ct.setSource(_cache); - ct.fill(); - // 4. mark as clean - _cache->markClean(*carea); - return; - } else { - _renderItem(ct, *carea, flags); - return; - } + // Short-circuit the simple case. + // We also use this path for filter background rendering, because masking, clipping, + // filters and opacity do not apply when rendering the ancestors of the filtered + // element + if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { + return _renderItem(ct, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } // iarea is the bounding box for intermediate rendering @@ -540,6 +535,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag DrawingSurface intermediate(*iarea); DrawingContext ict(intermediate); + unsigned render_result = RENDER_OK; // 1. Render clipping path with alpha = opacity. ict.setSource(0,0,0,_opacity); @@ -571,11 +567,27 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // 3. Render object itself ict.pushGroup(); - _renderItem(ict, *iarea, flags); + render_result = _renderItem(ict, *iarea, flags, stop_at); // 4. Apply filter. if (_filter && render_filters) { - _filter->render(this, ct, ict); + bool rendered = false; + if (_filter->uses_background() && _background_accumulate) { + DrawingItem *bg_root = this; + for (; bg_root; bg_root = bg_root->_parent) { + if (bg_root->_background_new) break; + } + if (bg_root) { + DrawingSurface bg(*iarea); + DrawingContext bgct(bg); + bg_root->render(bgct, *iarea, flags | RENDER_FILTER_BACKGROUND, this); + _filter->render(this, ict, &bgct); + rendered = true; + } + } + if (!rendered) { + _filter->render(this, ict, NULL); + } // 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(). @@ -600,6 +612,8 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag ct.fill(); ct.setSource(0,0,0,0); // the call above is to clear a ref on the intermediate surface held by ct + + return render_result; } void @@ -612,7 +626,7 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig // just render everything: item, clip, mask // First, render the object itself - _renderItem(ct, *carea, flags); + _renderItem(ct, *carea, flags, NULL); // render clip and mask, if any guint32 saved_rgba = _drawing.outlinecolor; // save current outline color diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index abc69be02..7a3b8047b 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -54,7 +54,8 @@ public: enum RenderFlags { RENDER_DEFAULT = 0, RENDER_CACHE_ONLY = 1, - RENDER_BYPASS_CACHE = 2 + RENDER_BYPASS_CACHE = 2, + RENDER_FILTER_BACKGROUND = 4 }; enum StateFlags { STATE_NONE = 0, @@ -81,6 +82,7 @@ public: Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } Drawing &drawing() const { return _drawing; } DrawingItem *parent() const; + bool isAncestorOf(DrawingItem *item) const; void appendChild(DrawingItem *item); void prependChild(DrawingItem *item); @@ -106,7 +108,7 @@ public: void *data() const { return _user_data; } void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = STATE_ALL, unsigned reset = 0); - void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); + unsigned render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0, DrawingItem *stop_at = NULL); void clip(DrawingContext &ct, Geom::IntRect const &area); DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags = 0); @@ -120,7 +122,10 @@ protected: CHILD_FILL_PATTERN = 5, // not yet implemented: referenced by fill pattern of parent CHILD_STROKE_PATTERN = 6 // not yet implemented: referenced by stroke pattern of parent }; - + enum RenderResult { + RENDER_OK = 0, + RENDER_STOP = 1 + }; void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); void _markForUpdate(unsigned state, bool propagate); void _markForRendering(); @@ -130,7 +135,8 @@ protected: Geom::OptIntRect _cacheRect(); virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { return 0; } - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at) { return RENDER_OK; } virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags) { return NULL; } virtual bool _canClip() { return false; } diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index 1b201927f..cd7b9150d 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -157,11 +157,11 @@ DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u return STATE_ALL; } -void -DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { - if (!_curve || !_style) return; - if (!area.intersects(_bbox)) return; // skip if not within bounding box + if (!_curve || !_style) return RENDER_OK; + if (!area.intersects(_bbox)) return RENDER_OK; // skip if not within bounding box bool outline = _drawing.outline(); @@ -208,8 +208,9 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // marker rendering for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->render(ct, area, flags); + i->render(ct, area, flags, stop_at); } + return RENDER_OK; } void diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 2938d6397..122130590 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -32,9 +32,10 @@ public: void setPaintBox(Geom::Rect const &box); protected: - unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 5e6396df1..1134771bc 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -149,8 +149,8 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } -void -DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; @@ -169,7 +169,7 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned ct.path(*g->_font->PathVector(g->_glyph)); ct.fill(); } - return; + return RENDER_OK; } // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding @@ -199,6 +199,7 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned } ct.newPath(); // clear path } + return RENDER_OK; } void diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 07962365c..4f3940dde 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -53,9 +53,10 @@ public: void setPaintBox(Geom::OptRect const &box); protected: - unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index d2f992859..4f7a8849e 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -25,13 +25,13 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(DrawingItem *item, DrawingContext &bgct, +FilterSlot::FilterSlot(DrawingItem *item, DrawingContext *bgct, DrawingContext &graphic, FilterUnits const &u) : _item(item) , _source_graphic(graphic.rawTarget()) - , _background_ct(bgct.raw()) + , _background_ct(bgct ? bgct->raw() : NULL) , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme - , _background_area(bgct.targetLogicalBounds().roundOutwards()) // fixme + , _background_area(bgct ? bgct->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme , _units(u) , _last_out(NR_FILTER_SOURCEGRAPHIC) , filterquality(FILTER_QUALITY_BEST) @@ -152,19 +152,25 @@ cairo_surface_t *FilterSlot::_get_transformed_background() { Geom::Affine trans = _units.get_matrix_display2pb(); - cairo_surface_t *bg = cairo_get_group_target(_background_ct); - cairo_surface_t *tbg = cairo_surface_create_similar( - bg, cairo_surface_get_content(bg), - _slot_w, _slot_h); - cairo_t *tbg_ct = cairo_create(tbg); - - cairo_translate(tbg_ct, -_slot_x, -_slot_y); - ink_cairo_transform(tbg_ct, trans); - 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); - cairo_destroy(tbg_ct); + cairo_surface_t *tbg; + + if (_background_ct) { + cairo_surface_t *bg = cairo_get_group_target(_background_ct); + tbg = cairo_surface_create_similar( + bg, cairo_surface_get_content(bg), + _slot_w, _slot_h); + cairo_t *tbg_ct = cairo_create(tbg); + + cairo_translate(tbg_ct, -_slot_x, -_slot_y); + ink_cairo_transform(tbg_ct, trans); + 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); + cairo_destroy(tbg_ct); + } else { + tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w, _slot_h); + } return tbg; } diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 1e7c3a5a6..d41b5180b 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -28,7 +28,7 @@ namespace Filters { class FilterSlot { public: /** Creates a new FilterSlot object. */ - FilterSlot(DrawingItem *item, DrawingContext &bgct, + FilterSlot(DrawingItem *item, DrawingContext *bgct, DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index ae50e641b..450ce689d 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -97,7 +97,7 @@ Filter::~Filter() } -int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic) +int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic @@ -113,28 +113,16 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, Draw Geom::Affine trans = item->ctm(); - Geom::Rect item_bbox; - { - Geom::OptRect maybe_bbox = item->itemBounds(); - if (maybe_bbox.isEmpty()) { - // Code below needs a bounding box - return 1; - } - item_bbox = *maybe_bbox; - } - if (item_bbox.hasZeroArea()) { - // It's no use to try and filter an empty object. - return 1; - } - Geom::Rect filter_area = filter_effect_area(item_bbox); + Geom::OptRect filter_area = filter_effect_area(item->itemBounds()); + if (!filter_area) return 1; FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); - units.set_item_bbox(item_bbox); - units.set_filter_area(filter_area); + units.set_item_bbox(item->itemBounds()); + units.set_filter_area(*filter_area); std::pair resolution - = _filter_resolution(filter_area, trans, filterquality); + = _filter_resolution(*filter_area, trans, filterquality); if (!(resolution.first > 0 && resolution.second > 0)) { // zero resolution - clear source graphic and return graphic.setSource(0,0,0,0); @@ -228,30 +216,36 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item */ } -Geom::IntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox) { +Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) { - Geom::Rect enlarged = filter_effect_area(item_bbox); - enlarged *= item->ctm(); + Geom::OptRect enlarged = filter_effect_area(item_bbox); + if (enlarged) { + *enlarged *= item->ctm(); - Geom::IntRect ret(enlarged.roundOutwards()); - return ret; + Geom::OptIntRect ret(enlarged->roundOutwards()); + return ret; + } else { + return Geom::OptIntRect(); + } } -Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) +Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) { Geom::Point minp, maxp; - double len_x = bbox.width(); - double len_y = bbox.height(); + double len_x = bbox ? bbox->width() : 0; + double len_y = bbox ? bbox->height() : 0; /* TODO: fetch somehow the object ex and em lengths */ _region_x.update(12, 6, len_x); _region_y.update(12, 6, len_y); _region_width.update(12, 6, len_x); _region_height.update(12, 6, len_y); if (_filter_units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) { + if (!bbox) return Geom::OptRect(); + if (_region_x.unit == SVGLength::PERCENT) { - minp[X] = bbox.min()[X] + _region_x.computed; + minp[X] = bbox->left() + _region_x.computed; } else { - minp[X] = bbox.min()[X] + _region_x.computed * len_x; + minp[X] = bbox->left() + _region_x.computed * len_x; } if (_region_width.unit == SVGLength::PERCENT) { maxp[X] = minp[X] + _region_width.computed; @@ -260,9 +254,9 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) } if (_region_y.unit == SVGLength::PERCENT) { - minp[Y] = bbox.min()[Y] + _region_y.computed; + minp[Y] = bbox->top() + _region_y.computed; } else { - minp[Y] = bbox.min()[Y] + _region_y.computed * len_y; + minp[Y] = bbox->top() + _region_y.computed * len_y; } if (_region_height.unit == SVGLength::PERCENT) { maxp[Y] = minp[Y] + _region_height.computed; @@ -278,7 +272,7 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) } else { g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units"); } - Geom::Rect area(minp, maxp); + Geom::OptRect area(minp, maxp); return area; } diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 87a0fae94..32e1df60b 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -34,7 +34,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(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic); + int render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct); /** * Creates a new filter primitive under this filter object. @@ -156,13 +156,13 @@ public: * to contain the filter effects region and transforms it to screen * coordinates */ - Geom::IntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox); + Geom::OptIntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in * SVG standard and in user coordinate system. */ - Geom::Rect filter_effect_area(Geom::Rect const &bbox); + Geom::OptRect filter_effect_area(Geom::OptRect const &bbox); // returns cache score factor double complexity(Geom::Affine const &ctm); -- cgit v1.2.3 From abe953dc63948d78532c0541a56e664dc386810a Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 25 Aug 2011 19:39:31 +0200 Subject: Remove duplicate bbox data from DrawingShape (bzr r10347.1.38) --- src/display/drawing-item.h | 6 +++--- src/display/drawing-shape.cpp | 11 ++--------- src/display/drawing-shape.h | 2 -- src/sp-shape.cpp | 8 -------- 4 files changed, 5 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 7a3b8047b..424616427 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -161,9 +161,9 @@ protected: Geom::Affine *_transform; ///< Incremental transform from parent to this item's coords Geom::Affine _ctm; ///< Total transform from item coords to display coords - Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords - Geom::OptIntRect _drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks - Geom::OptRect _item_bbox; ///< Bounding box in item coordinates + Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords including stroke + Geom::OptIntRect _drawbox; ///< Full visual bounding box - enlarged by filters, shrunk by clips and masks + Geom::OptRect _item_bbox; ///< Geometric bounding box in item coordinates DrawingItem *_clip; DrawingItem *_mask; diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index cd7b9150d..ac0ff2ccb 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -72,13 +72,6 @@ DrawingShape::setStyle(SPStyle *style) _nrstyle.set(style); } -void -DrawingShape::setPaintBox(Geom::Rect const &box) -{ - _paintbox = box; - _markForUpdate(STATE_ALL, false); -} - unsigned DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { @@ -187,8 +180,8 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = _nrstyle.prepareFill(ct, _paintbox); - has_stroke = _nrstyle.prepareStroke(ct, _paintbox); + has_fill = _nrstyle.prepareFill(ct, _item_bbox); + has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); has_stroke &= (_nrstyle.stroke_width != 0); if (has_fill || has_stroke) { diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 122130590..27bd7fbba 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -29,7 +29,6 @@ public: void setPath(SPCurve *curve); void setStyle(SPStyle *style); - void setPaintBox(Geom::Rect const &box); protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, @@ -44,7 +43,6 @@ protected: SPStyle *_style; NRStyle _nrstyle; - Geom::OptRect _paintbox; DrawingItem *_last_pick; unsigned _repick_after; }; diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index eff0665af..0d1ac029e 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -256,15 +256,11 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { /* This is suboptimal, because changing parent style schedules recalculation */ /* But on the other hand - how can we know that parent does not tie style and transform */ - Geom::OptRect paintbox = SP_ITEM(object)->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX); for (SPItemView *v = shape->display; v != NULL; v = v->next) { Inkscape::DrawingShape *sh = dynamic_cast(v->arenaitem); if (flags & SP_OBJECT_MODIFIED_FLAG) { sh->setPath(shape->curve); } - if (paintbox) { - sh->setPaintBox(*paintbox); - } } } @@ -860,10 +856,6 @@ Inkscape::DrawingItem * SPShape::sp_shape_show(SPItem *item, Inkscape::Drawing & Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); s->setStyle(object->style); s->setPath(shape->curve); - Geom::OptRect paintbox = item->getBounds(Geom::identity()); - if (paintbox) { - s->setPaintBox(*paintbox); - } /* This stanza checks that an object's marker style agrees with * the marker objects it has allocated. sp_shape_set_marker ensures -- cgit v1.2.3 From 969504cc521a5116e1b1b8ea9e0355f69e6c93eb Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 25 Aug 2011 20:33:10 +0200 Subject: Reduce default rendering cache size to 64 MiB (bzr r10347.1.39) --- src/display/canvas-arena.cpp | 21 +++++++++++++-------- src/display/canvas-arena.h | 4 ++-- src/preferences-skeleton.h | 2 +- src/ui/dialog/inkscape-preferences.cpp | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index ac2704895..4688a58e3 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -49,18 +49,23 @@ static void sp_canvas_arena_request_render (SPCanvasArena *ca, Geom::IntRect con static SPCanvasItemClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; -struct CacheBudgetObserver : public Inkscape::Preferences::Observer { - CacheBudgetObserver(SPCanvasArena *arena) - : Inkscape::Preferences::Observer("/options/renderingcache/size") +struct CachePrefObserver : public Inkscape::Preferences::Observer { + CachePrefObserver(SPCanvasArena *arena) + : Inkscape::Preferences::Observer("/options/renderingcache") , _arena(arena) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Inkscape::Preferences::Entry v = prefs->getEntry(observed_path); - notify(v); + std::vector v = prefs->getAllEntries(observed_path); + for (unsigned i=0; iaddObserver(*this); } void notify(Preferences::Entry const &v) { - _arena->drawing.setCacheBudget((1 << 20) * v.getIntLimited(128, 0, 4096)); + Glib::ustring name = v.getEntryName(); + if (name == "size") { + _arena->drawing.setCacheBudget((1 << 20) * v.getIntLimited(64, 0, 4096)); + } } SPCanvasArena *_arena; }; @@ -119,13 +124,13 @@ sp_canvas_arena_init (SPCanvasArena *arena) arena->sticky = FALSE; new (&arena->drawing) Inkscape::Drawing(arena); - arena->observer = new CacheBudgetObserver(arena); Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing); root->setPickChildren(true); - root->setCached(true, true); arena->drawing.setRoot(root); + arena->observer = new CachePrefObserver(arena); + arena->drawing.signal_request_update.connect( sigc::bind<0>( sigc::ptr_fun(&sp_canvas_arena_request_update), diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 463dc1bc3..f145a9c70 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -31,7 +31,7 @@ G_BEGIN_DECLS typedef struct _SPCanvasArena SPCanvasArena; typedef struct _SPCanvasArenaClass SPCanvasArenaClass; -struct CacheBudgetObserver; +struct CachePrefObserver; struct _SPCanvasArena { SPCanvasItem item; @@ -46,7 +46,7 @@ struct _SPCanvasArena { Inkscape::DrawingItem *active; /* fixme: */ Inkscape::DrawingItem *picked; - CacheBudgetObserver *observer; + CachePrefObserver *observer; double delta; }; diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 895eb7276..a71451455 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -231,7 +231,7 @@ static char const preferences_skeleton[] = " \n" "\n" " \n" -" " +" " " " " " " " diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 0129f196f..ae27f0720 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -752,8 +752,8 @@ void InkscapePreferences::initPageRendering() _("Configure number of processors/threads to use when rendering filters"), false); // rendering cache - _rendering_cache_size.init("/options/renderingcache/size", 0.0, 4096.0, 1.0, 32.0, 128.0, true, false); - _page_rendering.add_line( false, _("Rendering cache size:"), _rendering_cache_size, C_("mebibyte (2^20 bytes) abbreviation","MiB"), _("Set the amount of memory per drawing which can be used to store rendered parts of the drawing for later reuse; set to zero to disable caching"), false); + _rendering_cache_size.init("/options/renderingcache/size", 0.0, 4096.0, 1.0, 32.0, 64.0, true, false); + _page_rendering.add_line( false, _("Rendering cache size:"), _rendering_cache_size, C_("mebibyte (2^20 bytes) abbreviation","MiB"), _("Set the amount of memory per document which can be used to store rendered parts of the drawing for later reuse; set to zero to disable caching"), false); /* blur quality */ _blur_quality_best.init ( _("Best quality (slowest)"), "/options/blurquality/value", -- cgit v1.2.3