summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-08-09 05:51:45 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2011-08-09 05:51:45 +0000
commit74b91362758052e0f03bb819663a4606f08e4c69 (patch)
treed3c1c2e8620b067383f8014b055fe81fb34b6326 /src
parentTurn off debug message spam (diff)
downloadinkscape-74b91362758052e0f03bb819663a4606f08e4c69.tar.gz
inkscape-74b91362758052e0f03bb819663a4606f08e4c69.zip
Use cache even if only part of the redraw region is clean
(bzr r10347.1.28)
Diffstat (limited to 'src')
-rw-r--r--src/display/drawing-context.h3
-rw-r--r--src/display/drawing-item.cpp38
-rw-r--r--src/display/drawing-surface.cpp71
-rw-r--r--src/display/drawing-surface.h4
4 files changed, 75 insertions, 41 deletions
diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h
index 8d2e7d68a..4ada79057 100644
--- a/src/display/drawing-context.h
+++ b/src/display/drawing-context.h
@@ -64,6 +64,9 @@ public:
void rectangle(Geom::Rect const &r) {
cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height());
}
+ void rectangle(Geom::IntRect const &r) {
+ cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height());
+ }
void newPath() { cairo_new_path(_ct); }
void newSubpath() { cairo_new_sub_path(_ct); }
void path(Geom::PathVector const &pv);
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index e86e222e2..113bf9c33 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -422,7 +422,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
return;
}
- // carea is the bounding box for intermediate rendering.
+ // carea is the area to paint
Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
if (!carea) return;
@@ -430,8 +430,8 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
if (_cached) {
if (_cache) {
_cache->prepare();
- if (_cache->paintFromCache(ct, *carea))
- return;
+ _cache->paintFromCache(ct, carea);
+ if (!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
@@ -447,12 +447,6 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
// deleted in setCached()
}
- // expand carea to contain the dependent area of filters.
- if (_filter && render_filters) {
- _filter->area_enlarge(*carea, this);
- carea.intersectWith(_drawbox);
- }
-
// determine whether this shape needs intermediate rendering.
bool needs_intermediate_rendering = false;
bool &nir = needs_intermediate_rendering;
@@ -480,7 +474,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
if (!needs_intermediate_rendering) {
if (_cached && _cache) {
Inkscape::DrawingContext cachect(*_cache);
- cachect.rectangle(area);
+ cachect.rectangle(*carea);
cachect.clip();
{ // 1. clear the corresponding part of cache
@@ -498,7 +492,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
ct.setSource(_cache);
ct.paint();
// 4. mark as clean
- _cache->markClean(area);
+ _cache->markClean(*carea);
return;
} else {
_renderItem(ct, *carea, flags);
@@ -506,7 +500,19 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
}
}
- DrawingSurface intermediate(*carea);
+ // iarea is the bounding box for intermediate rendering
+ // Note 1: pixels inside iarea but outside carea might be invalid
+ // (incomplete filter dependence region).
+ // Note 2: We only need to render carea of clip and mask, but
+ // iarea of the object.
+ Geom::OptIntRect iarea = carea;
+ // expand carea to contain the dependent area of filters.
+ if (_filter && render_filters) {
+ _filter->area_enlarge(*iarea, this);
+ iarea.intersectWith(_drawbox);
+ }
+
+ DrawingSurface intermediate(*iarea);
DrawingContext ict(intermediate);
// 1. Render clipping path with alpha = opacity.
@@ -537,9 +543,9 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
ict.setOperator(CAIRO_OPERATOR_OVER);
}
- // 3. Render object itself.
+ // 3. Render object itself
ict.pushGroup();
- _renderItem(ict, *carea, flags);
+ _renderItem(ict, *iarea, flags);
// 4. Apply filter.
if (_filter && render_filters) {
@@ -557,12 +563,12 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag
// 6. Paint the completed rendering onto the base context (or into cache)
if (_cached && _cache) {
DrawingContext cachect(*_cache);
- cachect.rectangle(area);
+ cachect.rectangle(*carea);
cachect.clip();
cachect.setOperator(CAIRO_OPERATOR_SOURCE);
cachect.setSource(&intermediate);
cachect.paint();
- _cache->markClean(area);
+ _cache->markClean(*carea);
}
ct.setSource(&intermediate);
ct.paint();
diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp
index 39a622fe7..43cf50b88 100644
--- a/src/display/drawing-surface.cpp
+++ b/src/display/drawing-surface.cpp
@@ -188,16 +188,6 @@ DrawingCache::markClean(Geom::IntRect const &area)
cairo_rectangle_int_t clean = _convertRect(*r);
cairo_region_union_rectangle(_clean_region, &clean);
}
-bool
-DrawingCache::isClean(Geom::IntRect const &area) const
-{
- cairo_rectangle_int_t test = _convertRect(area);
- if (cairo_region_contains_rectangle(_clean_region, &test) == CAIRO_REGION_OVERLAP_IN) {
- return true;
- } else {
- return false;
- }
-}
/// Call this during the update phase to schedule a transformation of the cache.
void
@@ -267,20 +257,46 @@ DrawingCache::prepare()
_pending_transform.setIdentity();
}
-/** @brief Paints the clean area from cache and returns the remaining part */
-bool
-DrawingCache::paintFromCache(DrawingContext &ct, Geom::IntRect const &area)
+/** @brief Paints the clean area from cache and modifies the @a area
+ * parameter to the bounds of the region that must be repainted. */
+void
+DrawingCache::paintFromCache(DrawingContext &ct, Geom::OptIntRect &area)
{
- if (!isClean(area))
- return false;
-
- Inkscape::DrawingContext::Save save(ct);
- ct.rectangle(area);
- ct.clip();
- ct.setSource(this);
- ct.paint();
-
- return true;
+ if (!area) return;
+
+ // We subtract the clean region from the area, then get the bounds
+ // of the resulting region. This is the area that needs to be repainted
+ // by the item.
+ // Then we subtract the area that needs to be repainted from the
+ // original area and paint the resulting region from cache.
+ cairo_rectangle_int_t area_c = _convertRect(*area);
+ cairo_region_t *dirty_region = cairo_region_create_rectangle(&area_c);
+ cairo_region_t *cache_region = cairo_region_copy(dirty_region);
+ cairo_region_subtract(dirty_region, _clean_region);
+
+ if (cairo_region_is_empty(dirty_region)) {
+ area = Geom::OptIntRect();
+ } else {
+ cairo_rectangle_int_t to_repaint;
+ cairo_region_get_extents(dirty_region, &to_repaint);
+ *area = _convertRect(to_repaint);
+ cairo_region_subtract_rectangle(cache_region, &to_repaint);
+ }
+ cairo_region_destroy(dirty_region);
+
+ if (!cairo_region_is_empty(cache_region)) {
+ Inkscape::DrawingContext::Save save(ct);
+ int nr = cairo_region_num_rectangles(cache_region);
+ cairo_rectangle_int_t tmp;
+ for (int i = 0; i < nr; ++i) {
+ cairo_region_get_rectangle(cache_region, i, &tmp);
+ ct.rectangle(_convertRect(tmp));
+ }
+ ct.clip();
+ ct.setSource(this);
+ ct.paint();
+ }
+ cairo_region_destroy(cache_region);
}
cairo_rectangle_int_t
@@ -294,6 +310,15 @@ DrawingCache::_convertRect(Geom::IntRect const &area)
return ret;
}
+Geom::IntRect
+DrawingCache::_convertRect(cairo_rectangle_int_t const &r)
+{
+ Geom::IntRect ret = Geom::IntRect::from_xywh(
+ r.x, r.y,
+ r.width, r.height);
+ return ret;
+}
+
} // end namespace Inkscape
/*
diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h
index fd46d66ba..f3af33002 100644
--- a/src/display/drawing-surface.h
+++ b/src/display/drawing-surface.h
@@ -63,10 +63,9 @@ 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 scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans);
void prepare();
- bool paintFromCache(DrawingContext &ct, Geom::IntRect const &area);
+ void paintFromCache(DrawingContext &ct, Geom::OptIntRect &area);
protected:
cairo_region_t *_clean_region;
@@ -74,6 +73,7 @@ protected:
Geom::Affine _pending_transform;
private:
static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r);
+ static Geom::IntRect _convertRect(cairo_rectangle_int_t const &r);
};
} // end namespace Inkscape