summaryrefslogtreecommitdiffstats
path: root/src/attribute-rel-util.cpp
diff options
context:
space:
mode:
authorAndrew Higginson <at.higginson@gmail.com>2011-12-27 21:04:47 +0000
committerAndrew <at.higginson@gmail.com>2011-12-27 21:04:47 +0000
commit80960b623a99aae1402ab651b2974ef544ed3b03 (patch)
treeba49d42c2789e9e11f805e2d5263e10f9fedeef8 /src/attribute-rel-util.cpp
parenttry to fix bug (diff)
parentGDL: Cherry-pick upstream patch 73852 (2011-03-23) - Add missing return value. (diff)
downloadinkscape-80960b623a99aae1402ab651b2974ef544ed3b03.tar.gz
inkscape-80960b623a99aae1402ab651b2974ef544ed3b03.zip
merged with trunk so I can build again...
(bzr r10092.1.36)
Diffstat (limited to 'src/attribute-rel-util.cpp')
-rw-r--r--src/attribute-rel-util.cpp312
1 files changed, 312 insertions, 0 deletions
diff --git a/src/attribute-rel-util.cpp b/src/attribute-rel-util.cpp
new file mode 100644
index 000000000..49b6fd73e
--- /dev/null
+++ b/src/attribute-rel-util.cpp
@@ -0,0 +1,312 @@
+/*
+ * attribute-rel-util.h
+ *
+ * Created on: Sep 8, 2011
+ * Author: tavmjong
+ */
+
+/**
+ * Utility functions for cleaning SVG tree of unneeded attributes and style properties.
+ */
+
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <iostream>
+
+#include "preferences.h"
+
+#include "xml/attribute-record.h"
+
+#include "attribute-rel-css.h"
+#include "attribute-rel-svg.h"
+
+#include "attribute-rel-util.h"
+
+using Inkscape::XML::Node;
+using Inkscape::XML::AttributeRecord;
+using Inkscape::Util::List;
+
+/**
+ * Get preferences
+ */
+unsigned int sp_attribute_clean_get_prefs() {
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ unsigned int flags = 0;
+ if( prefs->getBool("/options/svgoutput/incorrect_attributes_warn") ) flags += SP_ATTR_CLEAN_ATTR_WARN;
+ if( prefs->getBool("/options/svgoutput/incorrect_attributes_remove") ) flags += SP_ATTR_CLEAN_ATTR_REMOVE;
+ if( prefs->getBool("/options/svgoutput/incorrect_style_properties_warn") ) flags += SP_ATTR_CLEAN_STYLE_WARN;
+ if( prefs->getBool("/options/svgoutput/incorrect_style_properties_remove" ) ) flags += SP_ATTR_CLEAN_STYLE_REMOVE;
+ if( prefs->getBool("/options/svgoutput/style_defaults_warn") ) flags += SP_ATTR_CLEAN_DEFAULT_WARN;
+ if( prefs->getBool("/options/svgoutput/style_defaults_remove") ) flags += SP_ATTR_CLEAN_DEFAULT_REMOVE;
+
+ return flags;
+}
+
+/**
+ * Remove or warn about inappropriate attributes and useless stype properties.
+ * repr: the root node in a document or any other node.
+ */
+void sp_attribute_clean_tree(Node *repr) {
+
+ g_return_if_fail (repr != NULL);
+
+ unsigned int flags = sp_attribute_clean_get_prefs();
+
+ if( flags ) {
+ sp_attribute_clean_recursive( repr, flags );
+ }
+}
+
+/**
+ * Clean recursively over all elements.
+ */
+void sp_attribute_clean_recursive(Node *repr, unsigned int flags) {
+
+ g_return_if_fail (repr != NULL);
+
+ if( repr->type() == Inkscape::XML::ELEMENT_NODE ) {
+ Glib::ustring element = repr->name();
+
+ // Only clean elements in svg namespace
+ if( element.substr(0,4) == "svg:" ) {
+ sp_attribute_clean_element(repr, flags );
+ }
+ }
+
+ for(Node *child=sp_repr_children( repr ) ; child ; child = sp_repr_next( child ) ) {
+ sp_attribute_clean_recursive( child, flags );
+ }
+}
+
+/**
+ * Clean attributes on an element
+ */
+void sp_attribute_clean_element(Node *repr, unsigned int flags) {
+
+ 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" ));
+
+ // Clean style: this attribute is unique in that normally we want to change it and not simply
+ // delete it.
+ sp_attribute_clean_style(repr, flags );
+
+ // Clean attributes
+ List<AttributeRecord const> attributes = repr->attributeList();
+
+ std::set<Glib::ustring> attributesToDelete;
+ for ( List<AttributeRecord const> iter = attributes ; iter ; ++iter ) {
+
+ Glib::ustring attribute = g_quark_to_string(iter->key);
+ //Glib::ustring value = (const char*)iter->value;
+
+ bool is_useful = sp_attribute_check_attribute( element, id, attribute, flags & SP_ATTR_CLEAN_ATTR_WARN );
+ if( !is_useful && (flags & SP_ATTR_CLEAN_ATTR_REMOVE) ) {
+ attributesToDelete.insert( attribute );
+ }
+ }
+
+ // Do actual deleting (done after so as not to perturb List iterator).
+ for( std::set<Glib::ustring>::const_iterator iter_d = attributesToDelete.begin();
+ iter_d != attributesToDelete.end(); ++iter_d ) {
+ repr->setAttribute( (*iter_d).c_str(), NULL, false );
+ }
+}
+
+
+/**
+ * Clean CSS style on an element.
+ */
+void sp_attribute_clean_style(Node *repr, unsigned int flags) {
+
+ 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_clean_style(repr, css, flags);
+
+ // g_warning( "sp_repr_write_stream_element(): Final style:" );
+ //sp_repr_css_print( 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.
+ gchar *value = sp_repr_css_write_string(css);
+ repr->setAttribute("style", value);
+ if (value) g_free (value);
+
+ sp_repr_css_attr_unref( css );
+}
+
+
+/**
+ * Clean CSS style on an element.
+ */
+gchar * sp_attribute_clean_style(Node *repr, gchar const *string, unsigned int flags) {
+
+ 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_clean_style(repr, css, flags);
+ gchar* string_cleaned = sp_repr_css_write_string( css );
+
+ sp_repr_css_attr_unref( css );
+
+ return string_cleaned;
+}
+
+
+/**
+ * Clean CSS style on an element.
+ *
+ * 1. Is a style property appropriate on the given element?
+ * e.g, font-size is useless on <svg:rect>
+ * 2. Is the value of the style property useful?
+ * Is it the same as the parent and it inherits?
+ * Is it the default value (and the property on the parent is not set or does not inherit)?
+ */
+void sp_attribute_clean_style(Node* repr, SPCSSAttr *css, unsigned int flags) {
+
+ 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" ));
+
+ // Find parent's style, including properties that are inherited.
+ // Note, a node may not have a parent if it has not yet been added to tree.
+ SPCSSAttr *css_parent = NULL;
+ if( repr->parent() ) css_parent = sp_repr_css_attr_inherited( repr->parent(), "style" );
+
+ // Loop over all properties in "style" node, keeping track of which to delete.
+ std::set<Glib::ustring> toDelete;
+ for ( List<AttributeRecord const> iter = css->attributeList() ; iter ; ++iter ) {
+
+ gchar const * property = g_quark_to_string(iter->key);
+ gchar const * value = iter->value;
+
+ // Check if a property is applicable to an element (i.e. is font-family useful for a <rect>?).
+ if( !SPAttributeRelCSS::findIfValid( property, element ) ) {
+ if( flags & SP_ATTR_CLEAN_STYLE_WARN ) {
+ g_warning( "<%s id=\"%s\">: CSS Style property: \"%s\" is inappropriate.",
+ element.c_str(), id.c_str(), property );
+ }
+ if( flags & SP_ATTR_CLEAN_STYLE_REMOVE ) {
+ toDelete.insert(property);
+ }
+ continue;
+ }
+
+ // Find parent value for same property (property)
+ gchar const * property_p = NULL;
+ gchar const * value_p = NULL;
+ if( css_parent != NULL ) {
+ for ( List<AttributeRecord const> iter_p = css_parent->attributeList() ; iter_p ; ++iter_p ) {
+
+ property_p = g_quark_to_string(iter_p->key);
+
+ if( !g_strcmp0( property, property_p ) ) {
+ value_p = iter_p->value;
+ break;
+ }
+ }
+ }
+
+ // If parent has same property value and property is inherited, mark for deletion.
+ if ( !g_strcmp0( value, value_p ) && SPAttributeRelCSS::findIfInherit( property ) ) {
+
+ if ( flags & SP_ATTR_CLEAN_DEFAULT_WARN ) {
+ g_warning( "<%s id=\"%s\">: CSS Style property: \"%s\" has same value as parent (%s).",
+ element.c_str(), id.c_str(), property, value );
+ }
+ if ( flags & SP_ATTR_CLEAN_DEFAULT_REMOVE ) {
+ toDelete.insert( property );
+ }
+ continue;
+ }
+
+ // If property value is same as default and the parent value not set or property is not inherited,
+ // mark for deletion.
+ if ( SPAttributeRelCSS::findIfDefault( property, value ) &&
+ ( (css_parent != NULL && value_p == NULL) || !SPAttributeRelCSS::findIfInherit( property ) ) ) {
+
+ if ( flags & SP_ATTR_CLEAN_DEFAULT_WARN ) {
+ g_warning( "<%s id=\"%s\">: CSS Style property: \"%s\" with default value (%s) not needed.",
+ element.c_str(), id.c_str(), property, value );
+ }
+ if ( flags & SP_ATTR_CLEAN_DEFAULT_REMOVE ) {
+ toDelete.insert( property );
+ }
+ continue;
+ }
+
+ } // End loop over style properties
+
+ // Delete unneeded style properties. Do this at the end so as to not perturb List iterator.
+ for( std::set<Glib::ustring>::const_iterator iter_d = toDelete.begin(); iter_d != toDelete.end(); ++iter_d ) {
+ sp_repr_css_set_property( css, (*iter_d).c_str(), NULL );
+ }
+
+}
+
+/**
+ * Check one attribute on an element
+ */
+bool sp_attribute_check_attribute(Glib::ustring element, Glib::ustring id, Glib::ustring attribute, bool warn) {
+
+ bool is_useful = true;
+
+ if( SPAttributeRelCSS::findIfProperty( attribute ) ) {
+
+ // First check if it is a presentation attribute. Presentation attributes can be applied to
+ // any element. At the moment, we are only going to check if it is a possibly useful
+ // attribute. Note, we don't explicitely check against the list of elements where presentation
+ // attributes are allowed (See SVG1.1 spec, Appendix M.2).
+ if( !SPAttributeRelCSS::findIfValid( attribute, element ) ) {
+
+ // Non-useful presentation attribute on SVG <element>
+ if( warn ) {
+ g_warning( "<%s id=\"%s\">: Non-useful presentation attribute: \"%s\" found.",
+ element.c_str(),
+ id.c_str(),
+ attribute.c_str() );
+ }
+ is_useful = false;
+ }
+
+ } else {
+
+ // Second check if it is a valid attribute
+ if ( !SPAttributeRelSVG::findIfValid( attribute, element ) ) {
+
+ // Invalid attribute on SVG <element>
+ if( warn ) {
+ g_warning( "<%s id=\"%s\">: Invalid attribute: \"%s\" found.",
+ element.c_str(),
+ id.c_str(),
+ attribute.c_str() );
+ }
+ is_useful = false;
+ }
+ }
+
+ return is_useful;
+}
+
+/*
+ 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 :