diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-08-25 19:16:02 +0000 |
|---|---|---|
| committer | Krzysztof Kosinski <tweenk.pl@gmail.com> | 2011-08-25 19:16:02 +0000 |
| commit | 093f4174abc07b4ea523617fccdd8028f2670fea (patch) | |
| tree | 5aba6cd030bc6b0dbb59ec48e32a0b0364b516bd /src | |
| parent | German translation update (diff) | |
| parent | Reduce default rendering cache size to 64 MiB (diff) | |
| download | inkscape-093f4174abc07b4ea523617fccdd8028f2670fea.tar.gz inkscape-093f4174abc07b4ea523617fccdd8028f2670fea.zip | |
Merge rendering cache branch (GSoC 2011)
(bzr r10579)
Diffstat (limited to 'src')
155 files changed, 4988 insertions, 5111 deletions
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 <cmath> #include <limits> +#include <boost/operators.hpp> #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 <typename C> 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<IntCoord> { typedef IntPoint PointType; @@ -69,6 +73,22 @@ struct CoordTraits<IntCoord> { 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<Coord> { 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 <cassert> #include <boost/none.hpp> #include <boost/optional.hpp> -#include <boost/operators.hpp> +#include <2geom/coord.h> namespace Geom { @@ -47,11 +47,7 @@ class GenericOptInterval; */ template <typename C> class GenericInterval - : boost::equality_comparable< GenericInterval<C> - , boost::additive< GenericInterval<C> - , boost::additive< GenericInterval<C>, C - , boost::orable< GenericInterval<C> - > > > > + : CoordTraits<C>::IntervalOps { typedef GenericInterval<C> 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 <limits> #include <boost/optional.hpp> +#include <2geom/coord.h> namespace Geom { @@ -54,11 +55,7 @@ class GenericOptRect; */ template <typename C> class GenericRect - : boost::additive< typename CoordTraits<C>::RectType, typename CoordTraits<C>::PointType - , boost::equality_comparable< typename CoordTraits<C>::RectType - , boost::orable< typename CoordTraits<C>::RectType - , boost::orable< typename CoordTraits<C>::RectType, typename CoordTraits<C>::OptRectType - > > > > + : CoordTraits<C>::RectOps { typedef typename CoordTraits<C>::IntervalType CInterval; typedef typename CoordTraits<C>::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 <code>-p[X]</code> 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<C>::OptRectType OptCRect; typedef boost::optional<CRect> Base; public: + /// @name Create potentially empty rectangles. + /// @{ GenericOptRect() : Base() {} GenericOptRect(GenericRect<C> 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 <typename InputIterator> + 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<Base*>(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<Base*>(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<C> &operator|=(OptCRect const &b) { unionWith(b); return *this; } + /** @brief Intersect with @a b */ GenericOptRect<C> &operator&=(CRect const &b) { intersectWith(b); return *this; } + /** @brief Intersect with @a b */ GenericOptRect<C> &operator&=(OptCRect const &b) { intersectWith(b); return *this; } + /// @} }; template <typename C> 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<Coord> OptInterval; */ class Interval : public GenericInterval<Coord> - , boost::multipliable< Interval - , boost::multiplicative< Interval, Coord - > > { typedef GenericInterval<Coord> 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<Coord> OptRect; */ class Rect : public GenericRect<Coord> - , boost::multipliable< Rect, Affine > { typedef GenericRect<Coord> 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 <typename T> 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 19504fa81..ca5fdc63b 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/drawing.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(), // an id attribute is not allowed to be the empty string _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 ), @@ -229,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 @@ -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( - SP_CANVAS_ARENA (drawing)->arena, + Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( + SP_CANVAS_ARENA (drawing)->drawing, dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL); + SP_CANVAS_ARENA (drawing)->drawing.root()->prependChild(ai); } namedview->show(this); @@ -403,6 +404,7 @@ void SPDesktop::destroy() if (drawing) { doc()->getRoot()->invoke_hide(dkey); + g_object_unref(drawing); drawing = NULL; } @@ -454,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::ColorRenderMode mode) { - SP_CANVAS_ARENA (drawing)->arena->colorrendermode = mode; +void SPDesktop::_setDisplayColorMode(Inkscape::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 @@ -485,15 +487,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,18 +1564,18 @@ 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)); 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) { - nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL); + SP_CANVAS_ARENA (drawing)->drawing.root()->prependChild(ai); } namedview->show(this); /* Ugly hack */ @@ -1662,10 +1664,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); @@ -1783,9 +1785,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/desktop.h b/src/desktop.h index 5fd786936..5dcd014ca 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -212,19 +212,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 194f341e1..109b235d0 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -14,6 +14,8 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include <climits> #include <glib/gmem.h> #include <gtk/gtk.h> #include <glibmm/i18n.h> @@ -23,8 +25,9 @@ #include "desktop-handles.h" #include "dialog-events.h" #include "display/cairo-utils.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" #include "document.h" #include "filter-chemistry.h" #include "helper/unit-menu.h" @@ -829,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 NRArenaItem *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) { @@ -849,11 +851,11 @@ static void clonetiler_trace_hide_tiled_clones_recursively(SPObject *from) static void clonetiler_trace_setup(SPDocument *doc, gdouble zoom, SPItem *original) { - 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); @@ -867,37 +869,22 @@ 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; } - 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, NULL, &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); + trace_drawing->root()->setTransform(Geom::Scale(trace_zoom)); + trace_drawing->update(); /* 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_RENDER_NO_CACHE ); - cairo_destroy(ct); + 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); @@ -908,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 fc7c8e9ab..1c7a21dae 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -23,6 +23,22 @@ 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 \ + 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 \ @@ -31,19 +47,7 @@ ink_common_sources += \ display/guideline.h \ display/nr-3dutils.cpp \ display/nr-3dutils.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/cairo-templates.h b/src/display/cairo-templates.h index a79f58548..d4c8e1493 100644 --- a/src/display/cairo-templates.h +++ b/src/display/cairo-templates.h @@ -12,6 +12,10 @@ #ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H #define SEEN_INKSCAPE_DISPLAY_CAIRO_TEMPLATES_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #ifdef HAVE_OPENMP #include <omp.h> #include "preferences.h" diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index dd4a4ed5c..4688a58e3 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -15,10 +15,15 @@ #include "display/display-forward.h" #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" +#include "preferences.h" + +using namespace Inkscape; enum { ARENA_EVENT, @@ -29,28 +34,42 @@ 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 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); -static void sp_canvas_arena_request_update (NRArena *arena, NRArenaItem *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}; +struct CachePrefObserver : public Inkscape::Preferences::Observer { + CachePrefObserver(SPCanvasArena *arena) + : Inkscape::Preferences::Observer("/options/renderingcache") + , _arena(arena) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + std::vector<Inkscape::Preferences::Entry> v = prefs->getAllEntries(observed_path); + for (unsigned i=0; i<v.size(); ++i) { + notify(v[i]); + } + prefs->addObserver(*this); + } + void notify(Preferences::Entry const &v) { + Glib::ustring name = v.getEntryName(); + if (name == "size") { + _arena->drawing.setCacheBudget((1 << 20) * v.getIntLimited(64, 0, 4096)); + } + } + SPCanvasArena *_arena; +}; + GType sp_canvas_arena_get_type (void) { @@ -96,7 +115,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 @@ -104,17 +123,28 @@ sp_canvas_arena_init (SPCanvasArena *arena) { arena->sticky = FALSE; - arena->arena = NRArena::create(); - arena->arena->canvasarena = arena; - arena->root = NRArenaGroup::create(arena->arena); - nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE); + new (&arena->drawing) Inkscape::Drawing(arena); - 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(); + Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing); + root->setPickChildren(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), + 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)); - nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena); + arena->active = NULL; } static void @@ -122,27 +152,8 @@ 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); - - 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); + delete arena->observer; + arena->drawing.~Drawing(); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -156,21 +167,22 @@ 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->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_ALL, reset); - nr_arena_item_invoke_update (arena->root, NULL, &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->drawing.root()->visualBounds(); + 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 */ - NRArenaItem *new_arena = nr_arena_item_invoke_pick (arena->root, 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; @@ -184,10 +196,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); @@ -197,76 +206,26 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned } static void +sp_canvas_arena_item_deleted(SPCanvasArena *arena, Inkscape::DrawingItem *item) +{ + if (arena->active == item) { + arena->active = NULL; + } +} + +static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) { + // todo: handle NR_ARENA_ITEM_RENDER_NO_CACHE 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; - - 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_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); -} + Inkscape::DrawingContext ct(buf->ct, r->min()); -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 - - 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, - 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); -} - -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); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx); + arena->drawing.render(ct, *r); } static double @@ -274,11 +233,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, NULL, &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->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK); + DrawingItem *picked = arena->drawing.pick(p, arena->drawing.delta, arena->sticky); arena->picked = picked; @@ -291,70 +247,20 @@ 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); + arena->drawing.setCacheLimit(expanded); } 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); @@ -366,7 +272,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; @@ -374,9 +279,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, NULL, &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->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; @@ -384,7 +288,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; } @@ -395,8 +298,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, NULL, &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->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; @@ -410,9 +313,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); @@ -442,17 +343,16 @@ 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 (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_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); + SPCanvas *canvas = SP_CANVAS_ITEM (ca)->canvas; + sp_canvas_request_redraw (canvas, area.left(), area.top(), area.right(), area.bottom()); } void @@ -481,13 +381,13 @@ 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()); + 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 220976da0..f145a9c70 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -15,9 +15,11 @@ #include <cairo.h> #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" -#include "display/nr-arena-item.h" G_BEGIN_DECLS @@ -29,6 +31,7 @@ G_BEGIN_DECLS typedef struct _SPCanvasArena SPCanvasArena; typedef struct _SPCanvasArenaClass SPCanvasArenaClass; +struct CachePrefObserver; struct _SPCanvasArena { SPCanvasItem item; @@ -37,24 +40,20 @@ struct _SPCanvasArena { guint sticky : 1; Geom::Point c; // what is this? - NRArena *arena; - NRArenaItem *root; - NRGC gc; + Inkscape::Drawing drawing; + Inkscape::UpdateContext ctx; - NRArenaItem *active; + Inkscape::DrawingItem *active; /* fixme: */ - NRArenaItem *picked; - gdouble delta; - - Geom::IntRect cache_area; - cairo_surface_t *cache; - cairo_region_t *dirty; + Inkscape::DrawingItem *picked; + CachePrefObserver *observer; + 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 bc7013214..7dccb76ef 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -10,12 +10,30 @@ typedef struct _SPCanvasItemClass SPCanvasItemClass; struct SPCanvasGroup; struct SPCanvasGroupClass; class SPCurve; +typedef struct _SPCanvasArena SPCanvasArena; namespace Inkscape { +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-context.cpp b/src/display/drawing-context.cpp new file mode 100644 index 000000000..3c0c2163b --- /dev/null +++ b/src/display/drawing-context.cpp @@ -0,0 +1,152 @@ +/** + * @file + * @brief Cairo drawing context with Inkscape extensions + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/cairo-utils.h" +#include "helper/geom.h" + +namespace Inkscape { + +using Geom::X; +using Geom::Y; + +/** @class DrawingContext::Save + * @brief RAII idiom for saving the state of DrawingContext. */ + +DrawingContext::Save::Save() + : _ct(NULL) +{} +DrawingContext::Save::Save(DrawingContext &ct) + : _ct(&ct) +{ + _ct->save(); +} +DrawingContext::Save::~Save() +{ + if (_ct) { + _ct->restore(); + } +} +void DrawingContext::Save::save(DrawingContext &ct) +{ + if (_ct) { + // TODO: it might be better to treat this occurence as a bug + _ct->restore(); + } + _ct = &ct; + _ct->save(); +} + +/** @class DrawingContext + * @brief Minimal wrapper over Cairo. + * + * This is a wrapper over cairo_t, extended with operations that work + * with 2Geom geometrical primitives. Some of this is probably duplicated + * in cairo-render-context.cpp, which provides higher level operations + * for drawing entire SPObjects when exporting. + */ + +DrawingContext::DrawingContext(cairo_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(); +} + +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) { + 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..4ada79057 --- /dev/null +++ b/src/display/drawing-context.h @@ -0,0 +1,128 @@ +/** + * @file + * @brief Cairo drawing context with Inkscape extensions + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_CONTEXT_H + +#include <boost/utility.hpp> +#include <glib.h> +#include <cairo.h> +#include <2geom/affine.h> +#include <2geom/angle.h> +#include <2geom/rect.h> +#include <2geom/transforms.h> + +namespace Inkscape { + +class DrawingSurface; + +class DrawingContext + : boost::noncopyable +{ +public: + class Save { + public: + Save(); + Save(DrawingContext &ct); + ~Save(); + void save(DrawingContext &ct); + private: + DrawingContext *_ct; + }; + + DrawingContext(cairo_t *ct, Geom::Point const &origin); + 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 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); + + 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; + bool _restore_context; + + 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-group.cpp b/src/display/drawing-group.cpp new file mode 100644 index 000000000..a678c3feb --- /dev/null +++ b/src/display/drawing-group.cpp @@ -0,0 +1,165 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing-group.h" +#include "libnr/nr-values.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); +} + +/** @brief Set whether the group returns children from pick calls. + * Previously this feature was called "transparent groups". + */ +void +DrawingGroup::setPickChildren(bool p) +{ + _pick_children = p; +} + +void +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) +{ + 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.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) { + 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; +} + +unsigned +DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +{ + 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 +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, unsigned flags) +{ + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingItem *picked = i->pick(p, delta, flags); + if (picked) { + return _pick_children ? picked : this; + } + } + return NULL; +} + +bool +DrawingGroup::_canClip() +{ + return true; +} + +bool is_drawing_group(DrawingItem *item) +{ + return dynamic_cast<DrawingGroup *>(item) != NULL; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h new file mode 100644 index 000000000..961e5b9a3 --- /dev/null +++ b/src/display/drawing-group.h @@ -0,0 +1,62 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_GROUP_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_GROUP_H + +#include "display/drawing-item.h" + +class SPStyle; + +namespace Inkscape { + +class DrawingGroup + : public DrawingItem +{ +public: + DrawingGroup(Drawing &drawing); + ~DrawingGroup(); + + bool pickChildren() { return _pick_children; } + void setPickChildren(bool p); + + void setStyle(SPStyle *style); + void setChildTransform(Geom::Affine const &new_trans); + +protected: + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + 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(); + + 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..fa0402699 --- /dev/null +++ b/src/display/drawing-image.cpp @@ -0,0 +1,264 @@ +/** + * @file + * @brief Bitmap image belonging to an SVG drawing + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-image.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; +} + +unsigned +DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +{ + bool outline = _drawing.outline(); + + if (!outline) { + if (!_pixbuf) return RENDER_OK; + + 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(); + } + return RENDER_OK; +} + +/** 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, unsigned /*sticky*/) +{ + if (!_pixbuf) return NULL; + + bool outline = _drawing.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..300d6f0b5 --- /dev/null +++ b/src/display/drawing-image.h @@ -0,0 +1,67 @@ +/** + * @file + * @brief Bitmap image belonging to an SVG drawing + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_IMAGE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_IMAGE_H + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <2geom/transforms.h> + +#include "display/drawing-item.h" + +namespace Inkscape { + +class DrawingImage + : public DrawingItem +{ +public: + DrawingImage(Drawing &drawing); + ~DrawingImage(); + + void setARGB32Pixbuf(GdkPixbuf *pb); + void setStyle(SPStyle *style); + void setScale(double sx, double sy); + void setOrigin(Geom::Point const &o); + void setClipbox(Geom::Rect const &box); + Geom::Rect bounds() const; + +protected: + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual 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; + 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..a5496e999 --- /dev/null +++ b/src/display/drawing-item.cpp @@ -0,0 +1,900 @@ +/** + * @file + * @brief Canvas item belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <climits> +#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-filter.h" +#include "preferences.h" +#include "style.h" + +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) + , _key(0) + , _opacity(1.0) + , _transform(NULL) + , _clip(NULL) + , _mask(NULL) + , _filter(NULL) + , _user_data(NULL) + , _cache(NULL) + , _state(0) + , _child_type(CHILD_ORPHAN) + , _background_new(0) + , _background_accumulate(0) + , _visible(true) + , _sensitive(true) + , _cached(0) + , _cached_persistent(0) + , _has_cache_iterator(0) + , _propagate(0) +// , _renders_opacity(0) + , _pick_children(0) +{} + +DrawingItem::~DrawingItem() +{ + _drawing.signal_item_deleted.emit(this); + //if (!_children.empty()) { + // g_warning("Removing item with children"); + //} + + // remove from the set of cached items and delete cache + setCached(false, true); + 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) { + _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 + _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; + delete _clip; + delete _mask; + delete _filter; +} + +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 regardless of child type + 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) +{ + item->_parent = this; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_NORMAL; + _children.push_back(*item); + _markForUpdate(STATE_ALL, false); +} + +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); +} + +/// Delete all regular children of this item (not mask or clip). +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; + i->_child_type = CHILD_ORPHAN; + } + _children.clear_and_dispose(DeleteDisposer()); +} + +/// Set the incremental transform for this item +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(); +} + +/// This is currently unused +void +DrawingItem::setSensitive(bool s) +{ + _sensitive = s; +} + +/** @brief Enable / disable storing the rendering in memory. + * Calling setCached(false, true) will also remove the persistent status + */ +void +DrawingItem::setCached(bool cached, bool persistent) +{ + 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; + } +} + +void +DrawingItem::setClip(DrawingItem *item) +{ + _markForRendering(); + delete _clip; + _clip = item; + if (item) { + item->_parent = this; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_CLIP; + } + _markForUpdate(STATE_ALL, true); +} + +void +DrawingItem::setMask(DrawingItem *item) +{ + _markForRendering(); + delete _mask; + _mask = item; + if (item) { + item->_parent = this; + assert(item->_child_type == CHILD_ORPHAN); + item->_child_type = CHILD_MASK; + } + _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) +{ + 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; +} + +/** @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) +{ + bool render_filters = _drawing.renderFilters(); + bool outline = _drawing.outline(); + + // Set reset flags according to propagation status + reset |= _propagate_state; + _propagate_state = 0; + + _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; + } + + // 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; + } + /* Remember the transformation matrix */ + Geom::Affine ctm_change = _ctm.inverse() * child_ctx.ctm; + _ctm = child_ctx.ctm; + + // 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) { + _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); + } + } + } + + 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_front(cr); + _cache_iterator = _drawing._candidate_items.begin(); + _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_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(); + } + } +} + +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 + } +}; + +/** @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. + */ +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 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 RENDER_OK; + } + + // carea is the area to paint + Geom::OptIntRect carea = Geom::intersect(area, _drawbox); + if (!carea) return RENDER_OK; + + // render from cache if possible + if (_cached) { + if (_cache) { + _cache->prepare(); + _cache->paintFromCache(ct, carea); + 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 + // we were previously 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() + } + + // 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 + nir |= (_cache != NULL); // 5. it is cached + + /* 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. + // 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 + // 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. + 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); + unsigned render_result = RENDER_OK; + + // 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(); + render_result = _renderItem(ict, *iarea, flags, stop_at); + + // 4. Apply filter. + if (_filter && render_filters) { + 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(). + } + + // 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(*carea); + cachect.setOperator(CAIRO_OPERATOR_SOURCE); + cachect.setSource(&intermediate); + cachect.fill(); + _cache->markClean(*carea); + } + ct.rectangle(*carea); + ct.setSource(&intermediate); + 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 +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, NULL); + + // 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 +} + +/** @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) +{ + // 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(); + } +} + +/** @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, 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; + // ignore invisible and insensitive items unless sticky + if (!(flags & PICK_STICKY) && !(_visible && _sensitive)) + return NULL; + + 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, flags); + } + 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() +{ + bool outline = _drawing.outline(); + Geom::OptIntRect dirty = outline ? _bbox : _drawbox; + if (!dirty) return; + + // dirty the caches of all parents + DrawingItem *bkg_root = NULL; + + for (DrawingItem *i = this; i; i = i->_parent) { + if (i != this && i->_filter) { + i->_filter->area_enlarge(*dirty, i); + } + if (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) + * 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) +{ + if (propagate) { + _propagate_state |= flags; + } + + if (_state & flags) { + _state &= ~flags; + if (_parent) { + _parent->_markForUpdate(flags, false); + } else { + _drawing.signal_request_update.emit(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) { + 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); + } + } + + _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() +{ + 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 + +/* + 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..424616427 --- /dev/null +++ b/src/display/drawing-item.h @@ -0,0 +1,212 @@ +/** + * @file + * @brief Canvas item belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H + +#include <list> +#include <exception> +#include <boost/operators.hpp> +#include <boost/utility.hpp> +#include <boost/intrusive/list.hpp> +#include <2geom/rect.h> +#include <2geom/affine.h> +#include "display/display-forward.h" + +class SPStyle; + +namespace Inkscape { + +struct UpdateContext { + Geom::Affine ctm; +}; + +struct CacheRecord + : boost::totally_ordered<CacheRecord> +{ + 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<CacheRecord> CacheList; + +class InvalidItemException : public std::exception { + virtual const char *what() const throw() { + return "Invalid item in drawing"; + } +}; + +class DrawingItem + : boost::noncopyable +{ +public: + enum RenderFlags { + RENDER_DEFAULT = 0, + RENDER_CACHE_ONLY = 1, + RENDER_BYPASS_CACHE = 2, + RENDER_FILTER_BACKGROUND = 4 + }; + enum StateFlags { + STATE_NONE = 0, + 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_BACKGROUND = (1<<4), // filter background data is up to date + STATE_ALL = (1<<5)-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); + 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; + bool isAncestorOf(DrawingItem *item) 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, bool persistent = false); + + 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); + 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); + +protected: + enum ChildType { + 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 + 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 + }; + 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(); + void _invalidateFilterBackground(Geom::IntRect const &area); + 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 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; } + + // 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<DrawingItem, ListHook, &DrawingItem::_child_hook> + > ChildrenList; + ChildrenList _children; + + unsigned _key; ///< Some SPItems can have more than one DrawingItem; + /// 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 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; + Inkscape::Filters::Filter *_filter; + void *_user_data; ///< Used to associate DrawingItems with SPItems that created them + DrawingCache *_cache; + + 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 + unsigned _cached_persistent : 1; ///< If set, will always be cached regardless of score + 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 _pick_children : 1; ///< For groups: if true, children are returned from pick(), + /// otherwise the group is returned + + friend class Drawing; +}; + +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..ac0ff2ccb --- /dev/null +++ b/src/display/drawing-shape.cpp @@ -0,0 +1,343 @@ +/** + * @file + * @brief Shape (styled path) belonging to an SVG drawing + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> +#include <2geom/curves.h> +#include <2geom/pathvector.h> +#include <2geom/svg-path.h> +#include <2geom/svg-path-parser.h> + +#include "display/cairo-utils.h" +#include "display/canvas-arena.h" +#include "display/canvas-bpath.h" +#include "display/curve.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-group.h" +#include "display/drawing-shape.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); +} + +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.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; +} + +unsigned +DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +{ + if (!_curve || !_style) return RENDER_OK; + if (!area.intersects(_bbox)) return RENDER_OK; // skip if not within bounding box + + bool outline = _drawing.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, _item_bbox); + has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); + 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, stop_at); + } + return RENDER_OK; +} + +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, unsigned flags) +{ + if (_repick_after > 0) + --_repick_after; + + 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; + + bool outline = _drawing.outline(); + bool pick_as_clip = flags & PICK_AS_CLIP; + + if (SP_SCALE24_TO_FLOAT(_style->opacity.value) == 0 && !outline && !pick_as_clip) + // fully transparent, no pick unless outline mode + return NULL; + + GTimeVal tstart, tfinish; + g_get_current_time (&tstart); + + double width; + 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 { + width = 0; + } + + double dist = Geom::infinity(); + int wind = 0; + 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); + 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 (wind_evenodd) { + if (wind & 0x1) { + _last_pick = this; + return this; + } + } else { + if (wind != 0) { + _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, flags & ~PICK_STICKY); + 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..27bd7fbba --- /dev/null +++ b/src/display/drawing-shape.h @@ -0,0 +1,63 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SHAPE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_SHAPE_H + +#include "display/drawing-item.h" +#include "display/nr-style.h" + +class SPStyle; +class SPCurve; + +namespace Inkscape { + +class DrawingShape + : public DrawingItem +{ +public: + DrawingShape(Drawing &drawing); + ~DrawingShape(); + + void setPath(SPCurve *curve); + void setStyle(SPStyle *style); + +protected: + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + 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(); + + SPCurve *_curve; + SPStyle *_style; + NRStyle _nrstyle; + + 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-surface.cpp b/src/display/drawing-surface.cpp new file mode 100644 index 000000000..5cbfaa3fe --- /dev/null +++ b/src/display/drawing-surface.cpp @@ -0,0 +1,354 @@ +/** + * @file + * @brief Cairo surface that remembers its origin + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +//#include <iostream> +#include "display/drawing-surface.h" +#include "display/drawing-context.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 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(NULL) + , _origin(area.min()) + , _scale(1, 1) + , _pixels(area.dimensions()) +{} + +/** @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(NULL) + , _origin(logbox.min()) + , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height()) + , _pixels(pixdims) +{} + +/** @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); + _pixels[X] = cairo_image_surface_get_width(surface); + _pixels[Y] = cairo_image_surface_get_height(surface); +} + +DrawingSurface::~DrawingSurface() +{ + if (_surface) + 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 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 +{ + Geom::Point logical_dims(_pixels[X] / _scale[X], _pixels[Y] / _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; +} + +/// 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]); + } + cairo_translate(ct, -_origin[X], -_origin[Y]); + 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()) + , _pending_area(area) +{} + +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); +} + +/// 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) +{ + _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::prepare() +{ + Geom::IntRect old_area = pixelArea(); + bool is_identity = _pending_transform.isIdentity(); + 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())) { + is_integer_translation = true; + cairo_region_translate(_clean_region, t[X], t[Y]); + 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(_pending_area); + cairo_region_intersect_rectangle(_clean_region, &limit); + _origin += t; + _pending_transform.setIdentity(); + return; + } + } + } + // otherwise, we need to transform the cache + Geom::IntPoint old_origin = old_area.min(); + cairo_surface_t *old_surface = _surface; + _surface = NULL; + _pixels = _pending_area.dimensions(); + _origin = _pending_area.min(); + + cairo_t *ct = createRawContext(); + if (!is_identity) { + 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); + 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(_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 modifies the @a area + * parameter to the bounds of the region that must be repainted. */ +void +DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area) +{ + 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)) { + 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.setSource(this); + 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) +{ + cairo_rectangle_int_t ret; + ret.x = area.left(); + ret.y = area.top(); + ret.width = area.width(); + ret.height = area.height(); + 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 + +/* + 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..e3637d402 --- /dev/null +++ b/src/display/drawing-surface.h @@ -0,0 +1,93 @@ +/** + * @file + * @brief Cairo surface that remembers its origin + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_SURFACE_H + +#include <boost/shared_ptr.hpp> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <2geom/affine.h> +#include <2geom/rect.h> +#include <2geom/transforms.h> + +namespace Inkscape { +class DrawingContext; + +class DrawingSurface +{ +public: + explicit DrawingSurface(Geom::IntRect const &area); + 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::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(); + +protected: + Geom::IntRect pixelArea() const; + + cairo_surface_t *_surface; + Geom::Point _origin; + Geom::Scale _scale; + Geom::IntPoint _pixels; + bool _has_context; + + friend class DrawingContext; +}; + +class DrawingCache + : public DrawingSurface +{ +public: + explicit DrawingCache(Geom::IntRect const &area); + ~DrawingCache(); + + void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite()); + void markClean(Geom::IntRect const &area = Geom::IntRect::infinite()); + void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); + void prepare(); + void paintFromCache(DrawingContext &ct, Geom::OptIntRect &area); + +protected: + cairo_region_t *_clean_region; + 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); +}; + +} // 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..1134771bc --- /dev/null +++ b/src/display/drawing-text.cpp @@ -0,0 +1,255 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/canvas-bpath.h" // for SPWindRule (WTF!) +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/drawing-text.h" +#include "helper/geom.h" +#include "libnrtype/font-instance.h" +#include "style.h" + +namespace Inkscape { + +DrawingGlyphs::DrawingGlyphs(Drawing &drawing) + : DrawingItem(drawing) + , _font(NULL) + , _glyph(0) +{} + +DrawingGlyphs::~DrawingGlyphs() +{ + if (_font) { + _font->Unref(); + _font = NULL; + } +} + +void +DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &trans) +{ + _markForRendering(); + + setTransform(trans); + + if (font) font->Ref(); + if (_font) _font->Unref(); + _font = font; + _glyph = glyph; + + _markForUpdate(STATE_ALL, false); +} + +unsigned +DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + DrawingText *ggroup = dynamic_cast<DrawingText *>(_parent); + if (!ggroup) throw InvalidItemException(); + + if (!_font || !ggroup->_style) return STATE_ALL; + if (ggroup->_nrstyle.fill.type == NRStyle::PAINT_NONE && + ggroup->_nrstyle.stroke.type == NRStyle::PAINT_NONE) + { + return STATE_ALL; + } + + Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); + 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, unsigned /*flags*/) +{ + 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); +} + +unsigned +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +{ + if (_drawing.outline()) { + guint32 rgba = _drawing.outlinecolor; + Inkscape::DrawingContext::Save save(ct); + ct.setSource(rgba); + ct.setTolerance(1.25); // low quality, but good enough for outline mode + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + // skip glpyhs with singular transforms + if (g->_ctm.isSingular()) continue; + ct.transform(g->_ctm); + ct.path(*g->_font->PathVector(g->_glyph)); + ct.fill(); + } + return RENDER_OK; + } + + // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding + bool has_stroke, has_fill; + + has_fill = _nrstyle.prepareFill(ct, _paintbox); + has_stroke = _nrstyle.prepareStroke(ct, _paintbox); + + if (has_fill || has_stroke) { + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_ctm.isSingular()) continue; + ct.transform(g->_ctm); + 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 + } + return RENDER_OK; +} + +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); + } + } + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + ct.transform(g->_ctm); + ct.path(*g->_font->PathVector(g->_glyph)); + } + ct.fill(); +} + +DrawingItem * +DrawingText::_pickItem(Geom::Point const &p, double delta, unsigned flags) +{ + DrawingItem *picked = DrawingGroup::_pickItem(p, delta, flags); + 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..4f3940dde --- /dev/null +++ b/src/display/drawing-text.h @@ -0,0 +1,83 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_TEXT_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_TEXT_H + +#include "display/drawing-group.h" +#include "display/nr-style.h" + +class SPStyle; +class font_instance; + +namespace Inkscape { + +class DrawingGlyphs + : public DrawingItem +{ +public: + DrawingGlyphs(Drawing &drawing); + ~DrawingGlyphs(); + + void setGlyph(font_instance *font, int glyph, Geom::Affine const &trans); + +protected: + unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); + + font_instance *_font; + int _glyph; + + 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: + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + unsigned flags, unsigned reset); + 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(); + + 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/drawing.cpp b/src/display/drawing.cpp new file mode 100644 index 000000000..06183fed2 --- /dev/null +++ b/src/display/drawing.cpp @@ -0,0 +1,205 @@ +/** + * @file + * @brief SVG drawing for display + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <algorithm> +#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) + , _cache_score_threshold(50000.0) + , _cache_budget(0) + , _canvasarena(arena) +{ + +} + +Drawing::~Drawing() +{ + delete _root; +} + +void +Drawing::setRoot(DrawingItem *item) +{ + delete _root; + _root = item; + if (item) { + assert(item->_child_type == DrawingItem::CHILD_ORPHAN); + item->_child_type = DrawingItem::CHILD_ROOT; + } +} + +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<DrawingItem *>::iterator i = _cached_items.begin(); + i != _cached_items.end(); ++i) + { + (*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) +{ + if (_root) { + _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<CacheRecord>()); + 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<DrawingItem*> 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<DrawingItem*> 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<DrawingItem*>::iterator j = to_uncache.begin(); j != to_uncache.end(); ++j) { + (*j)->setCached(false); + } +} + +} // 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..cfba4ebe6 --- /dev/null +++ b/src/display/drawing.h @@ -0,0 +1,113 @@ +/** + * @file + * @brief SVG drawing for display + *//* + * Authors: + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_H +#define SEEN_INKSCAPE_DISPLAY_DRAWING_H + +#include <set> +#include <boost/operators.hpp> +#include <boost/utility.hpp> +#include <sigc++/sigc++.h> +#include <2geom/rect.h> +#include "display/display-forward.h" +#include "display/drawing-item.h" +#include "display/rendermode.h" + +namespace Inkscape { + +class Drawing + : boost::noncopyable +{ +public: + struct OutlineColors { + guint32 paths; + guint32 clippaths; + guint32 masks; + guint32 images; + }; + + 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); + void setCacheBudget(size_t bytes); + + 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, unsigned flags); + + sigc::signal<void, DrawingItem *> signal_request_update; + sigc::signal<void, Geom::IntRect const &> signal_request_render; + sigc::signal<void, DrawingItem *> signal_item_deleted; + +private: + void _pickItemsForCaching(); + + typedef std::list<CacheRecord> CandidateList; + + DrawingItem *_root; + std::set<DrawingItem *> _cached_items; // modified by DrawingItem::setCached() + CacheList _candidate_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; + + double _cache_score_threshold; ///< do not consider objects for caching below this score + size_t _cache_budget; ///< maximum allowed size of cache + + 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/grayscale.cpp b/src/display/grayscale.cpp index 745a08c1e..e468044d3 100644 --- a/src/display/grayscale.cpp +++ b/src/display/grayscale.cpp @@ -82,7 +82,7 @@ guchar luminance(guchar r, guchar g, guchar b) { */ bool activeDesktopIsGrayscale() { if (SP_ACTIVE_DESKTOP) { - return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORRENDERMODE_GRAYSCALE); + return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORMODE_GRAYSCALE); } else { return false; } diff --git a/src/display/nr-arena-forward.h b/src/display/nr-arena-forward.h deleted file mode 100644 index 5a5cf228a..000000000 --- a/src/display/nr-arena-forward.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __NR_ARENA_FORWARD_H__ -#define __NR_ARENA_FORWARD_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -struct NRArena; -struct NRArenaClass; - -struct NRArenaItem; -struct NRArenaItemClass; - -struct NRArenaGroup; -struct NRArenaGroupClass; - -struct NRArenaShape; -struct NRArenaShapeClass; - -struct NRArenaShapeGroup; -struct NRArenaShapeGroupClass; - -struct NRArenaImage; -struct NRArenaImageClass; - -struct NRArenaGlyphs; -struct NRArenaGlyphsClass; - -struct NRArenaGlyphsGroup; -struct NRArenaGlyphsGroupClass; - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp deleted file mode 100644 index d09f66a2f..000000000 --- a/src/display/nr-arena-glyphs.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2002 Lauris Kaplinski - * - * Released under GNU GPL - * - */ - - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include "libnr/nr-convert2geom.h" -#include <2geom/affine.h> -#include "style.h" -#include "display/nr-arena.h" -#include "display/nr-arena-glyphs.h" -#include <cairo.h> -#include "display/cairo-utils.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, 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 NRArenaItemClass *glyphs_parent_class; - -NRType -nr_arena_glyphs_get_type(void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type(NR_TYPE_ARENA_ITEM, - "NRArenaGlyphs", - sizeof(NRArenaGlyphsClass), - sizeof(NRArenaGlyphs), - (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init, - (void (*)(NRObject *)) nr_arena_glyphs_init); - } - return type; -} - -static void -nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_glyphs_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>; - - item_class->update = nr_arena_glyphs_update; - item_class->clip = nr_arena_glyphs_clip; - item_class->pick = nr_arena_glyphs_pick; -} - -static void -nr_arena_glyphs_init(NRArenaGlyphs *glyphs) -{ - glyphs->g_transform.setIdentity(); - glyphs->font = NULL; - glyphs->glyph = 0; - glyphs->x = glyphs->y = 0.0; -} - -static void -nr_arena_glyphs_finalize(NRObject *object) -{ - NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object); - - if (glyphs->font) { - glyphs->font->Unref(); - glyphs->font=NULL; - } - - ((NRObjectClass *) glyphs_parent_class)->finalize(object); -} - -static guint -nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*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.x0 = floor(b->left()); - item->bbox.y0 = floor(b->top()); - item->bbox.x1 = ceil (b->right()); - item->bbox.y1 = ceil (b->bottom()); - } else { - item->bbox.x0 = 0; - item->bbox.y0 = 0; - item->bbox.x1 = -1; - item->bbox.y1 = -1; - } - - 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*/) -{ - NRArenaGlyphs *glyphs; - - glyphs = NR_ARENA_GLYPHS(item); - - if (!glyphs->font ) 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; - - 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, 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 NRArenaGroupClass *group_parent_class; - -NRType -nr_arena_glyphs_group_get_type(void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type(NR_TYPE_ARENA_GROUP, - "NRArenaGlyphsGroup", - sizeof(NRArenaGlyphsGroupClass), - sizeof(NRArenaGlyphsGroup), - (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init, - (void (*)(NRObject *)) nr_arena_glyphs_group_init); - } - return type; -} - -static void -nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_glyphs_group_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>; - - item_class->update = nr_arena_glyphs_group_update; - item_class->render = nr_arena_glyphs_group_render; - item_class->clip = nr_arena_glyphs_group_clip; - item_class->pick = nr_arena_glyphs_group_pick; -} - -static void -nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group) -{ - group->style = NULL; - group->paintbox.x0 = group->paintbox.y0 = 0.0F; - group->paintbox.x1 = group->paintbox.y1 = -1.0F; -} - -static void -nr_arena_glyphs_group_finalize(NRObject *object) -{ - NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object); - - 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, NRRectL *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(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, 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); - 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); - - 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; - - cairo_save(ct); - ink_cairo_transform(ct, transform); - feed_pathvector_to_cairo (ct, *pathv); - cairo_fill(ct); - cairo_restore(ct); - } - 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); - - 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); - } - - if (has_fill) { - ggroup->nrstyle.applyFill(ct); - cairo_fill_preserve(ct); - } - if (has_stroke) { - ggroup->nrstyle.applyStroke(ct); - cairo_stroke_preserve(ct); - } - cairo_new_path(ct); // 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*/) -{ - NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - - cairo_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); - } else { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); - } - } - ink_cairo_transform(ct, 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); - } - cairo_fill(ct); - cairo_restore(ct); - - return item->state; -} - -static NRArenaItem * -nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point 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); - - 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; - } - - 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 c43095cb2..000000000 --- a/src/display/nr-arena-glyphs.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef SEEN_NR_ARENA_GLYPHS_H -#define SEEN_NR_ARENA_GLYPHS_H - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2002 Lauris Kaplinski - * - * Released under GNU GPL - * - */ - -#define NR_TYPE_ARENA_GLYPHS (nr_arena_glyphs_get_type ()) -#define NR_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_GLYPHS, NRArenaGlyphs)) -#define NR_IS_ARENA_GLYPHS(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS)) - -#include "libnrtype/nrtype-forward.h" -#include "display/display-forward.h" -#include "forward.h" -#include "display/nr-arena-item.h" -#include "display/nr-style.h" - -#define test_glyph_liv - -struct SPCurve; -class Shape; -class SPPainter; - -NRType nr_arena_glyphs_get_type (void); - -struct NRArenaGlyphs : public NRArenaItem { - /* Glyphs data */ - Geom::Affine g_transform; - - font_instance *font; - gint glyph; - float x, y; - - static NRArenaGlyphs *create(NRArena *arena) { - NRArenaGlyphs *obj=reinterpret_cast<NRArenaGlyphs *>(nr_object_new(NR_TYPE_ARENA_GLYPHS)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaGlyphsClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_glyphs_set_path ( NRArenaGlyphs *glyphs, - SPCurve *curve, unsigned int lieutenant, - font_instance *font, int glyph, - Geom::Affine const *transform ); -void nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style); - -/* Integrated group of component glyphss */ - -typedef struct NRArenaGlyphsGroup NRArenaGlyphsGroup; -typedef struct NRArenaGlyphsGroupClass NRArenaGlyphsGroupClass; - -#include "nr-arena-group.h" - -#define NR_TYPE_ARENA_GLYPHS_GROUP (nr_arena_glyphs_group_get_type ()) -#define NR_ARENA_GLYPHS_GROUP(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_GLYPHS_GROUP, NRArenaGlyphsGroup)) -#define NR_IS_ARENA_GLYPHS_GROUP(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_GLYPHS_GROUP)) - -NRType nr_arena_glyphs_group_get_type (void); - -struct NRArenaGlyphsGroup : public NRArenaGroup { - NRRect paintbox; - NRStyle nrstyle; - - static NRArenaGlyphsGroup *create(NRArena *arena) { - NRArenaGlyphsGroup *obj=reinterpret_cast<NRArenaGlyphsGroup *>(nr_object_new(NR_TYPE_ARENA_GLYPHS_GROUP)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaGlyphsGroupClass { - NRArenaGroupClass parent_class; -}; - -/* Utility functions */ - -void nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *group); - -void nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *group, font_instance *font, int glyph, Geom::Affine const &transform); - -void nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *group, SPStyle *style); - -void nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *group, const NRRect *pbox); - -#endif // SEEN_NR_ARENA_GLYPHS_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp deleted file mode 100644 index 1d552fbc2..000000000 --- a/src/display/nr-arena-group.cpp +++ /dev/null @@ -1,299 +0,0 @@ -#define __NR_ARENA_GROUP_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "display/canvas-bpath.h" -#include "display/nr-arena.h" -#include "display/nr-arena-group.h" -#include "display/nr-filter.h" -#include "display/nr-filter-types.h" -#include "display/rendermode.h" -#include "style.h" -#include "sp-filter.h" -#include "sp-filter-reference.h" -#include "filters/blend.h" -#include "display/nr-filter-blend.h" -#include "helper/geom.h" - -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, 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 NRArenaItemClass *parent_class; - -NRType -nr_arena_group_get_type (void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type (NR_TYPE_ARENA_ITEM, - "NRArenaGroup", - sizeof (NRArenaGroupClass), - sizeof (NRArenaGroup), - (void (*) (NRObjectClass *)) nr_arena_group_class_init, - (void (*) (NRObject *)) nr_arena_group_init); - } - return type; -} - -static void -nr_arena_group_class_init (NRArenaGroupClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGroup>; - - item_class->children = nr_arena_group_children; - item_class->last_child = nr_arena_group_last_child; - item_class->add_child = nr_arena_group_add_child; - item_class->set_child_position = nr_arena_group_set_child_position; - item_class->remove_child = nr_arena_group_remove_child; - item_class->update = nr_arena_group_update; - item_class->render = nr_arena_group_render; - item_class->clip = nr_arena_group_clip; - item_class->pick = nr_arena_group_pick; -} - -static void -nr_arena_group_init (NRArenaGroup *group) -{ - group->transparent = FALSE; - group->children = NULL; - group->last = NULL; - group->style = NULL; - group->child_transform.setIdentity(); -} - -static NRArenaItem * -nr_arena_group_children (NRArenaItem *item) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - return group->children; -} - -static NRArenaItem * -nr_arena_group_last_child (NRArenaItem *item) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - return group->last; -} - -static void -nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - if (!ref) { - group->children = nr_arena_item_attach (item, child, NULL, group->children); - } else { - ref->next = nr_arena_item_attach (item, child, ref, ref->next); - } - - if (ref == group->last) group->last = child; - - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static void -nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - if (child == group->last) group->last = child->prev; - - if (child->prev) { - nr_arena_item_detach (item, child); - } else { - group->children = nr_arena_item_detach (item, child); - } - - nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static void -nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - if (child == group->last) group->last = child->prev; - - if (child->prev) { - nr_arena_item_detach (item, child); - } else { - group->children = nr_arena_item_detach (item, child); - } - - if (!ref) { - group->children = nr_arena_item_attach (item, child, NULL, group->children); - } else { - ref->next = nr_arena_item_attach (item, child, ref, ref->next); - } - - if (ref == group->last) group->last = child; - - nr_arena_item_request_render (child); -} - -static unsigned int -nr_arena_group_update (NRArenaItem *item, NRRectL *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 = NR_RECT_L_EMPTY; - 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); - } - } - - 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 (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, 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, pb, flags); - if (ret & NR_ARENA_ITEM_STATE_INVALID) break; - } - - return ret; -} - -static unsigned int -nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *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 p, double delta, unsigned int sticky) -{ - NRArenaGroup *group = NR_ARENA_GROUP (item); - - for (NRArenaItem *child = group->last; child != NULL; child = child->prev) { - NRArenaItem *picked = nr_arena_item_invoke_pick (child, p, delta, sticky); - if (picked) - return (group->transparent) ? picked : item; - } - - return NULL; -} - -void -nr_arena_group_set_transparent (NRArenaGroup *group, unsigned int transparent) -{ - nr_return_if_fail (group != NULL); - nr_return_if_fail (NR_IS_ARENA_GROUP (group)); - - group->transparent = transparent; -} - -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t) -{ - Geom::Affine nt(t); - nr_arena_group_set_child_transform(group, &nt); -} - -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t) -{ - if (!t) t = &GEOM_MATRIX_IDENTITY; - - if (!Geom::matrix_equalp(*t, group->child_transform, NR_EPSILON)) { - nr_arena_item_request_render (NR_ARENA_ITEM (group)); - group->child_transform = *t; - nr_arena_item_request_update (NR_ARENA_ITEM (group), NR_ARENA_ITEM_STATE_ALL, TRUE); - } -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-group.h b/src/display/nr-arena-group.h deleted file mode 100644 index 58394643c..000000000 --- a/src/display/nr-arena-group.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __NR_ARENA_GROUP_H__ -#define __NR_ARENA_GROUP_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. - * - * Released under GNU GPL - * - */ - -#define NR_TYPE_ARENA_GROUP (nr_arena_group_get_type ()) -#define NR_ARENA_GROUP(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_GROUP, NRArenaGroup)) -#define NR_IS_ARENA_GROUP(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_GROUP)) - -#include "nr-arena-item.h" -#include "style.h" - -NRType nr_arena_group_get_type (void); - -struct NRArenaGroup : public NRArenaItem{ - unsigned int transparent : 1; - NRArenaItem *children; - NRArenaItem *last; - Geom::Affine child_transform; - SPStyle *style; - - static NRArenaGroup *create(NRArena *arena) { - NRArenaGroup *obj = reinterpret_cast<NRArenaGroup *>(nr_object_new(NR_TYPE_ARENA_GROUP)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaGroupClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_group_set_transparent(NRArenaGroup *group, unsigned int transparent); - -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t); -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t); -void nr_arena_group_set_style(NRArenaGroup *group, SPStyle *style); - -#endif - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp deleted file mode 100644 index a943a6214..000000000 --- a/src/display/nr-arena-image.cpp +++ /dev/null @@ -1,408 +0,0 @@ -#define __NR_ARENA_IMAGE_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <2geom/transforms.h> -#include "../preferences.h" -#include "nr-arena-image.h" -#include "style.h" -#include "display/cairo-utils.h" -#include "display/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, 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 Geom::Rect nr_arena_image_rect (NRArenaImage *image); - -static NRArenaItemClass *parent_class; - -NRType -nr_arena_image_get_type (void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type (NR_TYPE_ARENA_ITEM, - "NRArenaImage", - sizeof (NRArenaImageClass), - sizeof (NRArenaImage), - (void (*) (NRObjectClass *)) nr_arena_image_class_init, - (void (*) (NRObject *)) nr_arena_image_init); - } - return type; -} - -static void -nr_arena_image_class_init (NRArenaImageClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_image_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaImage>; - - item_class->update = nr_arena_image_update; - item_class->render = nr_arena_image_render; - item_class->pick = nr_arena_image_pick; -} - -static void -nr_arena_image_init (NRArenaImage *image) -{ - image->pixbuf = NULL; - image->ctm.setIdentity(); - image->clipbox = Geom::Rect(); - image->ox = image->oy = 0.0; - image->sx = image->sy = 1.0; - - image->style = 0; - image->render_opacity = TRUE; -} - -static void -nr_arena_image_finalize (NRObject *object) -{ - NRArenaImage *image = NR_ARENA_IMAGE (object); - - if (image->pixbuf != NULL) { - g_object_unref(image->pixbuf); - cairo_surface_destroy(image->surface); - } - if (image->style) - sp_style_unref(image->style); - - ((NRObjectClass *) parent_class)->finalize (object); -} - -static unsigned int -nr_arena_image_update( NRArenaItem *item, NRRectL */*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) { - 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()); - } 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; - } - - 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*/ ) -{ - if (!ct) { - return item->state; - } - - 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. - cairo_save(ct); - ink_cairo_transform(ct, image->ctm); - - 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); - - cairo_matrix_t tt; - Geom::Affine total; - cairo_get_matrix(ct, &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_set_filter(p, CAIRO_FILTER_NEAREST); - } - - cairo_paint_with_alpha(ct, ((double) item->opacity) / 255.0); - cairo_restore(ct); - - } 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); - - 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); - } - 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) -{ - // 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 p, double delta, unsigned int /*sticky*/ ) -{ - NRArenaImage *image = NR_ARENA_IMAGE (item); - - if (!image->pixbuf) return NULL; - - bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - - if (outline) { - Geom::Rect r = nr_arena_image_rect (image); - - Geom::Point c00 = r.corner(0); - Geom::Point c01 = r.corner(3); - Geom::Point c11 = r.corner(2); - Geom::Point c10 = r.corner(1); - - // frame - if (distance_to_segment (p, c00, c10) < delta) return item; - if (distance_to_segment (p, c10, c11) < delta) return item; - if (distance_to_segment (p, c11, c01) < delta) return item; - if (distance_to_segment (p, c01, c00) < delta) return item; - - // diagonals - if (distance_to_segment (p, c00, c11) < delta) return item; - if (distance_to_segment (p, c10, c01) < delta) return item; - - return NULL; - - } else { - - unsigned char *const pixels = gdk_pixbuf_get_pixels(image->pixbuf); - int const width = gdk_pixbuf_get_width(image->pixbuf); - int const height = gdk_pixbuf_get_height(image->pixbuf); - int const rowstride = gdk_pixbuf_get_rowstride(image->pixbuf); - - Geom::Point tp = p * image->ctm.inverse(); - Geom::Rect r = nr_arena_image_rect(image); - - if (!r.contains(tp)) - return NULL; - - double vw = width * image->sx; - double vh = height * image->sy; - int ix = floor((tp[Geom::X] - image->ox) / vw * width); - int iy = floor((tp[Geom::Y] - image->oy) / vh * height); - - if ((ix < 0) || (iy < 0) || (ix >= width) || (iy >= height)) - return NULL; - - unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4; - // is the alpha not transparent? - return (pix_ptr[3] > 0) ? item : NULL; - } -} - -Geom::Rect -nr_arena_image_rect (NRArenaImage *image) -{ - Geom::Rect r = image->clipbox; - - if (image->pixbuf) { - double pw = gdk_pixbuf_get_width(image->pixbuf); - double ph = gdk_pixbuf_get_height(image->pixbuf); - double vw = pw * image->sx; - double vh = ph * image->sy; - Geom::Point p(image->ox, image->oy); - Geom::Point wh(vw, vh); - Geom::Rect view(p, p+wh); - Geom::OptRect res = r & view; - r = res ? *res : r; - } - - return r; -} - -/* Utility */ - -void -nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1 - if (pb != NULL) { - g_object_ref (pb); - } - if (image->pixbuf != NULL) { - g_object_unref(image->pixbuf); - cairo_surface_destroy(image->surface); - } - image->pixbuf = pb; - image->surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - image->clipbox = clip; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - image->ox = origin[Geom::X]; - image->oy = origin[Geom::Y]; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void -nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy) -{ - nr_return_if_fail (image != NULL); - nr_return_if_fail (NR_IS_ARENA_IMAGE (image)); - - image->sx = sx; - image->sy = sy; - - nr_arena_item_request_update (NR_ARENA_ITEM (image), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style) -{ - g_return_if_fail(image != NULL); - g_return_if_fail(NR_IS_ARENA_IMAGE(image)); - - if (style) sp_style_ref(style); - if (image->style) sp_style_unref(image->style); - image->style = style; - - //if image has a filter - if (style->filter.set && style->getFilter()) { - if (!image->filter) { - int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter())); - image->filter = new Inkscape::Filters::Filter(primitives); - } - sp_filter_build_renderer(SP_FILTER(style->getFilter()), image->filter); - } else { - //no filter set for this image - delete image->filter; - image->filter = NULL; - } - - if (style && style->enable_background.set - && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { - image->background_new = true; - } - - nr_arena_item_request_update(image, NR_ARENA_ITEM_STATE_ALL, FALSE); -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-image.h b/src/display/nr-arena-image.h deleted file mode 100644 index 6fa9223dd..000000000 --- a/src/display/nr-arena-image.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __NR_ARENA_IMAGE_H__ -#define __NR_ARENA_IMAGE_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <gdk-pixbuf/gdk-pixbuf.h> -#include <2geom/rect.h> -#include "nr-arena-item.h" -#include "style.h" - -#define NR_TYPE_ARENA_IMAGE (nr_arena_image_get_type ()) -#define NR_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_CAST ((o), NR_TYPE_ARENA_IMAGE, NRArenaImage)) -#define NR_IS_ARENA_IMAGE(o) (NR_CHECK_INSTANCE_TYPE ((o), NR_TYPE_ARENA_IMAGE)) - -NRType nr_arena_image_get_type (void); - -struct NRArenaImage : public NRArenaItem { - GdkPixbuf *pixbuf; - cairo_surface_t *surface; - - Geom::Affine ctm; - Geom::Rect clipbox; - double ox, oy; - double sx, sy; - - SPStyle *style; - - static NRArenaImage *create(NRArena *arena) { - NRArenaImage *obj=reinterpret_cast<NRArenaImage *>(nr_object_new(NR_TYPE_ARENA_IMAGE)); - obj->init(arena); - return obj; - } -}; - -struct NRArenaImageClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_image_set_argb32_pixbuf (NRArenaImage *image, GdkPixbuf *pb); -void nr_arena_image_set_style (NRArenaImage *image, SPStyle *style); -void nr_arena_image_set_clipbox (NRArenaImage *image, Geom::Rect const &clip); -void nr_arena_image_set_origin (NRArenaImage *image, Geom::Point const &origin); -void nr_arena_image_set_scale (NRArenaImage *image, double sx, double sy); - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp deleted file mode 100644 index 9ca5a7463..000000000 --- a/src/display/nr-arena-item.cpp +++ /dev/null @@ -1,882 +0,0 @@ -#define __NR_ARENA_ITEM_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#define noNR_ARENA_ITEM_VERBOSE -#define noNR_ARENA_ITEM_DEBUG_CASCADE - -#include <cstring> -#include <string> -#include <cairomm/cairomm.h> - -#include "display/cairo-utils.h" -#include "display/cairo-templates.h" -#include "display/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->transform = NULL; - item->clip = NULL; - item->mask = NULL; - item->px = NULL; - item->data = NULL; - item->filter = NULL; - item->background_pb = NULL; - item->background_new = false; -} - -static void -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); - - ((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, NRRectL *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 (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) { - if (!nr_rect_l_test_intersect_ptr(area, 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 */ - 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.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); - } else { - memcpy(&item->drawbox, &item->bbox, sizeof(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) { - nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox); - } else { - // for clipping, we need geometric bbox - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &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) { - nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox); - } else { - // for masking, we need full drawbox of mask - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); - } - } - - // 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); - } - - 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 (cairo_t *ct, NRArenaItem *item, NRRectL const *area, - NRPixBlock *pb, 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 (!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) - 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 - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->bbox); - if (nr_rect_l_test_empty(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); - 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, pb, 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); - } - item->arena->outlinecolor = saved_rgba; // restore outline color - - 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. - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->drawbox); - if (nr_rect_l_test_empty(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); - } - - using namespace Inkscape; - - unsigned state; - unsigned retstate; - - // determine whether this shape needs intermediate rendering. - bool needs_intermediate_rendering = false; - bool &nir = needs_intermediate_rendering; - bool needs_opacity = (item->opacity != 255 && !item->render_opacity); - - // this item needs an intermediate rendering if: - nir |= (item->clip != NULL); // 1. it has a clipping path - nir |= (item->mask != NULL); // 2. it has a mask - nir |= (item->filter != NULL && filter); // 3. it has a filter - nir |= needs_opacity; // 4. it is non-opaque - - double opacity = static_cast<double>(item->opacity) / 255.0; - - /* How the rendering is done. - * - * Clipping, masking and opacity are done by rendering them to a surface - * and then compositing the object's rendering onto it with the IN operator. - * The object itself is rendered to a group. - * - * Opacity is done by rendering the clipping path with an alpha - * value corresponding to the opacity. If there is no clipping path, - * the entire intermediate surface is painted with alpha corresponding - * to the opacity value. - */ - - // short-circuit the simple case. - if (!needs_intermediate_rendering) { - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, 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; - } - - 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); - - // 1. Render clipping path with alpha = opacity. - cairo_set_source_rgba(ict, 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); - if (item->clip) { - state = nr_arena_item_invoke_clip(ict, item->clip, const_cast<NRRectL*>(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); - } - // reset back to default - cairo_set_operator(ict, 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); - 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); - // 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); - } - - // 3. Render object itself. - cairo_push_group(ict); - state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, 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) { - // 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); - // 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); - - // 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); - // 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_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)) { - // 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) { - 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); - } - - // rasterize the clipping path - retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - 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); - } - } - - return retstate; -} - -NRArenaItem * -nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point 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; - - // TODO: rewrite using Geom::Rect - const double x = p[Geom::X]; - const double y = p[Geom::Y]; - - if (((x + delta) >= item->bbox.x0) && - ((x - delta) < item->bbox.x1) && - ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) - { - 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); - nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox); -} - -/* 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)) { - 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; - } - 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 &bbox) -{ - nr_return_if_fail(item != NULL); - nr_return_if_fail(NR_IS_ARENA_ITEM(item)); - - item->item_bbox = bbox; -} - -/** 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 d65a75ed8..000000000 --- a/src/display/nr-arena-item.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_DISPLAY_NR_ARENA_ITEM_H -#define SEEN_DISPLAY_NR_ARENA_ITEM_H - -#include <cairo.h> -#include <2geom/affine.h> -#include <2geom/rect.h> -#include "libnr/nr-forward.h" -#include "libnr/nr-rect-l.h" -#include "libnr/nr-object.h" -#include "gc-soft-ptr.h" -#include "nr-arena-forward.h" - -namespace Inkscape { -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_NONE 0x0000 -#define NR_ARENA_ITEM_STATE_ALL 0x01fe - -#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) - -struct NRGC { - NRGC(NRGC const *p) : parent(p) {} - NRGC const *parent; - Geom::Affine transform; -}; - -struct NRArenaItem : public NRObject { - - NRArena *arena; - Inkscape::GC::soft_ptr<NRArenaItem> parent; - NRArenaItem *next; - Inkscape::GC::soft_ptr<NRArenaItem> prev; - - /* Item state */ - unsigned 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; - /* Opacity itself */ - unsigned int opacity : 8; - - 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::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 - unsigned char *px; ///< Render cache; unused - - 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) { - 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, 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); -}; - -#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, NRRectL *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_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area); -NRArenaItem *nr_arena_item_invoke_pick (NRArenaItem *item, Geom::Point 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 &bbox); - -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 6d65611bf..000000000 --- a/src/display/nr-arena-shape.cpp +++ /dev/null @@ -1,610 +0,0 @@ -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <cairo.h> -#include <glib.h> -#include <fenv.h> -#include <typeinfo> - -#include <2geom/curves.h> -#include <2geom/pathvector.h> -#include <2geom/svg-path.h> -#include <2geom/svg-path-parser.h> -#include "display/cairo-utils.h" -#include "display/canvas-arena.h" -#include "display/canvas-bpath.h" -#include "display/curve.h" -#include "display/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, 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 NRArenaItemClass *shape_parent_class; - -NRType -nr_arena_shape_get_type(void) -{ - static NRType type = 0; - if (!type) { - type = nr_object_register_type(NR_TYPE_ARENA_ITEM, - "NRArenaShape", - sizeof(NRArenaShapeClass), - sizeof(NRArenaShape), - (void (*)(NRObjectClass *)) nr_arena_shape_class_init, - (void (*)(NRObject *)) nr_arena_shape_init); - } - return type; -} - -static void -nr_arena_shape_class_init(NRArenaShapeClass *klass) -{ - NRObjectClass *object_class; - NRArenaItemClass *item_class; - - object_class = (NRObjectClass *) klass; - item_class = (NRArenaItemClass *) klass; - - shape_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent; - - object_class->finalize = nr_arena_shape_finalize; - object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaShape>; - - item_class->children = nr_arena_shape_children; - item_class->add_child = nr_arena_shape_add_child; - item_class->set_child_position = nr_arena_shape_set_child_position; - item_class->remove_child = nr_arena_shape_remove_child; - item_class->update = nr_arena_shape_update; - item_class->render = nr_arena_shape_render; - item_class->clip = nr_arena_shape_clip; - item_class->pick = nr_arena_shape_pick; -} - -/** - * Initializes the arena shape, setting all parameters to null, 0, false, - * or other defaults - */ -static void -nr_arena_shape_init(NRArenaShape *shape) -{ - shape->curve = NULL; - shape->style = NULL; - shape->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; -} - -static void -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; - - ((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, NRRectL *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.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]); - } else { - item->bbox = NR_RECT_L_EMPTY; - } - } - 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); - } - } - } - 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); - - 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); - } - } - } - - /// \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; - - 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) { - nr_rect_l_union(&item->bbox, &item->bbox, &child->bbox); - } - } - - return NR_ARENA_ITEM_STATE_ALL; -} - -// cairo outline rendering: -static unsigned int -cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, Geom::OptRect /*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); - - return item->state; -} - -/** - * 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) -{ - 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)) { - 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 (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); - - // 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 - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); - if (has_fill) { - shape->nrstyle.applyFill(ct); - cairo_fill_preserve(ct); - } - if (has_stroke) { - shape->nrstyle.applyStroke(ct); - cairo_stroke_preserve(ct); - } - cairo_new_path(ct); // 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); - if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; - } - - return item->state; -} - - -static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) -{ - NRArenaShape *shape = NR_ARENA_SHAPE(item); - if (!shape->curve) { - return item->state; - } - - cairo_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); - } else { - cairo_set_fill_rule(ct, 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); - - return item->state; -} - -static NRArenaItem * -nr_arena_shape_pick(NRArenaItem *item, Geom::Point 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); - - 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; - } - - 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]; - - 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 7b86f7f59..000000000 --- a/src/display/nr-arena-shape.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef __NR_ARENA_SHAPE_H__ -#define __NR_ARENA_SHAPE_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#define NR_TYPE_ARENA_SHAPE (nr_arena_shape_get_type ()) -#define NR_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_CAST ((obj), NR_TYPE_ARENA_SHAPE, NRArenaShape)) -#define NR_IS_ARENA_SHAPE(obj) (NR_CHECK_INSTANCE_TYPE ((obj), NR_TYPE_ARENA_SHAPE)) - -#include <cairo.h> -#include "display/display-forward.h" -#include "forward.h" -#include "nr-arena-item.h" -#include "nr-style.h" -#include "libnr/nr-rect.h" - -NRType nr_arena_shape_get_type (void); - -struct NRArenaShape : public NRArenaItem { - /* Shape data */ - SPCurve *curve; - SPStyle *style; - NRStyle nrstyle; - 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; - - /* Markers */ - NRArenaItem *markers; - - NRArenaItem *last_pick; - guint repick_after; - - static NRArenaShape *create(NRArena *arena) { - NRArenaShape *obj=reinterpret_cast<NRArenaShape *>(nr_object_new(NR_TYPE_ARENA_SHAPE)); - obj->init(arena); - obj->key = 0; - return obj; - } - - void setPaintBox(Geom::Rect const &pbox); -}; - -struct NRArenaShapeClass { - NRArenaItemClass parent_class; -}; - -void nr_arena_shape_set_path(NRArenaShape *shape, SPCurve *curve, bool justTrans); -void nr_arena_shape_set_style(NRArenaShape *shape, SPStyle *style); -void nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox); - - -#endif /* !__NR_ARENA_SHAPE_H__ */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp deleted file mode 100644 index ce62a81dc..000000000 --- a/src/display/nr-arena.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#define __NR_ARENA_C__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "nr-arena-item.h" -#include "nr-arena.h" -#include "nr-filter-gaussian.h" -#include "nr-filter-types.h" -#include "preferences.h" -#include "color.h" -#include "libnr/nr-rect.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<NRArena>; -} - -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->colorrendermode = Inkscape::COLORRENDERMODE_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, NRArenaItem *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(); - 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->colorrendermode = Inkscape::COLORRENDERMODE_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, NRRectL *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); - - // 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->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; - } - if (aobject->callbacks && area && !nr_rect_l_test_empty_ptr(area)) { - 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); - } - } - } -} - -/** - 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; - -} - -#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 1c8216434..000000000 --- a/src/display/nr-arena.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __NR_ARENA_H__ -#define __NR_ARENA_H__ - -/* - * RGBA display list system for inkscape - * - * Author: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * Copyright (C) 2001 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <glib/gmacros.h> - -#include "display/rendermode.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)) - -#include <libnr/nr-forward.h> -#include <libnr/nr-object.h> -#include "nr-arena-forward.h" - -class SPPainter; - -NRType nr_arena_get_type (void); - -struct NRArenaEventVector { - NRObjectEventVector parent; - void (* request_update) (NRArena *arena, NRArenaItem *item, void *data); - void (* request_render) (NRArena *arena, NRRectL *area, void *data); -}; - -struct NRArena : public NRActiveObject { - static NRArena *create() { - return reinterpret_cast<NRArena *>(nr_object_new(NR_TYPE_ARENA)); - } - - double delta; - bool renderoffscreen; // if true then rendering must be exact - Inkscape::RenderMode rendermode; - Inkscape::ColorRenderMode colorrendermode; - int blurquality; // will be updated during update from preferences - int filterquality; // will be updated during update from preferences - - guint32 outlinecolor; - SPCanvasArena *canvasarena; // may be NULL is this arena is not the screen but used for export etc. -}; - -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_set_renderoffscreen (NRArena *arena); - -void nr_arena_separate_color_plates(guint32* rgba); - -#endif diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index 3cec479fa..267883b4b 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -196,6 +196,22 @@ bool FilterBlend::can_handle_affine(Geom::Affine const &) return true; } +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 64b3c9284..957d3cfc8 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -39,6 +39,8 @@ 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-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<gdouble> 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 eaed2a8bd..14144ace5 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" @@ -172,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..f744e9f48 100644 --- a/src/display/nr-filter-flood.h +++ b/src/display/nr-filter-flood.h @@ -27,10 +27,14 @@ 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 bool uses_background() { return false; } + 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 d240c1a43..8a7244e02 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -509,7 +509,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"); }; } @@ -542,7 +542,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"); }; } @@ -641,6 +641,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), @@ -682,6 +689,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 0cb7901b3..a22d23548 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -13,8 +13,9 @@ #include "document.h" #include "sp-item.h" #include "display/cairo-utils.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-context.h" +#include "display/drawing.h" +#include "display/drawing-item.h" #include "display/nr-filter.h" #include "display/nr-filter-image.h" #include "display/nr-filter-units.h" @@ -69,21 +70,20 @@ 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(); + Drawing drawing; Geom::OptRect optarea = SVGElem->getBounds(Geom::identity()); 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(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(); @@ -94,30 +94,18 @@ 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_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE); - nr_arena_item_invoke_render(ct, ai, &render_rect, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE); + drawing.update(render_rect); + drawing.render(ct, render_rect); SVGElem->invoke_hide(key); - nr_object_unref((NRObject*) arena); slot.set(_output, out); cairo_surface_destroy(out); @@ -208,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..28ac19a19 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -67,6 +67,22 @@ bool FilterMerge::can_handle_affine(Geom::Affine const &) return true; } +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 263fc8026..238f9a3e7 100644 --- a/src/display/nr-filter-merge.h +++ b/src/display/nr-filter-merge.h @@ -26,6 +26,8 @@ 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-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..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; @@ -22,24 +23,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 +64,18 @@ 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; } + + 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 * (length._set == false) WILL change the parameter as it is @@ -103,14 +98,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 +108,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-slot.cpp b/src/display/nr-filter-slot.cpp index 3464fda66..4f7a8849e 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -16,7 +16,7 @@ #include <2geom/transforms.h> #include "display/cairo-utils.h" -#include "display/nr-arena-item.h" +#include "display/drawing-context.h" #include "display/nr-filter-types.h" #include "display/nr-filter-gaussian.h" #include "display/nr-filter-slot.h" @@ -25,13 +25,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(DrawingItem *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 ? bgct->raw() : NULL) + , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme + , _background_area(bgct ? bgct->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme , _units(u) , _last_out(NR_FILTER_SOURCEGRAPHIC) , filterquality(FILTER_QUALITY_BEST) @@ -41,19 +41,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 +139,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); @@ -156,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_surface_t *tbg; - 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_set_source_surface(tbg_ct, bg, 0, 0); - cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(tbg_ct); - cairo_destroy(tbg_ct); + 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; } @@ -184,11 +186,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..d41b5180b 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -19,16 +19,17 @@ #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, cairo_t *bgct, NRRectL const *bgarea, - cairo_surface_t *graphic, NRRectL const *graphicarea, FilterUnits const &u); + FilterSlot(DrawingItem *item, DrawingContext *bgct, + DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); @@ -66,12 +67,12 @@ public: FilterUnits const &get_units() const { return _units; } Geom::Rect get_slot_area() const; - NRRectL const &get_sg_area() const { return *_source_graphic_area; } + NRRectL get_sg_area() const { NRRectL ret(_source_graphic_area); return ret; } private: typedef std::map<int, cairo_surface_t *> SlotMap; 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 @@ -81,8 +82,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-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..0b451d355 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -45,6 +45,8 @@ public: virtual ~FilterTurbulence(); 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-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]; } diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 963d98654..450ce689d 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -38,8 +38,9 @@ #include "display/nr-filter-tile.h" #include "display/nr-filter-turbulence.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing.h" +#include "display/drawing-item.h" +#include "display/drawing-context.h" #include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" @@ -96,50 +97,38 @@ Filter::~Filter() } -int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area) +int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct) { 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; } - 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; - 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<double,double> 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 - 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 +149,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea } } - FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); + FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgct, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -168,11 +157,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 +176,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, Inkscape::DrawingItem 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 @@ -204,7 +196,7 @@ void Filter::area_enlarge(NRRectL &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; @@ -212,9 +204,9 @@ void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { item_bbox = *maybe_bbox; std::pair<double,double> res_low - = _filter_resolution(item_bbox, item->ctm, filterquality); + = _filter_resolution(item_bbox, item->ctm(), filterquality); //std::pair<double,double> res_full - // = _filter_resolution(item_bbox, item->ctm, FILTER_QUALITY_BEST); + // = _filter_resolution(item_bbox, item->ctm(), FILTER_QUALITY_BEST); double pixels_per_block = fmax(item_bbox.width() / res_low.first, item_bbox.height() / res_low.second); bbox.x0 -= (int)pixels_per_block; @@ -224,39 +216,36 @@ 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::Point min(item_bbox.x0, item_bbox.y0); - Geom::Point max(item_bbox.x1, item_bbox.y1); - Geom::Rect tmp_bbox(min, max); +Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) { - Geom::Rect enlarged = filter_effect_area(tmp_bbox); - enlarged = enlarged * item->ctm; + Geom::OptRect enlarged = filter_effect_area(item_bbox); + if (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::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; @@ -265,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; @@ -283,10 +272,32 @@ 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; } +double Filter::complexity(Geom::Affine const &ctm) +{ + double factor = 1.0; + for (unsigned i = 0 ; i < _primitive.size() ; i++) { + if (_primitive[i]) { + double f = _primitive[i]->complexity(ctm); + factor += (f - 1.0); + } + } + 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 e1d4c10e5..32e1df60b 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -21,19 +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, cairo_t *bgct, NRRectL const *bgarea, cairo_t *graphic, NRRectL const *area); + int render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct); /** * Creates a new filter primitive under this filter object. @@ -149,19 +150,25 @@ 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, 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 */ - void compute_drawbox(NRArenaItem const *item, NRRectL &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); + + // says whether the filter accesses any of the background images + bool uses_background(); /** Creates a new filter with space for one filter element */ Filter(); diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 72fa0c444..fa5dd0d98 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -13,6 +13,8 @@ #include "style.h" #include "sp-paint-server.h" #include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!) +#include "display/drawing-context.h" +#include "libnr/nr-rect.h" void NRStyle::Paint::clear() { @@ -142,14 +144,15 @@ void NRStyle::set(SPStyle *style) update(); } -bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) +bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) { // update fill pattern if (!fill_pattern) { switch (fill.type) { - case PAINT_SERVER: - fill_pattern = sp_paint_server_create_pattern(fill.server, ct, paintbox, fill.opacity); - break; + case PAINT_SERVER: { + NRRect pb(paintbox); + fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), &pb, fill.opacity); + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -162,19 +165,20 @@ bool NRStyle::prepareFill(cairo_t *ct, NRRect *paintbox) return true; } -void NRStyle::applyFill(cairo_t *ct) +void NRStyle::applyFill(Inkscape::DrawingContext &ct) { - cairo_set_source(ct, fill_pattern); - cairo_set_fill_rule(ct, fill_rule); + ct.setSource(fill_pattern); + ct.setFillRule(fill_rule); } -bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) +bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) { if (!stroke_pattern) { switch (stroke.type) { - case PAINT_SERVER: - stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct, paintbox, stroke.opacity); - break; + case PAINT_SERVER: { + NRRect pb(paintbox); + stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), &pb, stroke.opacity); + } break; case PAINT_COLOR: { SPColor const &c = stroke.color; stroke_pattern = cairo_pattern_create_rgba( @@ -187,14 +191,14 @@ bool NRStyle::prepareStroke(cairo_t *ct, NRRect *paintbox) return true; } -void NRStyle::applyStroke(cairo_t *ct) +void NRStyle::applyStroke(Inkscape::DrawingContext &ct) { - cairo_set_source(ct, stroke_pattern); - cairo_set_line_width(ct, stroke_width); - cairo_set_line_cap(ct, line_cap); - cairo_set_line_join(ct, line_join); - cairo_set_miter_limit(ct, miter_limit); - cairo_set_dash(ct, dash, n_dash, dash_offset); + ct.setSource(stroke_pattern); + ct.setLineWidth(stroke_width); + ct.setLineCap(line_cap); + ct.setLineJoin(line_join); + ct.setMiterLimit(miter_limit); + cairo_set_dash(ct.raw(), dash, n_dash, dash_offset); // fixme } void NRStyle::update() diff --git a/src/display/nr-style.h b/src/display/nr-style.h index e741e46b4..0ba6ce2c6 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -13,22 +13,25 @@ #define SEEN_INKSCAPE_DISPLAY_NR_ARENA_STYLE_H #include <cairo.h> +#include <2geom/rect.h> #include "color.h" class SPColor; class SPPaintServer; class SPStyle; -struct NRRect; +namespace Inkscape { +class DrawingContext; +} struct NRStyle { NRStyle(); ~NRStyle(); void set(SPStyle *); - bool prepareFill(cairo_t *ct, NRRect *paintbox); - bool prepareStroke(cairo_t *ct, NRRect *paintbox); - void applyFill(cairo_t *ct); - void applyStroke(cairo_t *ct); + bool prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox); + bool prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox); + void applyFill(Inkscape::DrawingContext &ct); + void applyStroke(Inkscape::DrawingContext &ct); void update(); enum PaintType { diff --git a/src/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/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 diff --git a/src/document.cpp b/src/document.cpp index b699f8afa..72f92bd17 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" @@ -1126,8 +1126,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; @@ -1180,10 +1180,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; } @@ -1214,10 +1214,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/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 047a65868..d864394af 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/extension/internal/cairo-png-out.cpp b/src/extension/internal/cairo-png-out.cpp index f741c9f39..678a46095 100644 --- a/src/extension/internal/cairo-png-out.cpp +++ b/src/extension/internal/cairo-png-out.cpp @@ -27,8 +27,7 @@ #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/curve.h" #include "display/canvas-bpath.h" @@ -57,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); - NRArenaItem *root = 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(); @@ -76,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 7fdfaf8df..9cc3a4ce3 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -29,8 +29,7 @@ #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/curve.h" #include "display/canvas-bpath.h" @@ -86,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(); @@ -111,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 22b68b0ca..c3a8a790b 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -32,9 +32,8 @@ #include <glib/gmem.h> #include <glibmm/i18n.h> -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena-group.h" +#include "display/drawing.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; }; @@ -1093,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 @@ -1102,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 5d7c82bff..7ea5718f7 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -29,8 +29,7 @@ #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/curve.h" #include "display/canvas-bpath.h" @@ -82,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(); @@ -106,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 7eb7881dc..5e7fb991a 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -36,9 +36,7 @@ #include <glib/gmem.h> #include <glibmm/i18n.h> -#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 +86,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/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp index e4997fce1..f1f0ef3cb 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 376db7ee3..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/nr-arena-item.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; - nr_object_unref ((NRObject *) mod->arena); - mod->arena = NULL; + mod->root = NULL; // should have been deleted by invoke_hide /* 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 d5218aed8..c2276126b 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; + Inkscape::Drawing *drawing; + 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 16a2e6ea7..8603f8b66 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -20,53 +20,52 @@ #include "config.h" #endif +#include <2geom/pathvector.h> #include <gdk/gdkkeysyms.h> #include <queue> #include <deque> +#include <glibmm/i18n.h> -#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/drawing-context.h" +#include "display/drawing-image.h" +#include "display/drawing-item.h" +#include "display/drawing.h" +#include "display/sp-canvas.h" +#include "document.h" #include "flood-context.h" -#include "sp-metrics.h" -#include <glibmm/i18n.h> +#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 <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; @@ -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()); @@ -804,56 +799,51 @@ 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); - - /* 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(); - - 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); 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 - document->getRoot()->invoke_hide(dkey); + guint32 bgcolor, dtc; + + { // 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)); + // 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); + + 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); memset(trace_px, 0x00, width * height); 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 2e513afb2..3f987dc01 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -23,8 +23,9 @@ #include "interface.h" #include "helper/png-write.h" #include "display/cairo-utils.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" #include "document.h" #include "sp-item.h" #include "sp-root.h" @@ -110,61 +111,48 @@ 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 drawing for offscreen rendering*/ + Inkscape::Drawing drawing; + drawing.setExact(true); + 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( drawing, dkey, SP_ITEM_SHOW_DISPLAY); + root->setTransform(affine); + drawing.setRoot(root); - 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); - } - - NRRectL final_bbox; - final_bbox.x0 = 0; - final_bbox.y0 = 0;//row; - final_bbox.x1 = width; - final_bbox.y1 = height;//row + num_rows; + // 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); + } - nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); + Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height); + drawing.update(final_bbox); 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 ); + 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, @@ -179,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 a23c8fd43..24da697c1 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -23,8 +23,9 @@ #include <png.h> #include "png-write.h" #include "io/sys.h" -#include "display/nr-arena-item.h" -#include "display/nr-arena.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" #include "document.h" #include "sp-item.h" #include "sp-root.h" @@ -50,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::Drawing *drawing; // it is assumed that all unneeded items are hidden guchar *px; unsigned (*status)(float, void *); void *data; @@ -322,35 +323,24 @@ 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; - /* Update to renderable state */ - NRGC gc(NULL); - gc.transform.setIdentity(); + Geom::IntRect bbox = Geom::IntRect::from_xywh(0, row, ebp->width, num_rows); - nr_arena_item_invoke_update(ebp->root, &bbox, &gc, - NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); + /* Update to renderable state */ + 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); 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); + ebp->drawing->render(ct, bbox); cairo_surface_destroy(s); *to_free = px; @@ -460,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); - nr_arena_item_set_transform(NR_ARENA_ITEM(ebp.root), 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 @@ -492,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/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<SPDesktop*>(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 <glib/gmem.h> #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<InputStreamTextSource const *>(_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..c8fa9218d 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<NRArenaItem *> items; + std::vector<Inkscape::DrawingItem *> 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, 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,12 +444,12 @@ 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]) { - Geom::Affine tmp = marker->c2p; - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->items[i]), &tmp); + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->items[i]); + g->setChildTransform(marker->c2p); } } } @@ -522,8 +522,8 @@ sp_marker_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::X /** * This routine is disabled to break propagation. */ -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*/, Inkscape::Drawing &/*drawing*/, unsigned int /*key*/, unsigned int /*flags*/) { /* Break propagation */ return NULL; @@ -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) @@ -599,10 +599,10 @@ 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. */ -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<Inkscape::DrawingGroup *>(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/preferences-skeleton.h b/src/preferences-skeleton.h index 70ec0def4..70193bf96 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -231,6 +231,7 @@ static char const preferences_skeleton[] = " </group>\n" "\n" " <group id=\"options\">\n" +" <group id=\"renderingcache\" size=\"64\" />" " <group id=\"useoldpdfexporter\" value=\"0\" />" " <group id=\"highlightoriginal\" value=\"1\" />" " <group id=\"relinkclonesonduplicate\" value=\"0\" />" diff --git a/src/print.cpp b/src/print.cpp index 1ee58a3e6..2eadf0fa9 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -15,6 +15,8 @@ # include "config.h" #endif +#include "display/drawing.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 @@ -126,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; - mod->root = NULL; - nr_object_unref((NRObject *) mod->arena); - mod->arena = NULL; + mod->root = NULL; // should be deleted by invoke_hide /* end */ mod->set_param_string("destination", oldoutput); 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 1ce3ccd25..ca0ed2438 100644 --- a/src/select-context.cpp +++ b/src/select-context.cpp @@ -46,7 +46,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; @@ -418,7 +418,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); @@ -426,7 +426,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; @@ -442,7 +442,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); @@ -796,10 +796,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)); @@ -818,7 +818,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); @@ -1093,10 +1093,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..0b3320e59 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -15,8 +15,8 @@ #include <cstring> #include <string> -#include "display/nr-arena.h" -#include "display/nr-arena-group.h" +#include "display/drawing.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<Inkscape::DrawingGroup *>(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,17 @@ Inkscape::XML::Node *SPClipPath::write(SPObject *object, Inkscape::XML::Document return repr; } -NRArenaItem *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); - - NRArenaItem *ai = NRArenaGroup::create(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)) { - NRArenaItem *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 */ - nr_arena_item_add_child(ai, ac, NULL); + ai->appendChild(ac); } } } @@ -262,9 +261,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 +328,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 +353,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..11817eb77 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(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 bb931a869..ea8079bba 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<Inkscape::SnapCandidatePoint> &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, Inkscape::Drawing &drawing, 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<Inkscape::DrawingGroup *>(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<Inkscape::DrawingGroup *>(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::vector<Inkscape::Sna } } -static NRArenaItem * -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*/) { SPFlowtext *group = (SPFlowtext *) 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(drawing); + 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..de41ba47f 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" @@ -31,8 +31,8 @@ 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. */ - void _clearFlow(NRArenaGroup* in_arena); + /** 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 ea7d5089e..5f398b10e 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -28,7 +28,7 @@ #include <2geom/transforms.h> #include <glibmm/i18n.h> -#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<Inkscape::SnapCandidatePoint> &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, 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); 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<Inkscape::DrawingImage *>(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, Inkscape::Drawing &drawing, unsigned int /*key*/, unsigned int /*flags*/ ) { SPImage * image = SP_IMAGE(item); - NRArenaItem *ai = NRArenaImage::create(arena); + Inkscape::DrawingImage *ai = new Inkscape::DrawingImage(drawing); - 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<Inkscape::DrawingImage *>(v->arenaitem)); } } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 491b2a62a..f8ab0460a 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -22,7 +22,7 @@ #include <cstring> #include <string> -#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, 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<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); @@ -312,10 +312,10 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value) { } } -static NRArenaItem * -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) { - return SP_GROUP(item)->group->show(arena, key, flags); + return SP_GROUP(item)->group->show(drawing, key, flags); } static void @@ -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<Inkscape::DrawingGroup *>(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<Inkscape::DrawingGroup *>(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<Inkscape::DrawingGroup *>(v->arenaitem); + group->setStyle(object->style); + } } GSList *l = g_slist_reverse(_group->childList(true)); @@ -742,35 +744,28 @@ gchar *CGroup::getDescription() { len), len); } -NRArenaItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) { - NRArenaItem *ai; +Inkscape::DrawingItem *CGroup::show (Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { + Inkscape::DrawingGroup *ai; SPObject *object = _group; - ai = NRArenaGroup::create(arena); + ai = new Inkscape::DrawingGroup(drawing); + ai->setPickChildren(_group->effectiveLayerMode(key) == SPGroup::LAYER); + ai->setStyle(object->style); - 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); - - _showChildren(arena, ai, key, flags); + _showChildren(drawing, 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 (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)); while (l) { SPObject *o = SP_OBJECT (l->data); 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; - } + ac = child->invoke_show (drawing, key, flags); + 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..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 NRArenaItem *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, NRArenaItem *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 a4f2efa2c..07ce73c4b 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -29,8 +29,7 @@ #include "sp-item.h" #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 +144,10 @@ void SPItem::init() { display = NULL; clip_ref = new SPClipPathReference(this); - sigc::signal<void, SPObject *, SPObject *> cs1 = clip_ref->changedSignal(); - sigc::slot2<void,SPObject*, SPObject *> 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<void, SPObject *, SPObject *> cs2 = mask_ref->changedSignal(); - sigc::slot2<void,SPObject*, SPObject *> 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 +199,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 +389,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; - } + delete item->avoidRef; - if (item->clip_ref) { - item->clip_ref->detach(); - delete item->clip_ref; - item->clip_ref = NULL; - } - - 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 +460,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 +511,21 @@ 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()); } } 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 +536,21 @@ 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()); } } 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 +567,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 +579,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 +605,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) ); } @@ -1025,34 +1003,30 @@ 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(Inkscape::Drawing &drawing, 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); + ai = ((SPItemClass *) G_OBJECT_GET_CLASS(this))->show(this, drawing, 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(drawing, clip_key); + ai->setClip(ac); // Update bbox, in case the clip uses bbox units NRRect bbox; @@ -1063,15 +1037,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, drawing, mask_key); + ai->setMask(ac); // Update bbox, in case the mask uses bbox units NRRect bbox; @@ -1079,10 +1052,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; @@ -1100,20 +1073,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; @@ -1497,27 +1469,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; @@ -1525,17 +1497,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..633deb508 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -20,7 +20,7 @@ */ #include <vector> -#include "display/nr-arena-forward.h" +#include "display/display-forward.h" #include "sp-object.h" #include <2geom/affine.h> #include <libnr/nr-rect.h> @@ -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<void, Geom::Affine const *, SPItem *> 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(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); void invoke_hide(unsigned int key); void getSnappoints(std::vector<Inkscape::SnapCandidatePoint> &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<Inkscape::SnapCandidatePoint> &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, 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 38599188f..f23172a17 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -15,8 +15,8 @@ #include <string> #include <2geom/transforms.h> -#include "display/nr-arena.h" -#include "display/nr-arena-group.h" +#include "display/drawing.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<Inkscape::DrawingGroup *>(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,19 @@ 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, 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); - NRArenaItem *ai = NRArenaGroup::create(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)) { - NRArenaItem *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 mask */ - nr_arena_item_add_child (ai, ac, NULL); + ai->prependChild(ac); } } } @@ -320,7 +318,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 +365,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 +390,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..b1048e6be 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, 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 d1e7671ed..9aefdf6ff 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -22,11 +22,14 @@ #include "macros.h" #include "svg/svg.h" #include "display/cairo-utils.h" -#include "display/nr-arena.h" -#include "display/nr-arena-group.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/drawing.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" @@ -627,18 +630,19 @@ 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); - NRArenaGroup *root = NRArenaGroup::create(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 - NRArenaItem *cai; - cai = SP_ITEM(child)->invoke_show (arena, dkey, SP_ITEM_SHOW_DISPLAY); - nr_arena_item_append_child (root, cai); + Inkscape::DrawingItem *cai; + cai = SP_ITEM(child)->invoke_show (drawing, dkey, SP_ITEM_SHOW_DISPLAY); + root->appendChild(cai); } } @@ -658,9 +662,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,53 +677,42 @@ 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); + // 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]); - 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); + Inkscape::UpdateContext ctx; + ctx.ctm = vb2ps; + 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(root); - 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/sp-root.cpp b/src/sp-root.cpp index 918bd3295..a6df580d3 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, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); static void sp_root_print(SPItem *item, SPPrintContext *ctx); static SPGroupClass *parent_class; @@ -538,9 +538,10 @@ 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) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), root->c2p); + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem); + g->setChildTransform(root->c2p); } } @@ -607,18 +608,19 @@ 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 NRArenaItem * -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) { SPRoot *root = SP_ROOT(item); - NRArenaItem *ai; + 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) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), root->c2p); + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai); + g->setChildTransform(root->c2p); } } else { ai = NULL; diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 7f24dd089..4fd1deb69 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -30,7 +30,7 @@ #include <sigc++/adaptors/bind.h> #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<Inkscape::DrawingShape *>(v->arenaitem); + sh->setStyle(style); } } } @@ -255,14 +256,10 @@ 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) { - NRArenaShape * const s = NR_ARENA_SHAPE(v->arenaitem); + Inkscape::DrawingShape *sh = dynamic_cast<Inkscape::DrawingShape *>(v->arenaitem); if (flags & SP_OBJECT_MODIFIED_FLAG) { - nr_arena_shape_set_path(s, shape->curve, (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)); - } - if (paintbox) { - s->setPaintBox(*paintbox); + sh->setPath(shape->curve); } } } @@ -270,13 +267,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 +372,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 +392,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 +410,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 +430,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 +447,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 +471,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 +492,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<Inkscape::DrawingShape *>(v->arenaitem); + sh->setStyle(object->style); } } } @@ -850,19 +848,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, Inkscape::Drawing &drawing, 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); - Geom::OptRect paintbox = item->getBounds(Geom::identity()); - if (paintbox) { - s->setPaintBox(*paintbox); - } + Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); + s->setStyle(object->style); + s->setPath(shape->curve); /* This stanza checks that an object's marker style agrees with * the marker objects it has allocated. sp_shape_set_marker ensures @@ -876,23 +869,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 +904,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 +1006,7 @@ 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); - /* fixme: Do we need explicit remove here? (Lauris) */ - /* nr_arena_item_set_mask (v->arenaitem, NULL); */ + sp_marker_hide ((SPMarker *) (shape->marker[i]), v->arenaitem->key() + i); } /* Detach marker */ shape->release_connect[i].disconnect(); @@ -1064,9 +1055,7 @@ 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); - /* fixme: Do we need explicit remove here? (Lauris) */ - /* nr_arena_item_set_mask (v->arenaitem, NULL); */ + v->arenaitem->key() + key); } /* Unref marker */ diff --git a/src/sp-shape.h b/src/sp-shape.h index b91850d1f..355d8e7cc 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, 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<Inkscape::SnapCandidatePoint> &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..500e43c9c 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -19,7 +19,7 @@ #include <glibmm/i18n.h> #include "sp-switch.h" -#include "display/nr-arena-group.h" +#include "display/drawing-group.h" #include "conditions.h" #include <sigc++/functors/ptr_fun.h> @@ -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,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 (Inkscape::Drawing &drawing, 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 (drawing, 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..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, NRArenaItem *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 91218c986..bee28f8e3 100644 --- a/src/sp-symbol.cpp +++ b/src/sp-symbol.cpp @@ -19,7 +19,7 @@ #include <string> #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, 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,9 +325,10 @@ 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) { - nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), symbol->c2p); + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(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, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) { SPSymbol *symbol = SP_SYMBOL(item); - NRArenaItem *ai = 0; + Inkscape::DrawingItem *ai = 0; if (symbol->cloned) { // Cloned <symbol> 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); + ai = ((SPItemClass *) (parent_class))->show (item, drawing, key, flags); + Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai); + if (g) { + g->setChildTransform(symbol->c2p); } } } diff --git a/src/sp-text.cpp b/src/sp-text.cpp index c56f2e91f..9bb674843 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -35,7 +35,7 @@ #include <glibmm/i18n.h> #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, 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<Inkscape::SnapCandidatePoint> &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<Inkscape::DrawingGroup *>(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,18 +271,19 @@ 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 - // text object. Therefore we do here the same as in _update, that is, destroy all arena items + // 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 items // and create new ones. This is probably quite wasteful. if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) { SPText *text = SP_TEXT (object); 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<Inkscape::DrawingGroup *>(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 * -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*/) { 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(drawing); + 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..e426c425b 100644 --- a/src/sp-text.h +++ b/src/sp-text.h @@ -56,8 +56,8 @@ 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. */ - void _clearFlow(NRArenaGroup *in_arena); + /** discards the drawing objects representing this text. */ + 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..89df9130d 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -22,7 +22,7 @@ #include <2geom/transforms.h> #include <glibmm/i18n.h> -#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<Inkscape::SnapCandidatePoint> &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, 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); @@ -346,23 +346,23 @@ 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, Inkscape::Drawing &drawing, 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(drawing); + 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(drawing, 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<Inkscape::DrawingGroup *>(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<Inkscape::DrawingGroup *>(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<Inkscape::DrawingGroup *>(v->arenaitem); + g->setStyle(object->style); } } diff --git a/src/svg-view.cpp b/src/svg-view.cpp index 2f1a20b82..8773dfab7 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( - SP_CANVAS_ARENA (_drawing)->arena, + Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( + SP_CANVAS_ARENA (_drawing)->drawing, _dkey, SP_ITEM_SHOW_DISPLAY); if (ai) { - nr_arena_item_add_child (SP_CANVAS_ARENA (_drawing)->root, ai, NULL); + 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 813f532a4..7c47dc442 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" @@ -31,23 +29,14 @@ #include "sp-image.h" #include <2geom/transforms.h> -#include "display/nr-arena.h" -#include "display/nr-arena-shape.h" +#include "display/drawing.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,25 +236,25 @@ Tracer::sioxProcessImage(SPImage *img, return Glib::RefPtr<Gdk::Pixbuf>(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 = (double)(aImg->bbox.x1 - aImg->bbox.x0); - double height = (double)(aImg->bbox.y1 - aImg->bbox.y0); + double width = aImg->geometricBounds()->width(); + double height = aImg->geometricBounds()->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; - std::vector<NRArenaItem *> arenaItems; + std::vector<Inkscape::DrawingItem *> arenaItems; std::vector<SPShape *>::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 ; row<iheight ; row++) { - double ypos = ((double)aImg->bbox.y0) + ihscale * (double) row; + double ypos = aImg->geometricBounds()->top() + ihscale * (double) row; for (int col=0 ; col<simage.getWidth() ; col++) { //Get absolute X,Y position - double xpos = ((double)aImg->bbox.x0) + iwscale * (double)col; + double xpos = aImg->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<NRArenaItem *>::iterator aIter; + std::vector<Inkscape::DrawingItem *>::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<NRArenaItem *>::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<Gdk::Pixbuf> 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 cd1d65ba7..912bc1a40 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -27,54 +27,40 @@ #include "inkscape.h" #include "sp-rect.h" #include "document-private.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" #include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing.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::Drawing &drawing, 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); + drawing.root()->setTransform(Geom::Scale(scale_factor)); - gc.transform.setIdentity(); - nr_arena_item_invoke_update( root, NULL, &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); + Geom::IntRect ibox = (dbox * Geom::Scale(scale_factor)).roundOutwards(); - /* 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]); + drawing.update(ibox); /* 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_RENDER_NO_CACHE ); + drawing.render(ct, area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); cairo_surface_flush(s); - cairo_destroy(ct); GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, @@ -120,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); @@ -135,6 +121,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/ui/cache/svg_preview_cache.h b/src/ui/cache/svg_preview_cache.h index 0fac94782..2318307e2 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 <bryce@bryceharrington.org> - * * 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 <map> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <glibmm/ustring.h> +#include <2geom/rect.h> + +#include "display/display-forward.h" + +GdkPixbuf* render_pixbuf(Inkscape::Drawing &drawing, 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/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<SwatchPage*>::iterator it2 = possible.begin(); it2 != possible.end() && !found; ++it2 ) { SwatchPage* curr = *it2; index = 0; - for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { - if ( this == *zz ) { + for ( boost::ptr_vector<ColorItem>::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<ColorItem*>::iterator it = colorSet->_colors.begin(); it != colorSet->_colors.end(); ++it ) + for ( boost::ptr_vector<ColorItem>::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 <boost/ptr_container/ptr_vector.hpp> #include <gtkmm/tooltips.h> #include "widgets/ege-paint-def.h" @@ -33,7 +34,7 @@ public: Glib::ustring _name; int _prefWidth; - std::vector<ColorItem*> _colors; + boost::ptr_vector<ColorItem> _colors; }; 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 38ec6d1be..9865c0cdb 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -16,6 +16,7 @@ # include <config.h> #endif +#include <boost/scoped_ptr.hpp> #include <gtk/gtk.h> #include <glib/gmem.h> #include <glibmm/i18n.h> @@ -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, NRArenaItem *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 - NRArenaItem *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/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index d11ffd565..ae27f0720 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, 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", 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(); 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<ColorItem*> &tmpColors, + boost::ptr_vector<ColorItem> &tmpColors, std::map<ColorItem*, cairo_pattern_t*> &previewMappings, std::map<ColorItem*, SPGradient*> &gradMappings) { @@ -938,7 +938,7 @@ void SwatchesPanel::handleGradientsChange(SPDocument *document) { SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; if (docPalette) { - std::vector<ColorItem*> tmpColors; + boost::ptr_vector<ColorItem> tmpColors; std::map<ColorItem*, cairo_pattern_t*> tmpPrevs; std::map<ColorItem*, SPGradient*> tmpGrads; recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); @@ -953,9 +953,6 @@ void SwatchesPanel::handleGradientsChange(SPDocument *document) } docPalette->_colors.swap(tmpColors); - for (std::vector<ColorItem*>::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<ColorItem*> tmpColors; + boost::ptr_vector<ColorItem> tmpColors; std::map<ColorItem*, cairo_pattern_t*> tmpPrevs; std::map<ColorItem*, SPGradient*> 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<ColorItem*, cairo_pattern_t*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { cairo_pattern_destroy(it->second); } - for (std::vector<ColorItem*>::iterator it = tmpColors.begin(); it != tmpColors.end(); ++it) { - delete *it; - } } } @@ -1098,8 +1092,8 @@ void SwatchesPanel::_updateFromSelection() } sp_style_unref(tmpStyle); - for ( std::vector<ColorItem*>::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) { - ColorItem* item = *it; + for ( boost::ptr_vector<ColorItem>::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<ColorItem*>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { - _holder->addPreview(*it); + for ( boost::ptr_vector<ColorItem>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { + _holder->addPreview(&*it); } _holder->thawUpdates(); } 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 7958a9d07..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" @@ -641,10 +640,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 6110e6011..a57b56b5c 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -31,8 +31,9 @@ #include "document.h" #include "sp-item.h" #include "display/cairo-utils.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing.h" #include "io/sys.h" #include "sp-root.h" @@ -1074,9 +1075,22 @@ GdkPixbuf *IconImpl::loadPixmap(gchar const *name, unsigned /*lsize*/, unsigned return pb; } -// takes doc, root, icon, and icon name to produce pixels +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, drawing, 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::Drawing &drawing, gchar const *name, unsigned psize, unsigned &stride) { @@ -1099,28 +1113,21 @@ 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, NULL, &gc, - NR_ARENA_ITEM_STATE_ALL, - NR_ARENA_ITEM_STATE_NONE ); + drawing.root()->setTransform(Geom::Scale(sf)); + drawing.update(); /* 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,51 +1141,37 @@ 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, NULL, &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); + drawing.root()->setTransform(Geom::Scale(sf)); + drawing.update(); + 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); @@ -1190,12 +1183,9 @@ 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_RENDER_NO_CACHE ); - cairo_destroy(ct); + drawing.render(ct, ua); cairo_surface_destroy(s); // convert to GdkPixbuf format @@ -1216,9 +1206,21 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, class SVGDocCache { public: - SVGDocCache( SPDocument *doc, NRArenaItem *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; - NRArenaItem *root; + Inkscape::Drawing drawing; + unsigned visionkey; }; static std::map<Glib::ustring, SVGDocCache *> doc_cache; @@ -1285,27 +1287,14 @@ guchar *IconImpl::load_svg_pixels(std::list<Glib::ustring> 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 - NRArenaItem *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<Glib::ustring>::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 8b5582163..8d9b9b429 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/nr-arena.h" -#include "display/nr-arena-item.h" +#include "display/display-forward.h" +#include "display/drawing.h" #include "document-private.h" #include "gradient-chemistry.h" #include "helper/stock-items.h" @@ -153,7 +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*/, NRArenaItem *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); @@ -208,7 +208,7 @@ sp_marker_prev_new(unsigned psize, gchar const *mname, Glib::RefPtr<Gdk::Pixbuf> 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()); } @@ -248,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); - NRArenaItem *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<SPItem *>(marker_list->data)->getRepr(); @@ -271,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); @@ -289,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); } /** |
