diff options
| author | Andrew Higginson <at.higginson@gmail.com> | 2011-12-27 21:04:47 +0000 |
|---|---|---|
| committer | Andrew <at.higginson@gmail.com> | 2011-12-27 21:04:47 +0000 |
| commit | 80960b623a99aae1402ab651b2974ef544ed3b03 (patch) | |
| tree | ba49d42c2789e9e11f805e2d5263e10f9fedeef8 /src/attribute-rel-util.cpp | |
| parent | try to fix bug (diff) | |
| parent | GDL: Cherry-pick upstream patch 73852 (2011-03-23) - Add missing return value. (diff) | |
| download | inkscape-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.cpp | 312 |
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 : |
