diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 166a84d39b3e8e6f7b84e15727949735cafc6749..756fa6be265344e924c7d93aa895e8c8eeea3fcc 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -219,7 +219,13 @@ void DrawingItem::setTransform(Geom::Affine const &new_trans) if (_transform) { current = *_transform; } - + bool should_cache = !(new_trans.isTranslation(EPS) && !new_trans.isIdentity(EPS)); + if (_cached && !should_cache) { + setCached(false, true); + } else if (!_cached && should_cache) { + setCached(true, (_filter && _drawing.renderFilters())); + } + if (!Geom::are_near(current, new_trans, EPS)) { // mark the area where the object was for redraw. _markForRendering(); @@ -665,6 +671,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag { bool outline = _drawing.outline(); bool render_filters = _drawing.renderFilters(); + bool forcecache = _filter && render_filters; // 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) { @@ -686,21 +693,20 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag return RENDER_OK; } - // carea is the area to paint - Geom::OptIntRect carea = Geom::intersect(area, _drawbox); - + Geom::OptIntRect carea = area & _drawbox; if (!carea) { return RENDER_OK; } - // iarea is the bounding box for intermediate rendering - // Note 1: Pixels inside iarea but outside carea are invalid - // (incomplete filter dependence region). - // Note 2: We only need to render carea of clip and mask, but - // iarea of the object. - + // TODO study chenge the next iarea funcitions to this one commented + // Nonmaly _cacheRect is not in comandline. + // If we decide do it we need to chage a test rendering + // a few chaged + //if (_filter && render_filters) { + // carea = _cacheRect(); ? _cacheRect() : _drawbox; + //} Geom::OptIntRect iarea = carea; // expand carea to contain the dependent area of filters. - if (_filter && render_filters) { + if (forcecache) { iarea = _cacheRect(); if (!iarea) { iarea = carea; @@ -711,11 +717,12 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag setCached(true, true); } } - - if (!iarea) { + // carea is the area to paint + carea = iarea & _drawbox; + if (!carea) { return RENDER_OK; } - + // Device scale for HiDPI screens (typically 1 or 2) int device_scale = dc.surface()->device_scale(); @@ -732,7 +739,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag if (_cache) { _cache->prepare(); dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); - _cache->paintFromCache(dc, carea, _filter && render_filters); + _cache->paintFromCache(dc, carea, forcecache); if (!carea) { dc.setSource(0, 0, 0, 0); return RENDER_OK; @@ -742,6 +749,8 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // was just turned on after the last update phase, or because // we were previously outside of the canvas. Geom::OptIntRect cl = _cacheRect(); + if (!cl) + cl = carea; _cache = new DrawingCache(*cl, device_scale); } } else { @@ -766,7 +775,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag setCached(false, true); } _prev_nir = needs_intermediate_rendering; - nir |= (_cache != nullptr); // 5. it is to be cached + nir |= (_cache != nullptr); // 8. it is to be cached /* How the rendering is done. * @@ -787,11 +796,11 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { dc.setOperator(ink_css_blend_to_cairo_operator(SP_CSS_BLEND_NORMAL)); - return _renderItem(dc, *iarea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); + return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } - DrawingSurface intermediate(*iarea, device_scale); + DrawingSurface intermediate(*carea, device_scale); DrawingContext ict(intermediate); // This path fails for patterns/hatches when stepping the pattern to handle overflows. @@ -840,7 +849,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // 3. Render object itself ict.pushGroup(); - render_result = _renderItem(ict, *iarea, flags, stop_at); + render_result = _renderItem(ict, *carea, flags, stop_at); // 4. Apply filter. if (_filter && render_filters) { @@ -851,9 +860,9 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag if (bg_root->_background_new) break; } if (bg_root) { - DrawingSurface bg(*iarea, device_scale); + DrawingSurface bg(*carea, device_scale); DrawingContext bgdc(bg); - bg_root->render(bgdc, *iarea, flags | RENDER_FILTER_BACKGROUND, this); + bg_root->render(bgdc, *carea, flags | RENDER_FILTER_BACKGROUND, this); _filter->render(this, ict, &bgdc); rendered = true; } @@ -874,25 +883,16 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // 6. Paint the completed rendering onto the base context (or into cache) if (_cached && _cache) { DrawingContext cachect(*_cache); - Geom::OptIntRect cl = _cacheRect(); - if (_filter && render_filters && cl) { - cachect.rectangle(*cl); - } else { - cachect.rectangle(*iarea); - } + cachect.rectangle(*carea); cachect.setOperator(CAIRO_OPERATOR_SOURCE); cachect.setSource(&intermediate); cachect.fill(); - - if (_filter && render_filters && cl) { - _cache->markClean(*cl); - } else { - _cache->markClean(*iarea); - } + _cache->markClean(*carea); } dc.rectangle(*carea); dc.setSource(&intermediate); + // 7. Render blend mode dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); dc.fill(); diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 1b486463553992d3b0c703c3428b1786cc26b65e..284875be5c1ecb2d24073ad3cb60c6132c5e2b9c 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -214,7 +214,7 @@ protected: Inkscape::Filters::Filter *_filter; SPItem *_item; ///< Used to associate DrawingItems with SPItems that created them DrawingCache *_cache; - bool _prev_nir; + bool _prev_nir = false; CacheList::iterator _cache_iterator; diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index bf8653007f534a1c68e036e1f73dfcef6108f4f5..ae27a58a2a82e35bdbe7ae59df7e6370b5ca67ed 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -323,6 +323,10 @@ void DrawingCache::paintFromCache(DrawingContext &dc, Geom::OptIntRect &area, bo cairo_region_subtract(dirty_region, _clean_region); if (is_filter && !cairo_region_is_empty(dirty_region)) { // To allow fast panning on high zoom on filters + cairo_region_destroy(cache_region); + cairo_region_destroy(dirty_region); + cairo_region_destroy(_clean_region); + _clean_region = cairo_region_create(); return; } if (cairo_region_is_empty(dirty_region)) { diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index 09a2d11a86b8f03cd6d769e0dd1fb500cdc7ac45..f693a870f3c293d475dfa5d24d8feaeec93a75c9 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -145,16 +145,14 @@ Drawing::cacheLimit() const return _cache_limit; } void -Drawing::setCacheLimit(Geom::OptIntRect const &r, bool update_cache) +Drawing::setCacheLimit(Geom::OptIntRect const &r) { _cache_limit = r; - if (update_cache) { - for (auto _cached_item : _cached_items) - { - _cached_item->_markForUpdate(DrawingItem::STATE_CACHE, false); - } + for (auto _cached_item : _cached_items) { + _cached_item->_markForUpdate(DrawingItem::STATE_CACHE, false); } } + void Drawing::setCacheBudget(size_t bytes) { diff --git a/src/display/drawing.h b/src/display/drawing.h index 20df1b02b1162f20bd83fbe9ecaf9737238d474f..39773a773a55a50173719bdd9146c06ac73ff088 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -69,7 +69,7 @@ public: bool getOutlineSensitive() const { return _outline_sensitive; }; Geom::PathVector clip; Geom::OptIntRect const &cacheLimit() const; - void setCacheLimit(Geom::OptIntRect const &r, bool update_cache = true); + void setCacheLimit(Geom::OptIntRect const &r); void setCacheBudget(size_t bytes); OutlineColors const &colors() const { return _colors; } diff --git a/src/object/sp-item-group.cpp b/src/object/sp-item-group.cpp index c7bc6947659bde051fa87638cc9a3512d266f83c..df118b28ed3ce2f46be12c08f278d25e51e47015 100644 --- a/src/object/sp-item-group.cpp +++ b/src/object/sp-item-group.cpp @@ -1003,15 +1003,13 @@ void SPGroup::update_patheffect(bool write) { lpe_item->update_patheffect(write); // update satellites if (!lpe_item->hasPathEffect()) { - gchar *classes = g_strdup(lpe_item->getAttribute("class")); - if (classes) { - Glib::ustring classdata = classes; + if (auto classes = lpe_item->getAttribute("class")) { + auto classdata = Glib::ustring(classes); size_t pos = classdata.find("UnoptimicedTransforms"); - if ( pos != std::string::npos ) { + if (pos != Glib::ustring::npos) { lpe_item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } - g_free(classes); } } } diff --git a/src/object/sp-item.cpp b/src/object/sp-item.cpp index 02dabf68bf8a71ad063617dab181cd30e824cd4c..35f434cd7499cebc1713b9463bfc286a76f216e4 100644 --- a/src/object/sp-item.cpp +++ b/src/object/sp-item.cpp @@ -1609,12 +1609,22 @@ void SPItem::doWriteTransform(Geom::Affine const &transform, Geom::Affine const if (lpeitem) { lpeitem->notifyTransform(transform); } + bool unoptimized = false; + if (auto classes = getAttribute("class")) { + auto classdata = Glib::ustring(classes); + size_t pos = classdata.find("UnoptimicedTransforms"); + if (pos != Glib::ustring::npos) { + unoptimized = true; + } + } + if ( // run the object's set_transform (i.e. embed transform) only if: (dynamic_cast(this) && firstChild() && dynamic_cast(firstChild())) || (!preserve && // user did not chose to preserve all transforms (!clip_ref || !clip_ref->getObject()) && // the object does not have a clippath (!mask_ref || !mask_ref->getObject()) && // the object does not have a mask - !(!transform.isTranslation() && style && style->getFilter())) + !(!transform.isTranslation() && style && style->getFilter()) && + !unoptimized) // the object does not have a filter, or the transform is translation (which is supposed to not affect filters) ) { diff --git a/src/object/sp-lpe-item.cpp b/src/object/sp-lpe-item.cpp index 2994db4862153619bf4677aa7b2daa04455bf3f0..0f018731789b2414845c2e4445612c8993b75e42 100755 --- a/src/object/sp-lpe-item.cpp +++ b/src/object/sp-lpe-item.cpp @@ -357,15 +357,14 @@ bool SPLPEItem::optimizeTransforms() } } // LPEs with satellites (and his satellites) has this class auto - gchar *classes = g_strdup(getAttribute("class")); - if (classes) { - Glib::ustring classdata = classes; + if (auto classes = getAttribute("class")) { + auto classdata = Glib::ustring(classes); size_t pos = classdata.find("UnoptimicedTransforms"); - if ( pos != std::string::npos ) { + if (pos != Glib::ustring::npos) { return false; } } - g_free(classes); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); return !prefs->getBool("/options/preservetransform/value", false); } diff --git a/src/ui/widget/canvas.cpp b/src/ui/widget/canvas.cpp index 39c0cb55d322ede89d1cd4c5ae0b8a57ae844c8f..adf15b245c3606e9369c98dab9c057d133cd4b4b 100644 --- a/src/ui/widget/canvas.cpp +++ b/src/ui/widget/canvas.cpp @@ -3332,7 +3332,10 @@ bool CanvasPrivate::on_idle() // Recreate the store fragment at the current affine so that it covers the visible region + prerender margin. auto store = graphics->get_store(); store->rect = expandedBy(q->get_area_world(), prefs.margin + prefs.pad); - q->_drawing->setCacheLimit(store->rect, false); + Geom::IntRect expanded = store->rect; + Geom::IntPoint expansion(expanded.width()/2, expanded.height()/2); + expanded.expandBy(expansion); + q->_drawing->setCacheLimit(expanded); store->affine = q->_affine; auto content_size = store->rect.dimensions() * device_scale; @@ -3407,7 +3410,10 @@ bool CanvasPrivate::on_idle() // Create a new fragment centred on the viewport. auto rect = expandedBy(q->get_area_world(), prefs.margin + prefs.pad); auto content_size = rect.dimensions() * device_scale; - + Geom::IntRect expanded = rect; + Geom::IntPoint expansion(expanded.width()/2, expanded.height()/2); + expanded.expandBy(expansion); + q->_drawing->setCacheLimit(expanded); if (q->get_opengl_enabled()) { auto gl = glstate();