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