From d3ff443fecbadd4406852dd1e764503c481032f1 Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 01:44:32 +0530 Subject: [PATCH 01/10] Fix issue #96 and some other issues related to handling of style properties as XML attributes. --- po/POTFILES.in | 2 +- po/inkscape.pot | 32 +-- src/extension/internal/svg.cpp | 6 +- src/file-update.cpp | 2 +- src/object/sp-flowtext.cpp | 6 +- src/object/sp-item.cpp | 19 +- src/object/sp-object.cpp | 48 +++- src/object/sp-text.cpp | 1 - src/path-chemistry.cpp | 17 +- src/style-internal.cpp | 482 ++++++++++++++++++++++---------- src/style-internal.h | 129 +++++---- src/style.cpp | 95 +++++-- src/style.h | 81 +++++- src/text-editing.cpp | 8 +- src/ui/toolbar/text-toolbar.cpp | 6 +- 15 files changed, 625 insertions(+), 309 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 3549d06b35e..667d37cfff2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,6 +1,6 @@ # List of source files containing translatable strings. # Please keep this file sorted alphabetically. -# Generated by generate_POTFILES.sh at Wed Mar 20 19:13:27 IST 2019 +# Generated by generate_POTFILES.sh at Thu Mar 21 20:16:36 IST 2019 [encoding: UTF-8] org.inkscape.Inkscape.appdata.xml.in share/filters/filters.svg.h diff --git a/po/inkscape.pot b/po/inkscape.pot index f09fb716a76..cb6eebc8b26 100644 --- a/po/inkscape.pot +++ b/po/inkscape.pot @@ -33,7 +33,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: inkscape-devel@lists.sourceforge.net\n" -"POT-Creation-Date: 2019-03-20 20:07+0530\n" +"POT-Creation-Date: 2019-03-21 21:14+0530\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -13170,7 +13170,7 @@ msgstr "" msgid "Linked Flowed Text" msgstr "" -#: ../src/object/sp-flowtext.cpp:288 ../src/object/sp-text.cpp:347 +#: ../src/object/sp-flowtext.cpp:288 ../src/object/sp-text.cpp:344 #: ../src/ui/tools/text-tool.cpp:1643 msgid " [truncated]" msgstr "" @@ -13249,26 +13249,26 @@ msgstr "" msgid "Ungroup" msgstr "" -#: ../src/object/sp-item.cpp:1028 ../src/verbs.cpp:216 +#: ../src/object/sp-item.cpp:1039 ../src/verbs.cpp:216 msgid "Object" msgstr "" -#: ../src/object/sp-item.cpp:1040 +#: ../src/object/sp-item.cpp:1051 #, c-format msgid "%s; clipped" msgstr "" -#: ../src/object/sp-item.cpp:1046 +#: ../src/object/sp-item.cpp:1057 #, c-format msgid "%s; masked" msgstr "" -#: ../src/object/sp-item.cpp:1056 +#: ../src/object/sp-item.cpp:1067 #, c-format msgid "%s; filtered (%s)" msgstr "" -#: ../src/object/sp-item.cpp:1058 +#: ../src/object/sp-item.cpp:1069 #, c-format msgid "%s; filtered" msgstr "" @@ -13376,15 +13376,15 @@ msgstr "" msgid "Conditional Group" msgstr "" -#: ../src/object/sp-text.cpp:323 +#: ../src/object/sp-text.cpp:320 msgid "Auto-wrapped text" msgstr "" -#: ../src/object/sp-text.cpp:325 +#: ../src/object/sp-text.cpp:322 msgid "Text in-a-shape" msgstr "" -#: ../src/object/sp-text.cpp:327 ../src/verbs.cpp:331 +#: ../src/object/sp-text.cpp:324 ../src/verbs.cpp:331 #: ../share/extensions/lorem_ipsum.inx.h:8 #: ../share/extensions/replace_font.inx.h:11 ../share/extensions/split.inx.h:10 #: ../share/extensions/text_braille.inx.h:2 @@ -13399,12 +13399,12 @@ msgstr "" msgid "Text" msgstr "" -#: ../src/object/sp-text.cpp:351 +#: ../src/object/sp-text.cpp:348 #, c-format msgid "on path%s (%s, %s)" msgstr "" -#: ../src/object/sp-text.cpp:352 +#: ../src/object/sp-text.cpp:349 #, c-format msgid "%s (%s, %s)" msgstr "" @@ -13503,19 +13503,19 @@ msgstr "" msgid "No objects to convert to path in the selection." msgstr "" -#: ../src/path-chemistry.cpp:594 +#: ../src/path-chemistry.cpp:593 msgid "Select path(s) to reverse." msgstr "" -#: ../src/path-chemistry.cpp:602 +#: ../src/path-chemistry.cpp:601 msgid "Reversing paths..." msgstr "" -#: ../src/path-chemistry.cpp:640 +#: ../src/path-chemistry.cpp:639 msgid "Reverse path" msgstr "" -#: ../src/path-chemistry.cpp:643 +#: ../src/path-chemistry.cpp:642 msgid "No paths to reverse in the selection." msgstr "" diff --git a/src/extension/internal/svg.cpp b/src/extension/internal/svg.cpp index 50a045a94d7..44d2b574088 100644 --- a/src/extension/internal/svg.cpp +++ b/src/extension/internal/svg.cpp @@ -461,10 +461,8 @@ static void insert_text_fallback( Inkscape::XML::Node *repr, SPDocument *doc, In SPObject *source_obj = reinterpret_cast(rawptr); // Set tspan style - Glib::ustring style_text = (dynamic_cast(source_obj) ? source_obj->parent : source_obj)->style->write( SP_STYLE_FLAG_IFDIFF, SP_STYLE_SRC_UNSET, text->style); - if (!style_text.empty()) { - span_tspan->setAttribute("style", style_text.c_str()); - } + SPObject* style_obj = dynamic_cast(source_obj) ? source_obj->parent : source_obj; + style_obj->style->writeToXMLNode(span_tspan, false, text->style); // Add text node SPString *str = dynamic_cast(source_obj); diff --git a/src/file-update.cpp b/src/file-update.cpp index 5489ee499b7..b8690db7a08 100644 --- a/src/file-update.cpp +++ b/src/file-update.cpp @@ -188,7 +188,7 @@ void sp_file_text_run_recursive(void (*f)(SPObject *), SPObject *o) } void fix_update(SPObject *o) { - o->style->write(); + o->style->getCSSString(); o->updateRepr(); } diff --git a/src/object/sp-flowtext.cpp b/src/object/sp-flowtext.cpp index 0db7ab19225..9114cb1cb84 100644 --- a/src/object/sp-flowtext.cpp +++ b/src/object/sp-flowtext.cpp @@ -538,10 +538,8 @@ Inkscape::XML::Node *SPFlowtext::getAsText() this->layout.getSourceOfCharacter(it, &rawptr, &span_text_start_iter); SPObject *source_obj = reinterpret_cast(rawptr); - Glib::ustring style_text = (dynamic_cast(source_obj) ? source_obj->parent : source_obj)->style->write( SP_STYLE_FLAG_IFDIFF, SP_STYLE_SRC_UNSET, this->style); - if (!style_text.empty()) { - span_tspan->setAttribute("style", style_text.c_str()); - } + SPObject* style_obj = dynamic_cast(source_obj) ? source_obj->parent : source_obj; + style_obj->style->writeToXMLNode(span_tspan, false, this->style); SPString *str = dynamic_cast(source_obj); if (str) { diff --git a/src/object/sp-item.cpp b/src/object/sp-item.cpp index cba70f1262b..a5a161795ef 100644 --- a/src/object/sp-item.cpp +++ b/src/object/sp-item.cpp @@ -516,8 +516,23 @@ void SPItem::set(SPAttributeEnum key, gchar const* value) { } default: if (SP_ATTRIBUTE_IS_CSS(key)) { - style->clear(key); - object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + SPIBase* prop = object->style->getPropertyByName(key); + if (prop) { + bool style_modified = false; + if (value && (!prop->set || prop->style_src != SPStyleSrc::SP_STYLE_SRC_STYLE_PROP)) { + // Update the style property, if it is not overridden by the element's + // style attribute. + prop->clear(); + prop->readIfUnset(value, SPStyleSrc::SP_STYLE_SRC_ATTRIBUTE); + style_modified = true; + } else if (!value && prop->set && prop->style_src == SPStyleSrc::SP_STYLE_SRC_ATTRIBUTE) { + // Unsetting presentation attribute. + object->style->readFromObject(object); + style_modified = true; + } + if (style_modified) + object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } } else { SPObject::set(key, value); } diff --git a/src/object/sp-object.cpp b/src/object/sp-object.cpp index 714518f08b5..abff44f52b0 100644 --- a/src/object/sp-object.cpp +++ b/src/object/sp-object.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -997,10 +998,9 @@ void SPObject::readAttr(gchar const *key) } } -void SPObject::repr_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const *key, gchar const * /*oldval*/, gchar const * /*newval*/, bool is_interactive, gpointer data) +void SPObject::repr_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const *key, gchar const * oldval, gchar const * /*newval*/, bool is_interactive, gpointer data) { SPObject *object = SP_OBJECT(data); - object->readAttr(key); // manual changes to extension attributes require the normal @@ -1051,7 +1051,7 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML repr->setAttribute("xml:space", xml_space); } - if ( flags & SP_OBJECT_WRITE_EXT && + if ( (flags & SP_OBJECT_WRITE_EXT) && this->collectionPolicy() == SPObject::ALWAYS_COLLECT ) { repr->setAttribute("inkscape:collect", "always"); @@ -1061,22 +1061,42 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML if (style) { // Write if property set by style attribute in this object - Glib::ustring s = - style->write(SP_STYLE_FLAG_IFSET | SP_STYLE_FLAG_IFSRC, SP_STYLE_SRC_STYLE_PROP); - // Check for valid attributes. This may be time consuming. - // It is useful, though, for debugging Inkscape code. Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if( prefs->getBool("/options/svgoutput/check_on_editing") ) { + if (prefs->getBool("/options/svgoutput/check_on_editing")) { + // Check for valid attributes. This may be time consuming. + // It is useful, though, for debugging Inkscape code. + + // TODO: Need to do something about validating style attributes set as XML + // attributes. For now, just override them with CSS. + + Glib::ustring str_from_style = + style->getCSSString(SP_STYLE_FLAG_IFSET | SP_STYLE_FLAG_IFSRC, SPStyleSrc::SP_STYLE_SRC_STYLE_PROP); + Glib::ustring str_from_attrs = + style->getCSSString(SP_STYLE_FLAG_IFSET | SP_STYLE_FLAG_IFSRC, SPStyleSrc::SP_STYLE_SRC_ATTRIBUTE); + + Glib::ustring str_to_clean; + if (str_from_style.empty()) { + str_to_clean = std::move(str_from_attrs); + } else { + str_to_clean = std::move(str_from_style); + if (!str_from_attrs.empty()) { + str_to_clean += ';'; + str_to_clean += str_from_attrs; + } + } - unsigned int flags = sp_attribute_clean_get_prefs(); - Glib::ustring s_cleaned = sp_attribute_clean_style( repr, s.c_str(), flags ); - } + unsigned int clean_flags = sp_attribute_clean_get_prefs(); + Glib::ustring s_cleaned = sp_attribute_clean_style(repr, str_to_clean.c_str(), clean_flags); + + if (s_cleaned.empty()) { + repr->setAttribute("style", nullptr); + } else { + repr->setAttribute("style", s_cleaned.c_str()); + } - if( s.empty() ) { - repr->setAttribute("style", nullptr); } else { - repr->setAttribute("style", s.c_str()); + style->writeToXMLNode(repr, true, nullptr); } } else { diff --git a/src/object/sp-text.cpp b/src/object/sp-text.cpp index ff8bd9af7dd..60ec7717acc 100644 --- a/src/object/sp-text.cpp +++ b/src/object/sp-text.cpp @@ -281,7 +281,6 @@ Inkscape::XML::Node *SPText::write(Inkscape::XML::Document *xml_doc, Inkscape::X this->rebuildLayout(); // copied from update(), see LP Bug 1339305 SPItem::write(xml_doc, repr, flags); - return repr; } diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 81bc531c101..f1c4bb0b46b 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -491,9 +491,9 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) Inkscape::copy_object_properties(g_repr, item->getRepr()); /* Whole text's style */ - Glib::ustring style_str = - item->style->write( SP_STYLE_FLAG_IFDIFF, SP_STYLE_SRC_UNSET, item->parent ? item->parent->style : nullptr); // TODO investigate possibility - g_repr->setAttribute("style", style_str.c_str()); + item->style->writeToXMLNode( + g_repr, false, item->parent ? item->parent->style : nullptr); + // TODO investigate possibility Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); do { @@ -512,8 +512,6 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) while (dynamic_cast(pos_obj) && pos_obj->parent) { pos_obj = pos_obj->parent; // SPStrings don't have style } - Glib::ustring style_str = - pos_obj->style->write( SP_STYLE_FLAG_IFDIFF, SP_STYLE_SRC_UNSET, pos_obj->parent ? pos_obj->parent->style : nullptr); // TODO investigate possibility // get path from iter to iter_next: SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); @@ -533,7 +531,9 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) g_free(def_str); curve->unref(); - p_repr->setAttribute("style", style_str.c_str()); + pos_obj->style->writeToXMLNode( + p_repr, false, pos_obj->parent ? pos_obj->parent->style : nullptr); + // TODO investigate possibility g_repr->appendChild(p_repr); @@ -573,9 +573,8 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) repr->setAttribute("transform", item->getRepr()->attribute("transform")); /* Style */ - Glib::ustring style_str = - item->style->write( SP_STYLE_FLAG_IFDIFF, SP_STYLE_SRC_UNSET, item->parent ? item->parent->style : nullptr); // TODO investigate possibility - repr->setAttribute("style", style_str.c_str()); + item->style->writeToXMLNode( + repr, false, item->parent ? item->parent->style : nullptr); /* Definition */ gchar *def_str = sp_svg_write_path(curve->get_pathvector()); diff --git a/src/style-internal.cpp b/src/style-internal.cpp index a1c2935be2a..afe7577f3d7 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -52,34 +52,74 @@ using Inkscape::CSSOStringStream; // SPIBase -------------------------------------------------------------- -// Standard criteria for writing a property -// dfp == different from parent -inline bool should_write( guint const flags, bool set, bool dfp, bool src) { +void SPIBase::readIfUnset(gchar const* str, SPStyleSrc source) { + if (!str) { + return; + } + + bool has_important = false; + Glib::ustring stripped = strip_important(str, has_important); // Sets 'has_important' + // '!important' is invalid on attributes, don't read. + if (source == SP_STYLE_SRC_ATTRIBUTE && has_important) { + return; + } + + if (!set || (has_important && !important)) { + read(stripped.c_str()); + if (set) { + style_src = source; + if (has_important) { + important = true; + } + } + } +} + +Glib::ustring SPIBase::strip_important(const gchar* str, bool& important) { + assert (str != NULL); + Glib::ustring string = Glib::ustring(str); + auto pos = string.rfind(" !important"); + important = false; + if (pos != std::string::npos) { + important = true; + string.erase(pos); + } + return string; +} + +bool SPIBase::isWriteOK(unsigned int flags, SPStyleSrc source, SPIBase const* base) const { + // Is this class different from the SPIBase given, this is used in Object-to-Path + SPIBase const* my_base = dynamic_cast(base); + bool is_dfp = (!inherits || !my_base || (my_base != this)); // Different from parent + bool src_matches = (source == style_src || !(flags & SP_STYLE_FLAG_IFSRC)); bool should_write = false; - if ( ((flags & SP_STYLE_FLAG_ALWAYS) && src) || - ((flags & SP_STYLE_FLAG_IFSET) && set && src) || - ((flags & SP_STYLE_FLAG_IFDIFF) && set && src && dfp)) { + if ( ((flags & SP_STYLE_FLAG_ALWAYS) && src_matches) || + ((flags & SP_STYLE_FLAG_IFSET) && set && src_matches) || + ((flags & SP_STYLE_FLAG_IFDIFF) && set && src_matches && is_dfp)) + { should_write = true; } return should_write; } -const Glib::ustring SPIBase::write(guint const flags, SPStyleSrc const &style_src_req, SPIBase const *const base) const -{ - // Is this class different from the SPIBase given, this is used in Object-to-Path - SPIBase const *const my_base = dynamic_cast(base); - bool dfp = (!inherits || !my_base || (my_base != this)); // Different from parent - bool src = (style_src_req == style_src || !(flags & SP_STYLE_FLAG_IFSRC)); - if (should_write(flags, set, dfp, src)) { - auto value = this->get_value(); - if ( !value.empty() ) { - return (name + ":" + value + important_str() + ";"); - } +void SPIBase::appendCSSToString(Glib::ustring& str) const { + auto value = get_value(); + if (!value.empty()) { + str += name; + str += ':'; + str += value; + if (important) + str += " !important"; + str += ';'; } - return Glib::ustring(""); } +Glib::ustring SPIBase::getCSSString() const { + Glib::ustring s; + appendCSSToString(s); + return s; +} // SPIFloat ------------------------------------------------------------- @@ -101,9 +141,10 @@ SPIFloat::read( gchar const *str ) { } } -const Glib::ustring SPIFloat::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPIFloat::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } return Glib::ustring::format(this->value); } @@ -163,9 +204,10 @@ SPIScale24::read( gchar const *str ) { } } -const Glib::ustring SPIScale24::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPIScale24::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } return Glib::ustring::format(SP_SCALE24_TO_FLOAT(this->value)); } @@ -302,11 +344,14 @@ SPILength::read( gchar const *str ) { } } -const Glib::ustring SPILength::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPILength::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + auto value = this->computed; auto unit_out = Glib::ustring(""); + switch (this->unit) { case SP_CSS_UNIT_NONE: break; @@ -408,16 +453,15 @@ void SPILength::setDouble(double v) } // Generate a string and allow emove name for parsing dasharray, etc. -const Glib::ustring SPILength::toString(bool wname) const -{ -Inkscape: +const Glib::ustring SPILength::toString(bool wname) const { CSSOStringStream os; if (wname) { os << name << ":"; } os << this->get_value(); if (wname) { - os << important_str(); + if (important) + os << important_str(); os << ";"; } return os.str(); @@ -462,9 +506,10 @@ SPILengthOrNormal::read( gchar const *str ) { } }; -const Glib::ustring SPILengthOrNormal::get_value() const -{ - if (this->normal) return Glib::ustring("normal"); +Glib::ustring SPILengthOrNormal::get_value() const { + if (this->normal) { + return Glib::ustring("normal"); + } return SPILength::get_value(); } @@ -546,14 +591,17 @@ SPIFontVariationSettings::read( gchar const *str ) { } }; -const Glib::ustring SPIFontVariationSettings::get_value() const -{ - if (this->normal) return Glib::ustring("normal"); +Glib::ustring SPIFontVariationSettings::get_value() const { + if (this->normal) { + return Glib::ustring("normal"); + } auto ret = Glib::ustring(""); - for(auto it: axes) { + for (auto it : axes) { ret += "'" + it.first + "' " + Glib::ustring::format(it.second) + ", "; } - if (!ret.empty()) ret.erase(ret.size() - 2); + if (!ret.empty()) { + ret.erase(ret.size() - 2); + } return ret; } @@ -643,11 +691,12 @@ SPIEnum::read( gchar const *str ) { } } -const Glib::ustring SPIEnum::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - for (unsigned i = 0; enums[i].key; ++i) { - if (enums[i].value == static_cast< gint > (this->value) ) { +Glib::ustring SPIEnum::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + for (unsigned int i = 0; enums[i].key; ++i) { + if (enums[i].value == static_cast(this->value)) { return Glib::ustring(enums[i].key); } } @@ -770,14 +819,19 @@ SPIEnumBits::read( gchar const *str ) { } } -const Glib::ustring SPIEnumBits::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->value == 0) return Glib::ustring("normal"); +Glib::ustring SPIEnumBits::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->value == 0) { + return Glib::ustring("normal"); + } auto ret = Glib::ustring(""); - for (unsigned i = 0; enums[i].key; ++i) { + for (unsigned int i = 0; enums[i].key; ++i) { if (this->value & (1 << i)) { - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += enums[i].key; } } @@ -827,20 +881,31 @@ SPILigatures::read( gchar const *str ) { /* FIXME:: This whole class is bogus and should be an SPIBitEnum TODO */ -const Glib::ustring SPILigatures::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->value == SP_CSS_FONT_VARIANT_LIGATURES_NONE) return Glib::ustring("none"); - if (this->value == SP_CSS_FONT_VARIANT_LIGATURES_NORMAL) return Glib::ustring("normal"); +Glib::ustring SPILigatures::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->value == SP_CSS_FONT_VARIANT_LIGATURES_NONE) { + return Glib::ustring("none"); + } + if (this->value == SP_CSS_FONT_VARIANT_LIGATURES_NORMAL) { + return Glib::ustring("normal"); + } + auto ret = Glib::ustring(""); - if (!(value & SP_CSS_FONT_VARIANT_LIGATURES_COMMON)) + + if (!(value & SP_CSS_FONT_VARIANT_LIGATURES_COMMON)) { ret += "no-common-ligatures "; - if (value & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY) + } + if (value & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY) { ret += "discretionary-ligatures "; - if (value & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ) + } + if (value & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL) { ret += "historical-ligatures "; - if ( !(value & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) ) + } + if (!(value & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL)) { ret += "no-contextual "; + } ret.erase(ret.size() - 1); return ret; } @@ -911,19 +976,27 @@ SPINumeric::read( gchar const *str ) { } /* FIXME:: This whole class is bogus and should be an SPIBitEnum TODO */ -const Glib::ustring SPINumeric::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->value == 0) return Glib::ustring("normal"); +Glib::ustring SPINumeric::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->value == 0) { + return Glib::ustring("normal"); + } + auto ret = Glib::ustring(""); auto enums = enum_font_variant_numeric; + for (unsigned i = 1; enums[i].key; ++i) { // Bitmap is shifted by 1 because normal is zero if (this->value & (1 << (i - 1))) { - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += enums[i].key; } } + return ret; } @@ -992,19 +1065,27 @@ SPIEastAsian::read( gchar const *str ) { computed = value; } -const Glib::ustring SPIEastAsian::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->value == 0) return Glib::ustring("normal"); +Glib::ustring SPIEastAsian::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->value == 0) { + return Glib::ustring("normal"); + } + auto ret = Glib::ustring(""); unsigned j = 1; auto enums = enum_font_variant_east_asian; + for (unsigned i = 0; enums[i].key; ++i) { if (this->value & (1 << i)) { - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += enums[i].key; } } + return ret; } @@ -1038,19 +1119,24 @@ SPIString::read( gchar const *str ) { } -const Glib::ustring SPIString::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (!this->value) return Glib::ustring(""); - if( name.compare( "font-family" ) == 0 ) { - Glib::ustring font_family( this->value ); - css_font_family_quote( font_family ); +Glib::ustring SPIString::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (!this->value) { + return Glib::ustring(""); + } + + if (name.compare("font-family") == 0) { + Glib::ustring font_family(this->value); + css_font_family_quote(font_family); return font_family; - } else if( name.compare( "-inkscape-font-specification" ) == 0 ) { - Glib::ustring font_spec( this->value ); - css_quote( font_spec ); + } else if (name.compare("-inkscape-font-specification") == 0) { + Glib::ustring font_spec(this->value); + css_quote(font_spec); return font_spec; } + return Glib::ustring(this->value); } @@ -1135,11 +1221,14 @@ void SPIColor::read( gchar const *str ) { } } -const Glib::ustring SPIColor::get_value() const -{ +Glib::ustring SPIColor::get_value() const { // currentcolor goes first to handle special case for 'color' property - if (this->currentcolor) return Glib::ustring("currentColor"); - if (this->inherit) return Glib::ustring("inherit"); + if (this->currentcolor) { + return Glib::ustring("currentColor"); + } + if (this->inherit) { + return Glib::ustring("inherit"); + } return this->value.color.toString(); } @@ -1327,39 +1416,55 @@ SPIPaint::read( gchar const *str, SPStyle &style_in, SPDocument *document_in ) { read( str ); } -const Glib::ustring SPIPaint::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->noneSet) return Glib::ustring("none"); +Glib::ustring SPIPaint::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->noneSet) { + return Glib::ustring("none"); + } + // url must go first as other values can serve as fallbacks auto ret = Glib::ustring(""); if (this->value.href && this->value.href->getURI()) { ret += this->value.href->getURI()->cssStr(); } - switch(this->paintOrigin) { + + switch (this->paintOrigin) { case SP_CSS_PAINT_ORIGIN_CURRENT_COLOR: - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += "currentColor"; break; + case SP_CSS_PAINT_ORIGIN_CONTEXT_FILL: - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += "context-fill"; break; + case SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE: - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += "context-stroke"; break; + case SP_CSS_PAINT_ORIGIN_NORMAL: if (this->colorSet) { char color_buf[8]; sp_svg_write_color(color_buf, sizeof(color_buf), this->value.color.toRGBA32(0)); - if (!ret.empty()) ret += " "; + if (!ret.empty()) { + ret += " "; + } ret += color_buf; } if (this->value.color.icc) { ret += "icc-color("; ret += this->value.color.icc->colorProfile; - for(auto i: this->value.color.icc->colors) { + for (auto i : this->value.color.icc->colors) { ret += ", " + Glib::ustring::format(i); } ret += ")"; @@ -1560,8 +1665,7 @@ SPIPaintOrder::read( gchar const *str ) { } } -const Glib::ustring SPIPaintOrder::get_value() const -{ +Glib::ustring SPIPaintOrder::get_value() const { if (this->inherit) return Glib::ustring("inherit"); auto ret = Glib::ustring(""); for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) { @@ -1693,10 +1797,13 @@ SPIFilter::read( gchar const *str ) { } } -const Glib::ustring SPIFilter::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->href) return this->href->getURI()->cssStr(); +Glib::ustring SPIFilter::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->href) { + return this->href->getURI()->cssStr(); + } return Glib::ustring(""); } @@ -1813,13 +1920,18 @@ SPIDashArray::read( gchar const *str ) { return; } -const Glib::ustring SPIDashArray::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->values.empty()) return Glib::ustring("none"); +Glib::ustring SPIDashArray::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->values.empty()) { + return Glib::ustring("none"); + } auto ret = Glib::ustring(""); - for(auto value: this->values) { - if (!ret.empty()) ret += ", "; + for (auto value : this->values) { + if (!ret.empty()) { + ret += ", "; + } ret += value.toString(); } return ret; @@ -1914,21 +2026,27 @@ SPIFontSize::read( gchar const *str ) { } } -const Glib::ustring SPIFontSize::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPIFontSize::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); auto ret = Glib::ustring(""); + switch (this->type) { case SP_FONT_SIZE_LITERAL: for (unsigned i = 0; enum_font_size[i].key; i++) { - if (enum_font_size[i].value == static_cast< gint > (this->literal) ) { - if (!ret.empty()) ret += " "; + if (enum_font_size[i].value == static_cast(this->literal)) { + if (!ret.empty()) { + ret += " "; + } ret += enum_font_size[i].key; } } break; + case SP_FONT_SIZE_LENGTH: if (prefs->getBool("/options/font/textOutputPx", true)) { unit = SP_CSS_UNIT_PX; @@ -1936,8 +2054,10 @@ const Glib::ustring SPIFontSize::get_value() const ret += Glib::ustring::format(sp_style_css_size_px_to_units(this->computed, unit)); ret += sp_style_get_css_unit_string(unit); break; + case SP_FONT_SIZE_PERCENTAGE: return Glib::ustring::format(this->value * 100.0) + "%"; + default: g_error("Invalid FontSize value, not writing it."); } @@ -2005,6 +2125,7 @@ SPIFontSize::relative_fraction() const { default: g_assert_not_reached(); } + break; } case SP_FONT_SIZE_PERCENTAGE: @@ -2021,6 +2142,7 @@ SPIFontSize::relative_fraction() const { default: g_assert_not_reached(); } + break; } } g_assert_not_reached(); @@ -2208,9 +2330,11 @@ SPIFont::read( gchar const *str ) { } } -const Glib::ustring SPIFont::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPIFont::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + // At the moment, do nothing. We could add a preference to write out // 'font' shorthand rather than longhand properties. /* SPIFontSize const *const my_base = dynamic_cast(base); @@ -2284,21 +2408,27 @@ SPIBaselineShift::read( gchar const *str ) { } } -const Glib::ustring SPIBaselineShift::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPIBaselineShift::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + auto ret = Glib::ustring(""); + switch (this->type) { case SP_BASELINE_SHIFT_LITERAL: for (unsigned i = 0; enum_baseline_shift[i].key; i++) { - if (enum_baseline_shift[i].value == static_cast< gint > (this->literal) ) { - if (!ret.empty()) ret += " "; + if (enum_baseline_shift[i].value == static_cast(this->literal)) { + if (!ret.empty()) { + ret += " "; + } ret += enum_baseline_shift[i].key; } } break; + case SP_BASELINE_SHIFT_LENGTH: - if( this->unit == SP_CSS_UNIT_EM || this->unit == SP_CSS_UNIT_EX ) { + if (this->unit == SP_CSS_UNIT_EM || this->unit == SP_CSS_UNIT_EX) { ret += Glib::ustring::format(this->value); ret += (this->unit == SP_CSS_UNIT_EM ? "em" : "ex"); } else { @@ -2306,9 +2436,11 @@ const Glib::ustring SPIBaselineShift::get_value() const ret += Glib::ustring::format(this->computed) + "px"; } break; + case SP_BASELINE_SHIFT_PERCENTAGE: return Glib::ustring::format(this->value * 100.0) + "%"; } + return ret; } @@ -2470,15 +2602,28 @@ SPITextDecorationLine::read( gchar const *str ) { } } -const Glib::ustring SPITextDecorationLine::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPITextDecorationLine::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + auto ret = Glib::ustring(""); - if (this->underline) ret += " underline"; - if (this->overline) ret += " overline"; - if (this->line_through) ret += " line-through"; - if (this->blink) ret += " blink"; // Deprecated - if (ret.empty()) ret += "none"; + + if (this->underline) { + ret += " underline"; + } + if (this->overline) { + ret += " overline"; + } + if (this->line_through) { + ret += " line-through"; + } + if (this->blink) { + ret += " blink"; // Deprecated + } + if (ret.empty()) { + ret += "none"; + } return ret; } @@ -2588,14 +2733,26 @@ SPITextDecorationStyle::read( gchar const *str ) { } } -const Glib::ustring SPITextDecorationStyle::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); - if (this->solid) return Glib::ustring("solid"); - if (this->isdouble) return Glib::ustring("double"); - if (this->dotted) return Glib::ustring("dotted"); - if (this->dashed) return Glib::ustring("dashed"); - if (this->wavy) return Glib::ustring("wavy"); +Glib::ustring SPITextDecorationStyle::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + if (this->solid) { + return Glib::ustring("solid"); + } + if (this->isdouble) { + return Glib::ustring("double"); + } + if (this->dotted) { + return Glib::ustring("dotted"); + } + if (this->dashed) { + return Glib::ustring("dashed"); + } + if (this->wavy) { + return Glib::ustring("wavy"); + } + g_error("SPITextDecorationStyle::write(): No valid value for property"); return Glib::ustring(""); } @@ -2724,23 +2881,27 @@ SPITextDecoration::read( gchar const *str ) { // Returns CSS2 'text-decoration' (using settings in SPTextDecorationLine) // This is required until all SVG renderers support CSS3 'text-decoration' -const Glib::ustring SPITextDecoration::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPITextDecoration::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } return style->text_decoration_line.get_value(); } -const Glib::ustring -SPITextDecoration::write( guint const flags, SPStyleSrc const &style_src_req, SPIBase const *const base) const { + + +bool SPITextDecoration::isWriteOK(unsigned int flags, SPStyleSrc source, SPIBase const* base) const { SPITextDecoration const *const my_base = dynamic_cast(base); + if ( (flags & SP_STYLE_FLAG_ALWAYS) || - ((flags & SP_STYLE_FLAG_IFSET) && style->text_decoration_line.set) || - ((flags & SP_STYLE_FLAG_IFDIFF) && style->text_decoration_line.set - && (!my_base->style->text_decoration_line.set || - style->text_decoration_line != my_base->style->text_decoration_line ))) + ((flags & SP_STYLE_FLAG_IFSET) && style->text_decoration_line.set) || + ((flags & SP_STYLE_FLAG_IFDIFF) && style->text_decoration_line.set + && (!my_base->style->text_decoration_line.set || + style->text_decoration_line != my_base->style->text_decoration_line ))) { - return (name + ":" + this->get_value() + important_str() + ";"); + return true; } - return Glib::ustring(""); + + return false; } void @@ -2841,15 +3002,28 @@ SPIVectorEffect::read( gchar const *str ) { // << std::endl; } -const Glib::ustring SPIVectorEffect::get_value() const -{ - if (this->inherit) return Glib::ustring("inherit"); +Glib::ustring SPIVectorEffect::get_value() const { + if (this->inherit) { + return Glib::ustring("inherit"); + } + auto ret = Glib::ustring(""); - if (this->stroke) ret += " non-scaling-stroke"; - if (this->size) ret += " non-scaling-size"; - if (this->rotate) ret += " non-rotation"; - if (this->fixed) ret += " fixed-position"; - if (ret.empty()) ret += "none"; + + if (this->stroke) { + ret += " non-scaling-stroke"; + } + if (this->size) { + ret += " non-scaling-size"; + } + if (this->rotate) { + ret += " non-rotation"; + } + if (this->fixed) { + ret += " fixed-position"; + } + if (ret.empty()) { + ret += "none"; + } return ret; } diff --git a/src/style-internal.h b/src/style-internal.h index a28474870c8..0df3012df67 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -122,7 +122,7 @@ enum SPStyleSrc { * */ -/// Virtual base class for all SPStyle internal classes +/// Base class for all SPStyle internal classes class SPIBase { @@ -140,52 +140,50 @@ public: virtual ~SPIBase() = default; - virtual void read( gchar const *str ) = 0; - virtual void readIfUnset( gchar const *str, SPStyleSrc const &source = SP_STYLE_SRC_STYLE_PROP ) { - if (!str) return; - - bool has_important = false; - Glib::ustring stripped = strip_important(str, has_important); // Sets 'has_important' - // '!important' is invalid on attributes, don't read. - if (source == SP_STYLE_SRC_ATTRIBUTE && has_important){ - return; - } - - if ( !set || (has_important && !important) ) { - read( stripped.c_str() ); - if ( set ) { - style_src = source; - if (has_important) { - important = true; - } - } - } - } + virtual void read(gchar const *str) = 0; + virtual void readIfUnset(gchar const* str, SPStyleSrc source = SP_STYLE_SRC_STYLE_PROP); Glib::ustring important_str() const { return Glib::ustring(important ? " !important" : ""); } - Glib::ustring strip_important( gchar const *str, bool &important ) { - assert (str != NULL); - Glib::ustring string = Glib::ustring(str); - auto pos = string.rfind( " !important" ); - important = false; - if (pos != std::string::npos) { - important = true; - string.erase(pos); - } - return string; - } + Glib::ustring strip_important(gchar const *str, bool &important); - virtual void readAttribute( Inkscape::XML::Node *repr ) { - readIfUnset( repr->attribute( name.c_str() ), SP_STYLE_SRC_ATTRIBUTE ); + virtual void readAttribute(Inkscape::XML::Node *repr) { + readIfUnset(repr->attribute(name.c_str()) , SP_STYLE_SRC_ATTRIBUTE); } - virtual const Glib::ustring get_value() const = 0; - virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, - SPStyleSrc const &style_src_req = SP_STYLE_SRC_STYLE_PROP, - SPIBase const *const base = nullptr ) const; + /** + * @brief Returns a value indicating whether the current style property can be + * written into the style of an XML node, based on the given parameters. + * + * @param flags A bit set from the `SP_STYLE_FLAG_*` constants. + * @param source If the `SP_STYLE_FLAG_IFSET` flag is set, + * @param base The style property of the parent object. Only applicable if the + * `SP_STYLE_FLAG_IFDIFF` flag is set. + * @return True if the style property can be written, false otherwise. + */ + virtual bool isWriteOK( + unsigned int flags, SPStyleSrc source, SPIBase const* base) const; + + /** + * @brief Appends the CSS representation of the property (in the form `name:value;`) + * to the given string. + * @param str The string to which to append the CSS representation of the property. + */ + void appendCSSToString(Glib::ustring& str) const; + + /** + * @brief Returns a string representation of the property value. + */ + virtual Glib::ustring get_value() const = 0; + + /** + * @brief Returns the CSS representation of the property (in the form `name:value;`) + * as a string. + */ + Glib::ustring getCSSString() const; + virtual void clear() { set = false, inherit = false, important = false; } @@ -241,7 +239,7 @@ public: ~SPIFloat() override = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); value = value_default; @@ -316,7 +314,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); value = value_default; @@ -382,7 +380,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); unit = SP_CSS_UNIT_NONE, value = value_default; @@ -432,7 +430,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPILength::clear(); normal = true; @@ -474,7 +472,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); axes.clear(); @@ -542,7 +540,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); value = value_default, computed = computed_default; @@ -595,7 +593,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; }; @@ -619,7 +617,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; }; @@ -641,7 +639,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; }; @@ -663,7 +661,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; }; @@ -691,7 +689,7 @@ public: } void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override; // TODO check about value and value_default void cascade( const SPIBase* const parent ) override; void merge( const SPIBase* const parent ) override; @@ -737,7 +735,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); value.color.set(0); @@ -817,7 +815,7 @@ public: ~SPIPaint() override; // Clear and delete href. void read( gchar const *str ) override; virtual void read( gchar const *str, SPStyle &style, SPDocument *document = nullptr); - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override; virtual void reset( bool init ); // Used internally when reading or cascading void cascade( const SPIBase* const parent ) override; @@ -915,7 +913,7 @@ public: } void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) { @@ -966,7 +964,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); values.clear(); @@ -999,7 +997,7 @@ public: ~SPIFilter() override; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override; void cascade( const SPIBase* const parent ) override; void merge( const SPIBase* const parent ) override; @@ -1038,7 +1036,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); type = SP_FONT_SIZE_LITERAL, unit = SP_CSS_UNIT_NONE, @@ -1085,7 +1083,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); } @@ -1125,7 +1123,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); type=SP_BASELINE_SHIFT_LITERAL, unit=SP_CSS_UNIT_NONE, @@ -1172,7 +1170,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); underline = false, overline = false, line_through = false, blink = false; @@ -1211,7 +1209,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); solid = true, isdouble = false, dotted = false, dashed = false, wavy = false; @@ -1258,10 +1256,11 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; - const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, - SPStyleSrc const &style_src_req = SP_STYLE_SRC_STYLE_PROP, - SPIBase const *const base = nullptr ) const override; + Glib::ustring get_value() const override; + + virtual bool isWriteOK( + unsigned int flags, SPStyleSrc source, SPIBase const* base) const override; + void clear() override { SPIBase::clear(); style_td = nullptr; @@ -1315,7 +1314,7 @@ public: = default; void read( gchar const *str ) override; - const Glib::ustring get_value() const override; + Glib::ustring get_value() const override; void clear() override { SPIBase::clear(); stroke = false; diff --git a/src/style.cpp b/src/style.cpp index c87d84a9fdd..322365ee7d3 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -501,12 +501,15 @@ SPStyle::~SPStyle() { // std::cout << "SPStyle::~SPStyle(): Exit\n" << std::endl; } -const std::vector SPStyle::properties() { return this->_properties; } +std::vector const& SPStyle::properties() { + return this->_properties; +} void SPStyle::clear(SPAttributeEnum id) { SPIBase *p = _prop_helper.get(this, id); if (p) { + std::cout << "Clearing style: " << p->name << ": " << p->get_value() << "\n"; p->clear(); } else { g_warning("Unimplemented style property %d", id); @@ -716,40 +719,80 @@ SPStyle::readIfUnset(SPAttributeEnum id, gchar const *val, SPStyleSrc const &sou } } -/** - * Outputs the style to a CSS string. - * - * Use with SP_STYLE_FLAG_ALWAYS for copying an object's complete cascaded style to - * style_clipboard. - * - * Use with SP_STYLE_FLAG_IFDIFF and a pointer to the parent class when you need a CSS string for - * an object in the document tree. - * - * \pre flags in {IFSET, ALWAYS, IFDIFF}. - * \pre base. - * \post ret != NULL. - */ -Glib::ustring -SPStyle::write( guint const flags, SPStyleSrc const &style_src_req, SPStyle const *const base ) const { +SPIBase* SPStyle::getPropertyByName(char const* name) { + return _prop_helper.get(this, name); +} + +SPIBase* SPStyle::getPropertyByName(SPAttributeEnum name) { + return _prop_helper.get(this, name); +} +Glib::ustring SPStyle::getCSSString( + unsigned int flags, SPStyleSrc style_src_req, SPStyle const* base) const +{ // std::cout << "SPStyle::write: flags: " << flags << std::endl; Glib::ustring style_string; - for(std::vector::size_type i = 0; i != _properties.size(); ++i) { - if( base != nullptr ) { - style_string += _properties[i]->write( flags, style_src_req, base->_properties[i] ); - } else { - style_string += _properties[i]->write( flags, style_src_req, nullptr ); + + for (std::vector::size_type i = 0; i != _properties.size(); ++i) { + SPIBase* property = _properties[i]; + SPIBase* base_property = base ? base->_properties[i] : nullptr; + if (property->isWriteOK(flags, style_src_req, base_property)) { + property->appendCSSToString(style_string); } } // Remove trailing ';' - if( style_string.size() > 0 ) { - style_string.erase( style_string.size() - 1 ); + if (style_string.size() > 0) { + style_string.erase(style_string.size() - 1); } return style_string; } +void SPStyle::writeToXMLNode( + Inkscape::XML::Node* repr, bool preserve_attribs, SPStyle const* base) const +{ + + Glib::ustring style_string; + + for (std::size_t i = 0, n = _properties.size(); i < n; i++) { + SPIBase* property = _properties[i]; + SPIBase* base_property = base ? base->_properties[i] : nullptr; + + // Don't write unset properties or properties obtained from style sheets. + if (!property->set || property->style_src == SPStyleSrc::SP_STYLE_SRC_STYLE_SHEET) { + continue; + } + + if (base_property + && !property->isWriteOK(SP_STYLE_FLAG_IFDIFF, SPStyleSrc::SP_STYLE_SRC_UNSET, base_property)) + { + if (property->style_src == SP_STYLE_SRC_ATTRIBUTE) { + repr->setAttribute(property->name, nullptr); + } + continue; + } + + // !important cannot be used in XML attribs, so if that flag is set, + // write to the style attribute even if preserve_attribs is true. + if (preserve_attribs + && property->style_src == SP_STYLE_SRC_ATTRIBUTE + && !property->important) + { + repr->setAttribute(property->name, property->get_value()); + } else { + property->appendCSSToString(style_string); + } + } + + if (style_string.empty()) { + repr->setAttribute("style", nullptr); + } else { + style_string.erase(style_string.size() - 1); // Remove trailing semicolon + repr->setAttribute("style", style_string.c_str()); + } +} + // Corresponds to sp_style_merge_from_parent() /** * Sets computed values in \a style, which may involve inheriting from (or in some other way @@ -828,8 +871,8 @@ SPStyle::operator==(const SPStyle& rhs) { // for(std::vector::size_type i = 0; i != _properties.size(); ++i) { // if( *_properties[i] != *rhs._properties[i]) // std::cout << _properties[i]->name << ": " - // << _properties[i]->write(SP_STYLE_FLAG_ALWAYS,NULL) << " " - // << rhs._properties[i]->write(SP_STYLE_FLAG_ALWAYS,NULL) + // << _properties[i]->getCSSString() << " " + // << rhs._properties[i]->getCSSString() // << (*_properties[i] == *rhs._properties[i]) << std::endl; // } @@ -1352,7 +1395,7 @@ sp_css_attr_from_style(SPStyle const *const style, guint const flags) g_return_val_if_fail(((flags & SP_STYLE_FLAG_IFSET) || (flags & SP_STYLE_FLAG_ALWAYS)), NULL); - Glib::ustring style_str = style->write(flags); + Glib::ustring style_str = style->getCSSString(flags); SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_attr_add_from_string(css, style_str.c_str()); return css; diff --git a/src/style.h b/src/style.h index c9235f49a6e..6bfa6bf4865 100644 --- a/src/style.h +++ b/src/style.h @@ -46,16 +46,89 @@ public: SPStyle(SPDocument *document = nullptr, SPObject *object = nullptr);// document is ignored if valid object given ~SPStyle(); - const std::vector properties(); + std::vector const& properties(); void clear(); void clear(SPAttributeEnum id); void read(SPObject *object, Inkscape::XML::Node *repr); void readFromObject(SPObject *object); void readFromPrefs(Glib::ustring const &path); void readIfUnset(SPAttributeEnum id, char const *val, SPStyleSrc const &source = SP_STYLE_SRC_STYLE_PROP ); - Glib::ustring write( unsigned int const flags = SP_STYLE_FLAG_IFSET, - SPStyleSrc const &style_src_req = SP_STYLE_SRC_STYLE_PROP, - SPStyle const *const base = nullptr ) const; + + /** + * Outputs the style to a CSS string. + * + * Use with SP_STYLE_FLAG_ALWAYS for copying an object's complete cascaded style to + * style_clipboard. + * + * Use with SP_STYLE_FLAG_IFDIFF and a pointer to the parent class when you need a CSS string for + * an object in the document tree. + * + * \pre flags in {IFSET, ALWAYS, IFDIFF}. + * \pre base. + * \post ret != NULL. + */ + Glib::ustring getCSSString( + unsigned int flags = SP_STYLE_FLAG_IFSET, + SPStyleSrc style_src_req = SP_STYLE_SRC_STYLE_PROP, + SPStyle const* base = nullptr) const; + + /** + * @brief Writes the style into an XML node's style attribute and/or presentation + * XML attributes. + * + * Only style properties obtained from XML attributes and/or inline style + * attributes are considered. Style properties obtained from a style sheet + * are not considered. + * + * @param repr The XML node into which to write the style attributes. + * @param preserve_attribs If this is true, style properties which were obtained + * from XML attributes will be written as XML attributes. Otherwise, all + * style properties will be written into the `style` attribute, irrespective + * of their source. + * @param base Set this to the `SPStyle` instance of the parent style if inheritance + * checking is to be done. Otherwise set this to null. + */ + void writeToXMLNode( + Inkscape::XML::Node* repr, bool preserve_attribs = true, SPStyle const* base = nullptr) const; + + /** + * @brief Returns a pointer to the `SPIBase` instance for the style property with the + * given name. + * @param name The name of a style property. + * @return A pointer to the `SPIBase` instance for the property. + */ + SPIBase* getPropertyByName(char const* name); + + /** + * @brief Returns a pointer to the `SPIBase` instance for the style property with the + * given name. + * @param name The name of a style property as a constant from `SPAttributeEnum`. + * @return A pointer to the `SPIBase` instance for the property. + */ + SPIBase* getPropertyByName(SPAttributeEnum name); + + /** + * @brief Returns a pointer to the `SPIBase` instance for the style property with the + * given name. + * @param name The name of a style property. + * @return A pointer to the `SPIBase` instance for the property, null if `name` is + * invalid. + */ + SPIBase const* getPropertyByName(char const* name) const { + return const_cast(this)->getPropertyByName(name); + } + + /** + * @brief Returns a pointer to the `SPIBase` instance for the style property with the + * given name. + * @param name The name of a style property as a constant from `SPAttributeEnum`. + * @return A pointer to the `SPIBase` instance for the property, null if `name` is + * invalid. + */ + SPIBase const* getPropertyByName(SPAttributeEnum name) const { + return const_cast(this)->getPropertyByName(name); + } + void cascade( SPStyle const *const parent ); void merge( SPStyle const *const parent ); void mergeString( char const *const p ); diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 5291be09eab..ccbb4d22190 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -1376,7 +1376,7 @@ static void overwrite_style_with_string(SPObject *item, gchar const *style_strin if (item_style_string && *item_style_string) { style.mergeString(item_style_string); } - Glib::ustring new_style_string = style.write(); + Glib::ustring new_style_string = style.getCSSString(); item->getRepr()->setAttribute("style", new_style_string.empty() ? nullptr : new_style_string.c_str()); } @@ -1393,13 +1393,13 @@ static bool objects_have_equal_style(SPObject const *parent, SPObject const *chi // requires that the computed value is inherited, not the specified value. g_assert(parent->isAncestorOf(child)); - Glib::ustring parent_style = parent->style->write( SP_STYLE_FLAG_ALWAYS ); + Glib::ustring parent_style = parent->style->getCSSString(SP_STYLE_FLAG_ALWAYS); // we have to write parent_style then read it again, because some properties format their values // differently depending on whether they're set or not (*cough*dash-offset*cough*) SPStyle parent_spstyle(parent->document); parent_spstyle.mergeString(parent_style.c_str()); - parent_style = parent_spstyle.write(SP_STYLE_FLAG_ALWAYS); + parent_style = parent_spstyle.getCSSString(SP_STYLE_FLAG_ALWAYS); Glib::ustring child_style_construction; while (child != parent) { @@ -1415,7 +1415,7 @@ static bool objects_have_equal_style(SPObject const *parent, SPObject const *chi SPStyle child_spstyle(parent->document); child_spstyle.mergeString(child_style_construction.c_str()); - Glib::ustring child_style = child_spstyle.write(SP_STYLE_FLAG_ALWAYS); + Glib::ustring child_style = child_spstyle.getCSSString(SP_STYLE_FLAG_ALWAYS); bool equal = (child_style == parent_style); // Glib::ustring overloads == operator return equal; diff --git a/src/ui/toolbar/text-toolbar.cpp b/src/ui/toolbar/text-toolbar.cpp index bd73fe584ba..2571ad7c58a 100644 --- a/src/ui/toolbar/text-toolbar.cpp +++ b/src/ui/toolbar/text-toolbar.cpp @@ -1712,8 +1712,7 @@ TextToolbar::line_spacing_mode_changed(int mode) if (text_style->line_height.computed != 0 || text_style->line_height.normal) { if (mode != 1 || text_style->line_height.unit == SP_CSS_UNIT_NONE || text_style->line_height.normal) { - Glib::ustring line_height_string = text_style->line_height.write( SP_STYLE_FLAG_ALWAYS ); - line_height_string.erase(0, 12); // erase 'line-height:' + Glib::ustring line_height_string = text_style->line_height.get_value(); osfs << line_height_string; } else { // Convert to unitless value @@ -1731,8 +1730,7 @@ TextToolbar::line_spacing_mode_changed(int mode) } else { if (mode != 1 || tspans.line_height.unit == SP_CSS_UNIT_NONE || tspans.line_height.normal) { - Glib::ustring line_height_string = tspans.line_height.write( SP_STYLE_FLAG_ALWAYS ); - line_height_string.erase(0, 12); // erase 'line-height:' + Glib::ustring line_height_string = tspans.line_height.get_value(); osfs << line_height_string; } else { // Convert to unitless value -- GitLab From 39a722c4eccb7076b7d7fa0e25c2567036673ece Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 01:56:33 +0530 Subject: [PATCH 02/10] Minor changes over previous commit. --- src/object/sp-object.cpp | 2 +- src/object/sp-text.cpp | 1 + src/xml/event.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/object/sp-object.cpp b/src/object/sp-object.cpp index abff44f52b0..bc4e1083953 100644 --- a/src/object/sp-object.cpp +++ b/src/object/sp-object.cpp @@ -998,7 +998,7 @@ void SPObject::readAttr(gchar const *key) } } -void SPObject::repr_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const *key, gchar const * oldval, gchar const * /*newval*/, bool is_interactive, gpointer data) +void SPObject::repr_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const *key, gchar const * /*oldval*/, gchar const * /*newval*/, bool is_interactive, gpointer data) { SPObject *object = SP_OBJECT(data); object->readAttr(key); diff --git a/src/object/sp-text.cpp b/src/object/sp-text.cpp index 60ec7717acc..ff8bd9af7dd 100644 --- a/src/object/sp-text.cpp +++ b/src/object/sp-text.cpp @@ -281,6 +281,7 @@ Inkscape::XML::Node *SPText::write(Inkscape::XML::Document *xml_doc, Inkscape::X this->rebuildLayout(); // copied from update(), see LP Bug 1339305 SPItem::write(xml_doc, repr, flags); + return repr; } diff --git a/src/xml/event.cpp b/src/xml/event.cpp index b0c163784f2..86e042a2bfb 100644 --- a/src/xml/event.cpp +++ b/src/xml/event.cpp @@ -121,7 +121,7 @@ public: node.setContent(new_value); } - void notifyElementNameChanged(Node& node, GQuark /*old_value*/, GQuark new_value) + void notifyElementNameChanged(Node& node, GQuark /*old_value*/, GQuark new_value) override { node.setCodeUnsafe(new_value); } -- GitLab From 807dbed77eefce5ee32273d735001932163dc8af Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 02:02:45 +0530 Subject: [PATCH 03/10] Remove debug message --- src/style.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/style.cpp b/src/style.cpp index 322365ee7d3..5c6a31d2aaa 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -509,7 +509,6 @@ void SPStyle::clear(SPAttributeEnum id) { SPIBase *p = _prop_helper.get(this, id); if (p) { - std::cout << "Clearing style: " << p->name << ": " << p->get_value() << "\n"; p->clear(); } else { g_warning("Unimplemented style property %d", id); -- GitLab From 6e14f7959fe949f733538868f8a171375cee1369 Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 02:46:55 +0530 Subject: [PATCH 04/10] Ensure unit test compatibility --- src/style.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/style.h b/src/style.h index 6bfa6bf4865..9e7864220af 100644 --- a/src/style.h +++ b/src/style.h @@ -72,6 +72,19 @@ public: SPStyleSrc style_src_req = SP_STYLE_SRC_STYLE_PROP, SPStyle const* base = nullptr) const; + /** + * @brief Outputs the style to a CSS string. + * + * Equivalent to `getCSSString()`. + */ + inline Glib::ustring write( + unsigned int flags = SP_STYLE_FLAG_IFSET, + SPStyleSrc style_src_req = SP_STYLE_SRC_STYLE_PROP, + SPStyle const* base = nullptr) const + { + return getCSSString(); + } + /** * @brief Writes the style into an XML node's style attribute and/or presentation * XML attributes. -- GitLab From fbecfb102414dc1ee9208994c7631be02f5548ad Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 04:44:50 +0530 Subject: [PATCH 05/10] Ensure unit test compatibility --- src/style.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/style.h b/src/style.h index 9e7864220af..298c1bc9f06 100644 --- a/src/style.h +++ b/src/style.h @@ -82,7 +82,7 @@ public: SPStyleSrc style_src_req = SP_STYLE_SRC_STYLE_PROP, SPStyle const* base = nullptr) const { - return getCSSString(); + return getCSSString(flags, style_src_req, base); } /** -- GitLab From 8117097eebf6e37fb795cb41f390c49d8fdbb4af Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 12:56:08 +0530 Subject: [PATCH 06/10] Fix possible issue with text-decoration --- po/inkscape.pot | 80 ++++++++++++++++++++++++------------------------- src/style.cpp | 16 +++++----- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/po/inkscape.pot b/po/inkscape.pot index cb6eebc8b26..def62a49621 100644 --- a/po/inkscape.pot +++ b/po/inkscape.pot @@ -33,7 +33,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: inkscape-devel@lists.sourceforge.net\n" -"POT-Creation-Date: 2019-03-21 21:14+0530\n" +"POT-Creation-Date: 2019-03-22 12:08+0530\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -7818,13 +7818,13 @@ msgid "Default import resolution" msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:208 -#: ../src/extension/internal/svg.cpp:643 +#: ../src/extension/internal/svg.cpp:641 #, c-format msgid "Image Rendering Mode:" msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:208 -#: ../src/extension/internal/svg.cpp:643 +#: ../src/extension/internal/svg.cpp:641 #, c-format msgid "" "When an image is upscaled, apply smoothing or keep blocky (pixelated). (Will " @@ -7832,34 +7832,34 @@ msgid "" msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:209 -#: ../src/extension/internal/svg.cpp:644 +#: ../src/extension/internal/svg.cpp:642 #: ../src/ui/dialog/inkscape-preferences.cpp:1943 #, c-format msgid "None (auto)" msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:210 -#: ../src/extension/internal/svg.cpp:645 +#: ../src/extension/internal/svg.cpp:643 #: ../src/ui/dialog/inkscape-preferences.cpp:1943 #, c-format msgid "Smooth (optimizeQuality)" msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:211 -#: ../src/extension/internal/svg.cpp:646 +#: ../src/extension/internal/svg.cpp:644 #: ../src/ui/dialog/inkscape-preferences.cpp:1943 #, c-format msgid "Blocky (optimizeSpeed)" msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:214 -#: ../src/extension/internal/svg.cpp:649 +#: ../src/extension/internal/svg.cpp:647 #, c-format msgid "Hide the dialog next time and always apply the same actions." msgstr "" #: ../src/extension/internal/gdkpixbuf-input.cpp:214 -#: ../src/extension/internal/svg.cpp:649 +#: ../src/extension/internal/svg.cpp:647 #, c-format msgid "Don't ask again" msgstr "" @@ -8127,56 +8127,56 @@ msgstr "" msgid "PovRay Raytracer File" msgstr "" -#: ../src/extension/internal/svg.cpp:635 +#: ../src/extension/internal/svg.cpp:633 msgid "SVG Input" msgstr "" -#: ../src/extension/internal/svg.cpp:637 +#: ../src/extension/internal/svg.cpp:635 msgid "SVG Image Import Type:" msgstr "" -#: ../src/extension/internal/svg.cpp:638 +#: ../src/extension/internal/svg.cpp:636 msgid "Include SVG image as editable object(s) in the current file" msgstr "" -#: ../src/extension/internal/svg.cpp:639 +#: ../src/extension/internal/svg.cpp:637 msgid "Embed the SVG file in a image tag (not editable in this document)" msgstr "" -#: ../src/extension/internal/svg.cpp:640 +#: ../src/extension/internal/svg.cpp:638 msgid "Link the SVG file in a image tag (not editable in this document)." msgstr "" -#: ../src/extension/internal/svg.cpp:653 +#: ../src/extension/internal/svg.cpp:651 msgid "Scalable Vector Graphic (*.svg)" msgstr "" -#: ../src/extension/internal/svg.cpp:654 +#: ../src/extension/internal/svg.cpp:652 msgid "Inkscape native file format and W3C standard" msgstr "" -#: ../src/extension/internal/svg.cpp:662 +#: ../src/extension/internal/svg.cpp:660 msgid "SVG Output Inkscape" msgstr "" -#: ../src/extension/internal/svg.cpp:667 +#: ../src/extension/internal/svg.cpp:665 msgid "Inkscape SVG (*.svg)" msgstr "" -#: ../src/extension/internal/svg.cpp:668 +#: ../src/extension/internal/svg.cpp:666 msgid "SVG format with Inkscape extensions" msgstr "" -#: ../src/extension/internal/svg.cpp:676 +#: ../src/extension/internal/svg.cpp:674 #: ../share/extensions/output_scour.inx.h:19 msgid "SVG Output" msgstr "" -#: ../src/extension/internal/svg.cpp:681 +#: ../src/extension/internal/svg.cpp:679 msgid "Plain SVG (*.svg)" msgstr "" -#: ../src/extension/internal/svg.cpp:682 +#: ../src/extension/internal/svg.cpp:680 msgid "Scalable Vector Graphics format as defined by the W3C" msgstr "" @@ -13170,7 +13170,7 @@ msgstr "" msgid "Linked Flowed Text" msgstr "" -#: ../src/object/sp-flowtext.cpp:288 ../src/object/sp-text.cpp:344 +#: ../src/object/sp-flowtext.cpp:288 ../src/object/sp-text.cpp:347 #: ../src/ui/tools/text-tool.cpp:1643 msgid " [truncated]" msgstr "" @@ -13249,26 +13249,26 @@ msgstr "" msgid "Ungroup" msgstr "" -#: ../src/object/sp-item.cpp:1039 ../src/verbs.cpp:216 +#: ../src/object/sp-item.cpp:1043 ../src/verbs.cpp:216 msgid "Object" msgstr "" -#: ../src/object/sp-item.cpp:1051 +#: ../src/object/sp-item.cpp:1055 #, c-format msgid "%s; clipped" msgstr "" -#: ../src/object/sp-item.cpp:1057 +#: ../src/object/sp-item.cpp:1061 #, c-format msgid "%s; masked" msgstr "" -#: ../src/object/sp-item.cpp:1067 +#: ../src/object/sp-item.cpp:1071 #, c-format msgid "%s; filtered (%s)" msgstr "" -#: ../src/object/sp-item.cpp:1069 +#: ../src/object/sp-item.cpp:1073 #, c-format msgid "%s; filtered" msgstr "" @@ -13376,15 +13376,15 @@ msgstr "" msgid "Conditional Group" msgstr "" -#: ../src/object/sp-text.cpp:320 +#: ../src/object/sp-text.cpp:323 msgid "Auto-wrapped text" msgstr "" -#: ../src/object/sp-text.cpp:322 +#: ../src/object/sp-text.cpp:325 msgid "Text in-a-shape" msgstr "" -#: ../src/object/sp-text.cpp:324 ../src/verbs.cpp:331 +#: ../src/object/sp-text.cpp:327 ../src/verbs.cpp:331 #: ../share/extensions/lorem_ipsum.inx.h:8 #: ../share/extensions/replace_font.inx.h:11 ../share/extensions/split.inx.h:10 #: ../share/extensions/text_braille.inx.h:2 @@ -13399,12 +13399,12 @@ msgstr "" msgid "Text" msgstr "" -#: ../src/object/sp-text.cpp:348 +#: ../src/object/sp-text.cpp:351 #, c-format msgid "on path%s (%s, %s)" msgstr "" -#: ../src/object/sp-text.cpp:349 +#: ../src/object/sp-text.cpp:352 #, c-format msgid "%s (%s, %s)" msgstr "" @@ -26638,7 +26638,7 @@ msgid "Font not found on system" msgstr "" #: ../src/ui/toolbar/text-toolbar.cpp:341 -#: ../src/ui/toolbar/text-toolbar.cpp:2207 +#: ../src/ui/toolbar/text-toolbar.cpp:2205 #: ../src/ui/widget/font-selector.cpp:32 ../src/ui/widget/font-selector.cpp:143 msgid "Font size" msgstr "" @@ -27022,31 +27022,31 @@ msgstr "" msgid "Text: Change line-height unit" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:1828 +#: ../src/ui/toolbar/text-toolbar.cpp:1826 msgid "Text: Change line spacing mode" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:1866 +#: ../src/ui/toolbar/text-toolbar.cpp:1864 msgid "Text: Change word-spacing" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:1907 +#: ../src/ui/toolbar/text-toolbar.cpp:1905 msgid "Text: Change letter-spacing" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:1945 +#: ../src/ui/toolbar/text-toolbar.cpp:1943 msgid "Text: Change dx (kern)" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:1980 +#: ../src/ui/toolbar/text-toolbar.cpp:1978 msgid "Text: Change dy" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:2016 +#: ../src/ui/toolbar/text-toolbar.cpp:2014 msgid "Text: Change rotate" msgstr "" -#: ../src/ui/toolbar/text-toolbar.cpp:2043 +#: ../src/ui/toolbar/text-toolbar.cpp:2041 msgid "Text: Unset line height." msgstr "" diff --git a/src/style.cpp b/src/style.cpp index 5c6a31d2aaa..9a62868daaf 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -751,22 +751,24 @@ Glib::ustring SPStyle::getCSSString( void SPStyle::writeToXMLNode( Inkscape::XML::Node* repr, bool preserve_attribs, SPStyle const* base) const { - Glib::ustring style_string; + preserve_attribs = false; for (std::size_t i = 0, n = _properties.size(); i < n; i++) { SPIBase* property = _properties[i]; SPIBase* base_property = base ? base->_properties[i] : nullptr; - // Don't write unset properties or properties obtained from style sheets. - if (!property->set || property->style_src == SPStyleSrc::SP_STYLE_SRC_STYLE_SHEET) { + // Don't write properties obtained from style sheets. + if (property->style_src == SPStyleSrc::SP_STYLE_SRC_STYLE_SHEET) { continue; } - if (base_property - && !property->isWriteOK(SP_STYLE_FLAG_IFDIFF, SPStyleSrc::SP_STYLE_SRC_UNSET, base_property)) - { - if (property->style_src == SP_STYLE_SRC_ATTRIBUTE) { + unsigned int check_flags = SP_STYLE_FLAG_IFSET; + if (base_property) { + check_flags |= SP_STYLE_FLAG_IFDIFF; + } + if (!property->isWriteOK(check_flags, SPStyleSrc::SP_STYLE_SRC_UNSET, base_property)) { + if (property->set && property->style_src == SP_STYLE_SRC_ATTRIBUTE) { repr->setAttribute(property->name, nullptr); } continue; -- GitLab From 9065c522e539caa1cd1688456fc952cfc3c28316 Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 18:56:00 +0530 Subject: [PATCH 07/10] Fixed: SPStyle::writeToXMLNode() ignored preserve_attribs. --- src/style.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/style.cpp b/src/style.cpp index 9a62868daaf..96357b4c518 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -9,7 +9,6 @@ * bulia byak * Abhishek Sharma * Tavmjong Bah - * Kris De Gussem * * Copyright (C) 2001-2002 Lauris Kaplinski * Copyright (C) 2001 Ximian, Inc. @@ -752,7 +751,6 @@ void SPStyle::writeToXMLNode( Inkscape::XML::Node* repr, bool preserve_attribs, SPStyle const* base) const { Glib::ustring style_string; - preserve_attribs = false; for (std::size_t i = 0, n = _properties.size(); i < n; i++) { SPIBase* property = _properties[i]; -- GitLab From e87eef5af4294499d8eeb64f2cbfb5f51c514e17 Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Fri, 22 Mar 2019 18:59:24 +0530 Subject: [PATCH 08/10] Restore accidentally removed author info --- src/style.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/style.cpp b/src/style.cpp index 96357b4c518..604b2f06d81 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -9,6 +9,7 @@ * bulia byak * Abhishek Sharma * Tavmjong Bah + * Kris De Gussem * * Copyright (C) 2001-2002 Lauris Kaplinski * Copyright (C) 2001 Ximian, Inc. @@ -19,6 +20,7 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ + #include "style.h" #include -- GitLab From 5cede218f8ed2fd14e44e21f22db9141460a1ddf Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Sun, 24 Mar 2019 15:35:30 +0530 Subject: [PATCH 09/10] Fix issue with CSS vs XML style priority, and changes to class attributes and style content will now update the display properly. --- po/inkscape.pot | 2 +- src/3rdparty/libcroco/cr-stylesheet.c | 3 +- src/attributes.cpp | 1 + src/attributes.h | 1 + src/document.cpp | 52 ++++++++++++++++++++++++++- src/document.h | 38 +++++++++++++++++++- src/object/sp-item.cpp | 4 +-- src/object/sp-object.cpp | 1 + src/object/sp-style-elem.cpp | 17 +++------ src/style.cpp | 1 + 10 files changed, 102 insertions(+), 18 deletions(-) diff --git a/po/inkscape.pot b/po/inkscape.pot index def62a49621..6a2a8a56a24 100644 --- a/po/inkscape.pot +++ b/po/inkscape.pot @@ -33,7 +33,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: inkscape-devel@lists.sourceforge.net\n" -"POT-Creation-Date: 2019-03-22 12:08+0530\n" +"POT-Creation-Date: 2019-03-23 22:19+0530\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/src/3rdparty/libcroco/cr-stylesheet.c b/src/3rdparty/libcroco/cr-stylesheet.c index a2cfc20c93f..817ee4f1539 100644 --- a/src/3rdparty/libcroco/cr-stylesheet.c +++ b/src/3rdparty/libcroco/cr-stylesheet.c @@ -199,9 +199,10 @@ cr_stylesheet_append_import (CRStyleSheet * a_this, CRStyleSheet * a_new_import) g_return_val_if_fail (a_new_import, NULL); - if (a_this->import == NULL) + if (a_this->import == NULL) { a_this->import = a_new_import; return a_this; + } for (cur = a_this->import; cur->next; cur = cur->next) ; diff --git a/src/attributes.cpp b/src/attributes.cpp index d7081d4c974..592dec7754d 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -28,6 +28,7 @@ static SPStyleProp const props[] = { {SP_ATTR_INVALID, nullptr}, /* SPObject */ {SP_ATTR_ID, "id"}, + {SP_ATTR_CLASS, "class"}, {SP_ATTR_STYLE, "style"}, {SP_ATTR_INKSCAPE_COLLECT, "inkscape:collect"}, {SP_ATTR_INKSCAPE_LABEL, "inkscape:label"}, diff --git a/src/attributes.h b/src/attributes.h index 512c00499db..58dda6c2b68 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -33,6 +33,7 @@ enum SPAttributeEnum : unsigned { SP_ATTR_INVALID, ///< Must have value 0. /* SPObject */ SP_ATTR_ID, + SP_ATTR_CLASS, SP_ATTR_STYLE, SP_ATTR_INKSCAPE_COLLECT, SP_ATTR_INKSCAPE_LABEL, diff --git a/src/document.cpp b/src/document.cpp index 1fc32d8a056..3c91afdc8b9 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -101,8 +101,9 @@ SPDocument::SPDocument() : rdoc(nullptr), rroot(nullptr), root(nullptr), + root_style_sheet(nullptr), + style_sheet_list(), style_cascade(cr_cascade_new(nullptr, nullptr, nullptr)), - style_sheet(nullptr), ref_count(0), document_uri(nullptr), document_base(nullptr), @@ -1263,6 +1264,55 @@ Glib::ustring SPDocument::getLanguage() const return document_language; } +void SPDocument::addStyleSheet(CRStyleSheet* style_sheet) { + auto it = std::find(style_sheet_list.begin(), style_sheet_list.end(), style_sheet); + if (it != style_sheet_list.end() || style_sheet == nullptr) { + // Style sheet already in list. + return; + } + + style_sheet_list.push_back(style_sheet); + + if (root_style_sheet == nullptr) { + root_style_sheet = cr_stylesheet_new(nullptr); + cr_cascade_set_sheet(style_cascade, root_style_sheet, CRStyleOrigin::ORIGIN_AUTHOR); + } + cr_stylesheet_append_import(root_style_sheet, style_sheet); +} + +void SPDocument::replaceStyleSheet(CRStyleSheet* old_sheet, CRStyleSheet* new_sheet, bool destroy_old) { + auto old_it = std::find(style_sheet_list.begin(), style_sheet_list.end(), old_sheet); + + if (old_it == style_sheet_list.end()) { + // Old style sheet not in list. + addStyleSheet(new_sheet); + return; + } + + auto new_it = std::find(style_sheet_list.begin(), style_sheet_list.end(), new_sheet); + if (new_it != style_sheet_list.end() || new_sheet == nullptr) { + style_sheet_list.erase(old_it); + } else { + *old_it = new_sheet; + } + + // TODO: This is a hacky workaround to libcroco not supporting replacing or removing + // imports. So far I have not found any other way of doing this. Even creating a new + // root style sheet and destroying the old one will not work, since destroying the old root + // style sheet WILL destroy all its imports (the style sheets in the list) along with it. + // (It doesn't even check their reference counts, so holding references won't work either). + // This should be replaced once replacing/removing imports from style sheets is available + // in libcroco. + root_style_sheet->import = nullptr; + for (std::size_t i = 0; i < style_sheet_list.size(); i++) { + cr_stylesheet_append_import(root_style_sheet, style_sheet_list[i]); + } + + if (destroy_old && old_sheet != nullptr) { + cr_stylesheet_destroy(old_sheet); + } +} + /* Object modification root handler */ void SPDocument::requestModified() diff --git a/src/document.h b/src/document.h index b3fa7da4d7a..c9e4a7cd130 100644 --- a/src/document.h +++ b/src/document.h @@ -123,9 +123,18 @@ public: private: SPRoot *root; ///< Our SPRoot + /** + * @brief Root style sheet of this document. + * + * This style sheet combines all the sheets in `style_sheet_list`. + */ + CRStyleSheet* root_style_sheet; + + //! List of style sheets attached to this document. + std::vector style_sheet_list; + public: CRCascade *style_cascade; - CRStyleSheet *style_sheet; protected: char *document_uri; ///< A filename (not a URI yet), or NULL @@ -304,6 +313,33 @@ public: void importDefs(SPDocument *source); + /** + * @brief Adds a style sheet to this document. + * @param style_sheet The style sheet to add. If this is null or a style sheet + * which is already, does nothing. + */ + void addStyleSheet(CRStyleSheet* style_sheet); + + /** + * @brief Replaces a style sheet in the document with a new one. + * + * If `old_sheet` is null, `new_sheet` is appended to the document's style sheet + * list, if it does not exist. If `new_sheet` is null, `old_sheet` is removed from + * the document's style sheet list, if it exists in the list. + * + * @param old_sheet The old style sheet. + * @param new_sheet The new style sheet. + * @param destroy_old If this is set to true, destroys the old style sheet. + */ + void replaceStyleSheet(CRStyleSheet* old_sheet, CRStyleSheet* new_sheet, bool destroy_old = false); + + /** + * @brief Returns a vector containing all the style sheets attached to this document. + */ + inline std::vector const& getStyleSheetList() { + return style_sheet_list; + } + private: void do_change_uri(char const *const filename, bool const rebase); void setupViewport(SPItemCtx *ctx); diff --git a/src/object/sp-item.cpp b/src/object/sp-item.cpp index a5a161795ef..4af610ea2a9 100644 --- a/src/object/sp-item.cpp +++ b/src/object/sp-item.cpp @@ -519,9 +519,9 @@ void SPItem::set(SPAttributeEnum key, gchar const* value) { SPIBase* prop = object->style->getPropertyByName(key); if (prop) { bool style_modified = false; - if (value && (!prop->set || prop->style_src != SPStyleSrc::SP_STYLE_SRC_STYLE_PROP)) { + if (value && (!prop->set || prop->style_src == SPStyleSrc::SP_STYLE_SRC_ATTRIBUTE)) { // Update the style property, if it is not overridden by the element's - // style attribute. + // style attribute or style sheet. prop->clear(); prop->readIfUnset(value, SPStyleSrc::SP_STYLE_SRC_ATTRIBUTE); style_modified = true; diff --git a/src/object/sp-object.cpp b/src/object/sp-object.cpp index bc4e1083953..f08bdddc874 100644 --- a/src/object/sp-object.cpp +++ b/src/object/sp-object.cpp @@ -961,6 +961,7 @@ void SPObject::set(SPAttributeEnum key, gchar const* value) { object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); break; case SP_ATTR_STYLE: + case SP_ATTR_CLASS: object->style->readFromObject( object ); object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); break; diff --git a/src/object/sp-style-elem.cpp b/src/object/sp-style-elem.cpp index dae679bb469..8a29e05231a 100644 --- a/src/object/sp-style-elem.cpp +++ b/src/object/sp-style-elem.cpp @@ -66,7 +66,6 @@ void SPStyleElem::set(SPAttributeEnum key, const gchar* value) { } } - static void child_add_rm_cb(Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *, void *const data) @@ -188,7 +187,7 @@ import_style_cb (CRDocHandler *a_handler, std::cerr << "import_style_cb: No document!" << std::endl; return; } - if (!document->style_sheet) { + if (document->getStyleSheetList().empty()) { std::cerr << "import_style_cb: No document style sheet!" << std::endl; return; } @@ -207,7 +206,7 @@ import_style_cb (CRDocHandler *a_handler, CRStatus const parse_status = cr_parser_parse_file (parser, reinterpret_cast(import_file.c_str()), CR_UTF_8); if (parse_status == CR_OK) { - cr_stylesheet_append_import (document->style_sheet, stylesheet); + document->addStyleSheet(stylesheet); } else { std::cerr << "import_style_cb: Could not parse: " << import_file << std::endl; cr_stylesheet_destroy (stylesheet); @@ -455,6 +454,7 @@ void SPStyleElem::read_content() { // First, create the style-sheet object and track it in this // element so that it can be edited. It'll be combined with // the document's style sheet later. + CRStyleSheet* old_style_sheet = style_sheet; style_sheet = cr_stylesheet_new (nullptr); CRParser *parser = parser_init(style_sheet, document); @@ -468,16 +468,9 @@ void SPStyleElem::read_content() { cr_parser_parse_buf (parser, reinterpret_cast(text.c_str()), text.bytes(), CR_UTF_8); if (parse_status == CR_OK) { - if(!document->style_sheet) { - // if the style is the first style sheet that we've seen, set the document's - // first style sheet to this style and create a cascade object with it. - document->style_sheet = style_sheet; - cr_cascade_set_sheet (document->style_cascade, document->style_sheet, ORIGIN_AUTHOR); - } else { - // If not the first, then chain up this style_sheet - cr_stylesheet_append_import (document->style_sheet, style_sheet); - } + document->replaceStyleSheet(old_style_sheet, style_sheet, true); } else { + document->replaceStyleSheet(old_style_sheet, nullptr, true); cr_stylesheet_destroy (style_sheet); style_sheet = nullptr; if (parse_status != CR_PARSING_ERROR) { diff --git a/src/style.cpp b/src/style.cpp index 604b2f06d81..d7619e5492b 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -971,6 +971,7 @@ SPStyle::_mergeObjectStylesheet( SPObject const *const object ) { _mergeProps(props); cr_prop_list_destroy(props); } + } std::string -- GitLab From f97e0f3ccc83a779aea3304de759599d15daf9c6 Mon Sep 17 00:00:00 2001 From: Joseph Da Silva Date: Sat, 30 Mar 2019 22:03:22 +0530 Subject: [PATCH 10/10] Fixed: SVG path 'd' attribute being overwritten with stale data from style. --- src/style.cpp | 11 ++++++++++- src/style.h | 5 ++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/style.cpp b/src/style.cpp index d7619e5492b..26e05b25310 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -750,7 +750,7 @@ Glib::ustring SPStyle::getCSSString( } void SPStyle::writeToXMLNode( - Inkscape::XML::Node* repr, bool preserve_attribs, SPStyle const* base) const + Inkscape::XML::Node* repr, bool preserve_attribs, SPStyle const* base, bool write_path_data) const { Glib::ustring style_string; @@ -763,6 +763,15 @@ void SPStyle::writeToXMLNode( continue; } + // Since most of the current Inkscape code sets path data using setAttribute rather + // than through the style, this check is to prevent it from being overwritten with + // a (possibly stale) value in the SPStyle instance. + // This is a temporary fix which may be removed when code that sets path data is + // rewritten to handle it correctly as a style property. + if (!write_path_data && property->name == "d") { + continue; + } + unsigned int check_flags = SP_STYLE_FLAG_IFSET; if (base_property) { check_flags |= SP_STYLE_FLAG_IFDIFF; diff --git a/src/style.h b/src/style.h index 298c1bc9f06..6186e2256fb 100644 --- a/src/style.h +++ b/src/style.h @@ -100,9 +100,12 @@ public: * of their source. * @param base Set this to the `SPStyle` instance of the parent style if inheritance * checking is to be done. Otherwise set this to null. + * @param write_path_data Set this to true if the `d` property must be written if + * it is set in the `SPStyle` object. */ void writeToXMLNode( - Inkscape::XML::Node* repr, bool preserve_attribs = true, SPStyle const* base = nullptr) const; + Inkscape::XML::Node* repr, bool preserve_attribs = true, SPStyle const* base = nullptr, + bool write_path_data = false) const; /** * @brief Returns a pointer to the `SPIBase` instance for the style property with the -- GitLab