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/xml | |
| 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/xml')
| -rw-r--r-- | src/xml/CMakeLists.txt | 74 | ||||
| -rw-r--r-- | src/xml/Makefile_insert | 1 | ||||
| -rw-r--r-- | src/xml/attribute-record.h | 3 | ||||
| -rw-r--r-- | src/xml/comment-node.h | 2 | ||||
| -rw-r--r-- | src/xml/croco-node-iface.cpp | 5 | ||||
| -rw-r--r-- | src/xml/document.h | 2 | ||||
| -rw-r--r-- | src/xml/event.h | 4 | ||||
| -rw-r--r-- | src/xml/log-builder.cpp | 5 | ||||
| -rw-r--r-- | src/xml/log-builder.h | 4 | ||||
| -rw-r--r-- | src/xml/node-event-vector.h | 2 | ||||
| -rw-r--r-- | src/xml/node-observer.h | 5 | ||||
| -rw-r--r-- | src/xml/node.h | 9 | ||||
| -rw-r--r-- | src/xml/pi-node.h | 2 | ||||
| -rw-r--r-- | src/xml/quote.cpp | 2 | ||||
| -rw-r--r-- | src/xml/rebase-hrefs-test.h | 126 | ||||
| -rw-r--r-- | src/xml/rebase-hrefs.cpp | 234 | ||||
| -rw-r--r-- | src/xml/rebase-hrefs.h | 27 | ||||
| -rw-r--r-- | src/xml/repr-action-test.h | 1 | ||||
| -rw-r--r-- | src/xml/repr-css.cpp | 115 | ||||
| -rw-r--r-- | src/xml/repr-io.cpp | 84 | ||||
| -rw-r--r-- | src/xml/repr-sorting.h | 9 | ||||
| -rw-r--r-- | src/xml/repr-util.cpp | 18 | ||||
| -rw-r--r-- | src/xml/repr.h | 5 | ||||
| -rw-r--r-- | src/xml/simple-document.cpp | 9 | ||||
| -rw-r--r-- | src/xml/simple-document.h | 4 | ||||
| -rw-r--r-- | src/xml/simple-node.cpp | 57 | ||||
| -rw-r--r-- | src/xml/subtree.h | 1 | ||||
| -rw-r--r-- | src/xml/text-node.h | 15 | ||||
| -rw-r--r-- | src/xml/xml-forward.h | 58 |
29 files changed, 633 insertions, 250 deletions
diff --git a/src/xml/CMakeLists.txt b/src/xml/CMakeLists.txt index 775a4e72f..2a9789384 100644 --- a/src/xml/CMakeLists.txt +++ b/src/xml/CMakeLists.txt @@ -1,21 +1,55 @@ -SET(xml_SRC -composite-node-observer.cpp -croco-node-iface.cpp -event.cpp -log-builder.cpp -node-fns.cpp -quote.cpp -#quote-test.cpp -repr.cpp -#repr-action-test.cpp -repr-css.cpp -repr-io.cpp -repr-sorting.cpp -repr-util.cpp -simple-document.cpp -simple-node.cpp -subtree.cpp + +set(xml_SRC + composite-node-observer.cpp + croco-node-iface.cpp + event.cpp + log-builder.cpp + node-fns.cpp + quote.cpp + repr.cpp + repr-css.cpp + repr-io.cpp + repr-sorting.cpp + repr-util.cpp + simple-document.cpp + simple-node.cpp + subtree.cpp + helper-observer.cpp + rebase-hrefs.cpp + + + # ------- + # Headers + attribute-record.h + comment-node.h + composite-node-observer.h + croco-node-iface.h + document.h + element-node.h + event-fns.h + event.h + helper-observer.h + invalid-operation-exception.h + log-builder.h + node-event-vector.h + node-fns.h + node-iterators.h + node-observer.h + node.h + pi-node.h + quote-test.h + quote.h + rebase-hrefs-test.h + rebase-hrefs.h + repr-action-test.h + repr-sorting.h + repr.h + simple-document.h + simple-node.h + sp-css-attr.h + subtree.h + text-node.h ) -ADD_LIBRARY(xml STATIC ${xml_SRC}) -TARGET_LINK_LIBRARIES(xml -2geom ${INKSCAPE_LIBS})
\ No newline at end of file + +# add_inkscape_lib(xml_LIB "${xml_SRC}") +add_inkscape_source("${xml_SRC}") diff --git a/src/xml/Makefile_insert b/src/xml/Makefile_insert index 7190b7948..b10f2448b 100644 --- a/src/xml/Makefile_insert +++ b/src/xml/Makefile_insert @@ -47,5 +47,6 @@ ink_common_sources += \ # ### CxxTest stuff #### # ###################### CXXTEST_TESTSUITES += \ + $(srcdir)/xml/rebase-hrefs-test.h \ $(srcdir)/xml/repr-action-test.h \ $(srcdir)/xml/quote-test.h diff --git a/src/xml/attribute-record.h b/src/xml/attribute-record.h index bab0b5aa4..a61329b83 100644 --- a/src/xml/attribute-record.h +++ b/src/xml/attribute-record.h @@ -5,8 +5,7 @@ #ifndef SEEN_XML_SP_REPR_ATTR_H #define SEEN_XML_SP_REPR_ATTR_H -#include <glib/gquark.h> -#include <glib/gtypes.h> +#include <glib.h> #include "gc-managed.h" #include "util/share.h" diff --git a/src/xml/comment-node.h b/src/xml/comment-node.h index 2232fb61e..56b8ad476 100644 --- a/src/xml/comment-node.h +++ b/src/xml/comment-node.h @@ -15,7 +15,7 @@ #ifndef SEEN_INKSCAPE_XML_COMMENT_NODE_H #define SEEN_INKSCAPE_XML_COMMENT_NODE_H -#include <glib/gquark.h> +#include <glib.h> #include "xml/simple-node.h" namespace Inkscape { diff --git a/src/xml/croco-node-iface.cpp b/src/xml/croco-node-iface.cpp index afea4abba..6bd5a6920 100644 --- a/src/xml/croco-node-iface.cpp +++ b/src/xml/croco-node-iface.cpp @@ -1,7 +1,6 @@ - #include <cstring> #include <string> -#include <glib/gstrfuncs.h> +#include <glib.h> #include "xml/croco-node-iface.h" #include "xml/node.h" @@ -46,7 +45,7 @@ static gboolean is_element_node(CRXMLNodePtr n) { return static_cast<Node const } /** - * @brief Interface for XML nodes used by libcroco + * Interface for XML nodes used by libcroco. * * This structure defines operations on Inkscape::XML::Node used by the libcroco * CSS parsing library. diff --git a/src/xml/document.h b/src/xml/document.h index 98cc0522e..efbc9bff7 100644 --- a/src/xml/document.h +++ b/src/xml/document.h @@ -15,7 +15,6 @@ #ifndef SEEN_INKSCAPE_XML_SP_REPR_DOC_H #define SEEN_INKSCAPE_XML_SP_REPR_DOC_H -#include "xml/xml-forward.h" #include "xml/node.h" namespace Inkscape { @@ -92,6 +91,7 @@ public: */ virtual Node *createElement(char const *name)=0; virtual Node *createTextNode(char const *content)=0; + virtual Node *createTextNode(char const *content, bool is_CData)=0; virtual Node *createComment(char const *content)=0; virtual Node *createPI(char const *target, char const *content)=0; /*@}*/ diff --git a/src/xml/event.h b/src/xml/event.h index 18dc47865..55e2add88 100644 --- a/src/xml/event.h +++ b/src/xml/event.h @@ -18,15 +18,13 @@ #ifndef SEEN_INKSCAPE_XML_SP_REPR_ACTION_H #define SEEN_INKSCAPE_XML_SP_REPR_ACTION_H -#include <glib/gtypes.h> -#include <glib/gquark.h> +#include <glib.h> #include <glibmm/ustring.h> #include <iterator> #include "util/share.h" #include "util/forward-pointer-iterator.h" #include "gc-managed.h" -#include "xml/xml-forward.h" #include "xml/node.h" namespace Inkscape { diff --git a/src/xml/log-builder.cpp b/src/xml/log-builder.cpp index 951cd4029..2cbdcfacf 100644 --- a/src/xml/log-builder.cpp +++ b/src/xml/log-builder.cpp @@ -1,5 +1,6 @@ -/** @file - * @brief Object building an event log +/** + * @file + * Object building an event log. */ /* Copyright 2005 MenTaLguY <mental@rydia.net> * diff --git a/src/xml/log-builder.h b/src/xml/log-builder.h index 264c2ced7..aa8f2c1c6 100644 --- a/src/xml/log-builder.h +++ b/src/xml/log-builder.h @@ -15,12 +15,14 @@ #define SEEN_INKSCAPE_XML_LOG_BUILDER_H #include "gc-managed.h" -#include "xml/xml-forward.h" #include "xml/node-observer.h" namespace Inkscape { namespace XML { +class Event; +class Node; + /** * @brief Event log builder * diff --git a/src/xml/node-event-vector.h b/src/xml/node-event-vector.h index 0c291c230..e6396877d 100644 --- a/src/xml/node-event-vector.h +++ b/src/xml/node-event-vector.h @@ -14,7 +14,7 @@ #ifndef SEEN_INKSCAPE_XML_SP_REPR_EVENT_VECTOR #define SEEN_INKSCAPE_XML_SP_REPR_EVENT_VECTOR -#include <glib/gtypes.h> +#include <glib.h> #include "xml/node.h" diff --git a/src/xml/node-observer.h b/src/xml/node-observer.h index c3ec437b5..d0c85d1dd 100644 --- a/src/xml/node-observer.h +++ b/src/xml/node-observer.h @@ -18,9 +18,8 @@ #ifndef SEEN_INKSCAPE_XML_NODE_OBSERVER_H #define SEEN_INKSCAPE_XML_NODE_OBSERVER_H -#include <glib/gquark.h> +#include <glib.h> #include "util/share.h" -#include "xml/xml-forward.h" #ifndef INK_UNUSED #define INK_UNUSED(x) ((void)(x)) @@ -29,6 +28,8 @@ namespace Inkscape { namespace XML { +class Node; + /** * @brief Interface for XML node observers * diff --git a/src/xml/node.h b/src/xml/node.h index 17479e50b..c11f2fbdf 100644 --- a/src/xml/node.h +++ b/src/xml/node.h @@ -18,14 +18,19 @@ #ifndef SEEN_INKSCAPE_XML_NODE_H #define SEEN_INKSCAPE_XML_NODE_H -#include <glib/gtypes.h> +#include <glib.h> #include "gc-anchored.h" #include "util/list.h" -#include "xml/xml-forward.h" namespace Inkscape { namespace XML { +struct AttributeRecord; +struct Document; +class Event; +class NodeObserver; +struct NodeEventVector; + /** * @brief Enumeration containing all supported node types. */ diff --git a/src/xml/pi-node.h b/src/xml/pi-node.h index e1f59ab27..1f892f97a 100644 --- a/src/xml/pi-node.h +++ b/src/xml/pi-node.h @@ -14,7 +14,7 @@ #ifndef SEEN_INKSCAPE_XML_PI_NODE_H #define SEEN_INKSCAPE_XML_PI_NODE_H -#include <glib/gquark.h> +#include <glib.h> #include "xml/simple-node.h" namespace Inkscape { diff --git a/src/xml/quote.cpp b/src/xml/quote.cpp index e569ed818..51f9ffb97 100644 --- a/src/xml/quote.cpp +++ b/src/xml/quote.cpp @@ -12,7 +12,7 @@ */ #include <cstring> -#include <glib/gmem.h> +#include <glib.h> /** \return strlen(xml_quote_strdup(\a val)) (without doing the malloc). diff --git a/src/xml/rebase-hrefs-test.h b/src/xml/rebase-hrefs-test.h new file mode 100644 index 000000000..e00337836 --- /dev/null +++ b/src/xml/rebase-hrefs-test.h @@ -0,0 +1,126 @@ +#include <cxxtest/TestSuite.h> + +#include <cstdlib> +#include <glib.h> + +#include "uri.h" + + +class RebaseHrefsTest : public CxxTest::TestSuite +{ + Inkscape::XML::Document *document; + Inkscape::XML::Node *a, *b, *c, *root; + +public: + + RebaseHrefsTest() + { + Inkscape::GC::init(); + + document = sp_repr_document_new("test"); + root = document->root(); + + a = document->createElement("a"); + b = document->createElement("b"); + c = document->createElement("c"); + } + virtual ~RebaseHrefsTest() {} + +// createSuite and destroySuite get us per-suite setup and teardown +// without us having to worry about static initialization order, etc. + static RebaseHrefsTest *createSuite() { return new RebaseHrefsTest(); } + static void destroySuite( RebaseHrefsTest *suite ) { delete suite; } + + + void dump_str(gchar const *str, gchar const *prefix) + { + Glib::ustring tmp; + tmp = prefix; + tmp += " ["; + size_t const total = strlen(str); + for (unsigned i = 0; i < total; i++) { + gchar *const tmp2 = g_strdup_printf(" %02x", (0x0ff & str[i])); + tmp += tmp2; + g_free(tmp2); + } + + tmp += "]"; + g_message("%s", tmp.c_str()); + } + + void testFlipples() + { + using Inkscape::URI; + using Inkscape::MalformedURIException; + + gchar const* things[] = { + "data:foo,bar", + "http://www.google.com/image.png", + "ftp://ssd.com/doo", + "/foo/dee/bar.svg", + "foo.svg", + "file:/foo/dee/bar.svg", + "file:///foo/dee/bar.svg", + "file:foo.svg", + "/foo/bar\xe1\x84\x92.svg", + "file:///foo/bar\xe1\x84\x92.svg", + "file:///foo/bar%e1%84%92.svg", + "/foo/bar%e1%84%92.svg", + "bar\xe1\x84\x92.svg", + "bar%e1%84%92.svg", + NULL + }; + g_message("+------"); + for ( int i = 0; things[i]; i++ ) + { + try + { + URI uri(things[i]); + gboolean isAbs = g_path_is_absolute( things[i] ); + gchar *str = uri.toString(); + g_message( "abs:%d isRel:%d scheme:[%s] path:[%s][%s] uri[%s] / [%s]", (int)isAbs, + (int)uri.isRelative(), + uri.getScheme(), + uri.getPath(), + uri.getOpaque(), + things[i], + str ); + g_free(str); + } + catch ( MalformedURIException err ) + { + dump_str( things[i], "MalformedURIException" ); + xmlChar *redo = xmlURIEscape((xmlChar const *)things[i]); + g_message(" gone from [%s] to [%s]", things[i], redo ); + if ( redo == NULL ) + { + URI again = URI::fromUtf8( things[i] ); + g_message(" uri from [%s] to [%s]", things[i], again.toString() ); + gboolean isAbs = g_path_is_absolute( things[i] ); + gchar *str = again.toString(); + g_message( "abs:%d isRel:%d scheme:[%s] path:[%s][%s] uri[%s] / [%s]", (int)isAbs, + (int)again.isRelative(), + again.getScheme(), + again.getPath(), + again.getOpaque(), + things[i], + str ); + g_free(str); + g_message(" ----"); + } + } + } + g_message("+------"); + } +}; + +/* + 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/xml/rebase-hrefs.cpp b/src/xml/rebase-hrefs.cpp index b2efd7ee6..9d4f4f9fc 100644 --- a/src/xml/rebase-hrefs.cpp +++ b/src/xml/rebase-hrefs.cpp @@ -7,71 +7,65 @@ #include "util/share.h" #include "xml/attribute-record.h" #include "xml/node.h" -#include <glib/gmem.h> -#include <glib/gurifuncs.h> -#include <glib/gutils.h> -using Inkscape::XML::AttributeRecord; +#include <glib.h> +#include <glibmm/miscutils.h> +#include <glibmm/convert.h> +#include <glibmm/uriutils.h> +using Inkscape::XML::AttributeRecord; /** - * \pre href. + * Determine if a href needs rebasing. */ -static bool -href_needs_rebasing(char const *const href) +static bool href_needs_rebasing(std::string const &href) { - g_return_val_if_fail(href, false); + bool ret = true; - if (!*href || *href == '#') { - return false; + if ( href.empty() || (href[0] == '#') ) { + ret = false; /* False (no change) is the right behaviour even when the base URI differs from the * document URI: RFC 3986 defines empty string relative URL as referring to the containing * document, rather than referring to the base URI. */ - } - - /* Don't change data or http hrefs. */ - { - char *const scheme = g_uri_parse_scheme(href); - if (scheme) { + } else { + /* Don't change data or http hrefs. */ + std::string scheme = Glib::uri_parse_scheme(href); + if ( !scheme.empty() ) { /* Assume it shouldn't be changed. This is probably wrong if the scheme is `file' * (or if the scheme of the new base is non-file, though I believe that never * happens at the time of writing), but that's rare, and we won't try too hard to * handle this now: wait until after the freeze, then add liburiparser (or similar) * as a dependency and do it properly. For now we'll just try to be simple (while * at least still correctly handling data hrefs). */ - free(scheme); - return false; + ret = false; + } else if (Glib::path_is_absolute(href)) { + /* If absolute then keep it as is. + * + * Even in the following borderline cases: + * + * - We keep it absolute even if it is in new_base (directly or indirectly). + * + * - We assume that if xlink:href is absolute then we honour it in preference to + * sodipodi:absref even if sodipodi:absref points to an existing file while xlink:href + * doesn't. This is because we aren't aware of any bugs in xlink:href handling when + * it's absolute, so we assume that it's the best value to use even in this case.) + */ + /* No strong preference on what we do for sodipodi:absref. Once we're + * confident of our handling of xlink:href and xlink:base, we should clear it. + * Though for the moment we do the simple thing: neither clear nor set it. */ + ret = false; } } - /* If absolute then keep it as is. - * - * Even in the following borderline cases: - * - * - We keep it absolute even if it is in new_base (directly or indirectly). - * - * - We assume that if xlink:href is absolute then we honour it in preference to - * sodipodi:absref even if sodipodi:absref points to an existing file while xlink:href - * doesn't. This is because we aren't aware of any bugs in xlink:href handling when - * it's absolute, so we assume that it's the best value to use even in this case.) - */ - if (g_path_is_absolute(href)) { - /* No strong preference on what we do for sodipodi:absref. Once we're - * confident of our handling of xlink:href and xlink:base, we should clear it. - * Though for the moment we do the simple thing: neither clear nor set it. */ - return false; - } - - return true; + return ret; } -static gchar * -calc_abs_href(gchar const *const abs_base_dir, gchar const *const href, - gchar const *const sp_absref) +static std::string calc_abs_href(std::string const &abs_base_dir, std::string const &href, + gchar const *const sp_absref) { - gchar *ret = g_build_filename(abs_base_dir, href, NULL); + std::string ret = Glib::build_filename(abs_base_dir, href); if ( sp_absref - && !Inkscape::IO::file_test(ret, G_FILE_TEST_EXISTS) + && !Inkscape::IO::file_test(ret.c_str(), G_FILE_TEST_EXISTS) && Inkscape::IO::file_test(sp_absref, G_FILE_TEST_EXISTS) ) { /* sodipodi:absref points to an existing file while xlink:href doesn't. @@ -93,18 +87,12 @@ calc_abs_href(gchar const *const abs_base_dir, gchar const *const href, * effic: Once we no longer consult sodipodi:absref, we can do * `if (base unchanged) { return; }' at the start of rebase_hrefs. */ - g_free(ret); - ret = g_strdup(sp_absref); + ret = sp_absref; } return ret; } -/** - * Change relative xlink:href attributes to be relative to \a new_abs_base instead of old_abs_base. - * - * Note that old_abs_base and new_abs_base must each be non-NULL, absolute directory paths. - */ Inkscape::Util::List<AttributeRecord const> Inkscape::XML::rebase_href_attrs(gchar const *const old_abs_base, gchar const *const new_abs_base, @@ -115,6 +103,7 @@ Inkscape::XML::rebase_href_attrs(gchar const *const old_abs_base, using Inkscape::Util::ptr_shared; using Inkscape::Util::share_string; + if (old_abs_base == new_abs_base) { return attributes; } @@ -133,7 +122,7 @@ Inkscape::XML::rebase_href_attrs(gchar const *const old_abs_base, for (List<AttributeRecord const> ai(attributes); ai; ++ai) { if (ai->key == href_key) { old_href = ai->value; - if (!href_needs_rebasing(old_href)) { + if (!href_needs_rebasing(static_cast<char const *>(old_href))) { return attributes; } } else if (ai->key == absref_key) { @@ -153,23 +142,33 @@ Inkscape::XML::rebase_href_attrs(gchar const *const old_abs_base, * reversed.) */ } - gchar *const abs_href(calc_abs_href(old_abs_base, old_href, sp_absref)); - gchar const *const new_href = sp_relative_path_from_path(abs_href, new_abs_base); - ret = cons(AttributeRecord(href_key, share_string(new_href)), ret); + std::string abs_href = calc_abs_href(old_abs_base, static_cast<char const *>(old_href), sp_absref); + std::string new_href = sp_relative_path_from_path(abs_href, new_abs_base); + ret = cons(AttributeRecord(href_key, share_string(new_href.c_str())), ret); // Check if this is safe/copied or if it is only held. if (sp_absref) { /* We assume that if there wasn't previously a sodipodi:absref attribute * then we shouldn't create one. */ - ret = cons(AttributeRecord(absref_key, ( streq(abs_href, sp_absref) + ret = cons(AttributeRecord(absref_key, ( streq(abs_href.c_str(), sp_absref) ? sp_absref - : share_string(abs_href) )), + : share_string(abs_href.c_str()) )), ret); } - g_free(abs_href); + return ret; } -gchar * -Inkscape::XML::calc_abs_doc_base(gchar const *const doc_base) +// std::string Inkscape::XML::rebase_href_attrs( std::string const &oldAbsBase, std::string const &newAbsBase, gchar const * /*href*/, gchar const */*absref*/ ) +// { +// std::string ret; +// //g_message( "XX need to flip from [%s] to [%s]", oldAbsBase.c_str(), newAbsBase.c_str() ); + +// if ( oldAbsBase != newAbsBase ) { +// } + +// return ret; +// } + +std::string Inkscape::XML::calc_abs_doc_base(gchar const *doc_base) { /* Note that we don't currently try to handle the case of doc_base containing * `..' or `.' path components. This non-handling means that sometimes @@ -179,34 +178,27 @@ Inkscape::XML::calc_abs_doc_base(gchar const *const doc_base) * relative URL/IRI href processing (with liburiparser). * * (Note that one possibile difficulty with `..' is symlinks.) */ + std::string ret; if (!doc_base) { - return g_get_current_dir(); - } else if (g_path_is_absolute(doc_base)) { - return g_strdup(doc_base); + ret = Glib::get_current_dir(); + } else if (Glib::path_is_absolute(doc_base)) { + ret = doc_base; } else { - gchar *const cwd = g_get_current_dir(); - gchar *const ret = g_build_filename(cwd, doc_base, NULL); - g_free(cwd); - return ret; + ret = Glib::build_filename( Glib::get_current_dir(), doc_base ); } + + return ret; } -/** - * Change relative hrefs in doc to be relative to \a new_base instead of doc.base. - * - * (NULL doc base or new_base is interpreted as current working directory.) - * - * \param spns True iff doc should contain sodipodi:absref attributes. - */ void Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_base, bool const spns) { if (!doc->getBase()) { return; } - gchar *const old_abs_base = calc_abs_doc_base(doc->getBase()); - gchar *const new_abs_base = calc_abs_doc_base(new_base); + std::string old_abs_base = calc_abs_doc_base(doc->getBase()); + std::string new_abs_base = calc_abs_doc_base(new_base); /* TODO: Should handle not just image but also: * @@ -232,44 +224,76 @@ void Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_b for (GSList const *l = images; l != NULL; l = l->next) { Inkscape::XML::Node *ir = static_cast<SPObject *>(l->data)->getRepr(); - gchar const *const href = ir->attribute("xlink:href"); + std::string uri; + { + gchar const *tmp = ir->attribute("xlink:href"); + if ( !tmp ) { + continue; + } + uri = tmp; + } + if ( uri.substr(0, 7) == "file://" ) { + uri = Glib::filename_from_uri(uri); + } + // The following two cases are for absolute hrefs that can be converted to relative. + // Imported images, first time rebased, need an old base. + std::string href = uri; + if ( Glib::path_is_absolute(href) ) { + href = sp_relative_path_from_path(uri, old_abs_base); + } + // Files moved from a absolute path need a new one. + if ( Glib::path_is_absolute(href) ) { + href = sp_relative_path_from_path(uri, new_abs_base); + } + // Other bitmaps are either really absolute, or already relative. + +#ifdef WIN32 + /* Windows relative path needs their native separators before we + * compare it to native baserefs. */ + if ( !Glib::path_is_absolute(href) ) { + std::replace(href.begin(), href.end(), '/', '\\'); + } +#endif + /* TODO: Most of this function currently treats href as if it were a simple filename * (e.g. passing it to g_path_is_absolute, g_build_filename or IO::file_test, or avoiding * changing non-file hrefs), which breaks if href starts with a scheme or if href contains * any escaping. */ - if (!href || !href_needs_rebasing(href)) { - continue; - } + if ( href_needs_rebasing(href) ) { + std::string abs_href = calc_abs_href(old_abs_base, href, ir->attribute("sodipodi:absref")); - gchar *const abs_href(calc_abs_href(old_abs_base, href, ir->attribute("sodipodi:absref"))); - - /* todo: One difficult case once we support writing to non-file locations is where - * existing hrefs in the document point to local files. In this case, we should - * probably copy those referenced files to the new location at the same time. It's - * less clear what to do when copying from one non-file location to another. We may - * need to ask the user in some way (even if it's as a checkbox), but we'd like to - * bother the user as little as possible yet also want to warn the user about the case - * of file hrefs. */ - - gchar const *const new_href = sp_relative_path_from_path(abs_href, new_abs_base); - ir->setAttribute("xlink:href", new_href); - ir->setAttribute("sodipodi:absref", ( spns - ? abs_href - : NULL )); - /* impl: I assume that if !spns then any existing sodipodi:absref is about to get - * cleared (or is already cleared) anyway, in which case it doesn't matter whether we - * clear or leave any existing sodipodi:absref value. If that assumption turns out to - * be wrong, then leaving it means risking leaving the wrong value (if xlink:href - * referred to a different file than sodipodi:absref) while clearing it means risking - * losing information. */ - - g_free(abs_href); - /* (No need to free new_href, it's guaranteed to point into used_abs_href.) */ - } + /* todo: One difficult case once we support writing to non-file locations is where + * existing hrefs in the document point to local files. In this case, we should + * probably copy those referenced files to the new location at the same time. It's + * less clear what to do when copying from one non-file location to another. We may + * need to ask the user in some way (even if it's as a checkbox), but we'd like to + * bother the user as little as possible yet also want to warn the user about the case + * of file hrefs. */ - g_free(new_abs_base); - g_free(old_abs_base); + std::string new_href = sp_relative_path_from_path(abs_href, new_abs_base); + ir->setAttribute("sodipodi:absref", ( spns + ? abs_href.c_str() + : NULL )); + if (!Glib::path_is_absolute(new_href)) { +#ifdef WIN32 + /* Native Windows path separators are replaced with / so that the href + * also works on Gnu/Linux and OSX */ + std::replace(href.begin(), href.end(), '\\', '/'); +#endif + ir->setAttribute("xlink:href", new_href.c_str()); + } else { + ir->setAttribute("xlink:href", g_filename_to_uri(new_href.c_str(), NULL, NULL)); + } + + /* impl: I assume that if !spns then any existing sodipodi:absref is about to get + * cleared (or is already cleared) anyway, in which case it doesn't matter whether we + * clear or leave any existing sodipodi:absref value. If that assumption turns out to + * be wrong, then leaving it means risking leaving the wrong value (if xlink:href + * referred to a different file than sodipodi:absref) while clearing it means risking + * losing information. */ + } + } } diff --git a/src/xml/rebase-hrefs.h b/src/xml/rebase-hrefs.h index b4f288c4d..adb09e52a 100644 --- a/src/xml/rebase-hrefs.h +++ b/src/xml/rebase-hrefs.h @@ -1,7 +1,7 @@ #ifndef REBASE_HREFS_H_SEEN #define REBASE_HREFS_H_SEEN -#include <glib/gtypes.h> +#include <glib.h> #include "util/list.h" #include "xml/attribute-record.h" struct SPDocument; @@ -9,17 +9,36 @@ struct SPDocument; namespace Inkscape { namespace XML { -gchar *calc_abs_doc_base(gchar const *doc_base); +std::string calc_abs_doc_base(gchar const *doc_base); +/** + * Change relative hrefs in doc to be relative to \a new_base instead of doc.base. + * + * (NULL doc base or new_base is interpreted as current working directory.) + * + * @param spns True if doc should contain sodipodi:absref attributes. + */ void rebase_hrefs(SPDocument *doc, gchar const *new_base, bool spns); +/** + * Change relative xlink:href attributes to be relative to \a new_abs_base instead of old_abs_base. + * + * Note that old_abs_base and new_abs_base must each be non-NULL, absolute directory paths. + */ Inkscape::Util::List<AttributeRecord const> rebase_href_attrs( gchar const *old_abs_base, gchar const *new_abs_base, Inkscape::Util::List<AttributeRecord const> attributes); -} -} + +// /** +// * . +// * @return a non-empty replacement href if needed, empty otherwise. +// */ +// std::string rebase_href_attrs( std::string const &oldAbsBase, std::string const &newAbsBase, gchar const *href, gchar const *absref = 0 ); + +} // namespace XML +} // namespace Inkscape #endif /* !REBASE_HREFS_H_SEEN */ diff --git a/src/xml/repr-action-test.h b/src/xml/repr-action-test.h index afc9b2c46..ae4291397 100644 --- a/src/xml/repr-action-test.h +++ b/src/xml/repr-action-test.h @@ -88,7 +88,6 @@ public: } /* lots more tests needed ... */ - }; /* diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp index dc6494bcd..ced4f5da4 100644 --- a/src/xml/repr-css.cpp +++ b/src/xml/repr-css.cpp @@ -1,11 +1,28 @@ /* * bulia byak <buliabyak@users.sf.net> -*/ + * Tavmjong Bah <tavmjong@free.fr> (Documentation) + * + * Functions to manipulate SPCSSAttr which is a class derived from Inkscape::XML::Node See + * sp-css-attr.h and node.h + * + * SPCSSAttr is a special node type where the "attributes" are the properties in an element's style + * attribute. For example, style="fill:blue;stroke:none" is stored in a List (Inkscape::Util:List) + * where the key is the property (e.g. "fill" or "stroke") and the value is the property's value + * (e.g. "blue" or "none"). An element's properties are manipulated by adding, removing, or + * changing an item in the List. Utility functions are provided to go back and forth between the + * two ways of representing properties (by a string or by a list). + * + * Use sp_repr_write_string to go from a property list to a style string. + * + */ #define SP_REPR_CSS_C #include <cstring> +#include <string> +#include <sstream> #include <glibmm/ustring.h> +#include "svg/css-ostringstream.h" #include "xml/repr.h" #include "xml/simple-document.h" @@ -35,7 +52,9 @@ protected: static void sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr); - +/** + * Creates an empty SPCSSAttr (a class for manipulating CSS style properties). + */ SPCSSAttr * sp_repr_css_attr_new() { @@ -46,6 +65,9 @@ sp_repr_css_attr_new() return new SPCSSAttrImpl(attr_doc); } +/** + * Unreferences an SPCSSAttr (will be garbage collected if no references remain). + */ void sp_repr_css_attr_unref(SPCSSAttr *css) { @@ -53,6 +75,12 @@ sp_repr_css_attr_unref(SPCSSAttr *css) Inkscape::GC::release((Node *) css); } +/** + * Creates a new SPCSSAttr with one attribute (i.e. style) copied from an existing repr (node). The + * repr attribute data is in the form of a char const * string (e.g. fill:#00ff00;stroke:none). The + * string is parsed by libcroco which returns a CRDeclaration list (a typical C linked list) of + * properties and values. This list is then used to fill the attributes of the new SPCSSAttr. + */ SPCSSAttr *sp_repr_css_attr(Node *repr, gchar const *attr) { g_assert(repr != NULL); @@ -63,6 +91,9 @@ SPCSSAttr *sp_repr_css_attr(Node *repr, gchar const *attr) return css; } +/** + * Adds an attribute to an existing SPCSAttr with the cascaded value including all parents. + */ static void sp_repr_css_attr_inherited_recursive(SPCSSAttr *css, Node *repr, gchar const *attr) { @@ -72,11 +103,12 @@ sp_repr_css_attr_inherited_recursive(SPCSSAttr *css, Node *repr, gchar const *at if (parent) { sp_repr_css_attr_inherited_recursive(css, parent, attr); } - sp_repr_css_add_components(css, repr, attr); } - +/** + * Creates a new SPCSSAttr with one attribute whose value is determined by cascading. + */ SPCSSAttr *sp_repr_css_attr_inherited(Node *repr, gchar const *attr) { g_assert(repr != NULL); @@ -89,6 +121,11 @@ SPCSSAttr *sp_repr_css_attr_inherited(Node *repr, gchar const *attr) return css; } +/** + * Adds components (style properties) to an existing SPCSAttr from the specified attribute's data + * (nominally a style attribute). + * + */ static void sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr) { @@ -100,6 +137,10 @@ sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr) sp_repr_css_attr_add_from_string(css, data); } +/** + * Returns a character string of the value of a given style property or a default value if the + * attribute is not found. + */ char const * sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval) { @@ -112,6 +153,9 @@ sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval) : attr ); } +/** + * Returns true if a style property is present and its value is unset. + */ bool sp_repr_css_property_is_unset(SPCSSAttr *css, gchar const *name) { @@ -123,6 +167,9 @@ sp_repr_css_property_is_unset(SPCSSAttr *css, gchar const *name) } +/** + * Set a style property to a new value (e.g. fill to #ffff00). + */ void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value) { @@ -132,6 +179,9 @@ sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value) ((Node *) css)->setAttribute(name, value, false); } +/** + * Set a style property to "inkscape:unset". + */ void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name) { @@ -141,6 +191,9 @@ sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name) ((Node *) css)->setAttribute(name, "inkscape:unset", false); } +/** + * Return the value of a style property if property define, or a default value if not. + */ double sp_repr_css_double_property(SPCSSAttr *css, gchar const *name, double defval) { @@ -150,6 +203,9 @@ sp_repr_css_double_property(SPCSSAttr *css, gchar const *name, double defval) return sp_repr_get_double_attribute((Node *) css, name, defval); } +/** + * Write a style attribute string from a list of properties stored in an SPCSAttr object. + */ gchar * sp_repr_css_write_string(SPCSSAttr *css) { @@ -186,6 +242,9 @@ sp_repr_css_write_string(SPCSSAttr *css) return (buffer.empty() ? NULL : g_strdup (buffer.c_str())); } +/** + * Sets an attribute (e.g. style) to a string created from a list of style properties. + */ void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr) { @@ -195,11 +254,20 @@ sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr) gchar *value = sp_repr_css_write_string(css); + /* + * If the new value is different from the old value, this will sometimes send a signal via + * CompositeNodeObserver::notiftyAttributeChanged() which results in calling + * SPObject::sp_object_repr_attr_changed and thus updates the object's SPStyle. This update + * results in another call to repr->setAttribute(). + */ repr->setAttribute(attr, value); if (value) g_free (value); } +/** + * Loops through a List of style properties, printing key/value pairs. + */ void sp_repr_css_print(SPCSSAttr *css) { @@ -212,6 +280,9 @@ sp_repr_css_print(SPCSSAttr *css) } } +/** + * Merges two SPCSSAttr's. Properties in src overwrite properties in dst if present in both. + */ void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src) { @@ -221,19 +292,42 @@ sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src) dst->mergeFrom(src, ""); } - +/** + * Merges style properties as parsed by libcroco into an existing SPCSSAttr. + */ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *const decl) { guchar *const str_value_unsigned = cr_term_to_string(decl->value); gchar *const str_value = reinterpret_cast<gchar *>(str_value_unsigned); gchar *value_unquoted = attribute_unquote (str_value); // libcroco returns strings quoted in "" - ((Node *) css)->setAttribute(decl->property->stryng->str, value_unquoted, false); + + // libcroco uses %.17f for formatting... leading to trailing zeros or small rounding errors. + // CSSOStringStream is used here to write valid CSS (as in sp_style_write_string). This has + // the additional benefit of respecting the numerical precission set in the SVG Output + // preferences. We assume any numerical part comes first (if not, the whole string is copied). + std::stringstream ss( value_unquoted ); + double number = 0; + std::string characters; + std::string temp; + bool number_valid = !(ss >> number).fail(); + if( !number_valid ) ss.clear(); + while( !(ss >> temp).eof() ) { + characters += temp; + characters += " "; + } + characters += temp; + Inkscape::CSSOStringStream os; + if( number_valid ) os << number; + os << characters; + ((Node *) css)->setAttribute(decl->property->stryng->str, os.str().c_str(), false); g_free(value_unquoted); g_free(str_value); } /** + * Merges style properties as parsed by libcroco into an existing SPCSSAttr. + * * \pre decl_list != NULL */ static void @@ -248,6 +342,10 @@ sp_repr_css_merge_from_decl_list(SPCSSAttr *css, CRDeclaration const *const decl } } +/** + * Use libcroco to parse a string for CSS properties and then merge + * them into an existing SPCSSAttr. + */ void sp_repr_css_attr_add_from_string(SPCSSAttr *css, gchar const *p) { @@ -261,6 +359,11 @@ sp_repr_css_attr_add_from_string(SPCSSAttr *css, gchar const *p) } } +/** + * Creates a new SPCSAttr with the values filled from a repr, merges in properties from the given + * SPCSAttr, and then replaces that SPCSAttr with the new one. This is called, for example, for + * each object in turn when a selection's style is updated via sp_desktop_set_style(). + */ void sp_repr_css_change(Node *repr, SPCSSAttr *css, gchar const *attr) { diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index 5f7654ba8..7252845b1 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -24,6 +24,7 @@ #include "xml/attribute-record.h" #include "xml/rebase-hrefs.h" #include "xml/simple-document.h" +#include "xml/text-node.h" #include "io/sys.h" #include "io/uristream.h" @@ -32,6 +33,8 @@ #include "extension/extension.h" +#include "attribute-rel-util.h" + #include "preferences.h" using Inkscape::IO::Writer; @@ -52,6 +55,7 @@ static void sp_repr_write_stream_root_element(Node *repr, Writer &out, int inlineattrs, int indent, gchar const *old_href_abs_base, gchar const *new_href_abs_base); + static void sp_repr_write_stream_element(Node *repr, Writer &out, gint indent_level, bool add_whitespace, Glib::QueryQuark elide_prefix, @@ -78,6 +82,10 @@ public: instr(0), gzin(0) { + for (int k=0;k<4;k++) + { + firstFew[k]=0; + } } virtual ~XmlSource() { @@ -254,6 +262,7 @@ int XmlSource::close() Document * sp_repr_read_file (const gchar * filename, const gchar *default_ns) { + // g_warning( "Reading file: %s", filename ); xmlDocPtr doc = 0; Document * rdoc = 0; @@ -444,6 +453,18 @@ sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns) promote_to_namespace(root, INKSCAPE_EXTENSION_NS_NC); } } + + + // Clean unnecessary attributes and style properties from SVG documents. (Controlled by + // preferences.) Note: internal Inkscape svg files will also be cleaned (filters.svg, + // icons.svg). How can one tell if a file is internal? + if ( !strcmp(root->name(), "svg:svg" ) ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool clean = prefs->getBool("/options/svgoutput/check_on_reading"); + if( clean ) { + sp_attribute_clean_tree( root ); + } + } } g_hash_table_destroy (prefix_map); @@ -496,7 +517,9 @@ sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ return NULL; // we do not preserve all-whitespace nodes unless we are asked to } - return xml_doc->createTextNode(reinterpret_cast<gchar *>(node->content)); + // We keep track of original node type so that CDATA sections are preserved on output. + return xml_doc->createTextNode(reinterpret_cast<gchar *>(node->content), + node->type == XML_CDATA_SECTION_NODE ); } if (node->type == XML_COMMENT_NODE) { @@ -644,7 +667,7 @@ sp_repr_save_rebased_file(Document *doc, gchar const *const filename, gchar cons return false; } - gchar *old_href_abs_base = NULL; + std::string old_href_abs_base; gchar *new_href_abs_base = NULL; if (for_filename) { old_href_abs_base = calc_abs_doc_base(old_base); @@ -662,9 +685,8 @@ sp_repr_save_rebased_file(Document *doc, gchar const *const filename, gchar cons * to using sodipodi:absref instead of the xlink:href value, * then we should do `if streq() { free them and set both to NULL; }'. */ } - sp_repr_save_stream(doc, file, default_ns, compress, old_href_abs_base, new_href_abs_base); + sp_repr_save_stream(doc, file, default_ns, compress, old_href_abs_base.c_str(), new_href_abs_base); - g_free(old_href_abs_base); g_free(new_href_abs_base); if (fclose (file) != 0) { @@ -803,6 +825,12 @@ sp_repr_write_stream_root_element(Node *repr, Writer &out, using Inkscape::Util::ptr_shared; g_assert(repr != NULL); + + // Clean unnecessary attributes and stype properties. (Controlled by preferences.) + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool clean = prefs->getBool("/options/svgoutput/check_on_writing"); + if (clean) sp_attribute_clean_tree( repr ); + Glib::QueryQuark xml_prefix=g_quark_from_static_string("xml"); NSMap ns_map; @@ -849,7 +877,12 @@ void sp_repr_write_stream( Node *repr, Writer &out, gint indent_level, { switch (repr->type()) { case Inkscape::XML::TEXT_NODE: { - repr_quote_write( out, repr->content() ); + if( dynamic_cast<const Inkscape::XML::TextNode *>(repr)->is_CData() ) { + // Preserve CDATA sections, not converting '&' to &, etc. + out.printf( "<![CDATA[%s]]>", repr->content() ); + } else { + repr_quote_write( out, repr->content() ); + } break; } case Inkscape::XML::COMMENT_NODE: { @@ -879,17 +912,16 @@ void sp_repr_write_stream( Node *repr, Writer &out, gint indent_level, } -static void -sp_repr_write_stream_element (Node * repr, Writer & out, gint indent_level, - bool add_whitespace, - Glib::QueryQuark elide_prefix, - List<AttributeRecord const> attributes, - int inlineattrs, int indent, - gchar const *const old_href_base, - gchar const *const new_href_base) +void sp_repr_write_stream_element( Node * repr, Writer & out, + gint indent_level, bool add_whitespace, + Glib::QueryQuark elide_prefix, + List<AttributeRecord const> attributes, + int inlineattrs, int indent, + gchar const *old_href_base, + gchar const *new_href_base ) { - Node *child; - bool loose; + Node *child = 0; + bool loose = false; g_return_if_fail (repr != NULL); @@ -921,6 +953,28 @@ sp_repr_write_stream_element (Node * repr, Writer & out, gint indent_level, add_whitespace = false; } + // THIS DOESN'T APPEAR TO DO ANYTHING. Can it be commented out or deleted? + { + GQuark const href_key = g_quark_from_static_string("xlink:href"); + GQuark const absref_key = g_quark_from_static_string("sodipodi:absref"); + + gchar const *xxHref = 0; + gchar const *xxAbsref = 0; + for ( List<AttributeRecord const> ai(attributes); ai; ++ai ) { + if ( ai->key == href_key ) { + xxHref = ai->value; + } else if ( ai->key == absref_key ) { + xxAbsref = ai->value; + } + } + + // Might add a special case for absref but no href. + if ( old_href_base && new_href_base && xxHref ) { + //g_message("href rebase test with [%s] and [%s]", xxHref, xxAbsref); + //std::string newOne = rebase_href_attrs( old_href_base, new_href_base, xxHref, xxAbsref ); + } + } + for ( List<AttributeRecord const> iter = rebase_href_attrs(old_href_base, new_href_base, attributes); iter ; ++iter ) diff --git a/src/xml/repr-sorting.h b/src/xml/repr-sorting.h index d560dfa26..dddb8588c 100644 --- a/src/xml/repr-sorting.h +++ b/src/xml/repr-sorting.h @@ -7,7 +7,14 @@ #ifndef SEEN_XML_REPR_SORTING_H #define SEEN_XML_REPR_SORTING_H -#include "xml/xml-forward.h" +namespace Inkscape { +namespace XML { + +class Node; + +} // namespace XML +} // namespace Inkscape + Inkscape::XML::Node *LCA(Inkscape::XML::Node *a, Inkscape::XML::Node *b); Inkscape::XML::Node const *LCA(Inkscape::XML::Node const *a, Inkscape::XML::Node const *b); diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 9405cde01..aa244d842 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -1,4 +1,5 @@ -/** \file +/** + * @file * Miscellaneous helpers for reprs. */ @@ -404,7 +405,7 @@ int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::No } /** - * @brief Find an element node using an unique attribute + * Find an element node using an unique attribute. * * This function returns the first child of the specified node that has the attribute * @c key equal to @c value. Note that this function does not recurse. @@ -414,10 +415,9 @@ int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::No * @param value The value of the attribute to look for * @relatesalso Inkscape::XML::Node */ -Inkscape::XML::Node * -sp_repr_lookup_child(Inkscape::XML::Node *repr, - gchar const *key, - gchar const *value) +Inkscape::XML::Node *sp_repr_lookup_child(Inkscape::XML::Node *repr, + gchar const *key, + gchar const *value) { g_return_val_if_fail(repr != NULL, NULL); for ( Inkscape::XML::Node *child = repr->firstChild() ; child ; child = child->next() ) { @@ -494,9 +494,9 @@ sp_repr_get_boolean(Inkscape::XML::Node *repr, gchar const *key, unsigned int *v v = repr->attribute(key); if (v != NULL) { - if (!g_strcasecmp(v, "true") || - !g_strcasecmp(v, "yes" ) || - !g_strcasecmp(v, "y" ) || + if (!g_ascii_strcasecmp(v, "true") || + !g_ascii_strcasecmp(v, "yes" ) || + !g_ascii_strcasecmp(v, "y" ) || (atoi(v) != 0)) { *val = TRUE; } else { diff --git a/src/xml/repr.h b/src/xml/repr.h index bde3e533f..ffb8ab16b 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -15,7 +15,7 @@ #define SEEN_SP_REPR_H #include <stdio.h> -#include <glib/gtypes.h> +#include <glib.h> #include "gc-anchored.h" #include "xml/node.h" @@ -79,10 +79,13 @@ void sp_repr_write_stream(Inkscape::XML::Node *repr, Inkscape::IO::Writer &out, gchar const *new_href_base = NULL); 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); + +// TODO convert to std::string void sp_repr_save_stream(Inkscape::XML::Document *doc, FILE *to_file, gchar const *default_ns = NULL, bool compress = false, gchar const *old_href_base = NULL, gchar const *new_href_base = NULL); + bool sp_repr_save_file(Inkscape::XML::Document *doc, gchar const *filename, gchar const *default_ns=NULL); bool sp_repr_save_rebased_file(Inkscape::XML::Document *doc, gchar const *filename_utf8, gchar const *default_ns, diff --git a/src/xml/simple-document.cpp b/src/xml/simple-document.cpp index 2807133af..bae28e4b4 100644 --- a/src/xml/simple-document.cpp +++ b/src/xml/simple-document.cpp @@ -1,5 +1,6 @@ -/** @file - * @brief Garbage collected XML document implementation +/** + * @file + * Garbage collected XML document implementation. */ /* Copyright 2004-2005 MenTaLguY <mental@rydia.net> * @@ -58,6 +59,10 @@ Node *SimpleDocument::createTextNode(char const *content) { return new TextNode(Util::share_string(content), this); } +Node *SimpleDocument::createTextNode(char const *content, bool const is_CData) { + return new TextNode(Util::share_string(content), this, is_CData); +} + Node *SimpleDocument::createComment(char const *content) { return new CommentNode(Util::share_string(content), this); } diff --git a/src/xml/simple-document.h b/src/xml/simple-document.h index 8a37c577c..ff1d94b0c 100644 --- a/src/xml/simple-document.h +++ b/src/xml/simple-document.h @@ -31,7 +31,7 @@ class SimpleDocument : public SimpleNode, public: explicit SimpleDocument() : SimpleNode(g_quark_from_static_string("xml"), this), - _in_transaction(false) {} + _in_transaction(false), _is_CData(false) {} NodeType type() const { return Inkscape::XML::DOCUMENT_NODE; } @@ -44,6 +44,7 @@ public: Node *createElement(char const *name); Node *createTextNode(char const *content); + Node *createTextNode(char const *content, bool const is_CData); Node *createComment(char const *content); Node *createPI(char const *target, char const *content); @@ -76,6 +77,7 @@ protected: private: bool _in_transaction; LogBuilder _log_builder; + bool _is_CData; }; } diff --git a/src/xml/simple-node.cpp b/src/xml/simple-node.cpp index b7c0c34ed..c197d648b 100644 --- a/src/xml/simple-node.cpp +++ b/src/xml/simple-node.cpp @@ -16,7 +16,10 @@ #include <cstring> #include <string> -#include <glib/gstrfuncs.h> + +#include <glib.h> + +#include "preferences.h" #include "xml/node.h" #include "xml/simple-node.h" @@ -28,6 +31,8 @@ #include "util/share.h" #include "util/format.h" +#include "attribute-rel-util.h" + namespace Inkscape { namespace XML { @@ -311,6 +316,47 @@ SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const /*is_ { g_return_if_fail(name && *name); + // Check usefulness of attributes on elements in the svg namespace, optionally don't add them to tree. + Glib::ustring element = g_quark_to_string(_name); + //g_warning("setAttribute: %s: %s: %s", element.c_str(), name, value); + + gchar* cleaned_value = g_strdup( value ); + + // Only check elements in SVG name space and don't block setting attribute to NULL. + if( element.substr(0,4) == "svg:" && value != NULL) { + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if( prefs->getBool("/options/svgoutput/check_on_editing") ) { + + gchar const *id_char = attribute("id"); + Glib::ustring id = (id_char == NULL ? "" : id_char ); + unsigned int flags = sp_attribute_clean_get_prefs(); + bool attr_warn = flags & SP_ATTR_CLEAN_ATTR_WARN; + bool attr_remove = flags & SP_ATTR_CLEAN_ATTR_REMOVE; + + // Check attributes + if( (attr_warn || attr_remove) && value != NULL ) { + bool is_useful = sp_attribute_check_attribute( element, id, name, attr_warn ); + if( !is_useful && attr_remove ) { + g_free( cleaned_value ); + return; // Don't add to tree. + } + } + + // Check style properties -- Note: if element is not yet inserted into + // tree (and thus has no parent), default values will not be tested. + if( !strcmp( name, "style" ) && (flags >= SP_ATTR_CLEAN_STYLE_WARN) ) { + g_free( cleaned_value ); + cleaned_value = sp_attribute_clean_style( this, value, flags ); + // if( g_strcmp0( value, cleaned_value ) ) { + // g_warning( "SimpleNode::setAttribute: %s", id.c_str() ); + // g_warning( " original: %s", value); + // g_warning( " cleaned: %s", cleaned_value); + // } + } + } + } + GQuark const key = g_quark_from_string(name); MutableList<AttributeRecord> ref; @@ -321,14 +367,13 @@ SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const /*is_ } ref = existing; } - Debug::EventTracker<> tracker; ptr_shared<char> old_value=( existing ? existing->value : ptr_shared<char>() ); ptr_shared<char> new_value=ptr_shared<char>(); - if (value) { - new_value = share_string(value); + if (cleaned_value) { + new_value = share_string(cleaned_value); tracker.set<DebugSetAttribute>(*this, key, new_value); if (!existing) { if (ref) { @@ -354,7 +399,11 @@ SimpleNode::setAttribute(gchar const *name, gchar const *value, bool const /*is_ if ( new_value != old_value && (!old_value || !new_value || strcmp(old_value, new_value))) { _document->logger()->notifyAttributeChanged(*this, key, old_value, new_value); _observers.notifyAttributeChanged(*this, key, old_value, new_value); + //g_warning( "setAttribute notified: %s: %s: %s: %s", name, element.c_str(), old_value, new_value ); } + + g_free( cleaned_value ); + } void SimpleNode::addChild(Node *generic_child, Node *generic_ref) { diff --git a/src/xml/subtree.h b/src/xml/subtree.h index deee0cab1..11bf515f1 100644 --- a/src/xml/subtree.h +++ b/src/xml/subtree.h @@ -16,7 +16,6 @@ #define SEEN_INKSCAPE_XML_SUBTREE_H #include "gc-managed.h" -#include "xml/xml-forward.h" #include "xml/composite-node-observer.h" namespace Inkscape { diff --git a/src/xml/text-node.h b/src/xml/text-node.h index b0b7c884b..53798b822 100644 --- a/src/xml/text-node.h +++ b/src/xml/text-node.h @@ -15,7 +15,7 @@ #ifndef SEEN_INKSCAPE_XML_TEXT_NODE_H #define SEEN_INKSCAPE_XML_TEXT_NODE_H -#include <glib/gquark.h> +#include <glib.h> #include "xml/simple-node.h" namespace Inkscape { @@ -30,14 +30,25 @@ struct TextNode : public SimpleNode { : SimpleNode(g_quark_from_static_string("string"), doc) { setContent(content); + _is_CData = false; + } + TextNode(Util::ptr_shared<char> content, Document *doc, bool is_CData) + : SimpleNode(g_quark_from_static_string("string"), doc) + { + setContent(content); + _is_CData = is_CData; } TextNode(TextNode const &other, Document *doc) - : SimpleNode(other, doc) {} + : SimpleNode(other, doc) { + _is_CData = other._is_CData; + } Inkscape::XML::NodeType type() const { return Inkscape::XML::TEXT_NODE; } + bool is_CData() const { return _is_CData; } protected: SimpleNode *_duplicate(Document* doc) const { return new TextNode(*this, doc); } + bool _is_CData; }; } diff --git a/src/xml/xml-forward.h b/src/xml/xml-forward.h deleted file mode 100644 index bc7b8a405..000000000 --- a/src/xml/xml-forward.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __SEEN_XML_FORWARD_H__ -#define __SEEN_XML_FORWARD_H__ - -/** @file - * @brief Forward declarations for the XML namespace. - */ -/* Authors: - * Krzysztof KosiĆski <tweenk.pl@gmail.com> - * - * Copyright (C) 2008 Authors - * - * Released under GNU GPL. Read the file 'COPYING' for more information. - */ - -namespace Inkscape { -namespace XML { - -/* Copied from the relevant Doxygen page */ - -struct AttributeRecord; -struct CommentNode; -class CompositeNodeObserver; -struct Document; -class ElementNode; -class Event; -class EventAdd; -class EventDel; -class EventChgAttr; -class EventChgContent; -class EventChgOrder; -class InvalidOperationException; -class LogBuilder; -struct NodeEventVector; -struct NodeSiblingIteratorStrategy; -struct NodeParentIteratorStrategy; -class NodeObserver; -class Node; -struct PINode; -class SimpleDocument; -class SimpleNode; -class Subtree; -struct TextNode; - -} // namespace XML -} // namespace Inkscape - -#endif // __SEEN_XML_FORWARD_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 : |
