summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-08-09 01:14:07 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2011-08-09 01:14:07 +0000
commitf336c94939e9740501835b2584ad9a3160ac6d51 (patch)
tree8ceebf2af7ffbca62e9ada0f4d3f56bf71ba783d /src
parentRewrite NRArena -> Inkscape::Drawing. Call render and update (diff)
downloadinkscape-f336c94939e9740501835b2584ad9a3160ac6d51.tar.gz
inkscape-f336c94939e9740501835b2584ad9a3160ac6d51.zip
Initial autocache work
(bzr r10347.1.26)
Diffstat (limited to 'src')
-rw-r--r--src/display/canvas-arena.cpp2
-rw-r--r--src/display/drawing-item.cpp146
-rw-r--r--src/display/drawing-item.h22
-rw-r--r--src/display/drawing-surface.cpp47
-rw-r--r--src/display/drawing-surface.h5
-rw-r--r--src/display/drawing.cpp45
-rw-r--r--src/display/drawing.h29
-rw-r--r--src/display/nr-filter-blend.cpp5
-rw-r--r--src/display/nr-filter-blend.h1
-rw-r--r--src/display/nr-filter-colormatrix.cpp5
-rw-r--r--src/display/nr-filter-colormatrix.h1
-rw-r--r--src/display/nr-filter-component-transfer.cpp5
-rw-r--r--src/display/nr-filter-component-transfer.h1
-rw-r--r--src/display/nr-filter-composite.cpp5
-rw-r--r--src/display/nr-filter-composite.h1
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp5
-rw-r--r--src/display/nr-filter-convolve-matrix.h1
-rw-r--r--src/display/nr-filter-diffuselighting.cpp5
-rw-r--r--src/display/nr-filter-diffuselighting.h1
-rw-r--r--src/display/nr-filter-displacement-map.cpp5
-rw-r--r--src/display/nr-filter-displacement-map.h6
-rw-r--r--src/display/nr-filter-flood.cpp7
-rw-r--r--src/display/nr-filter-flood.h5
-rw-r--r--src/display/nr-filter-gaussian.cpp7
-rw-r--r--src/display/nr-filter-gaussian.h1
-rw-r--r--src/display/nr-filter-image.cpp6
-rw-r--r--src/display/nr-filter-image.h2
-rw-r--r--src/display/nr-filter-merge.cpp5
-rw-r--r--src/display/nr-filter-merge.h1
-rw-r--r--src/display/nr-filter-morphology.cpp7
-rw-r--r--src/display/nr-filter-morphology.h2
-rw-r--r--src/display/nr-filter-offset.cpp5
-rw-r--r--src/display/nr-filter-offset.h1
-rw-r--r--src/display/nr-filter-primitive.cpp4
-rw-r--r--src/display/nr-filter-primitive.h32
-rw-r--r--src/display/nr-filter-specularlighting.cpp135
-rw-r--r--src/display/nr-filter-specularlighting.h2
-rw-r--r--src/display/nr-filter-tile.cpp5
-rw-r--r--src/display/nr-filter-tile.h1
-rw-r--r--src/display/nr-filter-turbulence.cpp5
-rw-r--r--src/display/nr-filter-turbulence.h1
-rw-r--r--src/display/nr-filter.cpp12
-rw-r--r--src/display/nr-filter.h3
43 files changed, 367 insertions, 225 deletions
diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp
index 6026ebd3f..b254a55c8 100644
--- a/src/display/canvas-arena.cpp
+++ b/src/display/canvas-arena.cpp
@@ -105,7 +105,7 @@ sp_canvas_arena_init (SPCanvasArena *arena)
Inkscape::DrawingGroup *root = new DrawingGroup(arena->drawing);
root->setPickChildren(true);
- root->setCached(true);
+ root->setCached(true, true);
arena->drawing.setRoot(root);
arena->drawing.signal_request_update.connect(
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 47f6c55a1..3f409b8ee 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -9,6 +9,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <climits>
#include "display/cairo-utils.h"
#include "display/cairo-templates.h"
#include "display/drawing.h"
@@ -29,7 +30,7 @@ namespace Inkscape {
* portion of the SVG document. Typically this is created by the SP tree,
* in particular the show() virtual function.
*
- * @section ObjectLifetime Object Lifetime
+ * @section ObjectLifetime Object lifetime
* Deleting a DrawingItem will cause all of its children to be deleted as well.
* This can lead to nasty surprises if you hold references to things
* which are children of what is being deleted. Therefore, in the SP tree,
@@ -38,7 +39,7 @@ namespace Inkscape {
* - this will cause dangling pointers inside the SPItem and lead to a crash.
* Use the corresponing hide() method.
*
- * Outside of the SP tree you should not use any references after the root node
+ * Outside of the SP tree, you should not use any references after the root node
* has been deleted.
*/
@@ -57,6 +58,8 @@ DrawingItem::DrawingItem(Drawing &drawing)
, _visible(true)
, _sensitive(true)
, _cached(0)
+ , _cached_persistent(0)
+ , _has_cache_iterator(0)
, _propagate(0)
// , _renders_opacity(0)
, _clip_child(0)
@@ -77,6 +80,9 @@ DrawingItem::~DrawingItem()
if (_cached) {
_drawing._cached_items.erase(this);
}
+ if (_has_cache_iterator) {
+ _drawing._candidate_items.erase(_cache_iterator);
+ }
// remove this item from parent's children list
// due to the effect of clearChildren(), this only happens for the top-level deleted item
if (_parent) {
@@ -182,17 +188,27 @@ DrawingItem::setSensitive(bool s)
_sensitive = s;
}
-/// Enable / disable storing the rendering in memory.
+/** @brief Enable / disable storing the rendering in memory.
+ * Calling setCached(false, true) will also remove the persistent status
+ */
void
-DrawingItem::setCached(bool c)
+DrawingItem::setCached(bool cached, bool persistent)
{
- _cached = c;
- if (c) {
+ static const char *cache_env = getenv("_INKSCAPE_DISABLE_CACHE");
+ if (cache_env) return;
+
+ if (_cached_persistent && !persistent)
+ return;
+
+ _cached = cached;
+ _cached_persistent = persistent ? cached : false;
+ if (cached) {
_drawing._cached_items.insert(this);
} else {
_drawing._cached_items.erase(this);
+ delete _cache;
+ _cache = NULL;
}
- _markForUpdate(STATE_CACHE, false);
}
void
@@ -277,7 +293,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne
}
_state &= ~reset; // reset state of this item
- if ((~_state & flags) == 0) return; // nothing to do
+ if ((~_state & flags) == 0) return; // nothing to do
// TODO this might be wrong
if (_state & STATE_BBOX) {
@@ -323,20 +339,40 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne
}
}
- // update cache if enabled
- if (_cached) {
- Geom::OptIntRect cl = _drawing.cacheLimit();
- cl.intersectWith(_drawbox);
- if (cl) {
- if (_cache) {
- // this takes care of invalidation on transform
- _cache->resizeAndTransform(*cl, ctm_change);
- } else {
- _cache = new Inkscape::DrawingCache(*cl);
- // the cache is initially dirty
- }
+ // Update cache score for this item
+ if (_has_cache_iterator) {
+ // remove old score information
+ _drawing._candidate_items.erase(_cache_iterator);
+ _has_cache_iterator = false;
+ }
+ double score = _cacheScore();
+ if (score >= _drawing._cache_score_threshold) {
+ CacheRecord cr;
+ cr.score = score;
+ // if _cacheRect() is empty, a negative score will be returnedfrom _cacheScore(),
+ // so this will not execute (cache score threshold must be positive)
+ cr.cache_size = _cacheRect()->area() * 4;
+ cr.item = this;
+ _drawing._candidate_items.push_back(cr);
+ _cache_iterator = --_drawing._candidate_items.end();
+ _has_cache_iterator = true;
+ }
+
+ /* Update cache if enabled.
+ * General note: here we only tell the cache how it has to transform
+ * during the render phase. The transformation is deferred because
+ * after the update the item can have its caching turned off,
+ * e.g. because its filter was removed. This way we avoid tempoerarily
+ * using more memory than the cache budget */
+ if (_cache) {
+ Geom::OptIntRect cl = _cacheRect();
+ if (_visible && cl) { // never create cache for invisible items
+ // this takes care of invalidation on transform
+ _cache->scheduleTransform(*cl, ctm_change);
} else {
- // disable cache for this item - not visible
+ // Destroy cache for this item - outside of canvas or invisible.
+ // The opposite transition (invisible -> visible or object
+ // entering the canvas) is handled during the render phase
delete _cache;
_cache = NULL;
}
@@ -377,9 +413,10 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
bool outline = _drawing.outline();
bool render_filters = _drawing.renderFilters();
- /* If we are invisible, just return successfully */
+ // If we are invisible, return immediately
if (!_visible) return;
+ // TODO convert outline rendering to a separate virtual function
if (outline) {
_renderOutline(ct, area, flags);
return;
@@ -389,10 +426,25 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
if (!carea) return;
- // render from cache
- if (_cached && _cache) {
- if (_cache->paintFromCache(ct, *carea))
- return;
+ // render from cache if possible
+ if (_cached) {
+ if (_cache) {
+ _cache->prepare();
+ if (_cache->paintFromCache(ct, *carea))
+ return;
+ } else {
+ // There is no cache. This could be because caching of this item
+ // was just turned on after the last update phase, or because
+ // we are outside of the canvas.
+ Geom::OptIntRect cl = _drawing.cacheLimit();
+ cl.intersectWith(_drawbox);
+ if (cl) {
+ _cache = new DrawingCache(*cl);
+ }
+ }
+ } else {
+ // if our caching was turned off after the last update, it was already
+ // deleted in setCached()
}
// expand carea to contain the dependent area of filters.
@@ -695,6 +747,48 @@ DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style)
&& style->enable_background.value == SP_CSS_BACKGROUND_NEW) {
_background_new = true;
}*/
+
+ // TODO: STATE_ALL unsets too much
+ _markForUpdate(STATE_ALL, false);
+}
+
+double
+DrawingItem::_cacheScore()
+{
+ Geom::OptIntRect cache_rect = _cacheRect();
+ if (!cache_rect) return -1.0;
+
+ // a crude first approximation:
+ // the basic score is the number of pixels in the drawbox
+ double score = cache_rect->area();
+ // this is multiplied by the filter complexity and its expansion
+ if (_filter &&_drawing.renderFilters()) {
+ score *= _filter->complexity(_ctm);
+ Geom::IntRect ref_area = Geom::IntRect::from_xywh(0, 0, 16, 16);
+ Geom::IntRect test_area = ref_area;
+ Geom::IntRect limit_area(0, INT_MIN, 16, INT_MAX);
+ _filter->area_enlarge(test_area, this);
+ // area_enlarge never shrinks the rect, so the result of intersection below
+ // must be non-empty
+ score *= double((test_area & limit_area)->area()) / ref_area.area();
+ }
+ // if the object is clipped, add 1/2 of its bbox pixels
+ if (_clip && _clip->_bbox) {
+ score += _clip->_bbox->area() * 0.5;
+ }
+ // if masked, add mask score
+ if (_mask) {
+ score += _mask->_cacheScore();
+ }
+ g_message("caching score: %f", score);
+ return score;
+}
+
+Geom::OptIntRect
+DrawingItem::_cacheRect()
+{
+ Geom::OptIntRect r = _drawbox & _drawing.cacheLimit();
+ return r;
}
} // end namespace Inkscape
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index ba0c42695..b934570f2 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -12,7 +12,9 @@
#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
#define SEEN_INKSCAPE_DISPLAY_DRAWING_ITEM_H
+#include <list>
#include <exception>
+#include <boost/operators.hpp>
#include <boost/utility.hpp>
#include <boost/intrusive/list.hpp>
#include <2geom/rect.h>
@@ -27,6 +29,18 @@ struct UpdateContext {
Geom::Affine ctm;
};
+struct CacheRecord
+ : boost::totally_ordered<CacheRecord>
+{
+ bool operator<(CacheRecord const &other) const { return score < other.score; }
+ bool operator==(CacheRecord const &other) const { return score == other.score; }
+ operator DrawingItem *() const { return item; }
+ double score;
+ size_t cache_size;
+ DrawingItem *item;
+};
+typedef std::list<CacheRecord> CacheList;
+
class InvalidItemException : public std::exception {
virtual const char *what() const throw() {
return "Invalid item in drawing";
@@ -72,7 +86,7 @@ public:
bool sensitive() const { return _sensitive; }
void setSensitive(bool v);
bool cached() const { return _cached; }
- void setCached(bool c);
+ void setCached(bool c, bool persistent = false);
void setOpacity(float opacity);
void setTransform(Geom::Affine const &trans);
@@ -96,6 +110,8 @@ protected:
void _markForUpdate(unsigned state, bool propagate);
void _markForRendering();
void _setStyleCommon(SPStyle *&_style, SPStyle *style);
+ double _cacheScore();
+ Geom::OptIntRect _cacheRect();
virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
unsigned flags, unsigned reset) { return 0; }
virtual void _renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) {}
@@ -133,10 +149,14 @@ protected:
void *_user_data; ///< Used to associate DrawingItems with SPItems that created them
DrawingCache *_cache;
+ CacheList::iterator _cache_iterator;
+
unsigned _state : 8;
unsigned _visible : 1;
unsigned _sensitive : 1; ///< Whether this item responds to events
unsigned _cached : 1; ///< Whether the rendering is stored for reuse
+ unsigned _cached_persistent : 1; ///< If set, will always be cached regardless of score
+ unsigned _has_cache_iterator : 1; ///< If set, _cache_list_pos is valid
unsigned _propagate : 1; ///< Whether to call update for all children on next update
//unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity
unsigned _clip_child : 1; ///< If set, this is not a child of _parent, but a clipping path
diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp
index 28bdc1f3c..1faa3151e 100644
--- a/src/display/drawing-surface.cpp
+++ b/src/display/drawing-surface.cpp
@@ -9,6 +9,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <iostream>
#include "display/drawing-surface.h"
#include "display/drawing-context.h"
#include "display/cairo-utils.h"
@@ -165,6 +166,7 @@ DrawingSurface::pixelArea() const
DrawingCache::DrawingCache(Geom::IntRect const &area)
: DrawingSurface(area)
, _clean_region(cairo_region_create())
+ , _pending_area(area)
{}
DrawingCache::~DrawingCache()
@@ -196,28 +198,41 @@ DrawingCache::isClean(Geom::IntRect const &area) const
return false;
}
}
+
+/// Call this during the update phase to schedule a transformation of the cache.
+void
+DrawingCache::scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans)
+{
+ if (new_area.hasZeroArea() && trans.isIdentity()) return;
+ _pending_area = new_area;
+ _pending_transform *= trans;
+}
+
+/// Transforms the cache according to the transform specified during the update phase.
+/// Call this during render phase, before painting.
void
-DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine const &trans)
+DrawingCache::prepare()
{
Geom::IntRect old_area = pixelArea();
- bool is_identity = false;
- bool is_integer_translation = false;
- if (trans.isIdentity()) {
- is_identity = true;
- if (new_area == old_area) return;
+ bool is_identity = _pending_transform.isIdentity();
+ if (is_identity) {
+ if (_pending_area == old_area) return;
}
- if (!is_identity && trans.isTranslation()) {
- Geom::IntPoint t = trans.translation().round();
- if (Geom::are_near(Geom::Point(t), trans.translation())) {
+
+ bool is_integer_translation = false;
+ if (!is_identity && _pending_transform.isTranslation()) {
+ Geom::IntPoint t = _pending_transform.translation().round();
+ if (Geom::are_near(Geom::Point(t), _pending_transform.translation())) {
// integer translation or identity with change of area
is_integer_translation = true;
cairo_region_translate(_clean_region, t[X], t[Y]);
- if (old_area + t == new_area) {
+ if (old_area + t == _pending_area) {
// if the areas match, the only thing to do
// is to ensure that the clean area is not too large
- cairo_rectangle_int_t limit = _convertRect(new_area);
+ cairo_rectangle_int_t limit = _convertRect(_pending_area);
cairo_region_intersect_rectangle(_clean_region, &limit);
_origin += t;
+ _pending_transform.setIdentity();
return;
}
}
@@ -226,12 +241,12 @@ DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine con
Geom::IntPoint old_origin = old_area.min();
cairo_surface_t *old_surface = _surface;
_surface = NULL;
- _pixels = new_area.dimensions();
- _origin = new_area.min();
+ _pixels = _pending_area.dimensions();
+ _origin = _pending_area.min();
cairo_t *ct = createRawContext();
if (!is_identity) {
- ink_cairo_transform(ct, trans);
+ 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);
@@ -245,9 +260,11 @@ DrawingCache::resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine con
cairo_region_destroy(_clean_region);
_clean_region = cairo_region_create();
} else {
- cairo_rectangle_int_t limit = _convertRect(new_area);
+ cairo_rectangle_int_t limit = _convertRect(_pending_area);
cairo_region_intersect_rectangle(_clean_region, &limit);
}
+ std::cout << _pending_transform << old_area << _pending_area << std::endl;
+ _pending_transform.setIdentity();
}
/** @brief Paints the clean area from cache and returns the remaining part */
diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h
index f279d771b..fd46d66ba 100644
--- a/src/display/drawing-surface.h
+++ b/src/display/drawing-surface.h
@@ -64,11 +64,14 @@ public:
void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite());
void markClean(Geom::IntRect const &area = Geom::IntRect::infinite());
bool isClean(Geom::IntRect const &area) const;
- void resizeAndTransform(Geom::IntRect const &new_area, Geom::Affine const &trans);
+ void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans);
+ void prepare();
bool paintFromCache(DrawingContext &ct, Geom::IntRect const &area);
protected:
cairo_region_t *_clean_region;
+ Geom::IntRect _pending_area;
+ Geom::Affine _pending_transform;
private:
static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r);
};
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index 22bd84587..5881c84ed 100644
--- a/src/display/drawing.cpp
+++ b/src/display/drawing.cpp
@@ -9,6 +9,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <algorithm>
#include "display/drawing.h"
#include "nr-filter-gaussian.h"
#include "nr-filter-types.h"
@@ -24,6 +25,8 @@ Drawing::Drawing(SPCanvasArena *arena)
, _colormode(COLORMODE_NORMAL)
, _blur_quality(BLUR_QUALITY_BEST)
, _filter_quality(Filters::FILTER_QUALITY_BEST)
+ , _cache_score_threshold(50000.0)
+ , _cache_budget(128 << 20) // 128 MiB
, _canvasarena(arena)
{
@@ -126,23 +129,51 @@ Drawing::setCacheLimit(Geom::OptIntRect const &r)
void
Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
{
- // TODO add autocache
- if (!_root) return;
- _root->update(area, ctx, flags, reset);
+ if (_root) {
+ _root->update(area, ctx, flags, reset);
+ }
+ // process the updated cache scores
+ // we cache the objects with the highest score until the budget is exhausted
+ _candidate_items.sort(std::greater<CacheRecord>());
+ size_t used = 0;
+ CandidateList::iterator i;
+ for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) {
+ if (used + i->cache_size > _cache_budget) break;
+ used += i->cache_size;
+ }
+
+ std::set<DrawingItem*> to_cache;
+ for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) {
+ i->item->setCached(true);
+ to_cache.insert(i->item);
+ }
+ // Everything which is now in _cached_items but not in to_cache must be uncached
+ // Note that calling setCached on an item modifies _cached_items
+ // TODO: find a way to avoid the set copy
+ std::set<DrawingItem*> to_uncache;
+ std::set_difference(_cached_items.begin(), _cached_items.end(),
+ to_cache.begin(), to_cache.end(),
+ std::inserter(to_uncache, to_uncache.end()));
+ for (std::set<DrawingItem*>::iterator j = to_uncache.begin(); j != to_uncache.end(); ++j) {
+ (*j)->setCached(false);
+ }
}
void
Drawing::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flags)
{
- if (!_root) return;
- _root->render(ct, area, flags);
+ if (_root) {
+ _root->render(ct, area, flags);
+ }
}
DrawingItem *
Drawing::pick(Geom::Point const &p, double delta, bool sticky)
{
- if (!_root) return NULL;
- return _root->pick(p, delta, sticky);
+ if (_root) {
+ return _root->pick(p, delta, sticky);
+ }
+ return NULL;
}
} // end namespace Inkscape
diff --git a/src/display/drawing.h b/src/display/drawing.h
index 4560d277d..a8e70bbe6 100644
--- a/src/display/drawing.h
+++ b/src/display/drawing.h
@@ -13,6 +13,7 @@
#define SEEN_INKSCAPE_DISPLAY_DRAWING_H
#include <set>
+#include <boost/operators.hpp>
#include <boost/utility.hpp>
#include <sigc++/sigc++.h>
#include <2geom/rect.h>
@@ -22,17 +23,17 @@
namespace Inkscape {
-struct OutlineColors {
- guint32 paths;
- guint32 clippaths;
- guint32 masks;
- guint32 images;
-};
-
class Drawing
: boost::noncopyable
{
public:
+ struct OutlineColors {
+ guint32 paths;
+ guint32 clippaths;
+ guint32 masks;
+ guint32 images;
+ };
+
Drawing(SPCanvasArena *arena = NULL);
~Drawing();
@@ -66,8 +67,13 @@ public:
sigc::signal<void, DrawingItem *> signal_item_deleted;
private:
+ void _reportCacheScore(CacheRecord const &);
+
+ typedef std::list<CacheRecord> CandidateList;
+
DrawingItem *_root;
- std::set<DrawingItem *> _cached_items;
+ std::set<DrawingItem *> _cached_items; // modified by DrawingItem::setCached()
+ CacheList _candidate_items;
public:
// TODO: remove these temporarily public members
guint32 outlinecolor;
@@ -80,9 +86,12 @@ private:
int _filter_quality;
Geom::OptIntRect _cache_limit;
- OutlineColors _colors;
+ double _cache_score_threshold; ///< do not consider objects for caching below this score
+ size_t _cache_budget; ///< maximum allowed size of cache
- SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen but used for export etc.
+ OutlineColors _colors;
+ SPCanvasArena *_canvasarena; // may be NULL is this arena is not the screen
+ // but used for export etc.
friend class DrawingItem;
};
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
index 3cec479fa..99a142b44 100644
--- a/src/display/nr-filter-blend.cpp
+++ b/src/display/nr-filter-blend.cpp
@@ -196,6 +196,11 @@ bool FilterBlend::can_handle_affine(Geom::Affine const &)
return true;
}
+double FilterBlend::complexity(Geom::Affine const &)
+{
+ return 1.1;
+}
+
void FilterBlend::set_input(int slot) {
_input = slot;
}
diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h
index 64b3c9284..5f71d468d 100644
--- a/src/display/nr-filter-blend.h
+++ b/src/display/nr-filter-blend.h
@@ -39,6 +39,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
virtual void set_input(int slot);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp
index 7eb2fa2e9..6fa34bf0b 100644
--- a/src/display/nr-filter-colormatrix.cpp
+++ b/src/display/nr-filter-colormatrix.cpp
@@ -192,6 +192,11 @@ void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*tr
{
}
+double FilterColorMatrix::complexity(Geom::Affine const &)
+{
+ return 2.0;
+}
+
void FilterColorMatrix::set_type(FilterColorMatrixType t){
type = t;
}
diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h
index df851e0aa..5864a010e 100644
--- a/src/display/nr-filter-colormatrix.h
+++ b/src/display/nr-filter-colormatrix.h
@@ -38,6 +38,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
virtual void set_type(FilterColorMatrixType type);
virtual void set_value(gdouble value);
diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp
index 80bc07df8..887352f62 100644
--- a/src/display/nr-filter-component-transfer.cpp
+++ b/src/display/nr-filter-component-transfer.cpp
@@ -308,6 +308,11 @@ void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Affine const
{
}
+double FilterComponentTransfer::complexity(Geom::Affine const &)
+{
+ return 2.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-component-transfer.h b/src/display/nr-filter-component-transfer.h
index 89bc61403..6d65ae6d1 100644
--- a/src/display/nr-filter-component-transfer.h
+++ b/src/display/nr-filter-component-transfer.h
@@ -38,6 +38,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
FilterComponentTransferType type[4];
std::vector<gdouble> tableValues[4];
diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp
index 694ccaec5..b25ecdf2c 100644
--- a/src/display/nr-filter-composite.cpp
+++ b/src/display/nr-filter-composite.cpp
@@ -139,6 +139,11 @@ void FilterComposite::set_arithmetic(double k1, double k2, double k3, double k4)
this->k4 = k4;
}
+double FilterComposite::complexity(Geom::Affine const &)
+{
+ return 1.1;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-composite.h b/src/display/nr-filter-composite.h
index 930898830..95579cc0e 100644
--- a/src/display/nr-filter-composite.h
+++ b/src/display/nr-filter-composite.h
@@ -28,6 +28,7 @@ public:
virtual void render_cairo(FilterSlot &);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
virtual void set_input(int input);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp
index 06e28b074..469baf346 100644
--- a/src/display/nr-filter-convolve-matrix.cpp
+++ b/src/display/nr-filter-convolve-matrix.cpp
@@ -212,6 +212,11 @@ void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Affine const &/*tra
area.y1 += orderY - targetY - 1;
}
+double FilterConvolveMatrix::complexity(Geom::Affine const &)
+{
+ return kernelMatrix.size();
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-convolve-matrix.h b/src/display/nr-filter-convolve-matrix.h
index d13738260..8b7fc35d1 100644
--- a/src/display/nr-filter-convolve-matrix.h
+++ b/src/display/nr-filter-convolve-matrix.h
@@ -36,6 +36,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
void set_targetY(int coord);
void set_targetX(int coord);
diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp
index 039e56bb0..14144ace5 100644
--- a/src/display/nr-filter-diffuselighting.cpp
+++ b/src/display/nr-filter-diffuselighting.cpp
@@ -171,6 +171,11 @@ void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*t
area.y1 += 1;
}
+double FilterDiffuseLighting::complexity(Geom::Affine const &)
+{
+ return 9.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h
index 6e39242f6..bb3ceccb3 100644
--- a/src/display/nr-filter-diffuselighting.h
+++ b/src/display/nr-filter-diffuselighting.h
@@ -33,6 +33,7 @@ public:
virtual ~FilterDiffuseLighting();
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
union {
SPFeDistantLight *distant;
diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp
index 15200223b..75e310339 100644
--- a/src/display/nr-filter-displacement-map.cpp
+++ b/src/display/nr-filter-displacement-map.cpp
@@ -140,6 +140,11 @@ void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Affine const &tran
area.y1 += (int)(scaley)+2;
}
+double FilterDisplacementMap::complexity(Geom::Affine const &)
+{
+ return 3.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-displacement-map.h b/src/display/nr-filter-displacement-map.h
index aec4b7eb6..393a904c1 100644
--- a/src/display/nr-filter-displacement-map.h
+++ b/src/display/nr-filter-displacement-map.h
@@ -27,12 +27,14 @@ public:
static FilterPrimitive *create();
virtual ~FilterDisplacementMap();
+ virtual void render_cairo(FilterSlot &slot);
+ virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
+
virtual void set_input(int slot);
virtual void set_input(int input, int slot);
virtual void set_scale(double s);
virtual void set_channel_selector(int s, FilterDisplacementMapChannelSelector channel);
- virtual void render_cairo(FilterSlot &slot);
- virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
private:
double scale;
diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp
index a015d3f1f..5716c1bc5 100644
--- a/src/display/nr-filter-flood.cpp
+++ b/src/display/nr-filter-flood.cpp
@@ -86,6 +86,13 @@ void FilterFlood::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/)
{
}
+double FilterFlood::complexity(Geom::Affine const &)
+{
+ // flood is actually less expensive than normal rendering,
+ // but when flood is processed, the object has already been rendered
+ return 1.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h
index 6db90d439..c87bf6d8f 100644
--- a/src/display/nr-filter-flood.h
+++ b/src/display/nr-filter-flood.h
@@ -27,10 +27,13 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
+
virtual void set_opacity(double o);
virtual void set_color(guint32 c);
virtual void set_icc(SVGICCColor *icc_color);
- virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+
private:
double opacity;
guint32 color;
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp
index a777d76a4..988a8479e 100644
--- a/src/display/nr-filter-gaussian.cpp
+++ b/src/display/nr-filter-gaussian.cpp
@@ -691,6 +691,13 @@ bool FilterGaussian::can_handle_affine(Geom::Affine const &)
return false;
}
+double FilterGaussian::complexity(Geom::Affine const &trans)
+{
+ int area_x = _effect_area_scr(_deviation_x * trans.expansionX());
+ int area_y = _effect_area_scr(_deviation_y * trans.expansionY());
+ return 2.0 * area_x * area_y;
+}
+
void FilterGaussian::set_deviation(double deviation)
{
if(IS_FINITE(deviation) && deviation >= 0) {
diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h
index 811502016..f52bea01e 100644
--- a/src/display/nr-filter-gaussian.h
+++ b/src/display/nr-filter-gaussian.h
@@ -37,6 +37,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &m);
virtual bool can_handle_affine(Geom::Affine const &m);
+ virtual double complexity(Geom::Affine const &ctm);
/**
* Set the standard deviation value for gaussian blur. Deviation along
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index b176cdcef..a22d23548 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -196,6 +196,12 @@ bool FilterImage::can_handle_affine(Geom::Affine const &)
return true;
}
+double FilterImage::complexity(Geom::Affine const &)
+{
+ // TODO: right now we cannot actually measure this in any meaningful way.
+ return 1.1;
+}
+
void FilterImage::set_href(const gchar *href){
if (feImageHref) g_free (feImageHref);
feImageHref = (href) ? g_strdup (href) : NULL;
diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h
index 0651109ec..5af0b3338 100644
--- a/src/display/nr-filter-image.h
+++ b/src/display/nr-filter-image.h
@@ -29,6 +29,8 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
+
void set_document( SPDocument *document );
void set_href(const gchar *href);
void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height);
diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp
index 51d3975cb..6042da018 100644
--- a/src/display/nr-filter-merge.cpp
+++ b/src/display/nr-filter-merge.cpp
@@ -67,6 +67,11 @@ bool FilterMerge::can_handle_affine(Geom::Affine const &)
return true;
}
+double FilterMerge::complexity(Geom::Affine const &)
+{
+ return 1.02;
+}
+
void FilterMerge::set_input(int slot) {
_input_image[0] = slot;
}
diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h
index 263fc8026..cedab9086 100644
--- a/src/display/nr-filter-merge.h
+++ b/src/display/nr-filter-merge.h
@@ -26,6 +26,7 @@ public:
virtual void render_cairo(FilterSlot &);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
virtual void set_input(int input);
virtual void set_input(int input, int slot);
diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp
index c79667d3e..9e43d01f3 100644
--- a/src/display/nr-filter-morphology.cpp
+++ b/src/display/nr-filter-morphology.cpp
@@ -158,6 +158,13 @@ void FilterMorphology::area_enlarge(NRRectL &area, Geom::Affine const &trans)
area.y1 += enlarge_y;
}
+double FilterMorphology::complexity(Geom::Affine const &trans)
+{
+ int enlarge_x = ceil(xradius * trans.expansionX());
+ int enlarge_y = ceil(yradius * trans.expansionY());
+ return enlarge_x * enlarge_y;
+}
+
void FilterMorphology::set_operator(FilterMorphologyOperator &o){
Operator = o;
}
diff --git a/src/display/nr-filter-morphology.h b/src/display/nr-filter-morphology.h
index 5924085d9..512eca83c 100644
--- a/src/display/nr-filter-morphology.h
+++ b/src/display/nr-filter-morphology.h
@@ -33,6 +33,8 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
+
void set_operator(FilterMorphologyOperator &o);
void set_xradius(double x);
void set_yradius(double y);
diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp
index 3b0f83841..db8b6d92a 100644
--- a/src/display/nr-filter-offset.cpp
+++ b/src/display/nr-filter-offset.cpp
@@ -85,6 +85,11 @@ void FilterOffset::area_enlarge(NRRectL &area, Geom::Affine const &trans)
}
}
+double FilterOffset::complexity(Geom::Affine const &)
+{
+ return 1.02;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-offset.h b/src/display/nr-filter-offset.h
index 09c57f803..841be6008 100644
--- a/src/display/nr-filter-offset.h
+++ b/src/display/nr-filter-offset.h
@@ -29,6 +29,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
virtual bool can_handle_affine(Geom::Affine const &);
+ virtual double complexity(Geom::Affine const &ctm);
void set_dx(double amount);
void set_dy(double amount);
diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp
index 539e3e952..0a445b9e6 100644
--- a/src/display/nr-filter-primitive.cpp
+++ b/src/display/nr-filter-primitive.cpp
@@ -161,10 +161,6 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
return area;
}
-FilterTraits FilterPrimitive::get_input_traits() {
- return TRAIT_ANYTHING;
-}
-
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h
index ebecb91ec..259a25e7e 100644
--- a/src/display/nr-filter-primitive.h
+++ b/src/display/nr-filter-primitive.h
@@ -22,24 +22,6 @@ namespace Filters {
class FilterSlot;
class FilterUnits;
-/*
- * Different filter effects need different types of inputs. This is what
- * traits are used for: one can specify, what special restrictions
- * there are for inputs.
- *
- * Example: gaussian blur requires that x- and y-axis of input image
- * are paraller to blurred object's x- and y-axis, respectively.
- * Otherwise blur wouldn't rotate with the object.
- *
- * Values here should be powers of two, so these can be used as bitfield.
- * That is: any combination ef existing traits can be specified. (excluding
- * TRAIT_ANYTHING, which is alias for no traits defined)
- */
-enum FilterTraits {
- TRAIT_ANYTHING = 0,
- TRAIT_PARALLER = 1
-};
-
class FilterPrimitive {
public:
FilterPrimitive();
@@ -81,6 +63,10 @@ public:
*/
virtual void set_output(int slot);
+ // returns cache score factor, reflecting the cost of rendering this filter
+ // this should return how many times slower this primitive is that normal rendering
+ virtual double complexity(Geom::Affine const &/*ctm*/) { return 1.0; }
+
/**
* Sets the filter primitive subregion. Passing an unset length
* (length._set == false) WILL change the parameter as it is
@@ -103,14 +89,6 @@ public:
*/
Geom::Rect filter_primitive_area(FilterUnits const &units);
- /**
- * Queries the filter, which traits it needs from its input buffers.
- * At the time of writing this, only one trait was needed, having
- * user coordinate system and input pixelblock coordinates paraller to
- * each other.
- */
- virtual FilterTraits get_input_traits();
-
/** @brief Indicate whether the filter primitive can handle the given affine.
*
* Results of some filter primitives depend on the coordinate system used when rendering.
@@ -121,7 +99,7 @@ public:
* When any filter returns false, filter rendering is performed on an intermediate surface
* with edges parallel to the axes of the user coordinate system. This means
* the matrices from FilterUnits will contain at most a (possibly non-uniform) scale
- * and a translation. When all primitives of the filter return false, the rendering is
+ * and a translation. When all primitives of the filter return true, the rendering is
* performed in display coordinate space and no intermediate surface is used. */
virtual bool can_handle_affine(Geom::Affine const &) { return false; }
diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp
index 2e5f69d65..c28fd485a 100644
--- a/src/display/nr-filter-specularlighting.cpp
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -174,136 +174,6 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
-/*
-int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) {
- NRPixBlock *in = slot.get(_input);
- if (!in) {
- g_warning("Missing source image for feSpecularLighting (in=%d)", _input);
- return 1;
- }
-
- NRPixBlock *out = new NRPixBlock;
-
- //Fvector *L = NULL; //vector to the light
-
- int w = in->area.x1 - in->area.x0;
- int h = in->area.y1 - in->area.y0;
- int x0 = in->area.x0;
- int y0 = in->area.y0;
- int i, j;
- //As long as FilterRes and kernel unit is not supported we hardcode the
- //default value
- int dx = 1; //TODO setup
- int dy = 1; //TODO setup
- //surface scale
- Geom::Affine trans = units.get_matrix_primitiveunits2pb();
- gdouble ss = surfaceScale * trans[0];
- gdouble ks = specularConstant; //diffuse lighting constant
- NR::Fvector L, N, LC, H;
- gdouble inter;
-
- nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N,
- in->area.x0, in->area.y0, in->area.x1, in->area.y1,
- true);
- unsigned char *data_i = NR_PIXBLOCK_PX (in);
- unsigned char *data_o = NR_PIXBLOCK_PX (out);
- //No light, nothing to do
- switch (light_type) {
- case DISTANT_LIGHT:
- //the light vector is constant
- {
- DistantLight *dl = new DistantLight(light.distant, lighting_color);
- dl->light_vector(L);
- dl->light_components(LC);
- NR::normalized_sum(H, L, NR::EYE_VECTOR);
- //finish the work
- for (i = 0, j = 0; i < w*h; i++) {
- NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
- COMPUTE_INTER(inter, N, H, ks, specularExponent);
-
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); // CLAMP includes rounding!
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
- data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
- ++j;
- }
- out->empty = FALSE;
- delete dl;
- }
- break;
- case POINT_LIGHT:
- {
- PointLight *pl = new PointLight(light.point, lighting_color, trans);
- pl->light_components(LC);
- //TODO we need a reference to the filter to determine primitiveUnits
- //if objectBoundingBox is used, use a different matrix for light_vector
- // UPDATE: trans is now correct matrix from primitiveUnits to
- // pixblock coordinates
- //finish the work
- for (i = 0, j = 0; i < w*h; i++) {
- NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
- pl->light_vector(L,
- i % w + x0,
- i / w + y0,
- ss * (double) data_i[4*i+3]/ 255);
- NR::normalized_sum(H, L, NR::EYE_VECTOR);
- COMPUTE_INTER(inter, N, H, ks, specularExponent);
-
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
- data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
- ++j;
- }
- out->empty = FALSE;
- delete pl;
- }
- break;
- case SPOT_LIGHT:
- {
- SpotLight *sl = new SpotLight(light.spot, lighting_color, trans);
- //TODO we need a reference to the filter to determine primitiveUnits
- //if objectBoundingBox is used, use a different matrix for light_vector
- // UPDATE: trans is now correct matrix from primitiveUnits to
- // pixblock coordinates
- //finish the work
- for (i = 0, j = 0; i < w*h; i++) {
- NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
- sl->light_vector(L,
- i % w + x0,
- i / w + y0,
- ss * (double) data_i[4*i+3]/ 255);
- sl->light_components(LC, L);
- NR::normalized_sum(H, L, NR::EYE_VECTOR);
- COMPUTE_INTER(inter, N, H, ks, specularExponent);
-
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
- data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
- data_o[j] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
- ++j;
- }
- out->empty = FALSE;
- delete sl;
- }
- break;
- //else unknown light source, doing nothing
- case NO_LIGHT:
- default:
- {
- if (light_type != NO_LIGHT)
- g_warning("unknown light source %d", light_type);
- out->empty = false;
- }
- }
-
- //finishing
- slot.set(_output, out);
- //nr_pixblock_release(in);
- //delete in;
- return 0;
-}*/
-
void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*trans*/)
{
// TODO: support kernelUnitLength
@@ -314,6 +184,11 @@ void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const & /*
area.y1 += 1;
}
+double FilterSpecularLighting::complexity(Geom::Affine const &)
+{
+ return 9.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h
index 2fcb02588..8471b70b0 100644
--- a/src/display/nr-filter-specularlighting.h
+++ b/src/display/nr-filter-specularlighting.h
@@ -31,8 +31,10 @@ public:
FilterSpecularLighting();
static FilterPrimitive *create();
virtual ~FilterSpecularLighting();
+
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
union {
SPFeDistantLight *distant;
diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp
index b88386638..4aadde2aa 100644
--- a/src/display/nr-filter-tile.cpp
+++ b/src/display/nr-filter-tile.cpp
@@ -45,6 +45,11 @@ void FilterTile::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/)
{
}
+double FilterTile::complexity(Geom::Affine const &)
+{
+ return 1.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h
index 5c0a3e553..37e257f79 100644
--- a/src/display/nr-filter-tile.h
+++ b/src/display/nr-filter-tile.h
@@ -27,6 +27,7 @@ public:
virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans);
+ virtual double complexity(Geom::Affine const &ctm);
};
} /* namespace Filters */
diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp
index 60d5ce872..f065ded11 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -388,6 +388,11 @@ void FilterTurbulence::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
+double FilterTurbulence::complexity(Geom::Affine const &)
+{
+ return 5.0;
+}
+
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h
index 8d3639543..9f824ef48 100644
--- a/src/display/nr-filter-turbulence.h
+++ b/src/display/nr-filter-turbulence.h
@@ -45,6 +45,7 @@ public:
virtual ~FilterTurbulence();
virtual void render_cairo(FilterSlot &slot);
+ virtual double complexity(Geom::Affine const &ctm);
void set_baseFrequency(int axis, double freq);
void set_numOctaves(int num);
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index e84e6f0c2..df6b6222b 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -282,6 +282,18 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
return area;
}
+double Filter::complexity(Geom::Affine const &ctm)
+{
+ double factor;
+ for (unsigned i = 0 ; i < _primitive.size() ; i++) {
+ if (_primitive[i]) {
+ double f = _primitive[i]->complexity(ctm);
+ factor += (f - 1.0);
+ }
+ }
+ return factor;
+}
+
/* Constructor table holds pointers to static methods returning filter
* primitives. This table is indexed with FilterPrimitiveType, so that
* for example method in _constructor[NR_FILTER_GAUSSIANBLUR]
diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h
index 31705f53b..7d31e10ce 100644
--- a/src/display/nr-filter.h
+++ b/src/display/nr-filter.h
@@ -164,6 +164,9 @@ public:
*/
Geom::Rect filter_effect_area(Geom::Rect const &bbox);
+ // returns cache score factor
+ double complexity(Geom::Affine const &ctm);
+
/** Creates a new filter with space for one filter element */
Filter();
/**