diff options
Diffstat (limited to 'src/display')
36 files changed, 588 insertions, 375 deletions
diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 8e25c1843..404a94828 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -216,10 +216,10 @@ sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) Geom::OptIntRect r = buf->rect; if (!r || r->hasZeroArea()) return; - Inkscape::DrawingContext ct(buf->ct, r->min()); + Inkscape::DrawingContext dc(buf->ct, r->min()); arena->drawing.update(Geom::IntRect::infinite(), arena->ctx); - arena->drawing.render(ct, *r); + arena->drawing.render(dc, *r); } static double @@ -386,9 +386,9 @@ sp_canvas_arena_render_surface (SPCanvasArena *ca, cairo_surface_t *surface, Geo g_return_if_fail (ca != NULL); g_return_if_fail (SP_IS_CANVAS_ARENA (ca)); - Inkscape::DrawingContext ct(surface, r.min()); + Inkscape::DrawingContext dc(surface, r.min()); ca->drawing.update(Geom::IntRect::infinite(), ca->ctx); - ca->drawing.render(ct, r); + ca->drawing.render(dc, r); } /* diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index 858312f5b..312a8d655 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -141,7 +141,7 @@ attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], unsigned size, int Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0); #endif } else { - Gtk::HBox *space = manage (new Gtk::HBox); + Gtk::HBox *space = Gtk::manage (new Gtk::HBox); space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y); #if WITH_GTKMM_3_0 space->set_halign(Gtk::ALIGN_CENTER); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 3c4ad9b00..4b1dbd1ed 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -469,7 +469,7 @@ static inline void attach_all(Gtk::Table &table, Gtk::Widget const *const arr[], Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0); #endif } else { - Gtk::HBox *space = manage (new Gtk::HBox); + Gtk::HBox *space = Gtk::manage (new Gtk::HBox); space->set_size_request (SPACE_SIZE_X, SPACE_SIZE_Y); #if WITH_GTKMM_3_0 space->set_halign(Gtk::ALIGN_CENTER); diff --git a/src/display/curve.cpp b/src/display/curve.cpp index ae243853e..50f4c8954 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -34,7 +34,6 @@ SPCurve::SPCurve() : _refcount(1), _pathv() { - _pathv.clear(); } SPCurve::SPCurve(Geom::PathVector const& pathv) diff --git a/src/display/drawing-context.cpp b/src/display/drawing-context.cpp index de5beb0f6..319136e06 100644 --- a/src/display/drawing-context.cpp +++ b/src/display/drawing-context.cpp @@ -25,27 +25,27 @@ using Geom::Y; */ DrawingContext::Save::Save() - : _ct(NULL) + : _dc(NULL) {} -DrawingContext::Save::Save(DrawingContext &ct) - : _ct(&ct) +DrawingContext::Save::Save(DrawingContext &dc) + : _dc(&dc) { - _ct->save(); + _dc->save(); } DrawingContext::Save::~Save() { - if (_ct) { - _ct->restore(); + if (_dc) { + _dc->restore(); } } -void DrawingContext::Save::save(DrawingContext &ct) +void DrawingContext::Save::save(DrawingContext &dc) { - if (_ct) { + if (_dc) { // TODO: it might be better to treat this occurence as a bug - _ct->restore(); + _dc->restore(); } - _ct = &ct; - _ct->save(); + _dc = &dc; + _dc->save(); } /** diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index 35be9a86b..d990bcb73 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -31,11 +31,11 @@ public: class Save { public: Save(); - Save(DrawingContext &ct); + Save(DrawingContext &dc); ~Save(); - void save(DrawingContext &ct); + void save(DrawingContext &dc); private: - DrawingContext *_ct; + DrawingContext *_dc; }; DrawingContext(cairo_t *ct, Geom::Point const &origin); diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index b5ce18891..38ace001f 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -98,12 +98,12 @@ DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u } unsigned -DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { if (stop_at == NULL) { // normal rendering for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->render(ct, area, flags, stop_at); + i->render(dc, area, flags, stop_at); } } else { // background rendering @@ -111,11 +111,11 @@ DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne if (&*i == stop_at) return RENDER_OK; // do not render the stop_at item at all if (i->isAncestorOf(stop_at)) { // render its ancestors without masks, opacity or filters - i->render(ct, area, flags | RENDER_FILTER_BACKGROUND, stop_at); + i->render(dc, area, flags | RENDER_FILTER_BACKGROUND, stop_at); // stop further rendering return RENDER_OK; } else { - i->render(ct, area, flags, stop_at); + i->render(dc, area, flags, stop_at); } } } @@ -123,10 +123,10 @@ DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne } void -DrawingGroup::_clipItem(DrawingContext &ct, Geom::IntRect const &area) +DrawingGroup::_clipItem(DrawingContext &dc, Geom::IntRect const &area) { for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->clip(ct, area); + i->clip(dc, area); } } diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h index 775fec8c4..651e9d8af 100644 --- a/src/display/drawing-group.h +++ b/src/display/drawing-group.h @@ -34,9 +34,9 @@ public: protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + virtual unsigned _renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at); - virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual void _clipItem(DrawingContext &dc, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 1b9214c49..5844c8b08 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -102,22 +102,22 @@ DrawingImage::_updateItem(Geom::IntRect const &, UpdateContext const &, unsigned return STATE_ALL; } -unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) +unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) { bool outline = _drawing.outline(); if (!outline) { if (!_pixbuf) return RENDER_OK; - Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); - ct.newPath(); - ct.rectangle(_clipbox); - ct.clip(); + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + dc.newPath(); + dc.rectangle(_clipbox); + dc.clip(); - ct.translate(_origin); - ct.scale(_scale); - ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); + dc.translate(_origin); + dc.scale(_scale); + dc.setSource(_pixbuf->getSurfaceRaw(), 0, 0); if (_style) { // See: http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty @@ -128,24 +128,25 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar // Do nothing break; case SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY: - ct.patternSetFilter( CAIRO_FILTER_BEST ); + // In recent Cairo, BEST used Lanczos3, which is prohibitively slow + dc.patternSetFilter( CAIRO_FILTER_GOOD ); break; case SP_CSS_COLOR_RENDERING_OPTIMIZESPEED: default: - ct.patternSetFilter( CAIRO_FILTER_NEAREST ); + dc.patternSetFilter( CAIRO_FILTER_NEAREST ); break; } } - ct.paint(_opacity); + dc.paint(_opacity); } else { // outline; draw a rect instead Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint32 rgba = prefs->getInt("/options/wireframecolors/images", 0xff0000ff); - { Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); - ct.newPath(); + { Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + dc.newPath(); Geom::Rect r = bounds(); Geom::Point c00 = r.corner(0); @@ -153,21 +154,21 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar Geom::Point c11 = r.corner(2); Geom::Point c10 = r.corner(1); - ct.moveTo(c00); + dc.moveTo(c00); // the box - ct.lineTo(c10); - ct.lineTo(c11); - ct.lineTo(c01); - ct.lineTo(c00); + dc.lineTo(c10); + dc.lineTo(c11); + dc.lineTo(c01); + dc.lineTo(c00); // the diagonals - ct.lineTo(c11); - ct.moveTo(c10); - ct.lineTo(c01); + dc.lineTo(c11); + dc.moveTo(c10); + dc.lineTo(c01); } - ct.setLineWidth(0.5); - ct.setSource(rgba); - ct.stroke(); + dc.setLineWidth(0.5); + dc.setSource(rgba); + dc.stroke(); } return RENDER_OK; } diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index cebaafc85..64e4517b0 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -38,7 +38,7 @@ public: protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + virtual unsigned _renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index a9b07bb6e..ccf905e81 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -24,60 +24,60 @@ namespace Inkscape { #ifdef WITH_CSSBLEND -void set_cairo_blend_operator( DrawingContext &ct, unsigned blend_mode ) { +void set_cairo_blend_operator( DrawingContext &dc, unsigned blend_mode ) { // All of the blend modes are implemented in Cairo as of 1.10. // For a detailed description, see: // http://cairographics.org/operators/ switch (blend_mode) { case SP_CSS_BLEND_MULTIPLY: - ct.setOperator(CAIRO_OPERATOR_MULTIPLY); + dc.setOperator(CAIRO_OPERATOR_MULTIPLY); break; case SP_CSS_BLEND_SCREEN: - ct.setOperator(CAIRO_OPERATOR_SCREEN); + dc.setOperator(CAIRO_OPERATOR_SCREEN); break; case SP_CSS_BLEND_DARKEN: - ct.setOperator(CAIRO_OPERATOR_DARKEN); + dc.setOperator(CAIRO_OPERATOR_DARKEN); break; case SP_CSS_BLEND_LIGHTEN: - ct.setOperator(CAIRO_OPERATOR_LIGHTEN); + dc.setOperator(CAIRO_OPERATOR_LIGHTEN); break; case SP_CSS_BLEND_OVERLAY: - ct.setOperator(CAIRO_OPERATOR_OVERLAY); + dc.setOperator(CAIRO_OPERATOR_OVERLAY); break; case SP_CSS_BLEND_COLORDODGE: - ct.setOperator(CAIRO_OPERATOR_COLOR_DODGE); + dc.setOperator(CAIRO_OPERATOR_COLOR_DODGE); break; case SP_CSS_BLEND_COLORBURN: - ct.setOperator(CAIRO_OPERATOR_COLOR_BURN); + dc.setOperator(CAIRO_OPERATOR_COLOR_BURN); break; case SP_CSS_BLEND_HARDLIGHT: - ct.setOperator(CAIRO_OPERATOR_HARD_LIGHT); + dc.setOperator(CAIRO_OPERATOR_HARD_LIGHT); break; case SP_CSS_BLEND_SOFTLIGHT: - ct.setOperator(CAIRO_OPERATOR_SOFT_LIGHT); + dc.setOperator(CAIRO_OPERATOR_SOFT_LIGHT); break; case SP_CSS_BLEND_DIFFERENCE: - ct.setOperator(CAIRO_OPERATOR_DIFFERENCE); + dc.setOperator(CAIRO_OPERATOR_DIFFERENCE); break; case SP_CSS_BLEND_EXCLUSION: - ct.setOperator(CAIRO_OPERATOR_EXCLUSION); + dc.setOperator(CAIRO_OPERATOR_EXCLUSION); break; case SP_CSS_BLEND_HUE: - ct.setOperator(CAIRO_OPERATOR_HSL_HUE); + dc.setOperator(CAIRO_OPERATOR_HSL_HUE); break; case SP_CSS_BLEND_SATURATION: - ct.setOperator(CAIRO_OPERATOR_HSL_SATURATION); + dc.setOperator(CAIRO_OPERATOR_HSL_SATURATION); break; case SP_CSS_BLEND_COLOR: - ct.setOperator(CAIRO_OPERATOR_HSL_COLOR); + dc.setOperator(CAIRO_OPERATOR_HSL_COLOR); break; case SP_CSS_BLEND_LUMINOSITY: - ct.setOperator(CAIRO_OPERATOR_HSL_LUMINOSITY); + dc.setOperator(CAIRO_OPERATOR_HSL_LUMINOSITY); break; case SP_CSS_BLEND_NORMAL: default: - ct.setOperator(CAIRO_OPERATOR_OVER); + dc.setOperator(CAIRO_OPERATOR_OVER); break; } } @@ -127,6 +127,7 @@ DrawingItem::DrawingItem(Drawing &drawing) , _propagate(0) // , _renders_opacity(0) , _pick_children(0) + , _antialias(1) , _isolation(SP_CSS_ISOLATION_AUTO) , _blend_mode(SP_CSS_BLEND_NORMAL) {} @@ -229,6 +230,8 @@ DrawingItem::prependChild(DrawingItem *item) void DrawingItem::clearChildren() { + if (_children.empty()) return; + _markForRendering(); // prevent children from referencing the parent during deletion // this way, children won't try to remove themselves from a list @@ -266,8 +269,19 @@ DrawingItem::setTransform(Geom::Affine const &new_trans) void DrawingItem::setOpacity(float opacity) { - _opacity = opacity; - _markForRendering(); + if (_opacity != opacity) { + _opacity = opacity; + _markForRendering(); + } +} + +void +DrawingItem::setAntialiasing(bool a) +{ + if (_antialias != a) { + _antialias = a; + _markForRendering(); + } } void @@ -289,8 +303,10 @@ DrawingItem::setBlendMode(unsigned blend_mode) void DrawingItem::setVisible(bool v) { - _visible = v; - _markForRendering(); + if (_visible != v) { + _visible = v; + _markForRendering(); + } } /// This is currently unused @@ -545,7 +561,7 @@ struct MaskLuminanceToAlpha { * @param flags Rendering options. This deals mainly with cache control. */ unsigned -DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { bool outline = _drawing.outline(); bool render_filters = _drawing.renderFilters(); @@ -560,7 +576,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // TODO convert outline rendering to a separate virtual function if (outline) { - _renderOutline(ct, area, flags); + _renderOutline(dc, area, flags); return RENDER_OK; } @@ -568,14 +584,20 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag Geom::OptIntRect carea = Geom::intersect(area, _drawbox); if (!carea) return RENDER_OK; + if (_antialias) { + cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_DEFAULT); + } else { + cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_NONE); + } + // render from cache if possible if (_cached) { if (_cache) { _cache->prepare(); #ifdef WITH_CSSBLEND - set_cairo_blend_operator( ct, _blend_mode ); + set_cairo_blend_operator( dc, _blend_mode ); #endif - _cache->paintFromCache(ct, carea); + _cache->paintFromCache(dc, carea); if (!carea) return RENDER_OK; } else { // There is no cache. This could be because caching of this item @@ -625,7 +647,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // filters and opacity do not apply when rendering the ancestors of the filtered // element if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { - return _renderItem(ct, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); + return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } // iarea is the bounding box for intermediate rendering @@ -688,9 +710,9 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag } if (bg_root) { DrawingSurface bg(*iarea); - DrawingContext bgct(bg); - bg_root->render(bgct, *iarea, flags | RENDER_FILTER_BACKGROUND, this); - _filter->render(this, ict, &bgct); + DrawingContext bgdc(bg); + bg_root->render(bgdc, *iarea, flags | RENDER_FILTER_BACKGROUND, this); + _filter->render(this, ict, &bgdc); rendered = true; } } @@ -716,20 +738,20 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag cachect.fill(); _cache->markClean(*carea); } - ct.rectangle(*carea); - ct.setSource(&intermediate); + dc.rectangle(*carea); + dc.setSource(&intermediate); #ifdef WITH_CSSBLEND - set_cairo_blend_operator( ct, _blend_mode ); + set_cairo_blend_operator( dc, _blend_mode ); #endif - ct.fill(); - ct.setSource(0,0,0,0); - // the call above is to clear a ref on the intermediate surface held by ct + dc.fill(); + dc.setSource(0,0,0,0); + // the call above is to clear a ref on the intermediate surface held by dc return render_result; } void -DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +DrawingItem::_renderOutline(DrawingContext &dc, Geom::IntRect const &area, unsigned flags) { // intersect with bbox rather than drawbox, as we want to render things outside // of the clipping path as well @@ -738,7 +760,7 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig // just render everything: item, clip, mask // First, render the object itself - _renderItem(ct, *carea, flags, NULL); + _renderItem(dc, *carea, flags, NULL); // render clip and mask, if any guint32 saved_rgba = _drawing.outlinecolor; // save current outline color @@ -746,12 +768,12 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (_clip) { _drawing.outlinecolor = prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff); // green clips - _clip->render(ct, *carea, flags); + _clip->render(dc, *carea, flags); } // render mask as an object, using a different color if (_mask) { _drawing.outlinecolor = prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); // blue masks - _mask->render(ct, *carea, flags); + _mask->render(dc, *carea, flags); } _drawing.outlinecolor = saved_rgba; // restore outline color } @@ -765,31 +787,31 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig * of render() for details. */ void -DrawingItem::clip(Inkscape::DrawingContext &ct, Geom::IntRect const &area) +DrawingItem::clip(Inkscape::DrawingContext &dc, Geom::IntRect const &area) { // don't bother if the object does not implement clipping (e.g. DrawingImage) if (!_canClip()) return; if (!_visible) return; if (!area.intersects(_bbox)) return; - ct.setSource(0,0,0,1); - ct.pushGroup(); + dc.setSource(0,0,0,1); + dc.pushGroup(); // rasterize the clipping path - _clipItem(ct, area); + _clipItem(dc, area); if (_clip) { // 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 - ct.pushGroup(); - _clip->clip(ct, area); - ct.popGroupToSource(); - ct.setOperator(CAIRO_OPERATOR_IN); - ct.paint(); + dc.pushGroup(); + _clip->clip(dc, area); + dc.popGroupToSource(); + dc.setOperator(CAIRO_OPERATOR_IN); + dc.paint(); } - ct.popGroupToSource(); - ct.setOperator(CAIRO_OPERATOR_OVER); - ct.paint(); - ct.setSource(0,0,0,0); + dc.popGroupToSource(); + dc.setOperator(CAIRO_OPERATOR_OVER); + dc.paint(); + dc.setSource(0,0,0,0); } /** diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 1796d29d6..db803cf60 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -108,6 +108,7 @@ public: void setCached(bool c, bool persistent = false); void setOpacity(float opacity); + void setAntialiasing(bool a); void setIsolation(unsigned isolation); // CSS Compositing and Blending void setBlendMode(unsigned blend_mode); void setTransform(Geom::Affine const &trans); @@ -123,8 +124,8 @@ public: void *data() const { return _user_data; } void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = STATE_ALL, unsigned reset = 0); - unsigned render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0, DrawingItem *stop_at = NULL); - void clip(DrawingContext &ct, Geom::IntRect const &area); + unsigned render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags = 0, DrawingItem *stop_at = NULL); + void clip(DrawingContext &dc, Geom::IntRect const &area); DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags = 0); protected: @@ -141,7 +142,7 @@ protected: RENDER_OK = 0, RENDER_STOP = 1 }; - void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + void _renderOutline(DrawingContext &dc, Geom::IntRect const &area, unsigned flags); void _markForUpdate(unsigned state, bool propagate); void _markForRendering(); void _invalidateFilterBackground(Geom::IntRect const &area); @@ -150,9 +151,9 @@ protected: Geom::OptIntRect _cacheRect(); virtual unsigned _updateItem(Geom::IntRect const &/*area*/, UpdateContext const &/*ctx*/, unsigned /*flags*/, unsigned /*reset*/) { return 0; } - virtual unsigned _renderItem(DrawingContext &/*ct*/, Geom::IntRect const &/*area*/, unsigned /*flags*/, + virtual unsigned _renderItem(DrawingContext &/*dc*/, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) { return RENDER_OK; } - virtual void _clipItem(DrawingContext &/*ct*/, Geom::IntRect const &/*area*/) {} + virtual void _clipItem(DrawingContext &/*dc*/, Geom::IntRect const &/*area*/) {} virtual DrawingItem *_pickItem(Geom::Point const &/*p*/, double /*delta*/, unsigned /*flags*/) { return NULL; } virtual bool _canClip() { return false; } @@ -205,6 +206,7 @@ protected: //unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(), /// otherwise the group is returned + unsigned _antialias : 1; ///< Whether to use antialiasing unsigned _isolation : 1; unsigned _blend_mode : 4; diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index e80f12486..92d71fad3 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -12,7 +12,7 @@ #include <glib.h> #include <2geom/curves.h> #include <2geom/pathvector.h> -#include <2geom/svg-path.h> +#include <2geom/path-sink.h> #include <2geom/svg-path-parser.h> #include "display/cairo-utils.h" @@ -149,8 +149,53 @@ DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u return STATE_ALL; } +#ifdef WITH_SVG2 +void +DrawingShape::_renderFill(DrawingContext &dc) +{ + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + + bool has_fill = _nrstyle.prepareFill(dc, _item_bbox); + + if( has_fill ) { + dc.path(_curve->get_pathvector()); + _nrstyle.applyFill(dc); + dc.fillPreserve(); + dc.newPath(); // clear path + } +} + +void +DrawingShape::_renderStroke(DrawingContext &dc) +{ + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + + bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox); + has_stroke &= (_nrstyle.stroke_width != 0); + + if( has_stroke ) { + // TODO: remove segments outside of bbox when no dashes present + dc.path(_curve->get_pathvector()); + _nrstyle.applyStroke(dc); + dc.strokePreserve(); + dc.newPath(); // clear path + } +} +#endif + +void +DrawingShape::_renderMarkers(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +{ + // marker rendering + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->render(dc, area, flags, stop_at); + } +} + unsigned -DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) +DrawingShape::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { if (!_curve || !_style) return RENDER_OK; if (!area.intersects(_bbox)) return RENDER_OK; // skip if not within bounding box @@ -160,67 +205,96 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne if (outline) { guint32 rgba = _drawing.outlinecolor; - { Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); - ct.path(_curve->get_pathvector()); + // paint-order doesn't matter + { Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + dc.path(_curve->get_pathvector()); } - { Inkscape::DrawingContext::Save save(ct); - ct.setSource(rgba); - ct.setLineWidth(0.5); - ct.setTolerance(0.5); - ct.stroke(); + { Inkscape::DrawingContext::Save save(dc); + dc.setSource(rgba); + dc.setLineWidth(0.5); + dc.setTolerance(0.5); + dc.stroke(); } - } else { - bool has_stroke, has_fill; - // we assume the context has no path - Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); - - // update fill and stroke paints. - // this cannot be done during nr_arena_shape_update, because we need a Cairo context - // to render svg:pattern - has_fill = _nrstyle.prepareFill(ct, _item_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); - has_stroke &= (_nrstyle.stroke_width != 0); - - if (has_fill || has_stroke) { - // TODO: remove segments outside of bbox when no dashes present - ct.path(_curve->get_pathvector()); - if (has_fill) { - _nrstyle.applyFill(ct); - ct.fillPreserve(); - } - if (has_stroke) { - _nrstyle.applyStroke(ct); - ct.strokePreserve(); - } - ct.newPath(); // clear path - } // has fill or stroke pattern + + _renderMarkers(dc, area, flags, stop_at); + return RENDER_OK; + } - // marker rendering - for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->render(ct, area, flags, stop_at); +#ifdef WITH_SVG2 + if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL ) { + // This is the most common case, special case so we don't call get_pathvector(), etc. twice +#endif + { + // we assume the context has no path + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + + // update fill and stroke paints. + // this cannot be done during nr_arena_shape_update, because we need a Cairo context + // to render svg:pattern + bool has_fill = _nrstyle.prepareFill(dc, _item_bbox); + bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox); + has_stroke &= (_nrstyle.stroke_width != 0); + + if (has_fill || has_stroke) { + // TODO: remove segments outside of bbox when no dashes present + dc.path(_curve->get_pathvector()); + if (has_fill) { + _nrstyle.applyFill(dc); + dc.fillPreserve(); + } + if (has_stroke) { + _nrstyle.applyStroke(dc); + dc.strokePreserve(); + } + dc.newPath(); // clear path + } // has fill or stroke pattern + } + _renderMarkers(dc, area, flags, stop_at); + return RENDER_OK; + +#ifdef WITH_SVG2 + } + + // Handle different paint orders + for (unsigned i = 0; i < NRStyle::PAINT_ORDER_LAYERS; ++i) { + switch (_nrstyle.paint_order_layer[i]) { + case NRStyle::PAINT_ORDER_FILL: + _renderFill(dc); + break; + case NRStyle::PAINT_ORDER_STROKE: + _renderStroke(dc); + break; + case NRStyle::PAINT_ORDER_MARKER: + _renderMarkers(dc, area, flags, stop_at); + break; + default: + // PAINT_ORDER_AUTO Should not happen + break; + } } return RENDER_OK; +#endif } -void DrawingShape::_clipItem(DrawingContext &ct, Geom::IntRect const & /*area*/) +void DrawingShape::_clipItem(DrawingContext &dc, Geom::IntRect const & /*area*/) { if (!_curve) return; - Inkscape::DrawingContext::Save save(ct); + Inkscape::DrawingContext::Save save(dc); // handle clip-rule if (_style) { if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); + dc.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); } else { - ct.setFillRule(CAIRO_FILL_RULE_WINDING); + dc.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ct.transform(_ctm); - ct.path(_curve->get_pathvector()); - ct.fill(); + dc.transform(_ctm); + dc.path(_curve->get_pathvector()); + dc.fill(); } DrawingItem * diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 52496d86e..405c789e0 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -33,12 +33,19 @@ public: protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + virtual unsigned _renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at); - virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual void _clipItem(DrawingContext &dc, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); +#ifdef WITH_SVG2 + void _renderFill(DrawingContext &dc); + void _renderStroke(DrawingContext &dc); +#endif + void _renderMarkers(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); + SPCurve *_curve; SPStyle *_style; NRStyle _nrstyle; diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index bddccbd96..d2540de66 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -123,7 +123,7 @@ DrawingSurface::scale() const Geom::Affine DrawingSurface::drawingTransform() const { - Geom::Affine ret = _scale * Geom::Translate(-_origin); + Geom::Affine ret = Geom::Translate(-_origin) * _scale; return ret; } @@ -215,7 +215,7 @@ DrawingCache::prepare() bool is_identity = _pending_transform.isIdentity(); if (is_identity && _pending_area == old_area) return; // no change - bool is_integer_translation = false; + bool is_integer_translation = is_identity; if (!is_identity && _pending_transform.isTranslation()) { Geom::IntPoint t = _pending_transform.translation().round(); if (Geom::are_near(Geom::Point(t), _pending_transform.translation())) { @@ -224,6 +224,7 @@ DrawingCache::prepare() if (old_area + t == _pending_area) { // if the areas match, the only thing to do // is to ensure that the clean area is not too large + // we can exit early cairo_rectangle_int_t limit = _convertRect(_pending_area); cairo_region_intersect_rectangle(_clean_region, &limit); _origin += t; @@ -232,33 +233,36 @@ DrawingCache::prepare() } } } - // otherwise, we need to transform the cache + + // the area has changed, so the cache content needs to be copied Geom::IntPoint old_origin = old_area.min(); cairo_surface_t *old_surface = _surface; _surface = NULL; _pixels = _pending_area.dimensions(); _origin = _pending_area.min(); - cairo_t *ct = createRawContext(); - if (!is_identity) { - ink_cairo_transform(ct, _pending_transform); - } - cairo_set_source_surface(ct, old_surface, old_origin[X], old_origin[Y]); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); - - cairo_surface_destroy(old_surface); - cairo_destroy(ct); + if (is_integer_translation) { + // transform the cache only for integer translations and identities + cairo_t *ct = createRawContext(); + if (!is_identity) { + ink_cairo_transform(ct, _pending_transform); + } + cairo_set_source_surface(ct, old_surface, old_origin[X], old_origin[Y]); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_pattern_set_filter(cairo_get_source(ct), CAIRO_FILTER_NEAREST); + cairo_paint(ct); + cairo_destroy(ct); - if (!is_identity && !is_integer_translation) { + cairo_rectangle_int_t limit = _convertRect(_pending_area); + cairo_region_intersect_rectangle(_clean_region, &limit); + } else { // dirty everything cairo_region_destroy(_clean_region); _clean_region = cairo_region_create(); - } else { - cairo_rectangle_int_t limit = _convertRect(_pending_area); - cairo_region_intersect_rectangle(_clean_region, &limit); } + //std::cout << _pending_transform << old_area << _pending_area << std::endl; + cairo_surface_destroy(old_surface); _pending_transform.setIdentity(); } @@ -267,7 +271,7 @@ DrawingCache::prepare() * parameter to the bounds of the region that must be repainted. */ void -DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area) +DrawingCache::paintFromCache(DrawingContext &dc, Geom::OptIntRect &area) { if (!area) return; @@ -296,10 +300,10 @@ DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area) cairo_rectangle_int_t tmp; for (int i = 0; i < nr; ++i) { cairo_region_get_rectangle(cache_region, i, &tmp); - ct.rectangle(_convertRect(tmp)); + dc.rectangle(_convertRect(tmp)); } - ct.setSource(this); - ct.fill(); + dc.setSource(this); + dc.fill(); } cairo_region_destroy(cache_region); } @@ -310,21 +314,21 @@ DrawingCache::_dumpCache(Geom::OptIntRect const &area) { static int dumpnr = 0; cairo_surface_t *surface = ink_cairo_surface_copy(_surface); - DrawingContext ct(surface, _origin); + DrawingContext dc(surface, _origin); if (!cairo_region_is_empty(_clean_region)) { - Inkscape::DrawingContext::Save save(ct); + Inkscape::DrawingContext::Save save(dc); int nr = cairo_region_num_rectangles(_clean_region); cairo_rectangle_int_t tmp; for (int i = 0; i < nr; ++i) { cairo_region_get_rectangle(_clean_region, i, &tmp); - ct.rectangle(_convertRect(tmp)); + dc.rectangle(_convertRect(tmp)); } - ct.setSource(0,1,0,0.1); - ct.fill(); + dc.setSource(0,1,0,0.1); + dc.fill(); } - ct.rectangle(*area); - ct.setSource(1,0,0,0.1); - ct.fill(); + dc.rectangle(*area); + dc.setSource(1,0,0,0.1); + dc.fill(); char *fn = g_strdup_printf("dump%d.png", dumpnr++); cairo_surface_write_to_png(surface, fn); cairo_surface_destroy(surface); diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index 1ec848405..e937cca55 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -65,7 +65,7 @@ public: void markClean(Geom::IntRect const &area = Geom::IntRect::infinite()); void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); void prepare(); - void paintFromCache(DrawingContext &ct, Geom::OptIntRect &area); + void paintFromCache(DrawingContext &dc, Geom::OptIntRect &area); protected: cairo_region_t *_clean_region; diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index f652a2970..a280e221a 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -195,7 +195,7 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } -void DrawingText::decorateStyle(DrawingContext &ct, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2) +void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2) { double wave[16]={ 0.000000, 0.382499, 0.706825, 0.923651, 1.000000, 0.923651, 0.706825, 0.382499, @@ -235,12 +235,12 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_ISDOUBLE){ ps -= Geom::Point(0, vextent/12.0); pf -= Geom::Point(0, vextent/12.0); - ct.moveTo(ps); - ct.lineTo(pf); + dc.moveTo(ps); + dc.lineTo(pf); ps += Geom::Point(0, vextent/6.0); pf += Geom::Point(0, vextent/6.0); - ct.moveTo(ps); - ct.lineTo(pf); + dc.moveTo(ps); + dc.lineTo(pf); } /* The next three have a problem in that they are phase dependent. The bits of a line are not necessarily passing through this routine in order, so we have to use the xphase information @@ -251,14 +251,14 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); while(1){ if(dots[i]>0){ if(ps[Geom::X]> pf[Geom::X])break; - ct.moveTo(ps); + dc.moveTo(ps); ps += Geom::Point(step * (double)dots[i], 0.0); if(ps[Geom::X]>= pf[Geom::X]){ - ct.lineTo(pf); + dc.lineTo(pf); break; } else { - ct.lineTo(ps); + dc.lineTo(ps); } ps += Geom::Point(step * 4.0, 0.0); } @@ -272,14 +272,14 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); while(1){ if(dashes[i]>0){ if(ps[Geom::X]> pf[Geom::X])break; - ct.moveTo(ps); + dc.moveTo(ps); ps += Geom::Point(step * (double)dashes[i], 0.0); if(ps[Geom::X]>= pf[Geom::X]){ - ct.lineTo(pf); + dc.lineTo(pf); break; } else { - ct.lineTo(ps); + dc.lineTo(ps); } ps += Geom::Point(step * 8.0, 0.0); } @@ -293,23 +293,23 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); double amp = vextent/10.0; double x = ps[Geom::X]; double y = ps[Geom::Y]; - ct.moveTo(Geom::Point(x, y + amp * wave[i])); + dc.moveTo(Geom::Point(x, y + amp * wave[i])); while(1){ i = ((i + 1) & 15); x += step; - ct.lineTo(Geom::Point(x, y + amp * wave[i])); + dc.lineTo(Geom::Point(x, y + amp * wave[i])); if(x >= pf[Geom::X])break; } } else { // TEXT_DECORATION_STYLE_SOLID, also default in case it was not set for some reason - ct.moveTo(ps); - ct.lineTo(pf); -// ct.revrectangle(Geom::Rect(ps,pf)); + dc.moveTo(ps); + dc.lineTo(pf); +// dc.revrectangle(Geom::Rect(ps,pf)); } } /* returns scaled line thickness */ -double DrawingText::decorateItem(DrawingContext &ct, Geom::Affine const &aff, double phase_length) +double DrawingText::decorateItem(DrawingContext &dc, Geom::Affine const &aff, double phase_length) { double tsp_width_adj = _nrstyle.tspan_width / _nrstyle.font_size; double tsp_asc_adj = _nrstyle.ascender / _nrstyle.font_size; @@ -321,8 +321,8 @@ double DrawingText::decorateItem(DrawingContext &ct, Geom::Affine const &aff, do double scale = aff.descrim(); double xphase = phase_length/ _nrstyle.font_size; // used to figure out phase of patterns - Inkscape::DrawingContext::Save save(ct); - ct.transform(aff); // must be leftmost affine in span + Inkscape::DrawingContext::Save save(dc); + dc.transform(aff); // must be leftmost affine in span Geom::Point p1; Geom::Point p2; @@ -331,52 +331,52 @@ double DrawingText::decorateItem(DrawingContext &ct, Geom::Affine const &aff, do if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_UNDERLINE){ p1 = Geom::Point(0.0, -_nrstyle.underline_position); p2 = Geom::Point(tsp_width_adj,-_nrstyle.underline_position); - decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2); } if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_OVERLINE){ p1 = Geom::Point(0.0, tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); p2 = Geom::Point(tsp_width_adj,tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); - decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2); } if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_LINETHROUGH){ thickness = final_line_through_thickness; p1 = Geom::Point(0.0, _nrstyle.line_through_position); p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position); - decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2); } // Obviously this does not blink, but it does indicate which text has been set with that attribute if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_BLINK){ thickness = final_line_through_thickness; p1 = Geom::Point(0.0, _nrstyle.line_through_position - 2*final_line_through_thickness); p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position - 2*final_line_through_thickness); - decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2); p1 = Geom::Point(0.0, _nrstyle.line_through_position + 2*final_line_through_thickness); p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position + 2*final_line_through_thickness); - decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2); } thickness *= scale; return(thickness); } -unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) +unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) { if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; - Inkscape::DrawingContext::Save save(ct); - ct.setSource(rgba); - ct.setTolerance(0.5); // low quality, but good enough for outline mode + Inkscape::DrawingContext::Save save(dc); + dc.setSource(rgba); + dc.setTolerance(0.5); // low quality, but good enough for outline mode for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); if (!g) throw InvalidItemException(); - Inkscape::DrawingContext::Save save(ct); + Inkscape::DrawingContext::Save save(dc); // skip glyphs with singular transforms if (g->_ctm.isSingular()) continue; - ct.transform(g->_ctm); + dc.transform(g->_ctm); if(g->_drawable){ - ct.path(*g->_font->PathVector(g->_glyph)); - ct.fill(); + dc.path(*g->_font->PathVector(g->_glyph)); + dc.fill(); } } return RENDER_OK; @@ -398,11 +398,11 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are // Therefore, only apply this ctm temporarily. bool has_stroke, has_fill; { - Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); - has_fill = _nrstyle.prepareFill( ct, _item_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); + has_fill = _nrstyle.prepareFill( dc, _item_bbox); + has_stroke = _nrstyle.prepareStroke(dc, _item_bbox); } if (has_fill || has_stroke) { @@ -418,11 +418,11 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are invset = true; } - Inkscape::DrawingContext::Save save(ct); + Inkscape::DrawingContext::Save save(dc); if (g->_ctm.isSingular()) continue; - ct.transform(g->_ctm); + dc.transform(g->_ctm); if (g->_drawable) { - ct.path(*g->_font->PathVector(g->_glyph)); + dc.path(*g->_font->PathVector(g->_glyph)); } // get the leftmost affine transform (leftmost defined with respect to the x axis of the first transform). // That way the decoration will work no matter what mix of L->R, R->L text is in the span. @@ -448,17 +448,36 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are // draw the text itself // we need to apply this object's ctm again - Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + +#ifdef WITH_SVG2 + // Text doesn't have markers, we can do paint-order quick and dirty. + bool fill_first = false; + if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL || + _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_FILL || + _nrstyle.paint_order_layer[2] == NRStyle::PAINT_ORDER_STROKE ) { + fill_first = true; + } // Won't get "stroke fill stroke" but that isn't 'valid' + + if (has_fill && fill_first) { +#else if (has_fill) { - _nrstyle.applyFill(ct); - ct.fillPreserve(); +#endif + _nrstyle.applyFill(dc); + dc.fillPreserve(); } if (has_stroke) { - _nrstyle.applyStroke(ct); - ct.strokePreserve(); + _nrstyle.applyStroke(dc); + dc.strokePreserve(); } - ct.newPath(); // clear path +#ifdef WITH_SVG2 + if (has_fill && !fill_first) { + _nrstyle.applyFill(dc); + dc.fillPreserve(); + } +#endif + dc.newPath(); // clear path // draw text decoration if (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR && decorate) { @@ -477,27 +496,27 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are _nrstyle.fill.color.v.c[2], 1.0); } - ct.setSource(ergba); - ct.setTolerance(0.5); - double thickness = decorateItem(ct, aff, phase_length); - ct.setLineWidth(thickness); - ct.strokePreserve(); - ct.newPath(); // clear path + dc.setSource(ergba); + dc.setTolerance(0.5); + double thickness = decorateItem(dc, aff, phase_length); + dc.setLineWidth(thickness); + dc.strokePreserve(); + dc.newPath(); // clear path } } return RENDER_OK; } -void DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &/*area*/) +void DrawingText::_clipItem(DrawingContext &dc, Geom::IntRect const &/*area*/) { - Inkscape::DrawingContext::Save save(ct); + Inkscape::DrawingContext::Save save(dc); // handle clip-rule if (_style) { if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); + dc.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); } else { - ct.setFillRule(CAIRO_FILL_RULE_WINDING); + dc.setFillRule(CAIRO_FILL_RULE_WINDING); } } @@ -507,13 +526,13 @@ void DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &/*area*/) throw InvalidItemException(); } - Inkscape::DrawingContext::Save save(ct); - ct.transform(g->_ctm); + Inkscape::DrawingContext::Save save(dc); + dc.transform(g->_ctm); if(g->_drawable){ - ct.path(*g->_font->PathVector(g->_glyph)); + dc.path(*g->_font->PathVector(g->_glyph)); } } - ct.fill(); + dc.fill(); } DrawingItem * diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index fd122b54b..b863ca2a4 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -62,14 +62,14 @@ public: protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + virtual unsigned _renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at); - virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); + virtual void _clipItem(DrawingContext &dc, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); - double decorateItem(DrawingContext &ct, Geom::Affine const &aff, double phase_length); - void decorateStyle(DrawingContext &ct, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2); + double decorateItem(DrawingContext &dc, Geom::Affine const &aff, double phase_length); + void decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2); NRStyle _nrstyle; friend class DrawingGlyphs; diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index c192e4565..6e728b03d 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -167,22 +167,22 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl } void -Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +Drawing::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags) { if (_root) { - _root->render(ct, area, flags); + _root->render(dc, area, flags); } if (colorMode() == COLORMODE_GRAYSCALE) { // apply grayscale filter on top of everything - cairo_surface_t *input = ct.rawTarget(); + cairo_surface_t *input = dc.rawTarget(); cairo_surface_t *out = ink_cairo_surface_create_identical(input); ink_cairo_surface_filter(input, out, _grayscale_colormatrix); - Geom::Point origin = ct.targetLogicalBounds().min(); - ct.setSource(out, origin[Geom::X], origin[Geom::Y]); - ct.setOperator(CAIRO_OPERATOR_SOURCE); - ct.paint(); - ct.setOperator(CAIRO_OPERATOR_OVER); + Geom::Point origin = dc.targetLogicalBounds().min(); + dc.setSource(out, origin[Geom::X], origin[Geom::Y]); + dc.setOperator(CAIRO_OPERATOR_SOURCE); + dc.paint(); + dc.setOperator(CAIRO_OPERATOR_OVER); cairo_surface_destroy(out); } diff --git a/src/display/drawing.h b/src/display/drawing.h index 74ab57fae..cc74833ba 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -68,7 +68,7 @@ public: void setGrayscaleMatrix(gdouble value_matrix[20]); void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0); - void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); + void render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags = 0); DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags); sigc::signal<void, DrawingItem *> signal_request_update; diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp index 3bc00d2d7..dd90193fe 100644 --- a/src/display/nr-filter-component-transfer.cpp +++ b/src/display/nr-filter-component-transfer.cpp @@ -254,16 +254,21 @@ void FilterComponentTransfer::render_cairo(FilterSlot &slot) // parameters: R = 0, G = 1, B = 2, A = 3 // Cairo: R = 2, G = 1, B = 0, A = 3 + // If tableValues is empty, use identity. for (unsigned i = 0; i < 3; ++i) { guint32 color = 2 - i; switch (type[i]) { case COMPONENTTRANSFER_TYPE_TABLE: - ink_cairo_surface_filter(out, out, - ComponentTransferTable<false>(color, tableValues[i])); + if(!tableValues[i].empty()) { + ink_cairo_surface_filter(out, out, + ComponentTransferTable<false>(color, tableValues[i])); + } break; case COMPONENTTRANSFER_TYPE_DISCRETE: - ink_cairo_surface_filter(out, out, - ComponentTransferDiscrete<false>(color, tableValues[i])); + if(!tableValues[i].empty()) { + ink_cairo_surface_filter(out, out, + ComponentTransferDiscrete<false>(color, tableValues[i])); + } break; case COMPONENTTRANSFER_TYPE_LINEAR: ink_cairo_surface_filter(out, out, @@ -284,12 +289,16 @@ void FilterComponentTransfer::render_cairo(FilterSlot &slot) // fast paths for alpha channel switch (type[3]) { case COMPONENTTRANSFER_TYPE_TABLE: - ink_cairo_surface_filter(out, out, - ComponentTransferTable<true>(tableValues[3])); + if(!tableValues[3].empty()) { + ink_cairo_surface_filter(out, out, + ComponentTransferTable<true>(tableValues[3])); + } break; case COMPONENTTRANSFER_TYPE_DISCRETE: - ink_cairo_surface_filter(out, out, - ComponentTransferDiscrete<true>(tableValues[3])); + if(!tableValues[3].empty()) { + ink_cairo_surface_filter(out, out, + ComponentTransferDiscrete<true>(tableValues[3])); + } break; case COMPONENTTRANSFER_TYPE_LINEAR: ink_cairo_surface_filter(out, out, diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index b96e24cbc..24960af78 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -568,12 +568,21 @@ void FilterGaussian::render_cairo(FilterSlot &slot) return; } - Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + // Handle bounding box case. + double dx = _deviation_x; + double dy = _deviation_y; + if( slot.get_units().get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) { + Geom::OptRect const bbox = slot.get_units().get_item_bbox(); + if( bbox ) { + dx *= (*bbox).width(); + dy *= (*bbox).height(); + } + } - int w_orig = ink_cairo_surface_get_width(in); - int h_orig = ink_cairo_surface_get_height(in); - double deviation_x_orig = _deviation_x * trans.expansionX(); - double deviation_y_orig = _deviation_y * trans.expansionY(); + Geom::Affine trans = slot.get_units().get_matrix_user2pb(); + + double deviation_x_orig = dx * trans.expansionX(); + double deviation_y_orig = dy * trans.expansionY(); cairo_format_t fmt = cairo_image_surface_get_format(in); int bytes_per_pixel = 0; switch (fmt) { @@ -595,6 +604,8 @@ void FilterGaussian::render_cairo(FilterSlot &slot) int x_step = 1 << _effect_subsample_step_log2(deviation_x_orig, quality); int y_step = 1 << _effect_subsample_step_log2(deviation_y_orig, quality); bool resampling = x_step > 1 || y_step > 1; + int w_orig = ink_cairo_surface_get_width(in); + int h_orig = ink_cairo_surface_get_height(in); int w_downsampled = resampling ? static_cast<int>(ceil(static_cast<double>(w_orig)/x_step))+1 : w_orig; int h_downsampled = resampling ? static_cast<int>(ceil(static_cast<double>(h_orig)/y_step))+1 : h_orig; double deviation_x = deviation_x_orig / x_step; diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 92bb9dcaa..179ba0e0a 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -108,17 +108,17 @@ 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()); - Inkscape::DrawingContext ct(out, sa.min()); - ct.transform(user2pb); // we are now in primitive units - ct.translate(feImageX, feImageY); -// ct.scale(scaleX, scaleY); No scaling should be done + Inkscape::DrawingContext dc(out, sa.min()); + dc.transform(user2pb); // we are now in primitive units + dc.translate(feImageX, feImageY); +// dc.scale(scaleX, scaleY); No scaling should be done Geom::IntRect render_rect = area.roundOutwards(); - ct.translate(render_rect.min()); +// dc.translate(render_rect.min()); This seems incorrect // Update to renderable state drawing.update(render_rect); - drawing.render(ct, render_rect); + drawing.render(dc, render_rect); SVGElem->invoke_hide(key); // For the moment, we'll assume that any image is in sRGB color space @@ -174,7 +174,8 @@ void FilterImage::render_cairo(FilterSlot &slot) sa.width(), sa.height()); // For the moment, we'll assume that any image is in sRGB color space - set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB); + // set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB); + // This seemed like a sensible thing to do but it breaks filters-displace-01-f.svg cairo_t *ct = cairo_create(out); cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]); diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp index 01d6ffe56..af1081abe 100644 --- a/src/display/nr-filter-offset.cpp +++ b/src/display/nr-filter-offset.cpp @@ -40,8 +40,20 @@ void FilterOffset::render_cairo(FilterSlot &slot) cairo_t *ct = cairo_create(out); - Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); - Geom::Point offset(dx, dy); + // Handle bounding box case + double x = dx; + double y = dy; + if( slot.get_units().get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) { + Geom::OptRect bbox = slot.get_units().get_item_bbox(); + if( bbox ) { + x *= (*bbox).width(); + y *= (*bbox).height(); + } + } + + Geom::Affine trans = slot.get_units().get_matrix_user2pb(); + + Geom::Point offset(x, y); offset *= trans; offset[X] -= trans[4]; offset[Y] -= trans[5]; diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 95d5d4b09..b065ac445 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -121,30 +121,10 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) fa = *fa_opt; } - // This is definitely a hack... but what else to do? - // Current viewport might not be document viewport... but how to find? - SPDocument* document = inkscape_active_document(); - SPRoot* root = document->getRoot(); - Geom::Rect viewport; - if( root->viewBox_set ) { - viewport = root->viewBox; - } else { - // Pick some random values - viewport = Geom::Rect::from_xywh(0,0,480,360); - } - - /* Update computed values for ex, em, %. For %, assumes primitive unit is objectBoundingBox. */ - /* TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. */ - double len_x = bb.width(); - double len_y = bb.height(); - _subregion_x.update(12, 6, len_x); - _subregion_y.update(12, 6, len_y); - _subregion_width.update(12, 6, len_x); - _subregion_height.update(12, 6, len_y); // x, y, width, and height are independently defined (i.e. one can be defined, by default, to - // the filter area while another is defined relative to the bounding box). It is better to keep - // track of them separately and then compose the Rect at the end. + // the filter area (via default value ) while another is defined relative to the bounding + // box). It is better to keep track of them separately and then compose the Rect at the end. double x = 0; double y = 0; double width = 0; @@ -157,10 +137,21 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) if( !_subregion_height._set ) height = fa.height(); if( units.get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) { + + // Update computed values for ex, em, %. + // For %, assumes primitive unit is objectBoundingBox. + // TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. + double len_x = bb.width(); + double len_y = bb.height(); + _subregion_x.update(12, 6, len_x); + _subregion_y.update(12, 6, len_y); + _subregion_width.update(12, 6, len_x); + _subregion_height.update(12, 6, len_y); + // Values are in terms of fraction of bounding box. if( _subregion_x._set && (_subregion_x.unit != SVGLength::PERCENT) ) x = bb.min()[X] + bb.width() * _subregion_x.value; if( _subregion_y._set && (_subregion_y.unit != SVGLength::PERCENT) ) y = bb.min()[Y] + bb.height() * _subregion_y.value; - if( _subregion_width._set && (_subregion_width.unit != SVGLength::PERCENT) ) width = bb.width() * _subregion_width.value; + if( _subregion_width._set && (_subregion_width.unit != SVGLength::PERCENT) ) width = bb.width() * _subregion_width.value; if( _subregion_height._set && (_subregion_height.unit != SVGLength::PERCENT) ) height = bb.height() * _subregion_height.value; // Values are in terms of percent if( _subregion_x._set && (_subregion_x.unit == SVGLength::PERCENT) ) x = bb.min()[X] + _subregion_x.computed; @@ -168,17 +159,11 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) if( _subregion_width._set && (_subregion_width.unit == SVGLength::PERCENT) ) width = _subregion_width.computed; if( _subregion_height._set && (_subregion_height.unit == SVGLength::PERCENT) ) height = _subregion_height.computed; } else { - // Values are in terms of user space coordinates or percent of viewbox (yuck!), - // which is usually the size of SVG drawing. Default. - if( _subregion_x._set && (_subregion_x.unit != SVGLength::PERCENT) ) x = _subregion_x.computed; - if( _subregion_y._set && (_subregion_y.unit != SVGLength::PERCENT) ) y = _subregion_y.computed; - if( _subregion_width._set && (_subregion_width.unit != SVGLength::PERCENT) ) width = _subregion_width.computed; - if( _subregion_height._set && (_subregion_height.unit != SVGLength::PERCENT) ) height = _subregion_height.computed; - // Percent of viewport - if( _subregion_x._set && (_subregion_x.unit == SVGLength::PERCENT) ) x = _subregion_x.value * viewport.width(); - if( _subregion_y._set && (_subregion_y.unit == SVGLength::PERCENT) ) y = _subregion_y.value * viewport.height(); - if( _subregion_width._set && (_subregion_width.unit == SVGLength::PERCENT) ) width = _subregion_width.value * viewport.width(); - if( _subregion_height._set && (_subregion_height.unit == SVGLength::PERCENT) ) height = _subregion_height.value * viewport.height(); + // Values are in terms of user space coordinates or percent of viewport (already calculated in sp-filter-primitive.cpp). + if( _subregion_x._set ) x = _subregion_x.computed; + if( _subregion_y._set ) y = _subregion_y.computed; + if( _subregion_width._set ) width = _subregion_width.computed; + if( _subregion_height._set ) height = _subregion_height.computed; } return Geom::Rect (Geom::Point(x,y), Geom::Point(x + width, y + height)); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 755a30a74..e4c2f048e 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -25,13 +25,13 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(DrawingItem *item, DrawingContext *bgct, +FilterSlot::FilterSlot(DrawingItem *item, DrawingContext *bgdc, DrawingContext &graphic, FilterUnits const &u) : _item(item) , _source_graphic(graphic.rawTarget()) - , _background_ct(bgct ? bgct->raw() : NULL) + , _background_ct(bgdc ? bgdc->raw() : NULL) , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme - , _background_area(bgct ? bgct->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme + , _background_area(bgdc ? bgdc->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme , _units(u) , _last_out(NR_FILTER_SOURCEGRAPHIC) , filterquality(FILTER_QUALITY_BEST) diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 805027bfe..f3c98b8d9 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -28,7 +28,7 @@ namespace Filters { class FilterSlot { public: /** Creates a new FilterSlot object. */ - FilterSlot(DrawingItem *item, DrawingContext *bgct, + FilterSlot(DrawingItem *item, DrawingContext *bgdc, DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index e63b335d2..a2a8c5756 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -288,7 +288,7 @@ private: static double constexpr PerlinOffset = 4096.0; #else #if (__cplusplus < 201103L) - static double const PerlinOffset = 4096.0; + static double const PerlinOffset; #else static double constexpr PerlinOffset = 4096.0; #endif @@ -309,6 +309,10 @@ private: bool _fractalnoise; }; +#if !defined(CPP11) && __cplusplus < 201103L + double const TurbulenceGenerator::PerlinOffset = 4096.0; +#endif + FilterTurbulence::FilterTurbulence() : gen(new TurbulenceGenerator()) , XbaseFrequency(0) diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index af9c15cd8..90b233fbc 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -98,7 +98,7 @@ Filter::~Filter() } -int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct) +int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgdc) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic @@ -150,7 +150,7 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D } } - FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgct, graphic, units); + FilterSlot slot(const_cast<Inkscape::DrawingItem*>(item), bgdc, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -222,14 +222,19 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) { Geom::Point minp, maxp; - double len_x = bbox ? bbox->width() : 0; - double len_y = bbox ? bbox->height() : 0; - /* TODO: fetch somehow the object ex and em lengths */ - _region_x.update(12, 6, len_x); - _region_y.update(12, 6, len_y); - _region_width.update(12, 6, len_x); - _region_height.update(12, 6, len_y); + if (_filter_units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) { + + double len_x = bbox ? bbox->width() : 0; + double len_y = bbox ? bbox->height() : 0; + /* TODO: fetch somehow the object ex and em lengths */ + + // Update for em, ex, and % values + _region_x.update(12, 6, len_x); + _region_y.update(12, 6, len_y); + _region_width.update(12, 6, len_x); + _region_height.update(12, 6, len_y); + if (!bbox) return Geom::OptRect(); if (_region_x.unit == SVGLength::PERCENT) { @@ -254,7 +259,7 @@ Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) maxp[Y] = minp[Y] + _region_height.computed * len_y; } } else if (_filter_units == SP_FILTER_UNITS_USERSPACEONUSE) { - /* TODO: make sure bbox and fe region are in same coordinate system */ + // Region already set in sp-filter.cpp minp[X] = _region_x.computed; maxp[X] = minp[X] + _region_width.computed; minp[Y] = _region_y.computed; @@ -262,7 +267,9 @@ Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) } else { g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units"); } + Geom::OptRect area(minp, maxp); + // std::cout << "Filter::filter_effect_area: area: " << *area << std::endl; return area; } diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 5df38ffe9..f9dcf1d84 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -28,12 +28,12 @@ namespace Filters { class Filter { public: - /** Given background state from @a bgct and an intermediate rendering from the surface + /** Given background state from @a bgdc and an intermediate rendering from the surface * backing @a graphic, modify the contents of the surface backing @a graphic to represent * the results of filter rendering. @a bgarea and @a area specify bounding boxes * of both surfaces in world coordinates; Cairo contexts are assumed to be in default state * (0,0 = surface origin, no path, OVER operator) */ - int render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct); + int render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgdc); /** * Creates a new filter primitive under this filter object. diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 317f38635..125d0c6d6 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -68,7 +68,11 @@ NRStyle::NRStyle() , line_through_thickness(0) , line_through_position(0) , font_size(0) -{} +{ +#ifdef WITH_SVG2 + paint_order_layer[0] = PAINT_ORDER_NORMAL; +#endif +} NRStyle::~NRStyle() { @@ -148,18 +152,38 @@ void NRStyle::set(SPStyle *style) delete [] dash; } - n_dash = style->stroke_dash.n_dash; + n_dash = style->stroke_dasharray.values.size(); if (n_dash != 0) { - dash_offset = style->stroke_dash.offset; + dash_offset = style->stroke_dashoffset.value; dash = new double[n_dash]; for (unsigned int i = 0; i < n_dash; ++i) { - dash[i] = style->stroke_dash.dash[i]; + dash[i] = style->stroke_dasharray.values[i]; } } else { dash_offset = 0.0; dash = NULL; } + +#ifdef WITH_SVG2 + for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i) { + switch (style->paint_order.layer[i]) { + case SP_CSS_PAINT_ORDER_NORMAL: + paint_order_layer[i]=PAINT_ORDER_NORMAL; + break; + case SP_CSS_PAINT_ORDER_FILL: + paint_order_layer[i]=PAINT_ORDER_FILL; + break; + case SP_CSS_PAINT_ORDER_STROKE: + paint_order_layer[i]=PAINT_ORDER_STROKE; + break; + case SP_CSS_PAINT_ORDER_MARKER: + paint_order_layer[i]=PAINT_ORDER_MARKER; + break; + } + } +#endif + text_decoration_line = TEXT_DECORATION_LINE_CLEAR; if(style->text_decoration_line.inherit ){ text_decoration_line |= TEXT_DECORATION_LINE_INHERIT; } if(style->text_decoration_line.underline ){ text_decoration_line |= TEXT_DECORATION_LINE_UNDERLINE + TEXT_DECORATION_LINE_SET; } @@ -207,14 +231,14 @@ void NRStyle::set(SPStyle *style) update(); } -bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) +bool NRStyle::prepareFill(Inkscape::DrawingContext &dc, 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.raw(), paintbox, fill.opacity); - fill_pattern = fill.server->pattern_new(ct.raw(), paintbox, fill.opacity); + //fill_pattern = sp_paint_server_create_pattern(fill.server, dc.raw(), paintbox, fill.opacity); + fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity); } break; case PAINT_COLOR: { @@ -229,19 +253,19 @@ bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &pai return true; } -void NRStyle::applyFill(Inkscape::DrawingContext &ct) +void NRStyle::applyFill(Inkscape::DrawingContext &dc) { - ct.setSource(fill_pattern); - ct.setFillRule(fill_rule); + dc.setSource(fill_pattern); + dc.setFillRule(fill_rule); } -bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &paintbox) +bool NRStyle::prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) { if (!stroke_pattern) { switch (stroke.type) { case PAINT_SERVER: { - //stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), paintbox, stroke.opacity); - stroke_pattern = stroke.server->pattern_new(ct.raw(), paintbox, stroke.opacity); + //stroke_pattern = sp_paint_server_create_pattern(stroke.server, dc.raw(), paintbox, stroke.opacity); + stroke_pattern = stroke.server->pattern_new(dc.raw(), paintbox, stroke.opacity); } break; case PAINT_COLOR: { @@ -256,14 +280,14 @@ bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &p return true; } -void NRStyle::applyStroke(Inkscape::DrawingContext &ct) +void NRStyle::applyStroke(Inkscape::DrawingContext &dc) { - 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 + dc.setSource(stroke_pattern); + dc.setLineWidth(stroke_width); + dc.setLineCap(line_cap); + dc.setLineJoin(line_join); + dc.setMiterLimit(miter_limit); + cairo_set_dash(dc.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 8fd736cc3..717cda899 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -28,10 +28,10 @@ struct NRStyle { ~NRStyle(); void set(SPStyle *); - 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); + bool prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); + bool prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); + void applyFill(Inkscape::DrawingContext &dc); + void applyStroke(Inkscape::DrawingContext &dc); void update(); enum PaintType { @@ -68,6 +68,18 @@ struct NRStyle { cairo_pattern_t *fill_pattern; cairo_pattern_t *stroke_pattern; +#ifdef WITH_SVG2 + enum PaintOrderType { + PAINT_ORDER_NORMAL, + PAINT_ORDER_FILL, + PAINT_ORDER_STROKE, + PAINT_ORDER_MARKER + }; + + static const size_t PAINT_ORDER_LAYERS = 3; + PaintOrderType paint_order_layer[PAINT_ORDER_LAYERS]; +#endif + #define TEXT_DECORATION_LINE_CLEAR 0x00 #define TEXT_DECORATION_LINE_SET 0x01 #define TEXT_DECORATION_LINE_INHERIT 0x02 diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp index c350e4614..e6e427047 100644 --- a/src/display/sodipodi-ctrlrect.cpp +++ b/src/display/sodipodi-ctrlrect.cpp @@ -142,7 +142,18 @@ void CtrlRect::render(SPCanvasBuf *buf) ink_cairo_set_source_rgba32(buf->ct, _border_color); cairo_stroke(buf->ct); - if (_shadow_size > 0) { + if (_shadow_size == 1) { // highlight the border by drawing it in _shadow_color + if (_dashed) { + cairo_set_dash(buf->ct, dashes, 2, 4); + cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(), + area[X].max() - area[X].min(), area[Y].max() - area[Y].min()); + } else { + cairo_rectangle(buf->ct, -0.5 + area[X].min(), -0.5 + area[Y].min(), + area[X].max() - area[X].min(), area[Y].max() - area[Y].min()); + } + ink_cairo_set_source_rgba32(buf->ct, _shadow_color); + cairo_stroke(buf->ct); + } else if (_shadow_size > 1) { // fill the shadow ink_cairo_set_source_rgba32(buf->ct, _shadow_color); cairo_rectangle(buf->ct, 1 + area[X].max(), area[Y].min() + _shadow_size, _shadow_size, area[Y].max() - area[Y].min() + 1); // right shadow diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 455f628bc..6d903867b 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -35,7 +35,6 @@ #include "display/cairo-utils.h" #include "debug/gdk-event-latency-tracker.h" #include "desktop.h" -#include "sp-namedview.h" using Inkscape::Debug::GdkEventLatencyTracker; @@ -1387,8 +1386,13 @@ void SPCanvasImpl::realize(GtkWidget *widget) gdk_window_set_user_data (window, widget); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if ( prefs->getBool("/options/useextinput/value", true) ) + if (prefs->getBool("/options/useextinput/value", true)) { gtk_widget_set_events(widget, attributes.event_mask); +#if !GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_extension_events(widget, GDK_EXTENSION_EVENTS_ALL); + // TODO: Extension event stuff has been deprecated in GTK+ 3 +#endif + } #if !GTK_CHECK_VERSION(3,0,0) // This does nothing in GTK+ 3 @@ -1524,27 +1528,31 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) // Convert to world coordinates -- we have two cases because of different // offsets of the fields in the event structures. - // - GdkEvent ev = *event; + GdkEvent *ev = gdk_event_copy(event); - switch (ev.type) { + switch (ev->type) { case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - ev.crossing.x += canvas->x0; - ev.crossing.y += canvas->y0; + ev->crossing.x += canvas->x0; + ev->crossing.y += canvas->y0; break; case GDK_MOTION_NOTIFY: case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: - ev.motion.x += canvas->x0; - ev.motion.y += canvas->y0; + ev->motion.x += canvas->x0; + ev->motion.y += canvas->y0; break; default: break; } + // Block Undo and Redo while we drag /anything/ + if(event->type == GDK_BUTTON_PRESS && event->button.button == 1) + canvas->is_dragging = true; + else if(event->type == GDK_BUTTON_RELEASE) + canvas->is_dragging = false; // Choose where we send the event @@ -1588,12 +1596,14 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) while (item && !finished) { g_object_ref (item); - g_signal_emit (G_OBJECT (item), item_signals[ITEM_EVENT], 0, &ev, &finished); + g_signal_emit (G_OBJECT (item), item_signals[ITEM_EVENT], 0, ev, &finished); SPCanvasItem *parent = item->parent; g_object_unref (item); item = parent; } + gdk_event_free(ev); + return finished; } diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index b570b739e..72ae4b6bc 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -124,6 +124,7 @@ struct SPCanvas { SPCanvasItem *root; + bool is_dragging; double dx0; double dy0; int x0; diff --git a/src/display/sp-ctrlquadr.h b/src/display/sp-ctrlquadr.h index 9fdfd29b3..1dfb06456 100644 --- a/src/display/sp-ctrlquadr.h +++ b/src/display/sp-ctrlquadr.h @@ -12,9 +12,7 @@ * Released under GNU GPL */ -#include "sp-canvas.h" - - +#include <2geom/geom.h> #define SP_TYPE_CTRLQUADR (sp_ctrlquadr_get_type ()) #define SP_CTRLQUADR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CTRLQUADR, SPCtrlQuadr)) |
