diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 092c48ec3f777c455e32e1077bb040cbd8894333..160000a7842e099de0f7dd870337986f17b2a0fd 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1750,6 +1750,54 @@ objects_query_blend (const std::vector &objects, SPStyle *style_res) } } +int objects_query_isolation(const std::vector &objects, SPStyle *style_res) +{ + const int empty_prev = -2; + int isolation = 0; + float isolation_prev = empty_prev; + bool same_isolation = true; + guint items = 0; + + for (auto obj : objects) { + if (!obj) { + continue; + } + SPStyle *style = obj->style; + if (!style || !dynamic_cast(obj)) { + continue; + } + + items++; + + if (style->isolation.set) { + isolation = style->isolation.value; + } + // defaults to blend mode = "normal" + else { + isolation = 0; + } + + if (isolation_prev != empty_prev && isolation_prev != isolation) + same_isolation = false; + isolation_prev = isolation; + } + + if (items > 0) { + style_res->isolation.value = isolation; + } + + if (items == 0) { + return QUERY_STYLE_NOTHING; + } else if (items == 1) { + return QUERY_STYLE_SINGLE; + } else { + if (same_isolation) + return QUERY_STYLE_MULTIPLE_SAME; + else + return QUERY_STYLE_MULTIPLE_DIFFERENT; + } +} + /** * Write to style_res the average blurring of a list of objects. */ @@ -1873,6 +1921,8 @@ sp_desktop_query_style_from_list (const std::vector &list, SPStyle *sty } else if (property == QUERY_STYLE_PROPERTY_BLEND) { return objects_query_blend (list, style); + } else if (property == QUERY_STYLE_PROPERTY_ISOLATION) { + return objects_query_isolation(list, style); } else if (property == QUERY_STYLE_PROPERTY_BLUR) { return objects_query_blur (list, style); } @@ -1924,6 +1974,7 @@ sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query) int result_opacity = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY); int result_blur = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_BLUR); int result_blend = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_BLEND); + int result_isolation = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_ISOLATION); return (result_family != QUERY_STYLE_NOTHING || result_fstyle != QUERY_STYLE_NOTHING || @@ -1937,6 +1988,7 @@ sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query) result_strokejoin != QUERY_STYLE_NOTHING || result_paintorder != QUERY_STYLE_NOTHING || result_blur != QUERY_STYLE_NOTHING || + result_isolation != QUERY_STYLE_NOTHING || result_blend != QUERY_STYLE_NOTHING); } diff --git a/src/desktop-style.h b/src/desktop-style.h index b2e076400913e0e71599dc2c3fd43b93cba1a6e2..c32bc244797c57002069e26dc8af97a44836e36d 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -59,6 +59,7 @@ enum { // which property was queried (add when you need more) QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift QUERY_STYLE_PROPERTY_WRITINGMODES, // writing-mode, text-orientation QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity + QUERY_STYLE_PROPERTY_ISOLATION, // isolation QUERY_STYLE_PROPERTY_BLEND, // blend QUERY_STYLE_PROPERTY_BLUR // blur }; diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index d3ca85f7e1eedbbd95ed034c7d39e37dac1eb1a6..f560b9f19d3855723e10c66af87f72297d723698 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -1252,6 +1252,129 @@ private: /* None */ }; +unsigned ink_cairo_operator_to_css_blend(cairo_operator_t cairo_operator) +{ + // All of the blend modes are implemented in Cairo as of 1.10. + // For a detailed description, see: + // http://cairographics.org/operators/ + unsigned res = SP_CSS_BLEND_NORMAL; + switch (cairo_operator) { + case CAIRO_OPERATOR_MULTIPLY: + res = SP_CSS_BLEND_MULTIPLY; + break; + case CAIRO_OPERATOR_SCREEN: + res = SP_CSS_BLEND_SCREEN; + break; + case CAIRO_OPERATOR_DARKEN: + res = SP_CSS_BLEND_DARKEN; + break; + case CAIRO_OPERATOR_LIGHTEN: + res = SP_CSS_BLEND_LIGHTEN; + break; + case CAIRO_OPERATOR_OVERLAY: + res = SP_CSS_BLEND_OVERLAY; + break; + case CAIRO_OPERATOR_COLOR_DODGE: + res = SP_CSS_BLEND_COLORDODGE; + break; + case CAIRO_OPERATOR_COLOR_BURN: + res = SP_CSS_BLEND_COLORBURN; + break; + case CAIRO_OPERATOR_HARD_LIGHT: + res = SP_CSS_BLEND_HARDLIGHT; + break; + case CAIRO_OPERATOR_SOFT_LIGHT: + res = SP_CSS_BLEND_SOFTLIGHT; + break; + case CAIRO_OPERATOR_DIFFERENCE: + res = SP_CSS_BLEND_DIFFERENCE; + break; + case CAIRO_OPERATOR_EXCLUSION: + res = SP_CSS_BLEND_EXCLUSION; + break; + case CAIRO_OPERATOR_HSL_HUE: + res = SP_CSS_BLEND_HUE; + break; + case CAIRO_OPERATOR_HSL_SATURATION: + res = SP_CSS_BLEND_SATURATION; + break; + case CAIRO_OPERATOR_HSL_COLOR: + res = SP_CSS_BLEND_COLOR; + break; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + res = SP_CSS_BLEND_LUMINOSITY; + break; + case CAIRO_OPERATOR_OVER: + default: + res = SP_CSS_BLEND_NORMAL; + break; + } + return res; +} + +cairo_operator_t ink_css_blend_to_cairo_operator(unsigned css_blend) +{ + // All of the blend modes are implemented in Cairo as of 1.10. + // For a detailed description, see: + // http://cairographics.org/operators/ + + cairo_operator_t res = CAIRO_OPERATOR_OVER; + switch (css_blend) { + case SP_CSS_BLEND_MULTIPLY: + res = CAIRO_OPERATOR_MULTIPLY; + break; + case SP_CSS_BLEND_SCREEN: + res = CAIRO_OPERATOR_SCREEN; + break; + case SP_CSS_BLEND_DARKEN: + res = CAIRO_OPERATOR_DARKEN; + break; + case SP_CSS_BLEND_LIGHTEN: + res = CAIRO_OPERATOR_LIGHTEN; + break; + case SP_CSS_BLEND_OVERLAY: + res = CAIRO_OPERATOR_OVERLAY; + break; + case SP_CSS_BLEND_COLORDODGE: + res = CAIRO_OPERATOR_COLOR_DODGE; + break; + case SP_CSS_BLEND_COLORBURN: + res = CAIRO_OPERATOR_COLOR_BURN; + break; + case SP_CSS_BLEND_HARDLIGHT: + res = CAIRO_OPERATOR_HARD_LIGHT; + break; + case SP_CSS_BLEND_SOFTLIGHT: + res = CAIRO_OPERATOR_SOFT_LIGHT; + break; + case SP_CSS_BLEND_DIFFERENCE: + res = CAIRO_OPERATOR_DIFFERENCE; + break; + case SP_CSS_BLEND_EXCLUSION: + res = CAIRO_OPERATOR_EXCLUSION; + break; + case SP_CSS_BLEND_HUE: + res = CAIRO_OPERATOR_HSL_HUE; + break; + case SP_CSS_BLEND_SATURATION: + res = CAIRO_OPERATOR_HSL_SATURATION; + break; + case SP_CSS_BLEND_COLOR: + res = CAIRO_OPERATOR_HSL_COLOR; + break; + case SP_CSS_BLEND_LUMINOSITY: + res = CAIRO_OPERATOR_HSL_LUMINOSITY; + break; + case SP_CSS_BLEND_NORMAL: + default: + res = CAIRO_OPERATOR_OVER; + break; + } + return res; +} + + + int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface) { cairo_surface_flush(surface); diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index fbcee5413a45ef72141ec8092a1f3a28bd5a6ef5..36800f699b023dd50172572c754dc18846ad6e2e 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -156,7 +156,8 @@ void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); - +cairo_operator_t ink_css_blend_to_cairo_operator(unsigned blend_mode); +unsigned ink_cairo_operator_to_css_blend(cairo_operator_t cairo_operator); cairo_surface_t *ink_cairo_surface_copy(cairo_surface_t *s); cairo_surface_t *ink_cairo_surface_create_identical(cairo_surface_t *s); cairo_surface_t *ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c); diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index 1095fa1a345fa3f51fc4e70e3f422d600bf39bc7..aedb87ea2d3250f7a11200a55af57b869ba964db 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -101,6 +101,7 @@ public: void setMiterLimit(double miter) { cairo_set_miter_limit(_ct, miter); } void setFillRule(cairo_fill_rule_t rule) { cairo_set_fill_rule(_ct, rule); } void setOperator(cairo_operator_t op) { cairo_set_operator(_ct, op); } + cairo_operator_t getOperator() { return cairo_get_operator(_ct); } void setTolerance(double tol) { cairo_set_tolerance(_ct, tol); } void setSource(cairo_pattern_t *source) { cairo_set_source(_ct, source); } void setSource(cairo_surface_t *surface, double x, double y) { diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index 0d6a2edfc26e16d6a0bfb41fe144d1107426b64d..4fe84d7eb40e9da3152b863eb19299f5e43e79f3 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -10,10 +10,13 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include "display/drawing.h" -#include "display/drawing-item.h" #include "display/drawing-group.h" - +#include "display/cairo-utils.h" +#include "display/drawing-context.h" +#include "display/drawing-item.h" +#include "display/drawing-surface.h" +#include "display/drawing.h" +#include "style.h" namespace Inkscape { @@ -90,29 +93,70 @@ DrawingGroup::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, u unsigned DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { - if (stop_at == nullptr) { - // normal rendering - for (auto & i : _children) { - i.setAntialiasing(_antialias); - i.render(dc, area, flags, stop_at); + if (!parent() || (_isolation == SP_CSS_ISOLATION_ISOLATE && !_mix_blend_mode)) { + int device_scale = dc.surface()->device_scale(); + DrawingSurface intermediate(area, device_scale); + DrawingContext ict(intermediate); + ict.setOperator(CAIRO_OPERATOR_OVER); + if (parent()) { + flags = flags | RENDER_FILTER_BACKGROUND; } - } else { - // background rendering - for (auto & i : _children) { - 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 + if (stop_at == nullptr) { + // normal rendering + for (auto &i : _children) { i.setAntialiasing(_antialias); - i.render(dc, area, flags | RENDER_FILTER_BACKGROUND, stop_at); - // stop further rendering - return RENDER_OK; - } else { + i.render(ict, area, flags, stop_at); + } + } else { + // background rendering + for (auto &i : _children) { + 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.setAntialiasing(_antialias); + i.render(ict, area, flags | RENDER_FILTER_BACKGROUND, stop_at); + break; + } else { + i.setAntialiasing(_antialias); + i.render(ict, area, flags, stop_at); + } + } + } + dc.rectangle(area); + dc.setSource(&intermediate); + dc.setOperator(CAIRO_OPERATOR_OVER); + dc.fill(); + return RENDER_OK; + } else { + /* cairo_operator_t current_op = CAIRO_OPERATOR_OVER; + if (parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && !parent()->_mix_blend_mode) { + dc.setOperator(CAIRO_OPERATOR_OVER); + } */ + if (stop_at == nullptr) { + // normal rendering + for (auto &i : _children) { i.setAntialiasing(_antialias); i.render(dc, area, flags, stop_at); } + } else { + // background rendering + for (auto &i : _children) { + 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.setAntialiasing(_antialias); + i.render(dc, area, flags | RENDER_FILTER_BACKGROUND, stop_at); + break; + } else { + i.setAntialiasing(_antialias); + i.render(dc, area, flags, stop_at); + } + } } + return RENDER_OK; } - return RENDER_OK; } void diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 81d01846e8dfee7f5c200e26d4155127b07de4ec..52939e301cf8570ee4ffaa9c990af493d4cc2c49 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -28,65 +28,6 @@ #include "object/sp-item.h" namespace Inkscape { - -void set_cairo_blend_operator( DrawingContext &dc, unsigned blend_mode ) { - - // All of the blend modes are implemented in Cairo as of 1.10. - // For a detailed description, see: - // http://cairographics.org/operators/ - switch (blend_mode) { - case SP_CSS_BLEND_MULTIPLY: - dc.setOperator(CAIRO_OPERATOR_MULTIPLY); - break; - case SP_CSS_BLEND_SCREEN: - dc.setOperator(CAIRO_OPERATOR_SCREEN); - break; - case SP_CSS_BLEND_DARKEN: - dc.setOperator(CAIRO_OPERATOR_DARKEN); - break; - case SP_CSS_BLEND_LIGHTEN: - dc.setOperator(CAIRO_OPERATOR_LIGHTEN); - break; - case SP_CSS_BLEND_OVERLAY: - dc.setOperator(CAIRO_OPERATOR_OVERLAY); - break; - case SP_CSS_BLEND_COLORDODGE: - dc.setOperator(CAIRO_OPERATOR_COLOR_DODGE); - break; - case SP_CSS_BLEND_COLORBURN: - dc.setOperator(CAIRO_OPERATOR_COLOR_BURN); - break; - case SP_CSS_BLEND_HARDLIGHT: - dc.setOperator(CAIRO_OPERATOR_HARD_LIGHT); - break; - case SP_CSS_BLEND_SOFTLIGHT: - dc.setOperator(CAIRO_OPERATOR_SOFT_LIGHT); - break; - case SP_CSS_BLEND_DIFFERENCE: - dc.setOperator(CAIRO_OPERATOR_DIFFERENCE); - break; - case SP_CSS_BLEND_EXCLUSION: - dc.setOperator(CAIRO_OPERATOR_EXCLUSION); - break; - case SP_CSS_BLEND_HUE: - dc.setOperator(CAIRO_OPERATOR_HSL_HUE); - break; - case SP_CSS_BLEND_SATURATION: - dc.setOperator(CAIRO_OPERATOR_HSL_SATURATION); - break; - case SP_CSS_BLEND_COLOR: - dc.setOperator(CAIRO_OPERATOR_HSL_COLOR); - break; - case SP_CSS_BLEND_LUMINOSITY: - dc.setOperator(CAIRO_OPERATOR_HSL_LUMINOSITY); - break; - case SP_CSS_BLEND_NORMAL: - default: - dc.setOperator(CAIRO_OPERATOR_OVER); - break; - } -} - /** * @class DrawingItem * SVG drawing item for display. @@ -629,7 +570,6 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } } } - if (to_update & STATE_CACHE) { // Update cache score for this item if (_has_cache_iterator) { @@ -773,8 +713,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag if (_cached && !(flags & RENDER_BYPASS_CACHE)) { if (_cache) { _cache->prepare(); - set_cairo_blend_operator( dc, _mix_blend_mode ); - + dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); _cache->paintFromCache(dc, carea); if (!carea) { return RENDER_OK; @@ -798,13 +737,13 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag bool needs_opacity = (_opacity < 0.995); // this item needs an intermediate rendering if: - nir |= (_clip != nullptr); // 1. it has a clipping path - nir |= (_mask != nullptr); // 2. it has a mask - nir |= (_filter != nullptr && render_filters); // 3. it has a filter - nir |= needs_opacity; // 4. it is non-opaque - nir |= (_cache != nullptr); // 5. it is to be cached - nir |= (_mix_blend_mode != SP_CSS_BLEND_NORMAL); // 6. Blend mode not normal - nir |= (_isolation == SP_CSS_ISOLATION_ISOLATE); // 7. Explicit isolatiom + nir |= (_clip != nullptr); // 1. it has a clipping path + nir |= (_mask != nullptr); // 2. it has a mask + nir |= (_filter != nullptr && render_filters); // 3. it has a filter + nir |= needs_opacity; // 4. it is non-opaque + nir |= (_cache != nullptr); // 5. it is to be cached + nir |= (_mix_blend_mode != SP_CSS_BLEND_NORMAL); // 6. Blend mode not normal + // Isolation is handled by the drawing-group /* How the rendering is done. * @@ -817,12 +756,12 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag * the entire intermediate surface is painted with alpha corresponding * to the opacity value. */ - // 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) { + dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } @@ -925,11 +864,16 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag cachect.fill(); _cache->markClean(*carea); } + dc.rectangle(*carea); dc.setSource(&intermediate); - set_cairo_blend_operator( dc, _mix_blend_mode ); + // 7. Render blend mode + dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); dc.fill(); dc.setSource(0,0,0,0); + // Web isolation only works if parent doesnt have transform + + // the call above is to clear a ref on the intermediate surface held by dc return render_result; @@ -1115,7 +1059,7 @@ DrawingItem::_markForRendering() bkg_root = i; } } - + if (bkg_root) { bkg_root->_invalidateFilterBackground(*dirty); } diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index f0107cdc7466cc975e539a3878753716ff9d9670..809d6ae72585528836d0c4947f8aca35607fd401 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -94,6 +94,9 @@ public: DrawingItem(Drawing &drawing); virtual ~DrawingItem(); + unsigned _isolation : 1; + unsigned _mix_blend_mode : 4; + Geom::OptIntRect geometricBounds() const { return _bbox; } Geom::OptIntRect visualBounds() const { return _drawbox; } Geom::OptRect itemBounds() const { return _item_bbox; } @@ -227,9 +230,6 @@ protected: /// otherwise the group is returned unsigned _antialias : 2; ///< antialiasing level (NONE/FAST/GOOD(DEFAULT)/BEST) - unsigned _isolation : 1; - unsigned _mix_blend_mode : 4; - friend class Drawing; }; diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index b33dd20b64b4273f59ef85d025ed6ffd8d8a6bf0..216c8437f43de4ff7bf94727ab5e4c3831193d3c 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1838,7 +1838,6 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect cairo_surface_set_device_scale(imgs, _device_scale, _device_scale); buf.ct = cairo_create(imgs); - cairo_save(buf.ct); cairo_translate(buf.ct, -paint_rect.left(), -paint_rect.top()); cairo_set_source(buf.ct, _background); @@ -1850,6 +1849,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect if (_root->visible) { SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf); } + // cairo_surface_write_to_png( imgs, "debug2.png" ); // output to X diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index adc4f1eb5ba46f674a1715fd7e881e5fecb88c36..a1e5b91a8fc3da83c8b978a06845c4515032a1e8 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1569,6 +1569,9 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con } else { cairo_set_fill_rule(_cr, CAIRO_FILL_RULE_WINDING); } + if (style->mix_blend_mode.set && style->mix_blend_mode.value) { + cairo_set_operator(_cr, ink_css_blend_to_cairo_operator(style->mix_blend_mode.value)); + } cairo_fill(_cr); TEST(cairo_surface_write_to_png (_surface, "pathmask.png")); } @@ -1599,6 +1602,10 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con } } + if (style->mix_blend_mode.set && style->mix_blend_mode.value) { + cairo_set_operator(_cr, ink_css_blend_to_cairo_operator(style->mix_blend_mode.value)); + } + setPathVector(pathv); if (!no_fill && (order == STROKE_OVER_FILL || order == FILL_ONLY)) { @@ -1695,6 +1702,10 @@ bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb, } } + if (style->mix_blend_mode.set && style->mix_blend_mode.value) { + cairo_set_operator(_cr, ink_css_blend_to_cairo_operator(style->mix_blend_mode.value)); + } + cairo_paint(_cr); cairo_restore(_cr); @@ -1825,6 +1836,10 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma stroke = true; } + if (style->mix_blend_mode.set && style->mix_blend_mode.value) { + cairo_set_operator(_cr, (cairo_operator_t)style->mix_blend_mode.value); + } + // Text never has markers bool stroke_over_fill = true; if ( (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_STROKE && diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 9b4b55e2126ab828749b546c9617483155eb47f3..14727eba5f0242844cc7e06a27680dd1d22feb7c 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -408,6 +408,26 @@ void SvgBuilder::_setFillStyle(SPCSSAttr *css, GfxState *state, bool even_odd) { sp_repr_css_set_property(css, "fill-rule", even_odd ? "evenodd" : "nonzero"); } +/** + * \brief Sets blend style properties from poppler's GfxState data structure + * \update a SPCSSAttr with all mix-blend-mode set + */ +void SvgBuilder::_setBlendMode(Inkscape::XML::Node *node, GfxState *state) +{ + SPCSSAttr *css = sp_repr_css_attr(node, "style"); + GfxBlendMode blendmode = state->getBlendMode(); + if (blendmode) { + sp_repr_css_set_property(css, "mix-blend-mode", enum_blend_mode[blendmode].key); + } + Glib::ustring value; + sp_repr_css_write_string(css, value); + if (value.empty()) { + node->setAttribute("style", nullptr); + } else { + node->setAttribute("style", value.c_str()); + } + sp_repr_css_attr_unref(css); +} /** * \brief Sets style properties from poppler's GfxState data structure * \return SPCSSAttr with all the relevant properties set @@ -447,7 +467,7 @@ void SvgBuilder::addPath(GfxState *state, bool fill, bool stroke, bool even_odd) SPCSSAttr *css = _setStyle(state, fill, stroke, even_odd); sp_repr_css_change(path, css, "style"); sp_repr_css_attr_unref(css); - + _setBlendMode(path, state); _container->appendChild(path); Inkscape::GC::release(path); } @@ -1427,6 +1447,11 @@ void SvgBuilder::addChar(GfxState *state, double x, double y, bool has_fill = !( render_mode & 1 ); bool has_stroke = ( render_mode & 3 ) == 1 || ( render_mode & 3 ) == 2; new_glyph.style = _setStyle(state, has_fill, has_stroke); + // Find a way to handle blend modes on text + /* GfxBlendMode blendmode = state->getBlendMode(); + if (blendmode) { + sp_repr_css_set_property(new_glyph.style, "mix-blend-mode", enum_blend_mode[blendmode].key); + } */ new_glyph.render_mode = render_mode; sp_repr_css_merge(new_glyph.style, _font_style); // Merge with font style _invalidated_style = false; @@ -1435,6 +1460,10 @@ void SvgBuilder::addChar(GfxState *state, double x, double y, // Point to previous glyph's style information const SvgGlyph& prev_glyph = _glyphs.back(); new_glyph.style = prev_glyph.style; + /* GfxBlendMode blendmode = state->getBlendMode(); + if (blendmode) { + sp_repr_css_set_property(new_glyph.style, "mix-blend-mode", enum_blend_mode[blendmode].key); + } */ new_glyph.render_mode = prev_glyph.render_mode; } new_glyph.font_specification = _font_specification; @@ -1710,14 +1739,16 @@ Inkscape::XML::Node *SvgBuilder::_createMask(double width, double height) { } } -void SvgBuilder::addImage(GfxState * /*state*/, Stream *str, int width, int height, - GfxImageColorMap *color_map, bool interpolate, int *mask_colors) { +void SvgBuilder::addImage(GfxState *state, Stream *str, int width, int height, GfxImageColorMap *color_map, + bool interpolate, int *mask_colors) +{ - Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, interpolate, mask_colors); - if (image_node) { - _container->appendChild(image_node); + Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, interpolate, mask_colors); + if (image_node) { + _setBlendMode(image_node, state); + _container->appendChild(image_node); Inkscape::GC::release(image_node); - } + } } void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int height, @@ -1735,6 +1766,7 @@ void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int heigh _setFillStyle(css, state, false); sp_repr_css_change(rect, css, "style"); sp_repr_css_attr_unref(css); + _setBlendMode(rect, state); // Scaling 1x1 surfaces might not work so skip setting a mask with this size if ( width > 1 || height > 1 ) { @@ -1758,10 +1790,10 @@ void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int heigh Inkscape::GC::release(rect); } -void SvgBuilder::addMaskedImage(GfxState * /*state*/, Stream *str, int width, int height, - GfxImageColorMap *color_map, bool interpolate, - Stream *mask_str, int mask_width, int mask_height, - bool invert_mask, bool mask_interpolate) { +void SvgBuilder::addMaskedImage(GfxState *state, Stream *str, int width, int height, GfxImageColorMap *color_map, + bool interpolate, Stream *mask_str, int mask_width, int mask_height, bool invert_mask, + bool mask_interpolate) +{ Inkscape::XML::Node *mask_image_node = _createImage(mask_str, mask_width, mask_height, nullptr, mask_interpolate, nullptr, true, invert_mask); @@ -1787,14 +1819,15 @@ void SvgBuilder::addMaskedImage(GfxState * /*state*/, Stream *str, int width, in Inkscape::GC::release(mask_image_node); } if (image_node) { + _setBlendMode(image_node, state); Inkscape::GC::release(image_node); } } - -void SvgBuilder::addSoftMaskedImage(GfxState * /*state*/, Stream *str, int width, int height, - GfxImageColorMap *color_map, bool interpolate, - Stream *mask_str, int mask_width, int mask_height, - GfxImageColorMap *mask_color_map, bool mask_interpolate) { + +void SvgBuilder::addSoftMaskedImage(GfxState *state, Stream *str, int width, int height, GfxImageColorMap *color_map, + bool interpolate, Stream *mask_str, int mask_width, int mask_height, + GfxImageColorMap *mask_color_map, bool mask_interpolate) +{ Inkscape::XML::Node *mask_image_node = _createImage(mask_str, mask_width, mask_height, mask_color_map, mask_interpolate, nullptr, true); @@ -1815,6 +1848,7 @@ void SvgBuilder::addSoftMaskedImage(GfxState * /*state*/, Stream *str, int width Inkscape::GC::release(mask_image_node); } if (image_node) { + _setBlendMode(image_node, state); Inkscape::GC::release(image_node); } } diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index 8168617f61bad1e93dc576059ba00e76e23e014c..c42d694dec278f446ec9367ef40d811426d825eb 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -189,7 +189,7 @@ private: SPCSSAttr *_setStyle(GfxState *state, bool fill, bool stroke, bool even_odd=false); void _setStrokeStyle(SPCSSAttr *css, GfxState *state); void _setFillStyle(SPCSSAttr *css, GfxState *state, bool even_odd); - + void _setBlendMode(Inkscape::XML::Node *node, GfxState *state); void _flushText(); // Write buffered text into doc std::string _BestMatchingFont(std::string PDFname); diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index 22dd407e787980333698e1e42b2cffea698ea066..fd28cbc870c0536fdba2f2afa6d0b758c0a89f95 100644 --- a/src/ui/dialog/fill-and-stroke.cpp +++ b/src/ui/dialog/fill-and-stroke.cpp @@ -46,6 +46,7 @@ FillAndStroke::FillAndStroke() , _page_stroke_paint(Gtk::manage(new UI::Widget::NotebookPage(1, 1, true, true))) , _page_stroke_style(Gtk::manage(new UI::Widget::NotebookPage(1, 1, true, true))) , _composite_settings(SP_VERB_DIALOG_FILL_STROKE, "fillstroke", + UI::Widget::SimpleFilterModifier::ISOLATION | UI::Widget::SimpleFilterModifier::BLEND | UI::Widget::SimpleFilterModifier::BLUR | UI::Widget::SimpleFilterModifier::OPACITY) diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp index e2aa4e2c9ebe10ac1fd8246135ddee4f4516685b..06af29a6e305033281ad22b98dddb3f00b0335d2 100644 --- a/src/ui/dialog/layers.cpp +++ b/src/ui/dialog/layers.cpp @@ -740,6 +740,7 @@ LayersPanel::LayersPanel() : _pending(nullptr), _toggleEvent(nullptr), _compositeSettings(SP_VERB_DIALOG_LAYERS, "layers", + UI::Widget::SimpleFilterModifier::ISOLATION | UI::Widget::SimpleFilterModifier::BLEND | UI::Widget::SimpleFilterModifier::OPACITY | UI::Widget::SimpleFilterModifier::BLUR), diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 272d98595e07bdcdbaeaa1fa361c343fc81c5975..8682cfd0c307a0ca6c6e9c15b9a0b25faff4b711 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -577,17 +577,20 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { void ObjectsPanel::_setCompositingValues(SPItem *item) { // Block the connections to avoid interference + _isolationConnection.block(); _opacityConnection.block(); _blendConnection.block(); _blurConnection.block(); + // Set the isolation + int isolation = item->style->isolation.set ? item->style->isolation.value : SP_CSS_ISOLATION_AUTO; + _filter_modifier.set_isolation_mode(isolation, true); // Set the opacity double opacity = (item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1); opacity *= 100; // Display in percent. _filter_modifier.set_opacity_value(opacity); // Set the blend mode - _filter_modifier.set_blend_mode(item->style->mix_blend_mode.set ? item->style->mix_blend_mode.value - : SP_CSS_BLEND_NORMAL); + _filter_modifier.set_blend_mode(item->style->mix_blend_mode.value, true); SPGaussianBlur *spblur = nullptr; if (item->style->getFilter()) { for (auto& primitive_obj: item->style->getFilter()->children) { @@ -613,6 +616,7 @@ void ObjectsPanel::_setCompositingValues(SPItem *item) _filter_modifier.set_blur_value(blur_value); //Unblock connections + _isolationConnection.unblock(); _blurConnection.unblock(); _blendConnection.unblock(); _opacityConnection.unblock(); @@ -1185,6 +1189,7 @@ void ObjectsPanel::_blockAllSignals(bool should_block = true) { // incoming signals _documentChangedCurrentLayer.block(should_block); + _isolationConnection.block(should_block); _opacityConnection.block(should_block); _blendConnection.block(should_block); _blurConnection.block(should_block); @@ -1599,15 +1604,39 @@ void ObjectsPanel::_opacityChangedIter(const Gtk::TreeIter& iter) } } +/** + * Callback for when the isolation value is changed + */ +void ObjectsPanel::_isolationValueChanged() +{ + _blockCompositeUpdate = true; + _tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &ObjectsPanel::_isolationChangedIter)); + DocumentUndo::maybeDone(_document, "isolation", SP_VERB_DIALOG_OBJECTS, _("Set object isolation")); + _blockCompositeUpdate = false; +} + +/** + * Change the isolation of the selected items in the tree + * @param iter Current tree item + */ +void ObjectsPanel::_isolationChangedIter(const Gtk::TreeIter &iter) +{ + Gtk::TreeModel::Row row = *iter; + SPItem *item = row[_model->_colObject]; + if (item) { + item->style->isolation.set = TRUE; + item->style->isolation.value = _filter_modifier.get_isolation_mode(); + item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); + } +} + /** * Callback for when the blend mode is changed */ void ObjectsPanel::_blendValueChanged() { _blockCompositeUpdate = true; - const Glib::ustring blendmode = _filter_modifier.get_blend_mode(); - - _tree.get_selection()->selected_foreach_iter(sigc::bind(sigc::mem_fun(*this, &ObjectsPanel::_blendChangedIter), blendmode)); + _tree.get_selection()->selected_foreach_iter(sigc::mem_fun(*this, &ObjectsPanel::_blendChangedIter)); DocumentUndo::done(_document, SP_VERB_DIALOG_OBJECTS, _("Set object blend mode")); _blockCompositeUpdate = false; } @@ -1617,23 +1646,15 @@ void ObjectsPanel::_blendValueChanged() * @param iter Current tree item * @param blendmode Blend mode to set */ -void ObjectsPanel::_blendChangedIter(const Gtk::TreeIter& iter, Glib::ustring blendmode) +void ObjectsPanel::_blendChangedIter(const Gtk::TreeIter &iter) { Gtk::TreeModel::Row row = *iter; SPItem* item = row[_model->_colObject]; if (item) { - //Since blur and blend are both filters, we need to set both at the same time - SPStyle *style = item->style; - g_assert(style != nullptr); - SPCSSAttr *css = sp_css_attr_from_style(style, SP_STYLE_FLAG_ALWAYS | SP_STYLE_FLAG_IFSRC); - if (blendmode == "normal") { - sp_repr_css_unset_property(css, "mix-blend-mode"); - } else { - sp_repr_css_set_property(css, "mix-blend-mode", blendmode.c_str()); - } - sp_repr_css_change(item->getRepr(), css, "style"); - sp_repr_css_attr_unref(css); + item->style->mix_blend_mode.set = TRUE; + item->style->mix_blend_mode.value = _filter_modifier.get_blend_mode(); + item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); } } @@ -1717,7 +1738,8 @@ ObjectsPanel::ObjectsPanel() : _clipmaskHeader(C_("Clip and mask", "CM")), _highlightHeader(C_("Highlight", "HL")), _nameHeader(_("Label")), - _filter_modifier( UI::Widget::SimpleFilterModifier::BLEND | + _filter_modifier( UI::Widget::SimpleFilterModifier::ISOLATION | + UI::Widget::SimpleFilterModifier::BLEND | UI::Widget::SimpleFilterModifier::BLUR | UI::Widget::SimpleFilterModifier::OPACITY ), _colorSelectorDialog("dialogs.colorpickerwindow") @@ -1859,7 +1881,8 @@ ObjectsPanel::ObjectsPanel() : _blendConnection = _filter_modifier.signal_blend_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_blendValueChanged)); _blurConnection = _filter_modifier.signal_blur_changed().connect(sigc::mem_fun(*this, &ObjectsPanel::_blurValueChanged)); _opacityConnection = _filter_modifier.signal_opacity_changed().connect( sigc::mem_fun(*this, &ObjectsPanel::_opacityValueChanged)); - + _isolationConnection = _filter_modifier.signal_isolation_changed().connect( + sigc::mem_fun(*this, &ObjectsPanel::_isolationValueChanged)); //Pack the compositing functions and the button row _page.pack_end(_filter_modifier, Gtk::PACK_SHRINK); _page.pack_end(_buttonsRow, Gtk::PACK_SHRINK); diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index 3800b2da5d0e172f6fb173867faffc06d21a7403..1553033748599675b196e8b8eaaaec9fd552e02d 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -85,6 +85,7 @@ private: sigc::connection _selectedConnection; //Connections for when the opacity/blend/blur of the active selection in the document changes + sigc::connection _isolationConnection; sigc::connection _opacityConnection; sigc::connection _blendConnection; sigc::connection _blurConnection; @@ -217,11 +218,14 @@ private: void _objectsChangedWrapper(SPObject *obj); void _objectsChanged(SPObject *obj); void _addObject( SPObject* obj, Gtk::TreeModel::Row* parentRow ); - + + void _isolationChangedIter(const Gtk::TreeIter &iter); + void _isolationValueChanged(); + void _opacityChangedIter(const Gtk::TreeIter& iter); void _opacityValueChanged(); - - void _blendChangedIter(const Gtk::TreeIter& iter, Glib::ustring blendmode); + + void _blendChangedIter(const Gtk::TreeIter &iter); void _blendValueChanged(); void _blurChangedIter(const Gtk::TreeIter& iter, double blur); diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 931e08d15b231e7c05938346873455c67139b3ec..f994f85cf60b20bacbbf34f31de0d8fbdcaee998 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -31,6 +31,8 @@ #include "live_effects/effect.h" #include "live_effects/lpeobject.h" +#include "include/macros.h" + #include "object/sp-clippath.h" #include "object/sp-item-group.h" #include "object/sp-mask.h" @@ -498,7 +500,8 @@ bool NodeTool::root_handler(GdkEvent* event) { case GDK_MOTION_NOTIFY: { sp_update_helperpath(); SPItem *over_item = nullptr; - if (!desktop->canvas->_scrooling) { + if (!desktop->canvas->_scrooling || MOD__CTRL(event) || MOD__SHIFT(event) || MOD__ALT(event)) { + desktop->canvas->_scrooling = false; combine_motion_events(desktop->canvas, event->motion, 0); over_item = sp_event_context_find_item(desktop, event_point(event->button), FALSE, TRUE); } diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index 9bd97fabc4682e4cbe94d4a09f1c9100ea3ef886..6d5fdd2b9d151533cc12f1e941644a9f238e65c6 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -554,7 +554,6 @@ bool SelectTool::root_handler(GdkEvent* event) { if ((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning) { Geom::Point const motion_pt(event->motion.x, event->motion.y); Geom::Point const p(desktop->w2d(motion_pt)); - if ( within_tolerance && ( abs( (gint) event->motion.x - xp ) < tolerance ) && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) { diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 98074d354774ad45822ea2bd70ba4b07c454b429..08a3a3750723a47d21de2997c45d539b08208dc2 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -54,9 +54,11 @@ namespace Widget { SimpleFilterModifier::SimpleFilterModifier(int flags) : _flags(flags) , _lb_blend(_("Blend mode:")) + , _lb_isolation("Isolate") // Translate for 1.1 , _blend(SPBlendModeConverter, SP_ATTR_INVALID, false) , _blur(_("Blur (%)"), 0, 0, 100, 1, 0.1, 1) , _opacity(_("Opacity (%)"), 0, 0, 100, 1, 0.1, 1) + , _notify(true) { set_name("SimpleFilterModifier"); @@ -72,6 +74,13 @@ SimpleFilterModifier::SimpleFilterModifier(int flags) _lb_blend.set_mnemonic_widget(_blend); _hb_blend.pack_start(_lb_blend, false, false, 5); _hb_blend.pack_start(_blend, false, false, 5); + if (flags & ISOLATION) { + _isolation.property_active() = false; + _hb_blend.pack_start(_isolation, false, false, 5); + _hb_blend.pack_start(_lb_isolation, false, false, 5); + } + _hb_blend.pack_start(_lb_blend, false, false, 5); + _hb_blend.pack_start(_blend, false, false, 5); Gtk::Separator *separator = Gtk::manage(new Gtk::Separator()); separator->set_margin_top(8); separator->set_margin_bottom(8); @@ -90,34 +99,63 @@ SimpleFilterModifier::SimpleFilterModifier(int flags) _blend.signal_changed().connect(signal_blend_changed()); _blur.signal_value_changed().connect(signal_blur_changed()); _opacity.signal_value_changed().connect(signal_opacity_changed()); + _isolation.signal_toggled().connect(signal_isolation_changed()); +} + +sigc::signal &SimpleFilterModifier::signal_isolation_changed() +{ + if (_notify) { + return _signal_isolation_changed; + } + _notify = true; + return _signal_null; } sigc::signal& SimpleFilterModifier::signal_blend_changed() { - return _signal_blend_changed; + if (_notify) { + return _signal_blend_changed; + } + _notify = true; + return _signal_null; } sigc::signal& SimpleFilterModifier::signal_blur_changed() { + // we dont use notifi to block use aberaje for multiple return _signal_blur_changed; } sigc::signal& SimpleFilterModifier::signal_opacity_changed() { + // we dont use notifi to block use averaje for multiple return _signal_opacity_changed; } -const Glib::ustring SimpleFilterModifier::get_blend_mode() +int SimpleFilterModifier::get_isolation_mode() +{ + return _isolation.get_active() ? SP_CSS_ISOLATION_ISOLATE : SP_CSS_ISOLATION_AUTO; +} + +void SimpleFilterModifier::set_isolation_mode(const int val, bool notify) +{ + _notify = notify; + _isolation.set_active(val == SP_CSS_ISOLATION_ISOLATE); +} + +int SimpleFilterModifier::get_blend_mode() { const Util::EnumData *d = _blend.get_active_data(); if (d) { - return _blend.get_active_data()->key; - } else - return "normal"; + return _blend.get_active_data()->id; + } else { + return SP_CSS_BLEND_NORMAL; + } } -void SimpleFilterModifier::set_blend_mode(const int val) +void SimpleFilterModifier::set_blend_mode(const int val, bool notify) { + _notify = notify; _blend.set_active(val); } diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h index 9d595373975e965bbd9c88cf9ebdaf28ed982f3d..21b8e7c7f8247de5c462c50321958b7e19cf902b 100644 --- a/src/ui/widget/filter-effect-chooser.h +++ b/src/ui/widget/filter-effect-chooser.h @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -32,41 +33,44 @@ namespace Widget { class SimpleFilterModifier : public Gtk::VBox { public: - enum Flags { - NONE = 0, - BLUR = 1, - OPACITY= 2, - BLEND = 4 - }; + enum Flags { NONE = 0, BLUR = 1, OPACITY = 2, BLEND = 4, ISOLATION = 16 }; - SimpleFilterModifier(int flags); + SimpleFilterModifier(int flags); - sigc::signal& signal_blend_changed(); - sigc::signal& signal_blur_changed(); - sigc::signal& signal_opacity_changed(); + sigc::signal &signal_blend_changed(); + sigc::signal &signal_blur_changed(); + sigc::signal &signal_opacity_changed(); + sigc::signal &signal_isolation_changed(); - const Glib::ustring get_blend_mode(); - // Uses blend mode enum values, or -1 for a complex filter - void set_blend_mode(const int); + int get_isolation_mode(); + void set_isolation_mode(const int, bool notifi); - double get_blur_value() const; - void set_blur_value(const double); + int get_blend_mode(); + void set_blend_mode(const int, bool notifi); - double get_opacity_value() const; - void set_opacity_value(const double); + double get_blur_value() const; + void set_blur_value(const double); + + double get_opacity_value() const; + void set_opacity_value(const double); private: int _flags; + bool _notify; Gtk::HBox _hb_blend; Gtk::Label _lb_blend; + Gtk::Label _lb_isolation; ComboBoxEnum _blend; SpinScale _blur; SpinScale _opacity; + Gtk::CheckButton _isolation; + sigc::signal _signal_null; sigc::signal _signal_blend_changed; sigc::signal _signal_blur_changed; sigc::signal _signal_opacity_changed; + sigc::signal _signal_isolation_changed; }; } diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 4052e1d3809702168b4d43343ef8a7a877ad0f92..785cb589a78b473fc183a95e2109fc3792145585 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -37,6 +37,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _blend_tag(Glib::ustring(history_prefix) + ":blend"), _blur_tag(Glib::ustring(history_prefix) + ":blur"), _opacity_tag(Glib::ustring(history_prefix) + ":opacity"), + _isolation_tag(Glib::ustring(history_prefix) + ":isolation"), _filter_modifier(flags), _blocked(false) { @@ -48,6 +49,8 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _filter_modifier.signal_blend_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_blendBlurValueChanged)); _filter_modifier.signal_blur_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_blendBlurValueChanged)); _filter_modifier.signal_opacity_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_opacityValueChanged)); + _filter_modifier.signal_isolation_changed().connect( + sigc::mem_fun(*this, &ObjectCompositeSettings::_isolationValueChanged)); show_all_children(); } @@ -100,8 +103,6 @@ ObjectCompositeSettings::_blendBlurValueChanged() radius = 0; } - const Glib::ustring blendmode = _filter_modifier.get_blend_mode(); - //apply created filter to every selected item std::vector sel = _subject->list(); for (std::vector::const_iterator i = sel.begin() ; i != sel.end() ; ++i ) { @@ -112,18 +113,9 @@ ObjectCompositeSettings::_blendBlurValueChanged() SPItem * item = SP_ITEM(*i); SPStyle *style = item->style; g_assert(style != nullptr); - - SPCSSAttr *css = sp_repr_css_attr_new(); - - if (blendmode == "normal") { - sp_repr_css_unset_property(css, "mix-blend-mode"); - } else { - sp_repr_css_set_property(css, "mix-blend-mode", blendmode.c_str()); - } - - _subject->setCSS(css); - - sp_repr_css_attr_unref(css); + item->style->mix_blend_mode.set = TRUE; + item->style->mix_blend_mode.value = _filter_modifier.get_blend_mode(); + item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); if (radius == 0 && item->style->filter.set && filter_is_single_gaussian_blur(SP_FILTER(item->style->getFilter()))) { @@ -183,6 +175,35 @@ ObjectCompositeSettings::_opacityValueChanged() _blocked = false; } +void ObjectCompositeSettings::_isolationValueChanged() +{ + if (!_subject) { + return; + } + + SPDesktop *desktop = _subject->getDesktop(); + if (!desktop) { + return; + } + + if (_blocked) + return; + _blocked = true; + + for (auto item : _subject->list()) { + item->style->isolation.set = TRUE; + item->style->isolation.value = _filter_modifier.get_isolation_mode(); + item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); + } + + DocumentUndo::maybeDone(desktop->getDocument(), _isolation_tag.c_str(), _verb_code, _("Change isolation")); + + // resume interruptibility + // sp_canvas_end_forced_full_redraws(desktop->getCanvas()); + + _blocked = false; +} + void ObjectCompositeSettings::_subjectChanged() { if (!_subject) { @@ -211,16 +232,33 @@ ObjectCompositeSettings::_subjectChanged() { } //query now for current filter mode and average blurring of selection + const int isolation_result = _subject->queryStyle(&query, QUERY_STYLE_PROPERTY_ISOLATION); + switch (isolation_result) { + case QUERY_STYLE_NOTHING: + _filter_modifier.set_isolation_mode(SP_CSS_ISOLATION_AUTO, false); + break; + case QUERY_STYLE_SINGLE: + case QUERY_STYLE_MULTIPLE_SAME: + _filter_modifier.set_isolation_mode(query.isolation.value, true); // here dont work mix_blend_mode.set + break; + case QUERY_STYLE_MULTIPLE_DIFFERENT: + _filter_modifier.set_isolation_mode(SP_CSS_ISOLATION_AUTO, false); + // TODO: set text + break; + } + + // query now for current filter mode and average blurring of selection const int blend_result = _subject->queryStyle(&query, QUERY_STYLE_PROPERTY_BLEND); switch(blend_result) { case QUERY_STYLE_NOTHING: + _filter_modifier.set_blend_mode(0, false); break; case QUERY_STYLE_SINGLE: case QUERY_STYLE_MULTIPLE_SAME: - _filter_modifier.set_blend_mode(query.mix_blend_mode.value); // here dont work mix_blend_mode.set + _filter_modifier.set_blend_mode(query.mix_blend_mode.value, true); // here dont work mix_blend_mode.set break; case QUERY_STYLE_MULTIPLE_DIFFERENT: - // TODO: set text + _filter_modifier.set_blend_mode(0, false); break; } diff --git a/src/ui/widget/object-composite-settings.h b/src/ui/widget/object-composite-settings.h index 8e57bbf0cbb44ea6e1c8e0c601b0850a984cdc2b..96501185a67101425f2fdf8448c6973ee4e83a86 100644 --- a/src/ui/widget/object-composite-settings.h +++ b/src/ui/widget/object-composite-settings.h @@ -45,6 +45,7 @@ private: Glib::ustring _blend_tag; Glib::ustring _blur_tag; Glib::ustring _opacity_tag; + Glib::ustring _isolation_tag; StyleSubject *_subject; @@ -59,7 +60,7 @@ private: void _subjectChanged(); void _blendBlurValueChanged(); void _opacityValueChanged(); - + void _isolationValueChanged(); }; }