diff options
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/Makefile_insert | 1 | ||||
| -rw-r--r-- | src/attribute-sort-util.cpp | 206 | ||||
| -rw-r--r-- | src/attribute-sort-util.h | 62 | ||||
| -rw-r--r-- | src/attributes.cpp | 91 | ||||
| -rw-r--r-- | src/attributes.h | 101 | ||||
| -rw-r--r-- | src/preferences-skeleton.h | 3 | ||||
| -rw-r--r-- | src/xml/repr-io.cpp | 5 |
8 files changed, 383 insertions, 88 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf5130317..66f16b7fb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ set(sp_SRC attribute-rel-css.cpp attribute-rel-svg.cpp attribute-rel-util.cpp + attribute-sort-util.cpp sp-anchor.cpp sp-clippath.cpp sp-conn-end-pair.cpp @@ -92,6 +93,7 @@ set(sp_SRC attribute-rel-css.h attribute-rel-svg.h attribute-rel-util.h + attribute-sort-util.h sp-anchor.h sp-clippath.h sp-conn-end-pair.h diff --git a/src/Makefile_insert b/src/Makefile_insert index b9723ac42..55fde4dd2 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -8,6 +8,7 @@ ink_common_sources += \ attribute-rel-svg.cpp attribute-rel-svg.h \ attribute-rel-css.cpp attribute-rel-css.h \ attribute-rel-util.cpp attribute-rel-util.h \ + attribute-sort-util.cpp attribute-sort-util.h \ axis-manip.cpp axis-manip.h \ bad-uri-exception.h \ box3d.cpp box3d.h \ diff --git a/src/attribute-sort-util.cpp b/src/attribute-sort-util.cpp new file mode 100644 index 000000000..ef08a142f --- /dev/null +++ b/src/attribute-sort-util.cpp @@ -0,0 +1,206 @@ +/* + * attribute-sort-util.cpp + * + * Created on: Jun 10, 2016 + * Author: Tavmjong Bah + */ + +/** + * Utility functions for sorting attributes by name. + */ + +#include <fstream> +#include <sstream> +#include <string> +#include <iostream> +#include <vector> +#include <utility> // std::pair +#include <algorithm> // std::sort + +#include "attribute-sort-util.h" + +#include "xml/repr.h" +#include "xml/attribute-record.h" +#include "xml/sp-css-attr.h" + +#include "attributes.h" + +using Inkscape::XML::Node; +using Inkscape::XML::AttributeRecord; +using Inkscape::Util::List; + +/** + * Sort attributes by name. + */ +void sp_attribute_sort_tree(Node *repr) { + + g_return_if_fail (repr != NULL); + + sp_attribute_sort_recursive( repr ); +} + +/** + * Sort recursively over all elements. + */ +void sp_attribute_sort_recursive(Node *repr) { + + g_return_if_fail (repr != NULL); + + if( repr->type() == Inkscape::XML::ELEMENT_NODE ) { + Glib::ustring element = repr->name(); + + // Only sort elements in svg namespace + if( element.substr(0,4) == "svg:" ) { + sp_attribute_sort_element( repr ); + } + } + + for(Node *child=repr->firstChild() ; child ; child = child->next()) { + sp_attribute_sort_recursive( child ); + } +} + +/** + * Compare function + */ +bool cmp(std::pair< Glib::ustring, Glib::ustring > const &a, + std::pair< Glib::ustring, Glib::ustring > const &b) { + unsigned val_b = sp_attribute_lookup(b.first.c_str()); + if (val_b == 0) return true; // Unknown attributes at end. + return sp_attribute_lookup(a.first.c_str()) < val_b; +} + +/** + * Sort attributes on an element + */ +void sp_attribute_sort_element(Node *repr) { + + g_return_if_fail (repr != NULL); + g_return_if_fail (repr->type() == Inkscape::XML::ELEMENT_NODE); + + // Glib::ustring element = repr->name(); + // Glib::ustring id = (repr->attribute( "id" )==NULL ? "" : repr->attribute( "id" )); + + sp_attribute_sort_style(repr); + + // Sort attributes: + + // It doesn't seem possible to sort a List directly so we dump the list into + // a std::list and sort that. Not very efficient. Sad. + List<AttributeRecord const> attributes = repr->attributeList(); + + std::vector<std::pair< Glib::ustring, Glib::ustring > > my_list; + for ( List<AttributeRecord const> iter = attributes ; iter ; ++iter ) { + + Glib::ustring attribute = g_quark_to_string(iter->key); + Glib::ustring value = (const char*)iter->value; + + // C++11 my_list.emlace_back(attribute, value); + my_list.push_back(std::make_pair(attribute,value)); + } + std::sort(my_list.begin(), my_list.end(), cmp); + // Delete all attributes. + //for (auto it: my_list) { + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + repr->setAttribute( it->first.c_str(), NULL, false ); + } + // Insert all attributes in proper order + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + repr->setAttribute( it->first.c_str(), it->second.c_str(), false ); + } +} + + +/** + * Sort CSS style on an element. + */ +void sp_attribute_sort_style(Node *repr) { + + g_return_if_fail (repr != NULL); + g_return_if_fail (repr->type() == Inkscape::XML::ELEMENT_NODE); + + // Find element's style + SPCSSAttr *css = sp_repr_css_attr( repr, "style" ); + sp_attribute_sort_style(repr, css); + + // Convert css node's properties data to string and set repr node's attribute "style" to that string. + // sp_repr_css_set( repr, css, "style"); // Don't use as it will cause loop. + Glib::ustring value; + sp_repr_css_write_string(css, value); + if( value.empty() ) { + repr->setAttribute("style", NULL ); + } else { + repr->setAttribute("style", value.c_str()); + } + + sp_repr_css_attr_unref( css ); +} + + +/** + * Sort CSS style on an element. + */ +Glib::ustring sp_attribute_sort_style(Node *repr, gchar const *string) { + + g_return_val_if_fail (repr != NULL, NULL); + g_return_val_if_fail (repr->type() == Inkscape::XML::ELEMENT_NODE, NULL); + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string( css, string ); + sp_attribute_sort_style(repr, css); + Glib::ustring string_cleaned; + sp_repr_css_write_string (css, string_cleaned); + + sp_repr_css_attr_unref( css ); + + return string_cleaned; +} + + +/** + * Sort CSS style on an element. + */ +void sp_attribute_sort_style(Node* repr, SPCSSAttr *css) { + + g_return_if_fail (repr != NULL); + g_return_if_fail (css != NULL); + + Glib::ustring element = repr->name(); + Glib::ustring id = (repr->attribute( "id" )==NULL ? "" : repr->attribute( "id" )); + + // Loop over all properties in "style" node. + std::vector<std::pair< Glib::ustring, Glib::ustring > > my_list; + for ( List<AttributeRecord const> iter = css->attributeList() ; iter ; ++iter ) { + + Glib::ustring property = g_quark_to_string(iter->key); + Glib::ustring value = (const char*)iter->value; + + // C++11 my_list.emlace_back(property, value); + my_list.push_back(std::make_pair(property,value)); + } + std::sort(my_list.begin(), my_list.end(), cmp); + // Delete all attributes. + //for (auto it: my_list) { + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + sp_repr_css_set_property( css, it->first.c_str(), NULL ); + } + // Insert all attributes in proper order + for (std::vector<std::pair< Glib::ustring, Glib::ustring > >::iterator it = my_list.begin(); + it != my_list.end(); ++it) { + sp_repr_css_set_property( css, it->first.c_str(), it->second.c_str() ); + } +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/attribute-sort-util.h b/src/attribute-sort-util.h new file mode 100644 index 000000000..0b2f81ed9 --- /dev/null +++ b/src/attribute-sort-util.h @@ -0,0 +1,62 @@ +#ifndef __SP_ATTRIBUTE_SORT_UTIL_H__ +#define __SP_ATTRIBUTE_SORT_UTIL_H__ + +/* + * attribute-sort-util.h + * + * Created on: Jun 10, 2016 + * Author: Tavmjong Bah + */ + +#include <glibmm/ustring.h> +#include "xml/sp-css-attr.h" + +using Inkscape::XML::Node; + +/** + * Utility functions for sorting attributes. + */ + +/** + * Sort attributes by name. + */ +void sp_attribute_sort_tree(Node *repr); + +/** + * Recursively sort. + * repr: the root node in a document or any other node. + */ +void sp_attribute_sort_recursive(Node *repr); + +/** + * Sort one element (attributes). + */ +void sp_attribute_sort_element(Node *repr); + +/** + * Sort style properties for one element. + */ +void sp_attribute_sort_style(Node *repr); + +/** + * Sort style_property for a style string + */ +Glib::ustring sp_attribute_sort_style(Node *repr, gchar const *string); + +/** + * Sort style properties for one CSS. + */ +void sp_attribute_sort_style(Node* repr, SPCSSAttr *css); + +#endif /* __SP_ATTRIBUTE_SORT_UTIL_H__ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/attributes.cpp b/src/attributes.cpp index 24c16d5fc..e281dad65 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -420,11 +420,49 @@ static SPStyleProp const props[] = { {SP_ATTR_TEXT_EXCLUDE,"inkscape:excludeShape"}, {SP_ATTR_LAYOUT_OPTIONS,"inkscape:layoutOptions"}, - /* CSS2 */ - {SP_PROP_INKSCAPE_FONT_SPEC, "-inkscape-font-specification"}, + /* CSS & SVG Properites */ + + /* Paint */ + {SP_PROP_COLOR, "color"}, + {SP_PROP_OPACITY, "opacity"}, + {SP_PROP_FILL, "fill"}, + {SP_PROP_FILL_OPACITY, "fill-opacity"}, + {SP_PROP_FILL_RULE, "fill-rule"}, + {SP_PROP_STROKE, "stroke"}, + {SP_PROP_STROKE_OPACITY, "stroke-opacity"}, + {SP_PROP_STROKE_WIDTH, "stroke-width"}, + {SP_PROP_STROKE_LINECAP, "stroke-linecap"}, + {SP_PROP_STROKE_LINEJOIN, "stroke-linejoin"}, + {SP_PROP_STROKE_MITERLIMIT, "stroke-miterlimit"}, + {SP_PROP_STROKE_DASHARRAY, "stroke-dasharray"}, + {SP_PROP_STROKE_DASHOFFSET, "stroke-dashoffset"}, + {SP_PROP_MARKER, "marker"}, + {SP_PROP_MARKER_END, "marker-end"}, + {SP_PROP_MARKER_MID, "marker-mid"}, + {SP_PROP_MARKER_START, "marker-start"}, + {SP_PROP_PAINT_ORDER, "paint-order" }, + {SP_PROP_SOLID_COLOR, "solid-color"}, + {SP_PROP_SOLID_OPACITY, "solid-opacity"}, + + /* CSS Blending/Compositing */ + {SP_PROP_MIX_BLEND_MODE, "mix-blend-mode"}, + {SP_PROP_ISOLATION, "isolation"}, + + /* Misc. Display */ + {SP_PROP_DISPLAY, "display"}, + {SP_PROP_OVERFLOW, "overflow"}, + {SP_PROP_VISIBILITY, "visibility"}, + + /* Clip/Mask */ + {SP_PROP_CLIP, "clip"}, + {SP_PROP_CLIP_PATH, "clip-path"}, + {SP_PROP_CLIP_RULE, "clip-rule"}, + {SP_PROP_MASK, "mask"}, + /* Font */ {SP_PROP_FONT, "font"}, {SP_PROP_FONT_FAMILY, "font-family"}, + {SP_PROP_INKSCAPE_FONT_SPEC, "-inkscape-font-specification"}, {SP_PROP_FONT_SIZE, "font-size"}, {SP_PROP_FONT_SIZE_ADJUST, "font-size-adjust"}, {SP_PROP_FONT_STRETCH, "font-stretch"}, @@ -449,7 +487,7 @@ static SPStyleProp const props[] = { {SP_PROP_WORD_SPACING, "word-spacing"}, {SP_PROP_TEXT_TRANSFORM, "text-transform"}, - /* Text (css3) */ + /* Text (CSS3) */ {SP_PROP_DIRECTION, "direction"}, {SP_PROP_WRITING_MODE, "writing-mode"}, {SP_PROP_TEXT_ORIENTATION, "text-orientation"}, @@ -470,70 +508,43 @@ static SPStyleProp const props[] = { {SP_PROP_SHAPE_MARGIN, "shape-margin"}, /* Text Decoration */ - {SP_PROP_TEXT_DECORATION, "text-decoration"}, + {SP_PROP_TEXT_DECORATION, "text-decoration"}, // CSS 2/CSS3-Shorthand {SP_PROP_TEXT_DECORATION_LINE, "text-decoration-line"}, {SP_PROP_TEXT_DECORATION_STYLE, "text-decoration-style"}, {SP_PROP_TEXT_DECORATION_COLOR, "text-decoration-color"}, {SP_PROP_TEXT_DECORATION_FILL, "text-decoration-fill"}, {SP_PROP_TEXT_DECORATION_STROKE,"text-decoration-stroke"}, - /* Misc */ - {SP_PROP_CLIP, "clip"}, - {SP_PROP_COLOR, "color"}, - {SP_PROP_CURSOR, "cursor"}, - {SP_PROP_DISPLAY, "display"}, - {SP_PROP_OVERFLOW, "overflow"}, - {SP_PROP_VISIBILITY, "visibility"}, - {SP_PROP_MIX_BLEND_MODE, "mix-blend-mode"}, // CSS Blending and Compositing - {SP_PROP_ISOLATION, "isolation"}, - /* SVG */ - /* Clip/Mask */ - {SP_PROP_CLIP_PATH, "clip-path"}, - {SP_PROP_CLIP_RULE, "clip-rule"}, - {SP_PROP_MASK, "mask"}, - {SP_PROP_OPACITY, "opacity"}, /* Filter */ {SP_PROP_ENABLE_BACKGROUND, "enable-background"}, {SP_PROP_FILTER, "filter"}, {SP_PROP_FLOOD_COLOR, "flood-color"}, {SP_PROP_FLOOD_OPACITY, "flood-opacity"}, {SP_PROP_LIGHTING_COLOR, "lighting-color"}, + /* Gradient */ {SP_PROP_STOP_COLOR, "stop-color"}, {SP_PROP_STOP_OPACITY, "stop-opacity"}, {SP_PROP_STOP_PATH, "path"}, - /* Interactivity */ - {SP_PROP_POINTER_EVENTS, "pointer-events"}, - /* Paint */ + + /* Rendering */ {SP_PROP_COLOR_INTERPOLATION, "color-interpolation"}, {SP_PROP_COLOR_INTERPOLATION_FILTERS, "color-interpolation-filters"}, {SP_PROP_COLOR_PROFILE, "color-profile"}, {SP_PROP_COLOR_RENDERING, "color-rendering"}, - {SP_PROP_FILL, "fill"}, - {SP_PROP_FILL_OPACITY, "fill-opacity"}, - {SP_PROP_FILL_RULE, "fill-rule"}, {SP_PROP_IMAGE_RENDERING, "image-rendering"}, - {SP_PROP_MARKER, "marker"}, - {SP_PROP_MARKER_END, "marker-end"}, - {SP_PROP_MARKER_MID, "marker-mid"}, - {SP_PROP_MARKER_START, "marker-start"}, - {SP_PROP_PAINT_ORDER, "paint-order" }, {SP_PROP_SHAPE_RENDERING, "shape-rendering"}, - {SP_PROP_SOLID_COLOR, "solid-color"}, - {SP_PROP_SOLID_OPACITY, "solid-opacity"}, - {SP_PROP_STROKE, "stroke"}, - {SP_PROP_STROKE_DASHARRAY, "stroke-dasharray"}, - {SP_PROP_STROKE_DASHOFFSET, "stroke-dashoffset"}, - {SP_PROP_STROKE_LINECAP, "stroke-linecap"}, - {SP_PROP_STROKE_LINEJOIN, "stroke-linejoin"}, - {SP_PROP_STROKE_MITERLIMIT, "stroke-miterlimit"}, - {SP_PROP_STROKE_OPACITY, "stroke-opacity"}, - {SP_PROP_STROKE_WIDTH, "stroke-width"}, {SP_PROP_TEXT_RENDERING, "text-rendering"}, + + /* Interactivity */ + {SP_PROP_POINTER_EVENTS, "pointer-events"}, + {SP_PROP_CURSOR, "cursor"}, + /* Conditional */ {SP_PROP_SYSTEM_LANGUAGE, "systemLanguage"}, {SP_PROP_REQUIRED_FEATURES, "requiredFeatures"}, {SP_PROP_REQUIRED_EXTENSIONS, "requiredExtensions"}, + /* LivePathEffect */ {SP_PROP_PATH_EFFECT, "effect"}, }; diff --git a/src/attributes.h b/src/attributes.h index e82db5f2a..ff426e8cf 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -24,6 +24,13 @@ unsigned char const *sp_attribute_name(unsigned int id); */ #define SP_ATTRIBUTE_IS_CSS(k) (((k) >= SP_PROP_INKSCAPE_FONT_SPEC) && ((k) <= SP_PROP_TEXT_RENDERING)) +/* + * Do not change order of attributes and properties. Attribute and + * order in an SVG file is (optionally) determined by the order here. + * This makes comparing different versions of a drawing easier using + * line-by-line comparison. Also, inorder for proper parsing, some + * properites must be before others (e.g. 'font' before 'font-family'). + */ enum SPAttributeEnum { SP_ATTR_INVALID, ///< Must have value 0. /* SPObject */ @@ -420,14 +427,49 @@ enum SPAttributeEnum { SP_ATTR_TEXT_EXCLUDE, SP_ATTR_LAYOUT_OPTIONS, - /* CSS & SVG Properties */ + /* CSS & SVG Properties KEEP ORDER */ - /* Custom full font name because Font stuff below is inadequate REMOVE ME */ - SP_PROP_INKSCAPE_FONT_SPEC, + /* Paint */ + SP_PROP_COLOR, + SP_PROP_OPACITY, + SP_PROP_FILL, + SP_PROP_FILL_OPACITY, + SP_PROP_FILL_RULE, + SP_PROP_STROKE, + SP_PROP_STROKE_OPACITY, + SP_PROP_STROKE_WIDTH, + SP_PROP_STROKE_LINECAP, + SP_PROP_STROKE_LINEJOIN, + SP_PROP_STROKE_MITERLIMIT, + SP_PROP_STROKE_DASHARRAY, + SP_PROP_STROKE_DASHOFFSET, + SP_PROP_MARKER, + SP_PROP_MARKER_END, + SP_PROP_MARKER_MID, + SP_PROP_MARKER_START, + SP_PROP_PAINT_ORDER, /* SVG2 */ + SP_PROP_SOLID_COLOR, + SP_PROP_SOLID_OPACITY, + + /* CSS Blending/Compositing */ + SP_PROP_MIX_BLEND_MODE, + SP_PROP_ISOLATION, + + /* Misc. Display */ + SP_PROP_DISPLAY, + SP_PROP_OVERFLOW, + SP_PROP_VISIBILITY, - /* Font */ + /* Clip/Mask */ + SP_PROP_CLIP, + SP_PROP_CLIP_PATH, + SP_PROP_CLIP_RULE, + SP_PROP_MASK, + + /* Font: Order is important! */ SP_PROP_FONT, SP_PROP_FONT_FAMILY, + SP_PROP_INKSCAPE_FONT_SPEC, // Remove me SP_PROP_FONT_SIZE, SP_PROP_FONT_SIZE_ADJUST, SP_PROP_FONT_STRETCH, @@ -447,12 +489,12 @@ enum SPAttributeEnum { /* Text Layout */ SP_PROP_TEXT_INDENT, SP_PROP_TEXT_ALIGN, - SP_PROP_LINE_HEIGHT, SP_PROP_LETTER_SPACING, SP_PROP_WORD_SPACING, SP_PROP_TEXT_TRANSFORM, + /* Text (CSS3) */ SP_PROP_DIRECTION, SP_PROP_WRITING_MODE, SP_PROP_TEXT_ORIENTATION, @@ -472,32 +514,14 @@ enum SPAttributeEnum { SP_PROP_SHAPE_PADDING, SP_PROP_SHAPE_MARGIN, - /* Text Decoration CSS 2/CSS 3 Shorthand */ - SP_PROP_TEXT_DECORATION, - /* Text Decoration CSS 3/SVG 2 */ + /* Text Decoration */ + SP_PROP_TEXT_DECORATION, // CSS 2/CSS3-Shorthand SP_PROP_TEXT_DECORATION_LINE, SP_PROP_TEXT_DECORATION_STYLE, SP_PROP_TEXT_DECORATION_COLOR, SP_PROP_TEXT_DECORATION_FILL, SP_PROP_TEXT_DECORATION_STROKE, - /* Misc */ - SP_PROP_CLIP, - SP_PROP_COLOR, - SP_PROP_CURSOR, - SP_PROP_DISPLAY, - SP_PROP_OVERFLOW, - SP_PROP_VISIBILITY, - SP_PROP_MIX_BLEND_MODE, - SP_PROP_ISOLATION, - - /* SVG */ - /* Clip/Mask */ - SP_PROP_CLIP_PATH, - SP_PROP_CLIP_RULE, - SP_PROP_MASK, - SP_PROP_OPACITY, - /* Filter */ SP_PROP_ENABLE_BACKGROUND, SP_PROP_FILTER, @@ -510,36 +534,19 @@ enum SPAttributeEnum { SP_PROP_STOP_OPACITY, SP_PROP_STOP_PATH, - /* Interactivity */ - SP_PROP_POINTER_EVENTS, - - /* Paint */ + /* Rendering */ SP_PROP_COLOR_INTERPOLATION, SP_PROP_COLOR_INTERPOLATION_FILTERS, SP_PROP_COLOR_PROFILE, SP_PROP_COLOR_RENDERING, - SP_PROP_FILL, - SP_PROP_FILL_OPACITY, - SP_PROP_FILL_RULE, SP_PROP_IMAGE_RENDERING, - SP_PROP_MARKER, - SP_PROP_MARKER_END, - SP_PROP_MARKER_MID, - SP_PROP_MARKER_START, - SP_PROP_PAINT_ORDER, /* SVG2 */ SP_PROP_SHAPE_RENDERING, - SP_PROP_SOLID_COLOR, - SP_PROP_SOLID_OPACITY, - SP_PROP_STROKE, - SP_PROP_STROKE_DASHARRAY, - SP_PROP_STROKE_DASHOFFSET, - SP_PROP_STROKE_LINECAP, - SP_PROP_STROKE_LINEJOIN, - SP_PROP_STROKE_MITERLIMIT, - SP_PROP_STROKE_OPACITY, - SP_PROP_STROKE_WIDTH, SP_PROP_TEXT_RENDERING, + /* Interactivity */ + SP_PROP_POINTER_EVENTS, + SP_PROP_CURSOR, + /* Conditional */ SP_PROP_SYSTEM_LANGUAGE, SP_PROP_REQUIRED_FEATURES, diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 5ccc4d729..38196a58e 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -338,7 +338,8 @@ static char const preferences_skeleton[] = " style_defaults_remove=\"0\" " " check_on_reading=\"0\" " " check_on_editing=\"0\" " -" check_on_writing=\"0\"/>\n" +" check_on_writing=\"0\" " +" sort_attributes=\"0\"/>\n" " <group id=\"externalresources\">\n" " <group id=\"xml\" " " allow_net_access=\"0\"/>\n" diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index 4a6f59b43..6977bc1e2 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -34,6 +34,7 @@ #include "extension/extension.h" #include "attribute-rel-util.h" +#include "attribute-sort-util.h" #include "preferences.h" @@ -882,6 +883,10 @@ static void sp_repr_write_stream_root_element(Node *repr, Writer &out, bool clean = prefs->getBool("/options/svgoutput/check_on_writing"); if (clean) sp_attribute_clean_tree( repr ); + // Sort attributes in a canonical order (helps with "diffing" SVG files). + bool sort = prefs->getBool("/options/svgoutput/sort_attributes"); + if (sort) sp_attribute_sort_tree( repr ); + Glib::QueryQuark xml_prefix=g_quark_from_static_string("xml"); NSMap ns_map; |
