From 4570fc3cbb3d8e4427c6209c98876f6e88e10f80 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Date: Wed, 16 Oct 2019 01:35:35 +0200 Subject: [PATCH 1/8] add pdf import-export blend modes --- src/display/cairo-utils.cpp | 58 +++++++++++++++++++ src/display/cairo-utils.h | 2 +- src/display/drawing-item.cpp | 2 +- .../internal/cairo-render-context.cpp | 15 +++++ .../internal/pdfinput/svg-builder.cpp | 31 ++++++++-- src/extension/internal/pdfinput/svg-builder.h | 2 +- 6 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index d3ca85f7e1..21dbb1873e 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -1252,6 +1252,64 @@ private: /* None */ }; +void ink_cairo_css_blend_operator(cairo_t *ct, 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: + cairo_set_operator(ct, CAIRO_OPERATOR_MULTIPLY); + break; + case SP_CSS_BLEND_SCREEN: + cairo_set_operator(ct, CAIRO_OPERATOR_SCREEN); + break; + case SP_CSS_BLEND_DARKEN: + cairo_set_operator(ct, CAIRO_OPERATOR_DARKEN); + break; + case SP_CSS_BLEND_LIGHTEN: + cairo_set_operator(ct, CAIRO_OPERATOR_LIGHTEN); + break; + case SP_CSS_BLEND_OVERLAY: + cairo_set_operator(ct, CAIRO_OPERATOR_OVERLAY); + break; + case SP_CSS_BLEND_COLORDODGE: + cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_DODGE); + break; + case SP_CSS_BLEND_COLORBURN: + cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_BURN); + break; + case SP_CSS_BLEND_HARDLIGHT: + cairo_set_operator(ct, CAIRO_OPERATOR_HARD_LIGHT); + break; + case SP_CSS_BLEND_SOFTLIGHT: + cairo_set_operator(ct, CAIRO_OPERATOR_SOFT_LIGHT); + break; + case SP_CSS_BLEND_DIFFERENCE: + cairo_set_operator(ct, CAIRO_OPERATOR_DIFFERENCE); + break; + case SP_CSS_BLEND_EXCLUSION: + cairo_set_operator(ct, CAIRO_OPERATOR_EXCLUSION); + break; + case SP_CSS_BLEND_HUE: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_HUE); + break; + case SP_CSS_BLEND_SATURATION: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_SATURATION); + break; + case SP_CSS_BLEND_COLOR: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_COLOR); + break; + case SP_CSS_BLEND_LUMINOSITY: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_LUMINOSITY); + break; + case SP_CSS_BLEND_NORMAL: + default: + cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + break; + } +} + 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 fbcee5413a..9a176d9858 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -156,7 +156,7 @@ 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 &); - +void ink_cairo_css_blend_operator(cairo_t *ct, unsigned blend_mode); 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-item.cpp b/src/display/drawing-item.cpp index 81d01846e8..a9d70594a1 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -28,7 +28,7 @@ #include "object/sp-item.h" namespace Inkscape { - +// TODO find a way to use cairo utils one void set_cairo_blend_operator( DrawingContext &dc, unsigned blend_mode ) { // All of the blend modes are implemented in Cairo as of 1.10. diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index adc4f1eb5b..7280e6d584 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) { + ink_cairo_css_blend_operator(_cr, 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) { + ink_cairo_css_blend_operator(_cr, 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) { + ink_cairo_css_blend_operator(_cr, 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 9b4b55e212..36bdf1aab7 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(); + std::cout << blendmode << enum_blend_mode[blendmode].key << std::endl; + 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); } @@ -1151,7 +1171,7 @@ void SvgBuilder::updateFont(GfxState *state) { } os_font_size << css_font_size; sp_repr_css_set_property(_font_style, "font-size", os_font_size.str().c_str()); - + // Writing mode if ( font->getWMode() == 0 ) { sp_repr_css_set_property(_font_style, "writing-mode", "lr"); @@ -1650,7 +1670,7 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height sp_repr_css_change(image_node, css, "style"); sp_repr_css_attr_unref(css); } - + // PS/PDF images are placed via a transformation matrix, no preserveAspectRatio used image_node->setAttribute("preserveAspectRatio", "none"); @@ -1710,12 +1730,13 @@ Inkscape::XML::Node *SvgBuilder::_createMask(double width, double height) { } } -void SvgBuilder::addImage(GfxState * /*state*/, Stream *str, int width, int height, +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); + _setBlendMode(image_node, state); + _container->appendChild(image_node); Inkscape::GC::release(image_node); } } diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index 8168617f61..c42d694dec 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); -- GitLab From 56a2b40f840464cdd1c59942d25c12819e66c0d6 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Wed, 16 Oct 2019 15:45:20 +0200 Subject: [PATCH 2/8] Add export to PDF with bending modes --- src/extension/internal/pdfinput/svg-builder.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 36bdf1aab7..5aa0e672b7 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -415,7 +415,6 @@ void SvgBuilder::_setFillStyle(SPCSSAttr *css, GfxState *state, bool even_odd) { void SvgBuilder::_setBlendMode(Inkscape::XML::Node *node, GfxState *state) { SPCSSAttr *css = sp_repr_css_attr( node, "style" ); GfxBlendMode blendmode = state->getBlendMode(); - std::cout << blendmode << enum_blend_mode[blendmode].key << std::endl; if (blendmode) { sp_repr_css_set_property(css, "mix-blend-mode", enum_blend_mode[blendmode].key); } @@ -1447,6 +1446,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; @@ -1455,6 +1459,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; @@ -1756,6 +1764,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 ) { @@ -1779,7 +1788,7 @@ 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, +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) { @@ -1808,11 +1817,12 @@ 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, +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) { @@ -1836,6 +1846,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); } } -- GitLab From b0f037d663c4783ccc00677800997b41ba251fbe Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Thu, 17 Oct 2019 02:07:19 +0200 Subject: [PATCH 3/8] Add isolation --- src/desktop-style.cpp | 53 ++++++++++++++++++ src/desktop-style.h | 1 + src/display/drawing-item.cpp | 14 +++-- src/ui/dialog/fill-and-stroke.cpp | 1 + src/ui/dialog/layers.cpp | 1 + src/ui/dialog/objects.cpp | 38 ++++++++++++- src/ui/dialog/objects.h | 4 ++ src/ui/widget/filter-effect-chooser.cpp | 24 +++++++++ src/ui/widget/filter-effect-chooser.h | 11 +++- src/ui/widget/object-composite-settings.cpp | 59 +++++++++++++++++++-- src/ui/widget/object-composite-settings.h | 2 + 11 files changed, 197 insertions(+), 11 deletions(-) diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 092c48ec3f..9466432a54 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1750,6 +1750,55 @@ 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 +1922,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 +1975,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 +1989,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 b2e0764009..c32bc24479 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/drawing-item.cpp b/src/display/drawing-item.cpp index a9d70594a1..911a2814b4 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -773,8 +773,11 @@ 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 ); - + if (_isolation != SP_CSS_ISOLATION_ISOLATE || _mix_blend_mode) { + set_cairo_blend_operator( dc, _mix_blend_mode ); + } else { + set_cairo_blend_operator( dc, SP_CSS_BLEND_NORMAL ); + } _cache->paintFromCache(dc, carea); if (!carea) { return RENDER_OK; @@ -925,11 +928,16 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag cachect.fill(); _cache->markClean(*carea); } + set_cairo_blend_operator( dc, SP_CSS_BLEND_NORMAL ); dc.rectangle(*carea); dc.setSource(&intermediate); - set_cairo_blend_operator( dc, _mix_blend_mode ); + // 7. Render blend mode + if (_isolation != SP_CSS_ISOLATION_ISOLATE || _mix_blend_mode) { + set_cairo_blend_operator( dc, _mix_blend_mode ); + } dc.fill(); dc.setSource(0,0,0,0); + // the call above is to clear a ref on the intermediate surface held by dc return render_result; diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index 22dd407e78..fd28cbc870 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 e2aa4e2c9e..06af29a6e3 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 272d98595e..88c564722d 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -577,10 +577,14 @@ 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 + bool isolation = item->style->isolation.set && item->style->isolation.value == SP_CSS_ISOLATION_ISOLATE; + _filter_modifier.set_isolation_active(isolation); // Set the opacity double opacity = (item->style->opacity.set ? SP_SCALE24_TO_FLOAT(item->style->opacity.value) : 1); opacity *= 100; // Display in percent. @@ -613,6 +617,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 +1190,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,6 +1605,33 @@ 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_active() ? SP_CSS_ISOLATION_ISOLATE : SP_CSS_ISOLATION_AUTO; + item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); + } +} + /** * Callback for when the blend mode is changed */ @@ -1717,7 +1750,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 +1893,7 @@ 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 3800b2da5d..bc3712f927 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; @@ -218,6 +219,9 @@ private: 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(); diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 98074d3547..5885cb4f1d 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -54,6 +54,7 @@ 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) @@ -72,6 +73,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,6 +98,12 @@ 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() +{ + return _signal_isolation_changed; } sigc::signal& SimpleFilterModifier::signal_blend_changed() @@ -107,6 +121,16 @@ sigc::signal& SimpleFilterModifier::signal_opacity_changed() return _signal_opacity_changed; } +bool SimpleFilterModifier::get_isolation_active() +{ + return _isolation.get_active(); +} + +void SimpleFilterModifier::set_isolation_active(bool active) +{ + _isolation.set_active(active); +} + const Glib::ustring SimpleFilterModifier::get_blend_mode() { const Util::EnumData *d = _blend.get_active_data(); diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h index 9d59537397..9806e611c0 100644 --- a/src/ui/widget/filter-effect-chooser.h +++ b/src/ui/widget/filter-effect-chooser.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "combo-enums.h" #include "spin-scale.h" @@ -36,7 +37,8 @@ public: NONE = 0, BLUR = 1, OPACITY= 2, - BLEND = 4 + BLEND = 4, + ISOLATION = 16 }; SimpleFilterModifier(int flags); @@ -44,6 +46,7 @@ public: 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 @@ -55,18 +58,24 @@ public: double get_opacity_value() const; void set_opacity_value(const double); + bool get_isolation_active(); + void set_isolation_active(bool active); + private: int _flags; Gtk::HBox _hb_blend; Gtk::Label _lb_blend; + Gtk::Label _lb_isolation; ComboBoxEnum _blend; SpinScale _blur; SpinScale _opacity; + Gtk::CheckButton _isolation; 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 4052e1d380..6f0b0f5007 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,7 @@ 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(); } @@ -113,16 +115,13 @@ ObjectCompositeSettings::_blendBlurValueChanged() SPStyle *style = item->style; g_assert(style != nullptr); - SPCSSAttr *css = sp_repr_css_attr_new(); - + SPCSSAttr* css = sp_repr_css_attr (item->getRepr(), "style"); 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_set(item->getRepr(), css, "style"); sp_repr_css_attr_unref(css); if (radius == 0 && item->style->filter.set @@ -183,6 +182,42 @@ 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()) { + SPCSSAttr* css = sp_repr_css_attr (item->getRepr(), "style"); + if (_filter_modifier.get_isolation_active()) { + sp_repr_css_set_property (css, "isolation", "isolate"); + } else { + sp_repr_css_unset_property(css, "isolation"); + } + sp_repr_css_set(item->getRepr(), css, "style"); + sp_repr_css_attr_unref(css); + } + + 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,6 +246,20 @@ 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: + break; + case QUERY_STYLE_SINGLE: + case QUERY_STYLE_MULTIPLE_SAME: + _filter_modifier.set_isolation_active(query.isolation.value == SP_CSS_ISOLATION_ISOLATE); // here dont work mix_blend_mode.set + break; + case QUERY_STYLE_MULTIPLE_DIFFERENT: + // 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: diff --git a/src/ui/widget/object-composite-settings.h b/src/ui/widget/object-composite-settings.h index 8e57bbf0cb..4e1c63087f 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,6 +60,7 @@ private: void _subjectChanged(); void _blendBlurValueChanged(); void _opacityValueChanged(); + void _isolationValueChanged(); }; -- GitLab From 8ddd8170d89453183a799fdbf5a57dc352c02aa2 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Thu, 17 Oct 2019 18:11:44 +0200 Subject: [PATCH 4/8] Add export/import PDF blendmodes and add isolation midifier --- src/desktop-style.cpp | 9 +- src/display/cairo-utils.cpp | 101 ++++++++-------- src/display/drawing-item.cpp | 112 ++++++++++++++---- .../internal/pdfinput/svg-builder.cpp | 24 ++-- src/ui/dialog/objects.cpp | 40 +++---- src/ui/dialog/objects.h | 6 +- src/ui/tools/node-tool.cpp | 5 +- src/ui/widget/filter-effect-chooser.cpp | 33 ++++-- src/ui/widget/filter-effect-chooser.h | 15 +-- src/ui/widget/object-composite-settings.cpp | 51 ++++---- src/ui/widget/object-composite-settings.h | 1 - 11 files changed, 232 insertions(+), 165 deletions(-) diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 9466432a54..160000a784 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1750,8 +1750,7 @@ objects_query_blend (const std::vector &objects, SPStyle *style_res) } } -int -objects_query_isolation (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; @@ -1778,7 +1777,7 @@ objects_query_isolation (const std::vector &objects, SPStyle *style_res isolation = 0; } - if(isolation_prev != empty_prev && isolation_prev != isolation) + if (isolation_prev != empty_prev && isolation_prev != isolation) same_isolation = false; isolation_prev = isolation; } @@ -1792,7 +1791,7 @@ objects_query_isolation (const std::vector &objects, SPStyle *style_res } else if (items == 1) { return QUERY_STYLE_SINGLE; } else { - if(same_isolation) + if (same_isolation) return QUERY_STYLE_MULTIPLE_SAME; else return QUERY_STYLE_MULTIPLE_DIFFERENT; @@ -1923,7 +1922,7 @@ 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); + return objects_query_isolation(list, style); } else if (property == QUERY_STYLE_PROPERTY_BLUR) { return objects_query_blur (list, style); } diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 21dbb1873e..39c706da32 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -1252,61 +1252,62 @@ private: /* None */ }; -void ink_cairo_css_blend_operator(cairo_t *ct, unsigned blend_mode ) { +void ink_cairo_css_blend_operator(cairo_t *ct, 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: - cairo_set_operator(ct, CAIRO_OPERATOR_MULTIPLY); - break; - case SP_CSS_BLEND_SCREEN: - cairo_set_operator(ct, CAIRO_OPERATOR_SCREEN); - break; - case SP_CSS_BLEND_DARKEN: - cairo_set_operator(ct, CAIRO_OPERATOR_DARKEN); - break; - case SP_CSS_BLEND_LIGHTEN: - cairo_set_operator(ct, CAIRO_OPERATOR_LIGHTEN); - break; - case SP_CSS_BLEND_OVERLAY: - cairo_set_operator(ct, CAIRO_OPERATOR_OVERLAY); - break; - case SP_CSS_BLEND_COLORDODGE: - cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_DODGE); - break; - case SP_CSS_BLEND_COLORBURN: - cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_BURN); - break; - case SP_CSS_BLEND_HARDLIGHT: - cairo_set_operator(ct, CAIRO_OPERATOR_HARD_LIGHT); - break; - case SP_CSS_BLEND_SOFTLIGHT: - cairo_set_operator(ct, CAIRO_OPERATOR_SOFT_LIGHT); - break; - case SP_CSS_BLEND_DIFFERENCE: - cairo_set_operator(ct, CAIRO_OPERATOR_DIFFERENCE); - break; - case SP_CSS_BLEND_EXCLUSION: - cairo_set_operator(ct, CAIRO_OPERATOR_EXCLUSION); - break; - case SP_CSS_BLEND_HUE: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_HUE); - break; - case SP_CSS_BLEND_SATURATION: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_SATURATION); - break; - case SP_CSS_BLEND_COLOR: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_COLOR); - break; - case SP_CSS_BLEND_LUMINOSITY: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_LUMINOSITY); - break; - case SP_CSS_BLEND_NORMAL: - default: - cairo_set_operator(ct, CAIRO_OPERATOR_OVER); - break; + case SP_CSS_BLEND_MULTIPLY: + cairo_set_operator(ct, CAIRO_OPERATOR_MULTIPLY); + break; + case SP_CSS_BLEND_SCREEN: + cairo_set_operator(ct, CAIRO_OPERATOR_SCREEN); + break; + case SP_CSS_BLEND_DARKEN: + cairo_set_operator(ct, CAIRO_OPERATOR_DARKEN); + break; + case SP_CSS_BLEND_LIGHTEN: + cairo_set_operator(ct, CAIRO_OPERATOR_LIGHTEN); + break; + case SP_CSS_BLEND_OVERLAY: + cairo_set_operator(ct, CAIRO_OPERATOR_OVERLAY); + break; + case SP_CSS_BLEND_COLORDODGE: + cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_DODGE); + break; + case SP_CSS_BLEND_COLORBURN: + cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_BURN); + break; + case SP_CSS_BLEND_HARDLIGHT: + cairo_set_operator(ct, CAIRO_OPERATOR_HARD_LIGHT); + break; + case SP_CSS_BLEND_SOFTLIGHT: + cairo_set_operator(ct, CAIRO_OPERATOR_SOFT_LIGHT); + break; + case SP_CSS_BLEND_DIFFERENCE: + cairo_set_operator(ct, CAIRO_OPERATOR_DIFFERENCE); + break; + case SP_CSS_BLEND_EXCLUSION: + cairo_set_operator(ct, CAIRO_OPERATOR_EXCLUSION); + break; + case SP_CSS_BLEND_HUE: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_HUE); + break; + case SP_CSS_BLEND_SATURATION: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_SATURATION); + break; + case SP_CSS_BLEND_COLOR: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_COLOR); + break; + case SP_CSS_BLEND_LUMINOSITY: + cairo_set_operator(ct, CAIRO_OPERATOR_HSL_LUMINOSITY); + break; + case SP_CSS_BLEND_NORMAL: + default: + cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + break; } } diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 911a2814b4..7df7ecc9e1 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -87,6 +87,66 @@ void set_cairo_blend_operator( DrawingContext &dc, unsigned blend_mode ) { } } +cairo_operator_t get_cairo_blend_operator(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/ + cairo_operator_t ret = CAIRO_OPERATOR_OVER; + switch (blend_mode) { + case SP_CSS_BLEND_MULTIPLY: + ret = CAIRO_OPERATOR_MULTIPLY; + break; + case SP_CSS_BLEND_SCREEN: + ret = CAIRO_OPERATOR_SCREEN; + break; + case SP_CSS_BLEND_DARKEN: + ret = CAIRO_OPERATOR_DARKEN; + break; + case SP_CSS_BLEND_LIGHTEN: + ret = CAIRO_OPERATOR_LIGHTEN; + break; + case SP_CSS_BLEND_OVERLAY: + ret = CAIRO_OPERATOR_OVERLAY; + break; + case SP_CSS_BLEND_COLORDODGE: + ret = CAIRO_OPERATOR_COLOR_DODGE; + break; + case SP_CSS_BLEND_COLORBURN: + ret = CAIRO_OPERATOR_COLOR_BURN; + break; + case SP_CSS_BLEND_HARDLIGHT: + ret = CAIRO_OPERATOR_HARD_LIGHT; + break; + case SP_CSS_BLEND_SOFTLIGHT: + ret = CAIRO_OPERATOR_SOFT_LIGHT; + break; + case SP_CSS_BLEND_DIFFERENCE: + ret = CAIRO_OPERATOR_DIFFERENCE; + break; + case SP_CSS_BLEND_EXCLUSION: + ret = CAIRO_OPERATOR_EXCLUSION; + break; + case SP_CSS_BLEND_HUE: + ret = CAIRO_OPERATOR_HSL_HUE; + break; + case SP_CSS_BLEND_SATURATION: + ret = CAIRO_OPERATOR_HSL_SATURATION; + break; + case SP_CSS_BLEND_COLOR: + ret = CAIRO_OPERATOR_HSL_COLOR; + break; + case SP_CSS_BLEND_LUMINOSITY: + ret = CAIRO_OPERATOR_HSL_LUMINOSITY; + break; + case SP_CSS_BLEND_NORMAL: + default: + ret = CAIRO_OPERATOR_OVER; + break; + } + return ret; +} + /** * @class DrawingItem * SVG drawing item for display. @@ -629,8 +689,11 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } } } - - if (to_update & STATE_CACHE) { + bool nocache = _mix_blend_mode != SP_CSS_BLEND_NORMAL; + if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE) { + nocache = true; + } + if (to_update & STATE_CACHE && !nocache) { // Update cache score for this item if (_has_cache_iterator) { // remove old score information @@ -770,14 +833,9 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // Render from cache if possible // Bypass in case of pattern, see below. - if (_cached && !(flags & RENDER_BYPASS_CACHE)) { + if (!_mix_blend_mode && _cached && !(flags & RENDER_BYPASS_CACHE)) { if (_cache) { _cache->prepare(); - if (_isolation != SP_CSS_ISOLATION_ISOLATE || _mix_blend_mode) { - set_cairo_blend_operator( dc, _mix_blend_mode ); - } else { - set_cairo_blend_operator( dc, SP_CSS_BLEND_NORMAL ); - } _cache->paintFromCache(dc, carea); if (!carea) { return RENDER_OK; @@ -801,13 +859,14 @@ 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 + nir |= (_isolation == SP_CSS_ISOLATION_ISOLATE); // 7. Explicit isolatiom + nir |= (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE); // 8. Explicit parent isolatiom /* How the rendering is done. * @@ -826,7 +885,16 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // filters and opacity do not apply when rendering the ancestors of the filtered // element if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { + if (parent() && + parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && + cairo_get_operator(dc.raw()) != get_cairo_blend_operator(SP_CSS_BLEND_NORMAL)) + { + set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); + } else if (cairo_get_operator(dc.raw()) != get_cairo_blend_operator(_mix_blend_mode)) { + set_cairo_blend_operator(dc, _mix_blend_mode); + } return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); + } // iarea is the bounding box for intermediate rendering @@ -920,7 +988,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag ict.paint(); // 6. Paint the completed rendering onto the base context (or into cache) - if (_cached && _cache) { + if (!_mix_blend_mode &&_cached && _cache) { DrawingContext cachect(*_cache); cachect.rectangle(*carea); cachect.setOperator(CAIRO_OPERATOR_SOURCE); @@ -928,15 +996,17 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag cachect.fill(); _cache->markClean(*carea); } - set_cairo_blend_operator( dc, SP_CSS_BLEND_NORMAL ); + dc.rectangle(*carea); dc.setSource(&intermediate); // 7. Render blend mode - if (_isolation != SP_CSS_ISOLATION_ISOLATE || _mix_blend_mode) { - set_cairo_blend_operator( dc, _mix_blend_mode ); - } + set_cairo_blend_operator(dc, _mix_blend_mode); dc.fill(); dc.setSource(0,0,0,0); + // Web isolation only works if parent doesnt have transform + if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE) { + set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); + } // the call above is to clear a ref on the intermediate surface held by dc @@ -1123,7 +1193,7 @@ DrawingItem::_markForRendering() bkg_root = i; } } - + if (bkg_root) { bkg_root->_invalidateFilterBackground(*dirty); } diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 5aa0e672b7..4402af5a6e 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -412,20 +412,21 @@ void SvgBuilder::_setFillStyle(SPCSSAttr *css, GfxState *state, bool even_odd) { * \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" ); +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 ); + if (value.empty()) { + node->setAttribute("style", nullptr); } else { node->setAttribute("style", value.c_str()); } - sp_repr_css_attr_unref( css ); + sp_repr_css_attr_unref(css); } /** * \brief Sets style properties from poppler's GfxState data structure @@ -1170,7 +1171,7 @@ void SvgBuilder::updateFont(GfxState *state) { } os_font_size << css_font_size; sp_repr_css_set_property(_font_style, "font-size", os_font_size.str().c_str()); - + // Writing mode if ( font->getWMode() == 0 ) { sp_repr_css_set_property(_font_style, "writing-mode", "lr"); @@ -1678,7 +1679,7 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height sp_repr_css_change(image_node, css, "style"); sp_repr_css_attr_unref(css); } - + // PS/PDF images are placed via a transformation matrix, no preserveAspectRatio used image_node->setAttribute("preserveAspectRatio", "none"); @@ -1738,11 +1739,12 @@ 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) { + 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); diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 88c564722d..2cdbdc1257 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -583,15 +583,14 @@ void ObjectsPanel::_setCompositingValues(SPItem *item) _blurConnection.block(); // Set the isolation - bool isolation = item->style->isolation.set && item->style->isolation.value == SP_CSS_ISOLATION_ISOLATE; - _filter_modifier.set_isolation_active(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) { @@ -1620,14 +1619,14 @@ void ObjectsPanel::_isolationValueChanged() * Change the isolation of the selected items in the tree * @param iter Current tree item */ -void ObjectsPanel::_isolationChangedIter(const Gtk::TreeIter& iter) +void ObjectsPanel::_isolationChangedIter(const Gtk::TreeIter &iter) { Gtk::TreeModel::Row row = *iter; - SPItem* item = row[_model->_colObject]; - if (item) - { + SPItem *item = row[_model->_colObject]; + if (item) { item->style->isolation.set = TRUE; - item->style->isolation.value = _filter_modifier.get_isolation_active() ? SP_CSS_ISOLATION_ISOLATE : SP_CSS_ISOLATION_AUTO; + item->style->isolation.value = + _filter_modifier.get_isolation_mode(); item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); } } @@ -1638,9 +1637,7 @@ void ObjectsPanel::_isolationChangedIter(const Gtk::TreeIter& iter) 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; } @@ -1650,23 +1647,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); } } @@ -1893,7 +1882,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)); + _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 bc3712f927..4d1efa6c0d 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -218,14 +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 _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 931e08d15b..93066fdb65 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/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 5885cb4f1d..26a2b04354 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -58,6 +58,7 @@ SimpleFilterModifier::SimpleFilterModifier(int flags) , _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"); @@ -103,45 +104,57 @@ SimpleFilterModifier::SimpleFilterModifier(int flags) sigc::signal& SimpleFilterModifier::signal_isolation_changed() { - return _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; } -bool SimpleFilterModifier::get_isolation_active() +int SimpleFilterModifier::get_isolation_mode() { - return _isolation.get_active(); + return _isolation.get_active() ? SP_CSS_ISOLATION_ISOLATE : SP_CSS_ISOLATION_AUTO; } -void SimpleFilterModifier::set_isolation_active(bool active) +void SimpleFilterModifier::set_isolation_mode(const int val, bool notify) { - _isolation.set_active(active); + _notify = notify; + _isolation.set_active(val == SP_CSS_ISOLATION_ISOLATE); } -const Glib::ustring SimpleFilterModifier::get_blend_mode() +int SimpleFilterModifier::get_blend_mode() { const Util::EnumData *d = _blend.get_active_data(); if (d) { - return _blend.get_active_data()->key; + return _blend.get_active_data()->id; } else - return "normal"; + 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 9806e611c0..7d166112ba 100644 --- a/src/ui/widget/filter-effect-chooser.h +++ b/src/ui/widget/filter-effect-chooser.h @@ -15,9 +15,9 @@ */ #include +#include #include #include -#include #include "combo-enums.h" #include "spin-scale.h" @@ -48,9 +48,11 @@ public: 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); + + int get_blend_mode(); + void set_blend_mode(const int, bool notifi); double get_blur_value() const; void set_blur_value(const double); @@ -58,11 +60,9 @@ public: double get_opacity_value() const; void set_opacity_value(const double); - bool get_isolation_active(); - void set_isolation_active(bool active); - private: int _flags; + bool _notify; Gtk::HBox _hb_blend; Gtk::Label _lb_blend; @@ -72,6 +72,7 @@ private: SpinScale _opacity; Gtk::CheckButton _isolation; + sigc::signal _signal_null; sigc::signal _signal_blend_changed; sigc::signal _signal_blur_changed; sigc::signal _signal_opacity_changed; diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 6f0b0f5007..785cb589a7 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -49,7 +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)); + _filter_modifier.signal_isolation_changed().connect( + sigc::mem_fun(*this, &ObjectCompositeSettings::_isolationValueChanged)); show_all_children(); } @@ -102,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 ) { @@ -114,15 +113,9 @@ ObjectCompositeSettings::_blendBlurValueChanged() SPItem * item = SP_ITEM(*i); SPStyle *style = item->style; g_assert(style != nullptr); - - SPCSSAttr* css = sp_repr_css_attr (item->getRepr(), "style"); - 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_set(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); if (radius == 0 && item->style->filter.set && filter_is_single_gaussian_blur(SP_FILTER(item->style->getFilter()))) { @@ -182,8 +175,7 @@ ObjectCompositeSettings::_opacityValueChanged() _blocked = false; } -void -ObjectCompositeSettings::_isolationValueChanged() +void ObjectCompositeSettings::_isolationValueChanged() { if (!_subject) { return; @@ -198,22 +190,16 @@ ObjectCompositeSettings::_isolationValueChanged() return; _blocked = true; - for (auto item:_subject->list()) { - SPCSSAttr* css = sp_repr_css_attr (item->getRepr(), "style"); - if (_filter_modifier.get_isolation_active()) { - sp_repr_css_set_property (css, "isolation", "isolate"); - } else { - sp_repr_css_unset_property(css, "isolation"); - } - sp_repr_css_set(item->getRepr(), css, "style"); - sp_repr_css_attr_unref(css); + 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")); + DocumentUndo::maybeDone(desktop->getDocument(), _isolation_tag.c_str(), _verb_code, _("Change isolation")); // resume interruptibility - //sp_canvas_end_forced_full_redraws(desktop->getCanvas()); + // sp_canvas_end_forced_full_redraws(desktop->getCanvas()); _blocked = false; } @@ -247,29 +233,32 @@ 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) { + 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_active(query.isolation.value == SP_CSS_ISOLATION_ISOLATE); // here dont work mix_blend_mode.set + _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 + // 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 4e1c63087f..96501185a6 100644 --- a/src/ui/widget/object-composite-settings.h +++ b/src/ui/widget/object-composite-settings.h @@ -61,7 +61,6 @@ private: void _blendBlurValueChanged(); void _opacityValueChanged(); void _isolationValueChanged(); - }; } -- GitLab From f527fdd83ffbfa0f13312704a0ecea42581f7b29 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Thu, 17 Oct 2019 18:15:31 +0200 Subject: [PATCH 5/8] Add export/import PDF blendmodes and add isolation midifier. Styling --- src/display/drawing-item.cpp | 112 +++++++++--------- .../internal/pdfinput/svg-builder.cpp | 20 ++-- src/ui/dialog/objects.cpp | 5 +- src/ui/dialog/objects.h | 4 +- src/ui/tools/node-tool.cpp | 2 +- src/ui/widget/filter-effect-chooser.cpp | 4 +- src/ui/widget/filter-effect-chooser.h | 34 +++--- 7 files changed, 86 insertions(+), 95 deletions(-) diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 7df7ecc9e1..64f4a79134 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -87,62 +87,63 @@ void set_cairo_blend_operator( DrawingContext &dc, unsigned blend_mode ) { } } -cairo_operator_t get_cairo_blend_operator(unsigned blend_mode) { +cairo_operator_t get_cairo_blend_operator(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/ cairo_operator_t ret = CAIRO_OPERATOR_OVER; switch (blend_mode) { - case SP_CSS_BLEND_MULTIPLY: - ret = CAIRO_OPERATOR_MULTIPLY; - break; - case SP_CSS_BLEND_SCREEN: - ret = CAIRO_OPERATOR_SCREEN; - break; - case SP_CSS_BLEND_DARKEN: - ret = CAIRO_OPERATOR_DARKEN; - break; - case SP_CSS_BLEND_LIGHTEN: - ret = CAIRO_OPERATOR_LIGHTEN; - break; - case SP_CSS_BLEND_OVERLAY: - ret = CAIRO_OPERATOR_OVERLAY; - break; - case SP_CSS_BLEND_COLORDODGE: - ret = CAIRO_OPERATOR_COLOR_DODGE; - break; - case SP_CSS_BLEND_COLORBURN: - ret = CAIRO_OPERATOR_COLOR_BURN; - break; - case SP_CSS_BLEND_HARDLIGHT: - ret = CAIRO_OPERATOR_HARD_LIGHT; - break; - case SP_CSS_BLEND_SOFTLIGHT: - ret = CAIRO_OPERATOR_SOFT_LIGHT; - break; - case SP_CSS_BLEND_DIFFERENCE: - ret = CAIRO_OPERATOR_DIFFERENCE; - break; - case SP_CSS_BLEND_EXCLUSION: - ret = CAIRO_OPERATOR_EXCLUSION; - break; - case SP_CSS_BLEND_HUE: - ret = CAIRO_OPERATOR_HSL_HUE; - break; - case SP_CSS_BLEND_SATURATION: - ret = CAIRO_OPERATOR_HSL_SATURATION; - break; - case SP_CSS_BLEND_COLOR: - ret = CAIRO_OPERATOR_HSL_COLOR; - break; - case SP_CSS_BLEND_LUMINOSITY: - ret = CAIRO_OPERATOR_HSL_LUMINOSITY; - break; - case SP_CSS_BLEND_NORMAL: - default: - ret = CAIRO_OPERATOR_OVER; - break; + case SP_CSS_BLEND_MULTIPLY: + ret = CAIRO_OPERATOR_MULTIPLY; + break; + case SP_CSS_BLEND_SCREEN: + ret = CAIRO_OPERATOR_SCREEN; + break; + case SP_CSS_BLEND_DARKEN: + ret = CAIRO_OPERATOR_DARKEN; + break; + case SP_CSS_BLEND_LIGHTEN: + ret = CAIRO_OPERATOR_LIGHTEN; + break; + case SP_CSS_BLEND_OVERLAY: + ret = CAIRO_OPERATOR_OVERLAY; + break; + case SP_CSS_BLEND_COLORDODGE: + ret = CAIRO_OPERATOR_COLOR_DODGE; + break; + case SP_CSS_BLEND_COLORBURN: + ret = CAIRO_OPERATOR_COLOR_BURN; + break; + case SP_CSS_BLEND_HARDLIGHT: + ret = CAIRO_OPERATOR_HARD_LIGHT; + break; + case SP_CSS_BLEND_SOFTLIGHT: + ret = CAIRO_OPERATOR_SOFT_LIGHT; + break; + case SP_CSS_BLEND_DIFFERENCE: + ret = CAIRO_OPERATOR_DIFFERENCE; + break; + case SP_CSS_BLEND_EXCLUSION: + ret = CAIRO_OPERATOR_EXCLUSION; + break; + case SP_CSS_BLEND_HUE: + ret = CAIRO_OPERATOR_HSL_HUE; + break; + case SP_CSS_BLEND_SATURATION: + ret = CAIRO_OPERATOR_HSL_SATURATION; + break; + case SP_CSS_BLEND_COLOR: + ret = CAIRO_OPERATOR_HSL_COLOR; + break; + case SP_CSS_BLEND_LUMINOSITY: + ret = CAIRO_OPERATOR_HSL_LUMINOSITY; + break; + case SP_CSS_BLEND_NORMAL: + default: + ret = CAIRO_OPERATOR_OVER; + break; } return ret; } @@ -885,16 +886,13 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // filters and opacity do not apply when rendering the ancestors of the filtered // element if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { - if (parent() && - parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && - cairo_get_operator(dc.raw()) != get_cairo_blend_operator(SP_CSS_BLEND_NORMAL)) - { + if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && + cairo_get_operator(dc.raw()) != get_cairo_blend_operator(SP_CSS_BLEND_NORMAL)) { set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); } else if (cairo_get_operator(dc.raw()) != get_cairo_blend_operator(_mix_blend_mode)) { set_cairo_blend_operator(dc, _mix_blend_mode); } return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); - } // iarea is the bounding box for intermediate rendering @@ -988,7 +986,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag ict.paint(); // 6. Paint the completed rendering onto the base context (or into cache) - if (!_mix_blend_mode &&_cached && _cache) { + if (!_mix_blend_mode && _cached && _cache) { DrawingContext cachect(*_cache); cachect.rectangle(*carea); cachect.setOperator(CAIRO_OPERATOR_SOURCE); @@ -1193,7 +1191,7 @@ DrawingItem::_markForRendering() bkg_root = i; } } - + if (bkg_root) { bkg_root->_invalidateFilterBackground(*dirty); } diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 4402af5a6e..14727eba5f 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -1748,7 +1748,7 @@ void SvgBuilder::addImage(GfxState *state, Stream *str, int width, int height, G _setBlendMode(image_node, state); _container->appendChild(image_node); Inkscape::GC::release(image_node); - } + } } void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int height, @@ -1790,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); @@ -1823,11 +1823,11 @@ void SvgBuilder::addMaskedImage(GfxState *state, Stream *str, int width, int hei 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); diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 2cdbdc1257..8682cfd0c3 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -1625,8 +1625,7 @@ void ObjectsPanel::_isolationChangedIter(const Gtk::TreeIter &iter) SPItem *item = row[_model->_colObject]; if (item) { item->style->isolation.set = TRUE; - item->style->isolation.value = - _filter_modifier.get_isolation_mode(); + item->style->isolation.value = _filter_modifier.get_isolation_mode(); item->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); } } @@ -1647,7 +1646,7 @@ void ObjectsPanel::_blendValueChanged() * @param iter Current tree item * @param blendmode Blend mode to set */ -void ObjectsPanel::_blendChangedIter(const Gtk::TreeIter& iter) +void ObjectsPanel::_blendChangedIter(const Gtk::TreeIter &iter) { Gtk::TreeModel::Row row = *iter; SPItem* item = row[_model->_colObject]; diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index 4d1efa6c0d..1553033748 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -224,8 +224,8 @@ private: void _opacityChangedIter(const Gtk::TreeIter& iter); void _opacityValueChanged(); - - void _blendChangedIter(const Gtk::TreeIter& iter); + + 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 93066fdb65..f994f85cf6 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -500,7 +500,7 @@ bool NodeTool::root_handler(GdkEvent* event) { case GDK_MOTION_NOTIFY: { sp_update_helperpath(); SPItem *over_item = nullptr; - if (!desktop->canvas->_scrooling || MOD__CTRL(event) || MOD__SHIFT(event)|| MOD__ALT(event)) { + 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/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 26a2b04354..dae53193d2 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -102,7 +102,7 @@ SimpleFilterModifier::SimpleFilterModifier(int flags) _isolation.signal_toggled().connect(signal_isolation_changed()); } -sigc::signal& SimpleFilterModifier::signal_isolation_changed() +sigc::signal &SimpleFilterModifier::signal_isolation_changed() { if (_notify) { return _signal_isolation_changed; @@ -128,7 +128,7 @@ sigc::signal& SimpleFilterModifier::signal_blur_changed() sigc::signal& SimpleFilterModifier::signal_opacity_changed() { - //we dont use notifi to block use averaje for multiple + // we dont use notifi to block use averaje for multiple return _signal_opacity_changed; } diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h index 7d166112ba..21b8e7c7f8 100644 --- a/src/ui/widget/filter-effect-chooser.h +++ b/src/ui/widget/filter-effect-chooser.h @@ -33,32 +33,26 @@ namespace Widget { class SimpleFilterModifier : public Gtk::VBox { public: - enum Flags { - NONE = 0, - BLUR = 1, - OPACITY= 2, - BLEND = 4, - ISOLATION = 16 - }; + 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_isolation_changed(); + sigc::signal &signal_blend_changed(); + sigc::signal &signal_blur_changed(); + sigc::signal &signal_opacity_changed(); + sigc::signal &signal_isolation_changed(); - int get_isolation_mode(); - void set_isolation_mode(const int, bool notifi); + int get_isolation_mode(); + void set_isolation_mode(const int, bool notifi); - int get_blend_mode(); - void set_blend_mode(const int, bool notifi); + int get_blend_mode(); + void set_blend_mode(const int, bool notifi); - double get_blur_value() const; - void set_blur_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); + double get_opacity_value() const; + void set_opacity_value(const double); private: int _flags; -- GitLab From 7258c136fd2a6893fa14ec0073de1ea463aaddab Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Fri, 18 Oct 2019 18:58:02 +0200 Subject: [PATCH 6/8] Working on blends --- src/display/drawing-item.cpp | 7 ++++--- src/display/sp-canvas.cpp | 12 ++++++------ src/ui/widget/filter-effect-chooser.cpp | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 64f4a79134..f5d9a0ec8f 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -886,12 +886,13 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // filters and opacity do not apply when rendering the ancestors of the filtered // element if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) { - if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && +/* if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && cairo_get_operator(dc.raw()) != get_cairo_blend_operator(SP_CSS_BLEND_NORMAL)) { set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); } else if (cairo_get_operator(dc.raw()) != get_cairo_blend_operator(_mix_blend_mode)) { set_cairo_blend_operator(dc, _mix_blend_mode); - } + } */ + return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } @@ -1002,7 +1003,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag dc.fill(); dc.setSource(0,0,0,0); // Web isolation only works if parent doesnt have transform - if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE) { + if (is_drawing_group(this) || (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE)) { set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); } diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index b33dd20b64..c4caf5563b 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1839,17 +1839,17 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect 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); - cairo_set_operator(buf.ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(buf.ct); - cairo_restore(buf.ct); // cairo_surface_write_to_png( imgs, "debug1.png" ); if (_root->visible) { SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf); } + cairo_save(buf.ct); + cairo_translate(buf.ct, -paint_rect.left(), -paint_rect.top()); + cairo_set_source(buf.ct, _background); + cairo_set_operator(buf.ct, CAIRO_OPERATOR_DEST_OVER); + cairo_paint(buf.ct); + cairo_restore(buf.ct); // cairo_surface_write_to_png( imgs, "debug2.png" ); // output to X diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index dae53193d2..08a3a37507 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -148,8 +148,9 @@ int SimpleFilterModifier::get_blend_mode() const Util::EnumData *d = _blend.get_active_data(); if (d) { return _blend.get_active_data()->id; - } else + } else { return SP_CSS_BLEND_NORMAL; + } } void SimpleFilterModifier::set_blend_mode(const int val, bool notify) -- GitLab From ba176735f988a96cfa0d653fdbd36dfe44d6801c Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 19 Oct 2019 04:45:45 +0200 Subject: [PATCH 7/8] Improve blending isolated --- src/display/cairo-utils.cpp | 100 +++++++++-- src/display/cairo-utils.h | 3 +- src/display/drawing-context.h | 1 + src/display/drawing-group.cpp | 76 ++++++-- src/display/drawing-item.cpp | 163 ++---------------- src/display/drawing-item.h | 6 +- src/display/sp-canvas.cpp | 14 +- .../internal/cairo-render-context.cpp | 6 +- src/ui/tools/select-tool.cpp | 1 - 9 files changed, 173 insertions(+), 197 deletions(-) diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 39c706da32..f560b9f19d 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -1252,65 +1252,129 @@ private: /* None */ }; -void ink_cairo_css_blend_operator(cairo_t *ct, unsigned blend_mode) +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/ - switch (blend_mode) { + + cairo_operator_t res = CAIRO_OPERATOR_OVER; + switch (css_blend) { case SP_CSS_BLEND_MULTIPLY: - cairo_set_operator(ct, CAIRO_OPERATOR_MULTIPLY); + res = CAIRO_OPERATOR_MULTIPLY; break; case SP_CSS_BLEND_SCREEN: - cairo_set_operator(ct, CAIRO_OPERATOR_SCREEN); + res = CAIRO_OPERATOR_SCREEN; break; case SP_CSS_BLEND_DARKEN: - cairo_set_operator(ct, CAIRO_OPERATOR_DARKEN); + res = CAIRO_OPERATOR_DARKEN; break; case SP_CSS_BLEND_LIGHTEN: - cairo_set_operator(ct, CAIRO_OPERATOR_LIGHTEN); + res = CAIRO_OPERATOR_LIGHTEN; break; case SP_CSS_BLEND_OVERLAY: - cairo_set_operator(ct, CAIRO_OPERATOR_OVERLAY); + res = CAIRO_OPERATOR_OVERLAY; break; case SP_CSS_BLEND_COLORDODGE: - cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_DODGE); + res = CAIRO_OPERATOR_COLOR_DODGE; break; case SP_CSS_BLEND_COLORBURN: - cairo_set_operator(ct, CAIRO_OPERATOR_COLOR_BURN); + res = CAIRO_OPERATOR_COLOR_BURN; break; case SP_CSS_BLEND_HARDLIGHT: - cairo_set_operator(ct, CAIRO_OPERATOR_HARD_LIGHT); + res = CAIRO_OPERATOR_HARD_LIGHT; break; case SP_CSS_BLEND_SOFTLIGHT: - cairo_set_operator(ct, CAIRO_OPERATOR_SOFT_LIGHT); + res = CAIRO_OPERATOR_SOFT_LIGHT; break; case SP_CSS_BLEND_DIFFERENCE: - cairo_set_operator(ct, CAIRO_OPERATOR_DIFFERENCE); + res = CAIRO_OPERATOR_DIFFERENCE; break; case SP_CSS_BLEND_EXCLUSION: - cairo_set_operator(ct, CAIRO_OPERATOR_EXCLUSION); + res = CAIRO_OPERATOR_EXCLUSION; break; case SP_CSS_BLEND_HUE: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_HUE); + res = CAIRO_OPERATOR_HSL_HUE; break; case SP_CSS_BLEND_SATURATION: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_SATURATION); + res = CAIRO_OPERATOR_HSL_SATURATION; break; case SP_CSS_BLEND_COLOR: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_COLOR); + res = CAIRO_OPERATOR_HSL_COLOR; break; case SP_CSS_BLEND_LUMINOSITY: - cairo_set_operator(ct, CAIRO_OPERATOR_HSL_LUMINOSITY); + res = CAIRO_OPERATOR_HSL_LUMINOSITY; break; case SP_CSS_BLEND_NORMAL: default: - cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + 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 9a176d9858..36800f699b 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 &); -void ink_cairo_css_blend_operator(cairo_t *ct, unsigned blend_mode); +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 1095fa1a34..aedb87ea2d 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 0d6a2edfc2..d7ada17f80 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -11,9 +11,12 @@ */ #include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" #include "display/drawing-item.h" #include "display/drawing-group.h" - +#include "display/cairo-utils.h" +#include "style.h" namespace Inkscape { @@ -90,29 +93,68 @@ 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 f5d9a0ec8f..a6cef723f9 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -28,126 +28,6 @@ #include "object/sp-item.h" namespace Inkscape { -// TODO find a way to use cairo utils one -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; - } -} - -cairo_operator_t get_cairo_blend_operator(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/ - cairo_operator_t ret = CAIRO_OPERATOR_OVER; - switch (blend_mode) { - case SP_CSS_BLEND_MULTIPLY: - ret = CAIRO_OPERATOR_MULTIPLY; - break; - case SP_CSS_BLEND_SCREEN: - ret = CAIRO_OPERATOR_SCREEN; - break; - case SP_CSS_BLEND_DARKEN: - ret = CAIRO_OPERATOR_DARKEN; - break; - case SP_CSS_BLEND_LIGHTEN: - ret = CAIRO_OPERATOR_LIGHTEN; - break; - case SP_CSS_BLEND_OVERLAY: - ret = CAIRO_OPERATOR_OVERLAY; - break; - case SP_CSS_BLEND_COLORDODGE: - ret = CAIRO_OPERATOR_COLOR_DODGE; - break; - case SP_CSS_BLEND_COLORBURN: - ret = CAIRO_OPERATOR_COLOR_BURN; - break; - case SP_CSS_BLEND_HARDLIGHT: - ret = CAIRO_OPERATOR_HARD_LIGHT; - break; - case SP_CSS_BLEND_SOFTLIGHT: - ret = CAIRO_OPERATOR_SOFT_LIGHT; - break; - case SP_CSS_BLEND_DIFFERENCE: - ret = CAIRO_OPERATOR_DIFFERENCE; - break; - case SP_CSS_BLEND_EXCLUSION: - ret = CAIRO_OPERATOR_EXCLUSION; - break; - case SP_CSS_BLEND_HUE: - ret = CAIRO_OPERATOR_HSL_HUE; - break; - case SP_CSS_BLEND_SATURATION: - ret = CAIRO_OPERATOR_HSL_SATURATION; - break; - case SP_CSS_BLEND_COLOR: - ret = CAIRO_OPERATOR_HSL_COLOR; - break; - case SP_CSS_BLEND_LUMINOSITY: - ret = CAIRO_OPERATOR_HSL_LUMINOSITY; - break; - case SP_CSS_BLEND_NORMAL: - default: - ret = CAIRO_OPERATOR_OVER; - break; - } - return ret; -} - /** * @class DrawingItem * SVG drawing item for display. @@ -690,11 +570,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne } } } - bool nocache = _mix_blend_mode != SP_CSS_BLEND_NORMAL; - if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE) { - nocache = true; - } - if (to_update & STATE_CACHE && !nocache) { + if (to_update & STATE_CACHE) { // Update cache score for this item if (_has_cache_iterator) { // remove old score information @@ -834,9 +710,10 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // Render from cache if possible // Bypass in case of pattern, see below. - if (!_mix_blend_mode && _cached && !(flags & RENDER_BYPASS_CACHE)) { + if (_cached && !(flags & RENDER_BYPASS_CACHE)) { if (_cache) { _cache->prepare(); + dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); _cache->paintFromCache(dc, carea); if (!carea) { return RENDER_OK; @@ -860,14 +737,15 @@ 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 |= (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE); // 8. Explicit parent 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 +/* nir |= (_isolation == SP_CSS_ISOLATION_ISOLATE); // 7. Explicit isolatiom + nir |= (!parent() || parent()->_isolation == SP_CSS_ISOLATION_ISOLATE); // 8. Explicit parent isolatiom + nir |= (!parent() || parent()->_mix_blend_mode != SP_CSS_BLEND_NORMAL); // 8. Explicit parent isolatiom */ /* How the rendering is done. * @@ -880,19 +758,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) { -/* if (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE && - cairo_get_operator(dc.raw()) != get_cairo_blend_operator(SP_CSS_BLEND_NORMAL)) { - set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); - } else if (cairo_get_operator(dc.raw()) != get_cairo_blend_operator(_mix_blend_mode)) { - set_cairo_blend_operator(dc, _mix_blend_mode); - } */ - + dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } @@ -987,7 +858,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag ict.paint(); // 6. Paint the completed rendering onto the base context (or into cache) - if (!_mix_blend_mode && _cached && _cache) { + if (_cached && _cache) { DrawingContext cachect(*_cache); cachect.rectangle(*carea); cachect.setOperator(CAIRO_OPERATOR_SOURCE); @@ -999,13 +870,11 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag dc.rectangle(*carea); dc.setSource(&intermediate); // 7. Render blend mode - set_cairo_blend_operator(dc, _mix_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 - if (is_drawing_group(this) || (parent() && parent()->_isolation == SP_CSS_ISOLATION_ISOLATE)) { - set_cairo_blend_operator(dc, SP_CSS_BLEND_NORMAL); - } + // the call above is to clear a ref on the intermediate surface held by dc diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index f0107cdc74..bfee6e814b 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -93,6 +93,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; } @@ -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 c4caf5563b..216c8437f4 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1838,18 +1838,18 @@ 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_surface_write_to_png( imgs, "debug1.png" ); - - if (_root->visible) { - SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf); - } cairo_save(buf.ct); cairo_translate(buf.ct, -paint_rect.left(), -paint_rect.top()); cairo_set_source(buf.ct, _background); - cairo_set_operator(buf.ct, CAIRO_OPERATOR_DEST_OVER); + cairo_set_operator(buf.ct, CAIRO_OPERATOR_SOURCE); cairo_paint(buf.ct); cairo_restore(buf.ct); + // cairo_surface_write_to_png( imgs, "debug1.png" ); + + 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 7280e6d584..a1e5b91a8f 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1570,7 +1570,7 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con cairo_set_fill_rule(_cr, CAIRO_FILL_RULE_WINDING); } if (style->mix_blend_mode.set && style->mix_blend_mode.value) { - ink_cairo_css_blend_operator(_cr, 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")); @@ -1603,7 +1603,7 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con } if (style->mix_blend_mode.set && style->mix_blend_mode.value) { - ink_cairo_css_blend_operator(_cr, style->mix_blend_mode.value); + cairo_set_operator(_cr, ink_css_blend_to_cairo_operator(style->mix_blend_mode.value)); } setPathVector(pathv); @@ -1703,7 +1703,7 @@ bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb, } if (style->mix_blend_mode.set && style->mix_blend_mode.value) { - ink_cairo_css_blend_operator(_cr, style->mix_blend_mode.value); + cairo_set_operator(_cr, ink_css_blend_to_cairo_operator(style->mix_blend_mode.value)); } cairo_paint(_cr); diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index 9bd97fabc4..6d5fdd2b9d 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 ) ) { -- GitLab From a07a70168abbb8695d99ad45ee2f73285bb63bc4 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 19 Oct 2019 04:50:15 +0200 Subject: [PATCH 8/8] Improve blending isolated. Styling --- src/display/drawing-group.cpp | 22 ++++++++++++---------- src/display/drawing-item.cpp | 4 +--- src/display/drawing-item.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index d7ada17f80..4fe84d7eb4 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -10,12 +10,12 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include "display/drawing.h" -#include "display/drawing-context.h" -#include "display/drawing-surface.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 { @@ -103,14 +103,15 @@ DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne } if (stop_at == nullptr) { // normal rendering - for (auto & i : _children) { + for (auto &i : _children) { i.setAntialiasing(_antialias); 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 + 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); @@ -134,14 +135,15 @@ DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne } */ if (stop_at == nullptr) { // normal rendering - for (auto & i : _children) { + 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 + 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); diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index a6cef723f9..52939e301c 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -743,9 +743,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag 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 |= (!parent() || parent()->_isolation == SP_CSS_ISOLATION_ISOLATE); // 8. Explicit parent isolatiom - nir |= (!parent() || parent()->_mix_blend_mode != SP_CSS_BLEND_NORMAL); // 8. Explicit parent isolatiom */ + // Isolation is handled by the drawing-group /* How the rendering is done. * diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index bfee6e814b..809d6ae725 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -93,7 +93,7 @@ public: DrawingItem(Drawing &drawing); virtual ~DrawingItem(); - + unsigned _isolation : 1; unsigned _mix_blend_mode : 4; -- GitLab