summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-08-21 15:33:09 +0000
committerKrzysztof Kosinski <tweenk.pl@gmail.com>2011-08-21 15:33:09 +0000
commit0fc028f7050c91bfdb1a50ba8cb6462b2bf03d57 (patch)
tree1815a638b17050a590d36c2515121cf0d5dae129 /src/display
parentFix rendering glitches appearing when filtered, cached groups have (diff)
downloadinkscape-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.cpp25
-rw-r--r--src/display/drawing-group.h5
-rw-r--r--src/display/drawing-image.cpp7
-rw-r--r--src/display/drawing-image.h3
-rw-r--r--src/display/drawing-item.cpp112
-rw-r--r--src/display/drawing-item.h14
-rw-r--r--src/display/drawing-shape.cpp11
-rw-r--r--src/display/drawing-shape.h5
-rw-r--r--src/display/drawing-text.cpp7
-rw-r--r--src/display/drawing-text.h5
-rw-r--r--src/display/nr-filter-slot.cpp38
-rw-r--r--src/display/nr-filter-slot.h2
-rw-r--r--src/display/nr-filter.cpp56
-rw-r--r--src/display/nr-filter.h6
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);