From b48dce26baf99e3d27cff16c78f81f2fa94e2933 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 29 Jun 2021 11:08:26 -0400 Subject: [PATCH] Never copy computed style Modify how the style attribute is copied and (with "paste style") pasted to never recompute the style. Also modify "paste style" to overwrite the class attribute as well. With these changes, copying and pasting objects will no longer modify the style attribute, and "paste style" now overwrites the target's style and class attributes with the verbatim values of the object on the clipboard. (Note that this includes removing said attributes from the target if they are not set on the source.) This, due to CSS rules, may result in "paste style" producing a different effective style on the target than on the source, but is arguably more correct. It may also cause problems when copying and pasting across documents, though users that would be affected (i.e. due to use of CSS styling) are likely to be aware of the cause. --- src/ui/clipboard.cpp | 41 +++++++++++++++-------------------------- src/xml/node.cpp | 22 +++++++++++++++++++++- src/xml/node.h | 17 ++++++++++++++++- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 6c92624d60..09f72589cf 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -424,7 +424,7 @@ bool ClipboardManagerImpl::paste(SPDesktop *desktop, bool in_place) if ( Inkscape::have_viable_layer(desktop, desktop->getMessageStack()) == false ) { return false; } - + Glib::ustring target = _getBestTarget(); // Special cases of clipboard content handling go here @@ -591,10 +591,13 @@ bool ClipboardManagerImpl::pasteStyle(ObjectSet *set) bool pasted = false; if (clipnode) { - set->document()->importDefs(tempdoc.get()); - SPCSSAttr *style = sp_repr_css_attr(clipnode, "style"); - sp_desktop_set_style(set, set->desktop(), style); - pasted = true; + for (auto node : set->xmlNodes()) { + pasted = node->copyAttribute("class", clipnode, true) || pasted; + pasted = node->copyAttribute("style", clipnode, true) || pasted; + } + if (pasted) { + set->document()->importDefs(tempdoc.get()); + } } else { _userWarn(set->desktop(), _("No style on the clipboard.")); @@ -900,16 +903,6 @@ void ClipboardManagerImpl::_copySelection(ObjectSet *selection) else obj_copy = _copyNode(obj, _doc, _clipnode); - // copy complete inherited style - SPCSSAttr *css = sp_repr_css_attr_inherited(obj, "style"); - for (auto iter : item->style->properties()) { - if (iter->style_src == SPStyleSrc::STYLE_SHEET) { - css->setAttributeOrRemoveIfEmpty(iter->name(), iter->get_value()); - } - } - sp_repr_css_set(obj_copy, css, "style"); - sp_repr_css_attr_unref(css); - // 1.1 COPYPASTECLONESTAMPLPEBUG if (_clipboardSPDoc) { SPItem *newitem = dynamic_cast(_clipboardSPDoc->getObjectByRepr(obj_copy)); @@ -928,18 +921,14 @@ void ClipboardManagerImpl::_copySelection(ObjectSet *selection) // copy style for Paste Style action if (!sorted_items.empty()) { SPObject *object = sorted_items[0]; - SPItem *item = dynamic_cast(object); - if (item) { - SPCSSAttr *style = take_style_from_item(item); - sp_repr_css_set(_clipnode, style, "style"); - sp_repr_css_attr_unref(style); - } - // copy path effect from the first path if (object) { - gchar const *effect =object->getRepr()->attribute("inkscape:path-effect"); - if (effect) { - _clipnode->setAttribute("inkscape:path-effect", effect); - } + auto *const node = object->getRepr(); + + _clipnode->copyAttribute("class", node, true); + _clipnode->copyAttribute("style", node, true); + + // copy path effect from the first path + _clipnode->copyAttribute("inkscape:path-effect", node); } } diff --git a/src/xml/node.cpp b/src/xml/node.cpp index 94a41989a7..516e03a9bc 100644 --- a/src/xml/node.cpp +++ b/src/xml/node.cpp @@ -26,6 +26,26 @@ void Node::setAttribute(Util::const_char_ptr key, Util::const_char_ptr value) this->setAttributeImpl(key.data(), value.data()); } +bool Node::copyAttribute(Util::const_char_ptr key, Node const *source_node, + bool remove_if_empty) +{ + if (source_node) { + if (auto const value = source_node->attribute(key.data())) { + if (*value || !remove_if_empty) { + setAttribute(key, value); + } + return true; + } + + if (remove_if_empty) { + removeAttribute(key); + return true; + } + } + + return false; +} + bool Node::getAttributeBoolean(Util::const_char_ptr key, bool default_value) const { auto v = this->attribute(key.data()); @@ -150,4 +170,4 @@ void Node::setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inksc } } // namespace XML -} // namespace Inkscape \ No newline at end of file +} // namespace Inkscape diff --git a/src/xml/node.h b/src/xml/node.h index 5c84394dfa..3847c56dae 100644 --- a/src/xml/node.h +++ b/src/xml/node.h @@ -206,11 +206,26 @@ public: * * @param key Name of the attribute to change * @param value The new value of the attribute - * @param is_interactive Ignored */ void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value); + /** + * @brief Copy attribute value from another node to this node + * + * @param key Name of the attribute to change + * @param source_node Node from which to take the attribute value + * @param remove_if_empty + * If true, and the source node has no such attribute, or the source + * node's value for the attribute is an empty string, the attribute + * will be removed (if present) from this node. + * + * @return true if the attribute was set, false otherwise. + */ + + bool copyAttribute(Util::const_char_ptr key, Node const *source_node, + bool remove_if_empty = false); + /** * Parses the boolean value of an attribute "key" in repr and sets val accordingly, or to false if * the attr is not set. -- GitLab