diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-08-21 15:33:09 +0000 |
|---|---|---|
| committer | Krzysztof Kosinski <tweenk.pl@gmail.com> | 2011-08-21 15:33:09 +0000 |
| commit | 0fc028f7050c91bfdb1a50ba8cb6462b2bf03d57 (patch) | |
| tree | 1815a638b17050a590d36c2515121cf0d5dae129 /src/display | |
| parent | Fix rendering glitches appearing when filtered, cached groups have (diff) | |
| download | inkscape-0fc028f7050c91bfdb1a50ba8cb6462b2bf03d57.tar.gz inkscape-0fc028f7050c91bfdb1a50ba8cb6462b2bf03d57.zip | |
Filter background rendering now matches the SVG specification.
(bzr r10347.1.37)
Diffstat (limited to 'src/display')
| -rw-r--r-- | src/display/drawing-group.cpp | 25 | ||||
| -rw-r--r-- | src/display/drawing-group.h | 5 | ||||
| -rw-r--r-- | src/display/drawing-image.cpp | 7 | ||||
| -rw-r--r-- | src/display/drawing-image.h | 3 | ||||
| -rw-r--r-- | src/display/drawing-item.cpp | 112 | ||||
| -rw-r--r-- | src/display/drawing-item.h | 14 | ||||
| -rw-r--r-- | src/display/drawing-shape.cpp | 11 | ||||
| -rw-r--r-- | src/display/drawing-shape.h | 5 | ||||
| -rw-r--r-- | src/display/drawing-text.cpp | 7 | ||||
| -rw-r--r-- | src/display/drawing-text.h | 5 | ||||
| -rw-r--r-- | src/display/nr-filter-slot.cpp | 38 | ||||
| -rw-r--r-- | src/display/nr-filter-slot.h | 2 | ||||
| -rw-r--r-- | src/display/nr-filter.cpp | 56 | ||||
| -rw-r--r-- | src/display/nr-filter.h | 6 |
14 files changed, 170 insertions, 126 deletions
diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index d9a75925e..a678c3feb 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -95,12 +95,29 @@ DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u return beststate; } -void -DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingGroup::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { - for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->render(ct, area, flags); + if (stop_at == NULL) { + // normal rendering + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + i->render(ct, area, flags, stop_at); + } + } else { + // background rendering + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + if (&*i == stop_at) return RENDER_OK; // do not render the stop_at item at all + if (i->isAncestorOf(stop_at)) { + // render its ancestors without masks, opacity or filters + i->render(ct, area, flags | RENDER_FILTER_BACKGROUND, stop_at); + // stop further rendering + return RENDER_OK; + } else { + i->render(ct, area, flags, stop_at); + } + } } + return RENDER_OK; } void diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h index 377c0be39..961e5b9a3 100644 --- a/src/display/drawing-group.h +++ b/src/display/drawing-group.h @@ -32,9 +32,10 @@ public: void setChildTransform(Geom::Affine const &new_trans); protected: - unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 074393ab5..fa0402699 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -112,13 +112,13 @@ DrawingImage::_updateItem(Geom::IntRect const &, UpdateContext const &, unsigned return STATE_ALL; } -void -DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { bool outline = _drawing.outline(); if (!outline) { - if (!_pixbuf) return; + if (!_pixbuf) return RENDER_OK; Inkscape::DrawingContext::Save save(ct); ct.transform(_ctm); @@ -172,6 +172,7 @@ DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne ct.setSource(rgba); ct.stroke(); } + return RENDER_OK; } /** Calculates the closest distance from p to the segment a1-a2*/ diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index 9f758398b..300d6f0b5 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -37,7 +37,8 @@ public: protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); GdkPixbuf *_pixbuf; diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index c517b1bb5..a5496e999 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -123,6 +123,16 @@ DrawingItem::parent() const return _parent; } +/// Returns true if item is among the descendants. Will return false if item == this. +bool +DrawingItem::isAncestorOf(DrawingItem *item) const +{ + for (DrawingItem *i = item->_parent; i; i = i->_parent) { + if (i == this) return true; + } + return false; +} + void DrawingItem::appendChild(DrawingItem *item) { @@ -314,6 +324,16 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (!area.intersects(outline ? _bbox : _drawbox)) return; } + // compute which elements need an update + unsigned to_update = _state ^ flags; + + // this needs to be called before we recurse into children + if (to_update & STATE_BACKGROUND) { + _background_accumulate = _background_new; + if (_child_type == CHILD_NORMAL && _parent->_background_accumulate) + _background_accumulate = true; + } + UpdateContext child_ctx(ctx); if (_transform) { child_ctx.ctm = *_transform * ctx.ctm; @@ -322,14 +342,13 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne Geom::Affine ctm_change = _ctm.inverse() * child_ctx.ctm; _ctm = child_ctx.ctm; - // update _bbox - unsigned to_update = _state ^ flags; + // update _bbox and call this function for children _state = _updateItem(area, child_ctx, flags, reset); if (to_update & STATE_BBOX) { // compute drawbox - if (_filter && render_filters && _item_bbox) { - _drawbox = _filter->compute_drawbox(this, *_item_bbox); + if (_filter && render_filters) { + _drawbox = _filter->compute_drawbox(this, _item_bbox); } else { _drawbox = _bbox; } @@ -396,14 +415,6 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } } - if (to_update & STATE_BACKGROUND) { - // Update _background_accumulate flag - // The code below correctly passes information from _background_new down the tree - _background_accumulate = _background_new; - if (_child_type == CHILD_NORMAL && _parent->_background_accumulate) - _background_accumulate = true; - } - if (to_update & STATE_RENDER) { // now that we know drawbox, dirty the corresponding rect on canvas // unless filtered, groups do not need to render by themselves, only their members @@ -433,32 +444,36 @@ struct MaskLuminanceToAlpha { * * @param flags Rendering options. This deals mainly with cache control. */ -void -DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { bool outline = _drawing.outline(); bool render_filters = _drawing.renderFilters(); + // stop_at is handled in DrawingGroup, but this check is required to handle the case + // where a filtered item with background-accessing filter has enable-background: new + if (this == stop_at) return RENDER_STOP; + // If we are invisible, return immediately - if (!_visible) return; - if (_ctm.isSingular(NR_EPSILON)) return; + if (!_visible) return RENDER_OK; + if (_ctm.isSingular(NR_EPSILON)) return RENDER_OK; // TODO convert outline rendering to a separate virtual function if (outline) { _renderOutline(ct, area, flags); - return; + return RENDER_OK; } // carea is the area to paint Geom::OptIntRect carea = Geom::intersect(area, _drawbox); - if (!carea) return; + if (!carea) return RENDER_OK; // render from cache if possible if (_cached) { if (_cache) { _cache->prepare(); _cache->paintFromCache(ct, carea); - if (!carea) return; + if (!carea) return RENDER_OK; } else { // There is no cache. This could be because caching of this item // was just turned on after the last update phase, or because @@ -484,6 +499,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag nir |= (_mask != NULL); // 2. it has a mask nir |= (_filter != NULL && render_filters); // 3. it has a filter nir |= needs_opacity; // 4. it is non-opaque + nir |= (_cache != NULL); // 5. it is cached /* How the rendering is done. * @@ -497,33 +513,12 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag * to the opacity value. */ - // short-circuit the simple case. - if (!needs_intermediate_rendering) { - if (_cached && _cache) { - Inkscape::DrawingContext cachect(*_cache); - cachect.rectangle(*carea); - cachect.clip(); - - { // 1. clear the corresponding part of cache - Inkscape::DrawingContext::Save save(cachect); - cachect.setSource(0,0,0,0); - cachect.setOperator(CAIRO_OPERATOR_SOURCE); - cachect.paint(); - } - // 2. render to cache - _renderItem(cachect, *carea, flags); - // 3. copy from cache to output - Inkscape::DrawingContext::Save save(ct); - ct.rectangle(*carea); - ct.setSource(_cache); - ct.fill(); - // 4. mark as clean - _cache->markClean(*carea); - return; - } else { - _renderItem(ct, *carea, flags); - return; - } + // Short-circuit the simple case. + // We also use this path for filter background rendering, because masking, clipping, + // filters and opacity do not apply when rendering the ancestors of the filtered + // element + if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { + return _renderItem(ct, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } // iarea is the bounding box for intermediate rendering @@ -540,6 +535,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag DrawingSurface intermediate(*iarea); DrawingContext ict(intermediate); + unsigned render_result = RENDER_OK; // 1. Render clipping path with alpha = opacity. ict.setSource(0,0,0,_opacity); @@ -571,11 +567,27 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // 3. Render object itself ict.pushGroup(); - _renderItem(ict, *iarea, flags); + render_result = _renderItem(ict, *iarea, flags, stop_at); // 4. Apply filter. if (_filter && render_filters) { - _filter->render(this, ct, ict); + bool rendered = false; + if (_filter->uses_background() && _background_accumulate) { + DrawingItem *bg_root = this; + for (; bg_root; bg_root = bg_root->_parent) { + if (bg_root->_background_new) break; + } + if (bg_root) { + DrawingSurface bg(*iarea); + DrawingContext bgct(bg); + bg_root->render(bgct, *iarea, flags | RENDER_FILTER_BACKGROUND, this); + _filter->render(this, ict, &bgct); + rendered = true; + } + } + if (!rendered) { + _filter->render(this, ict, NULL); + } // Note that because the object was rendered to a group, // the internals of the filter need to use cairo_get_group_target() // instead of cairo_get_target(). @@ -600,6 +612,8 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag ct.fill(); ct.setSource(0,0,0,0); // the call above is to clear a ref on the intermediate surface held by ct + + return render_result; } void @@ -612,7 +626,7 @@ DrawingItem::_renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsig // just render everything: item, clip, mask // First, render the object itself - _renderItem(ct, *carea, flags); + _renderItem(ct, *carea, flags, NULL); // render clip and mask, if any guint32 saved_rgba = _drawing.outlinecolor; // save current outline color diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index abc69be02..7a3b8047b 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -54,7 +54,8 @@ public: enum RenderFlags { RENDER_DEFAULT = 0, RENDER_CACHE_ONLY = 1, - RENDER_BYPASS_CACHE = 2 + RENDER_BYPASS_CACHE = 2, + RENDER_FILTER_BACKGROUND = 4 }; enum StateFlags { STATE_NONE = 0, @@ -81,6 +82,7 @@ public: Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } Drawing &drawing() const { return _drawing; } DrawingItem *parent() const; + bool isAncestorOf(DrawingItem *item) const; void appendChild(DrawingItem *item); void prependChild(DrawingItem *item); @@ -106,7 +108,7 @@ public: void *data() const { return _user_data; } void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = STATE_ALL, unsigned reset = 0); - void render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0); + unsigned render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags = 0, DrawingItem *stop_at = NULL); void clip(DrawingContext &ct, Geom::IntRect const &area); DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags = 0); @@ -120,7 +122,10 @@ protected: CHILD_FILL_PATTERN = 5, // not yet implemented: referenced by fill pattern of parent CHILD_STROKE_PATTERN = 6 // not yet implemented: referenced by stroke pattern of parent }; - + enum RenderResult { + RENDER_OK = 0, + RENDER_STOP = 1 + }; void _renderOutline(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); void _markForUpdate(unsigned state, bool propagate); void _markForRendering(); @@ -130,7 +135,8 @@ protected: Geom::OptIntRect _cacheRect(); virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { return 0; } - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {} + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at) { return RENDER_OK; } virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area) {} virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags) { return NULL; } virtual bool _canClip() { return false; } diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index 1b201927f..cd7b9150d 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -157,11 +157,11 @@ DrawingShape::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u return STATE_ALL; } -void -DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { - if (!_curve || !_style) return; - if (!area.intersects(_bbox)) return; // skip if not within bounding box + if (!_curve || !_style) return RENDER_OK; + if (!area.intersects(_bbox)) return RENDER_OK; // skip if not within bounding box bool outline = _drawing.outline(); @@ -208,8 +208,9 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // marker rendering for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - i->render(ct, area, flags); + i->render(ct, area, flags, stop_at); } + return RENDER_OK; } void diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h index 2938d6397..122130590 100644 --- a/src/display/drawing-shape.h +++ b/src/display/drawing-shape.h @@ -32,9 +32,10 @@ public: void setPaintBox(Geom::Rect const &box); protected: - unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 5e6396df1..1134771bc 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -149,8 +149,8 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } -void -DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; @@ -169,7 +169,7 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned ct.path(*g->_font->PathVector(g->_glyph)); ct.fill(); } - return; + return RENDER_OK; } // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding @@ -199,6 +199,7 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned } ct.newPath(); // clear path } + return RENDER_OK; } void diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 07962365c..4f3940dde 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -53,9 +53,10 @@ public: void setPaintBox(Geom::OptRect const &box); protected: - unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, + virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); - virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags); + virtual unsigned _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, + DrawingItem *stop_at); virtual void _clipItem(DrawingContext &ct, Geom::IntRect const &area); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index d2f992859..4f7a8849e 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -25,13 +25,13 @@ namespace Inkscape { namespace Filters { -FilterSlot::FilterSlot(DrawingItem *item, DrawingContext &bgct, +FilterSlot::FilterSlot(DrawingItem *item, DrawingContext *bgct, DrawingContext &graphic, FilterUnits const &u) : _item(item) , _source_graphic(graphic.rawTarget()) - , _background_ct(bgct.raw()) + , _background_ct(bgct ? bgct->raw() : NULL) , _source_graphic_area(graphic.targetLogicalBounds().roundOutwards()) // fixme - , _background_area(bgct.targetLogicalBounds().roundOutwards()) // fixme + , _background_area(bgct ? bgct->targetLogicalBounds().roundOutwards() : Geom::IntRect()) // fixme , _units(u) , _last_out(NR_FILTER_SOURCEGRAPHIC) , filterquality(FILTER_QUALITY_BEST) @@ -152,19 +152,25 @@ cairo_surface_t *FilterSlot::_get_transformed_background() { Geom::Affine trans = _units.get_matrix_display2pb(); - cairo_surface_t *bg = cairo_get_group_target(_background_ct); - cairo_surface_t *tbg = cairo_surface_create_similar( - bg, cairo_surface_get_content(bg), - _slot_w, _slot_h); - cairo_t *tbg_ct = cairo_create(tbg); - - cairo_translate(tbg_ct, -_slot_x, -_slot_y); - ink_cairo_transform(tbg_ct, trans); - cairo_translate(tbg_ct, _background_area.left(), _background_area.top()); - cairo_set_source_surface(tbg_ct, bg, 0, 0); - cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(tbg_ct); - cairo_destroy(tbg_ct); + cairo_surface_t *tbg; + + if (_background_ct) { + cairo_surface_t *bg = cairo_get_group_target(_background_ct); + tbg = cairo_surface_create_similar( + bg, cairo_surface_get_content(bg), + _slot_w, _slot_h); + cairo_t *tbg_ct = cairo_create(tbg); + + cairo_translate(tbg_ct, -_slot_x, -_slot_y); + ink_cairo_transform(tbg_ct, trans); + cairo_translate(tbg_ct, _background_area.left(), _background_area.top()); + cairo_set_source_surface(tbg_ct, bg, 0, 0); + cairo_set_operator(tbg_ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(tbg_ct); + cairo_destroy(tbg_ct); + } else { + tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w, _slot_h); + } return tbg; } diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 1e7c3a5a6..d41b5180b 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -28,7 +28,7 @@ namespace Filters { class FilterSlot { public: /** Creates a new FilterSlot object. */ - FilterSlot(DrawingItem *item, DrawingContext &bgct, + FilterSlot(DrawingItem *item, DrawingContext *bgct, DrawingContext &graphic, FilterUnits const &u); /** Destroys the FilterSlot object and all its contents */ virtual ~FilterSlot(); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index ae50e641b..450ce689d 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -97,7 +97,7 @@ Filter::~Filter() } -int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic) +int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct) { if (_primitive.empty()) { // when no primitives are defined, clear source graphic @@ -113,28 +113,16 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &bgct, Draw Geom::Affine trans = item->ctm(); - Geom::Rect item_bbox; - { - Geom::OptRect maybe_bbox = item->itemBounds(); - if (maybe_bbox.isEmpty()) { - // Code below needs a bounding box - return 1; - } - item_bbox = *maybe_bbox; - } - if (item_bbox.hasZeroArea()) { - // It's no use to try and filter an empty object. - return 1; - } - Geom::Rect filter_area = filter_effect_area(item_bbox); + Geom::OptRect filter_area = filter_effect_area(item->itemBounds()); + if (!filter_area) return 1; FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); - units.set_item_bbox(item_bbox); - units.set_filter_area(filter_area); + units.set_item_bbox(item->itemBounds()); + units.set_filter_area(*filter_area); std::pair<double,double> resolution - = _filter_resolution(filter_area, trans, filterquality); + = _filter_resolution(*filter_area, trans, filterquality); if (!(resolution.first > 0 && resolution.second > 0)) { // zero resolution - clear source graphic and return graphic.setSource(0,0,0,0); @@ -228,30 +216,36 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item */ } -Geom::IntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox) { +Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) { - Geom::Rect enlarged = filter_effect_area(item_bbox); - enlarged *= item->ctm(); + Geom::OptRect enlarged = filter_effect_area(item_bbox); + if (enlarged) { + *enlarged *= item->ctm(); - Geom::IntRect ret(enlarged.roundOutwards()); - return ret; + Geom::OptIntRect ret(enlarged->roundOutwards()); + return ret; + } else { + return Geom::OptIntRect(); + } } -Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) +Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) { Geom::Point minp, maxp; - double len_x = bbox.width(); - double len_y = bbox.height(); + double len_x = bbox ? bbox->width() : 0; + double len_y = bbox ? bbox->height() : 0; /* TODO: fetch somehow the object ex and em lengths */ _region_x.update(12, 6, len_x); _region_y.update(12, 6, len_y); _region_width.update(12, 6, len_x); _region_height.update(12, 6, len_y); if (_filter_units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) { + if (!bbox) return Geom::OptRect(); + if (_region_x.unit == SVGLength::PERCENT) { - minp[X] = bbox.min()[X] + _region_x.computed; + minp[X] = bbox->left() + _region_x.computed; } else { - minp[X] = bbox.min()[X] + _region_x.computed * len_x; + minp[X] = bbox->left() + _region_x.computed * len_x; } if (_region_width.unit == SVGLength::PERCENT) { maxp[X] = minp[X] + _region_width.computed; @@ -260,9 +254,9 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) } if (_region_y.unit == SVGLength::PERCENT) { - minp[Y] = bbox.min()[Y] + _region_y.computed; + minp[Y] = bbox->top() + _region_y.computed; } else { - minp[Y] = bbox.min()[Y] + _region_y.computed * len_y; + minp[Y] = bbox->top() + _region_y.computed * len_y; } if (_region_height.unit == SVGLength::PERCENT) { maxp[Y] = minp[Y] + _region_height.computed; @@ -278,7 +272,7 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) } else { g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units"); } - Geom::Rect area(minp, maxp); + Geom::OptRect area(minp, maxp); return area; } diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index 87a0fae94..32e1df60b 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -34,7 +34,7 @@ public: * the results of filter rendering. @a bgarea and @a area specify bounding boxes * of both surfaces in world coordinates; Cairo contexts are assumed to be in default state * (0,0 = surface origin, no path, OVER operator) */ - int render(Inkscape::DrawingItem const *item, DrawingContext &bgct, DrawingContext &graphic); + int render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgct); /** * Creates a new filter primitive under this filter object. @@ -156,13 +156,13 @@ public: * to contain the filter effects region and transforms it to screen * coordinates */ - Geom::IntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::Rect const &item_bbox); + Geom::OptIntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in * SVG standard and in user coordinate system. */ - Geom::Rect filter_effect_area(Geom::Rect const &bbox); + Geom::OptRect filter_effect_area(Geom::OptRect const &bbox); // returns cache score factor double complexity(Geom::Affine const &ctm); |
