Index: src/preferences-skeleton.h =================================================================== --- src/preferences-skeleton.h (revision 20798) +++ src/preferences-skeleton.h (working copy) @@ -301,7 +301,7 @@ " images=\"4278190335\"" //ff0000ff " clips=\"16711935\"" // 00ff00ff " masks=\"65535\"/>\n" // 0x0000ffff -" \n" +" \n" " \n" " \n" " \n" Index: src/extension/internal/filter/filter-file.cpp =================================================================== --- src/extension/internal/filter/filter-file.cpp (revision 20798) +++ src/extension/internal/filter/filter-file.cpp (working copy) @@ -159,7 +159,7 @@ node->setAttribute("xmlns:inkscape", SP_INKSCAPE_NS_URI); mywriter writer; - sp_repr_write_stream(node, writer, 0, FALSE, g_quark_from_static_string("svg"), 0, 0); + sp_repr_write_stream(node, writer, 0, FALSE, g_quark_from_static_string("svg"), 0, 0, TRUE); Inkscape::Extension::build_from_mem(xml_str, new Filter::Filter(g_strdup(writer.c_str()))); g_free(xml_str); Index: src/xml/repr.h =================================================================== --- src/xml/repr.h (revision 20798) +++ src/xml/repr.h (working copy) @@ -71,8 +71,8 @@ Inkscape::XML::Document *sp_repr_read_file(gchar const *filename, gchar const *default_ns); Inkscape::XML::Document *sp_repr_read_mem(gchar const *buffer, int length, gchar const *default_ns); void sp_repr_write_stream (Inkscape::XML::Node *repr, Inkscape::IO::Writer &out, - gint indent_level, bool add_whitespace, Glib::QueryQuark elide_prefix, - int inlineattrs, int indent); + gint indent_level, bool add_whitespace, Glib::QueryQuark elide_prefix, + int inlineattrs, int indent, bool force); Inkscape::XML::Document *sp_repr_read_buf (const Glib::ustring &buf, const gchar *default_ns); Glib::ustring sp_repr_save_buf(Inkscape::XML::Document *doc); void sp_repr_save_stream(Inkscape::XML::Document *doc, FILE *to_file, gchar const *default_ns=NULL, bool compress = false); Index: src/xml/repr-io.cpp =================================================================== --- src/xml/repr-io.cpp (revision 20798) +++ src/xml/repr-io.cpp (working copy) @@ -6,6 +6,7 @@ * Authors: * Lauris Kaplinski * bulia byak + * Ed Halley * * Copyright (C) 1999-2002 Lauris Kaplinski * @@ -44,8 +45,8 @@ Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns); static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map); static gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar *default_ns, GHashTable *prefix_map); -static void sp_repr_write_stream_root_element (Node *repr, Writer &out, bool add_whitespace, gchar const *default_ns, int inlineattrs, int indent); -static void sp_repr_write_stream_element (Node *repr, Writer &out, gint indent_level, bool add_whitespace, Glib::QueryQuark elide_prefix, List attributes, int inlineattrs, int indent); +static void sp_repr_write_stream_root_element (Node *repr, Writer &out, bool add_whitespace, gchar const *default_ns, int inlineattrs, int indent, bool force); +static void sp_repr_write_stream_element (Node *repr, Writer &out, gint indent_level, bool add_whitespace, Glib::QueryQuark elide_prefix, List attributes, int inlineattrs, int indent, bool force); #ifdef HAVE_LIBWMF static xmlDocPtr sp_wmf_convert (const char * file_name); @@ -516,6 +517,7 @@ { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool inlineattrs = prefs->getBool("/options/svgoutput/inlineattrs"); + bool force = prefs->getBool("/options/svgoutput/forcedefaultstyles"); int indent = prefs->getInt("/options/svgoutput/indent", 2); /* fixme: do this The Right Way */ @@ -530,12 +532,12 @@ repr ; repr = sp_repr_next(repr) ) { if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) { - sp_repr_write_stream_root_element(repr, *out, TRUE, default_ns, inlineattrs, indent); + sp_repr_write_stream_root_element(repr, *out, TRUE, default_ns, inlineattrs, indent, force); } else if ( repr->type() == Inkscape::XML::COMMENT_NODE ) { - sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent); + sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent, force); out->writeChar( '\n' ); } else { - sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent); + sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent, force); } } } @@ -621,18 +623,18 @@ Inkscape::IO::StdOutputStream bout; Inkscape::IO::OutputStreamWriter out(bout); - sp_repr_write_stream (repr, out, 0, TRUE, GQuark(0), 0, 2); + sp_repr_write_stream (repr, out, 0, TRUE, GQuark(0), 0, 2, TRUE); return; } /* (No doubt this function already exists elsewhere.) */ -static void -repr_quote_write (Writer &out, const gchar * val) +static const gchar * +repr_quote_write (Writer &out, const gchar * val, char delim = '\0') { - if (!val) return; + if (!val) return val; - for (; *val != '\0'; val++) { + for (; *val != '\0' && *val != delim; val++) { switch (*val) { case '"': out.writeString( """ ); break; case '&': out.writeString( "&" ); break; @@ -641,8 +643,99 @@ default: out.writeChar( *val ); break; } } + return val; } + +static const gchar * +repr_clause_skip (const gchar * val, char delim = ';') +{ + if (!val) return val; + while (*val != '\0' && *val != delim) + val++; + if (delim && *val == delim) + val++; + return val; +} + + +static bool +repr_clause_equal (const gchar * val, const gchar * against, char delim = ';') +{ + if (!val) return FALSE; + if (!against) return FALSE; + int l = strlen(against); + int c = strncmp(val, against, l); + if (c != 0) return FALSE; + if (val[l] && val[l] != delim) return FALSE; + return TRUE; +} + + +static bool +repr_default_clause_found (const gchar * val) +{ + // this should probably be specific per schema version of SVG + static const gchar* _defaults[] = { + "opacity:1", "enable-background:accumulate", + "visibility:visible", "overflow:visible", + "fill:#000000", "fill:black", + "fill-opacity:1", + "fill-rule:nonzero", + "stroke:#000000", "stroke:black", + "stroke-opacity:1", + "stroke-dasharray:none", + "stroke-dashoffset:0", + NULL, + }; + const gchar** def; + for (def = _defaults; *def; def++) + if (repr_clause_equal(val, *def)) + return TRUE; + return FALSE; +} + + +static void +repr_write_smart_attribute (Writer & out, + const gchar * key, const gchar * value, bool force) +{ + out.printf(" %s=\"", key); + // lots of default/redundant info in style="" can be skipped + if (!force && 0 == strcmp(key, "style")) { + bool fillnone = FALSE; + bool strokenone = FALSE; + bool markernone = FALSE; + const gchar * val = value; + while (*val) { + if (repr_clause_equal(val, "fill:none")) fillnone = TRUE; + if (repr_clause_equal(val, "stroke:none")) strokenone = TRUE; + if (repr_clause_equal(val, "marker:none")) markernone = TRUE; + val = repr_clause_skip(val); + } + val = value; + while (*val) { + if (fillnone && 0 == strncmp(val, "fill-", 5)) + val = repr_clause_skip(val); + else if (strokenone && 0 == strncmp(val, "stroke-", 7)) + val = repr_clause_skip(val); + else if (markernone && 0 == strncmp(val, "marker-", 7)) + val = repr_clause_skip(val); + else if (repr_default_clause_found(val)) + val = repr_clause_skip(val); + else { + val = repr_quote_write(out, val, ';'); + if (*val++) + out.writeChar(';'); + } + } + } else { + repr_quote_write(out, value); + } + out.writeChar('"'); +} + + namespace { typedef std::map LocalNameMap; @@ -708,7 +801,7 @@ void sp_repr_write_stream_root_element (Node *repr, Writer &out, bool add_whitespace, gchar const *default_ns, - int inlineattrs, int indent) + int inlineattrs, int indent, bool force) { using Inkscape::Util::ptr_shared; g_assert(repr != NULL); @@ -746,12 +839,12 @@ } } - return sp_repr_write_stream_element(repr, out, 0, add_whitespace, elide_prefix, attributes, inlineattrs, indent); + return sp_repr_write_stream_element(repr, out, 0, add_whitespace, elide_prefix, attributes, inlineattrs, indent, force); } void sp_repr_write_stream (Node *repr, Writer &out, gint indent_level, - bool add_whitespace, Glib::QueryQuark elide_prefix, int inlineattrs, int indent) + bool add_whitespace, Glib::QueryQuark elide_prefix, int inlineattrs, int indent, bool force) { if (repr->type() == Inkscape::XML::TEXT_NODE) { repr_quote_write (out, repr->content()); @@ -760,7 +853,7 @@ } else if (repr->type() == Inkscape::XML::PI_NODE) { out.printf( "", repr->name(), repr->content() ); } else if (repr->type() == Inkscape::XML::ELEMENT_NODE) { - sp_repr_write_stream_element(repr, out, indent_level, add_whitespace, elide_prefix, repr->attributeList(), inlineattrs, indent); + sp_repr_write_stream_element(repr, out, indent_level, add_whitespace, elide_prefix, repr->attributeList(), inlineattrs, indent, force); } else { g_assert_not_reached(); } @@ -772,7 +865,7 @@ bool add_whitespace, Glib::QueryQuark elide_prefix, List attributes, - int inlineattrs, int indent) + int inlineattrs, int indent, bool force) { Node *child; bool loose; @@ -819,9 +912,8 @@ } } } - out.printf(" %s=\"", g_quark_to_string(iter->key)); - repr_quote_write(out, iter->value); - out.writeChar('"'); + repr_write_smart_attribute(out, g_quark_to_string(iter->key), + iter->value, force); } loose = TRUE; @@ -837,7 +929,7 @@ out.writeString( "\n" ); } for (child = repr->firstChild(); child != NULL; child = child->next()) { - sp_repr_write_stream (child, out, (loose) ? (indent_level + 1) : 0, add_whitespace, elide_prefix, inlineattrs, indent); + sp_repr_write_stream (child, out, (loose) ? (indent_level + 1) : 0, add_whitespace, elide_prefix, inlineattrs, indent, force); } if (loose && add_whitespace && indent) { Index: src/ui/dialog/inkscape-preferences.cpp =================================================================== --- src/ui/dialog/inkscape-preferences.cpp (revision 20798) +++ src/ui/dialog/inkscape-preferences.cpp (working copy) @@ -1018,6 +1020,9 @@ _svgoutput_indent.init("/options/svgoutput/indent", 0.0, 1000.0, 1.0, 2.0, 2.0, true, false); _page_svgoutput.add_line( false, _("Indent, spaces:"), _svgoutput_indent, "", _("The number of spaces to use for indenting nested elements; set to 0 for no indentation"), false); + _svgoutput_forcedefaultstyles.init( _("Force default styles"), "/options/svgoutput/forcedefaultstyles", false); + _page_svgoutput.add_line( false, "", _svgoutput_forcedefaultstyles, "", _("Write explicit styles even if they're defaults"), false); + _page_svgoutput.add_group_header( _("Path data")); _svgoutput_allowrelativecoordinates.init( _("Allow relative coordinates"), "/options/svgoutput/allowrelativecoordinates", true); Index: src/ui/dialog/inkscape-preferences.h =================================================================== --- src/ui/dialog/inkscape-preferences.h (revision 20798) +++ src/ui/dialog/inkscape-preferences.h (working copy) @@ -249,6 +250,7 @@ PrefSpinButton _svgoutput_numericprecision; PrefSpinButton _svgoutput_minimumexponent; PrefCheckButton _svgoutput_inlineattrs; + PrefCheckButton _svgoutput_forcedefaultstyles; PrefSpinButton _svgoutput_indent; PrefCheckButton _svgoutput_allowrelativecoordinates; PrefCheckButton _svgoutput_forcerepeatcommands;