summaryrefslogtreecommitdiffstats
path: root/src/xml
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/xml
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/xml')
-rw-r--r--src/xml/CMakeLists.txt74
-rw-r--r--src/xml/Makefile_insert1
-rw-r--r--src/xml/attribute-record.h3
-rw-r--r--src/xml/comment-node.h2
-rw-r--r--src/xml/croco-node-iface.cpp5
-rw-r--r--src/xml/document.h2
-rw-r--r--src/xml/event.h4
-rw-r--r--src/xml/log-builder.cpp5
-rw-r--r--src/xml/log-builder.h4
-rw-r--r--src/xml/node-event-vector.h2
-rw-r--r--src/xml/node-observer.h5
-rw-r--r--src/xml/node.h9
-rw-r--r--src/xml/pi-node.h2
-rw-r--r--src/xml/quote.cpp2
-rw-r--r--src/xml/rebase-hrefs-test.h126
-rw-r--r--src/xml/rebase-hrefs.cpp234
-rw-r--r--src/xml/rebase-hrefs.h27
-rw-r--r--src/xml/repr-action-test.h1
-rw-r--r--src/xml/repr-css.cpp115
-rw-r--r--src/xml/repr-io.cpp84
-rw-r--r--src/xml/repr-sorting.h9
-rw-r--r--src/xml/repr-util.cpp18
-rw-r--r--src/xml/repr.h5
-rw-r--r--src/xml/simple-document.cpp9
-rw-r--r--src/xml/simple-document.h4
-rw-r--r--src/xml/simple-node.cpp57
-rw-r--r--src/xml/subtree.h1
-rw-r--r--src/xml/text-node.h15
-rw-r--r--src/xml/xml-forward.h58
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 &amp;, 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 :