diff --git a/src/sp-object.cpp b/src/sp-object.cpp
index 83bb7282c44dd5b617192d5c7d3cdbf397365f93..fd17b3c12f521daeb688391ae93946cbc7aefe6c 100644 (file)
--- a/src/sp-object.cpp
+++ b/src/sp-object.cpp
#include "helper/sp-marshal.h"
#include "xml/node-event-vector.h"
#include "attributes.h"
+#include "color-profile-fns.h"
#include "document.h"
#include "style.h"
#include "sp-object-repr.h"
#include "sp-root.h"
+#include "sp-style-elem.h"
+#include "sp-script.h"
#include "streq.h"
#include "strneq.h"
#include "xml/repr.h"
#include "debug/demangle.h"
#include "util/share.h"
#include "util/format.h"
+#include "util/longest-common-suffix.h"
-#include "algorithms/longest-common-suffix.h"
using std::memcpy;
using std::strchr;
using std::strcmp;
sp_object_repr_order_changed
};
+// A friend class used to set internal members on SPObject so as to not expose settors in SPObject's public API
+class SPObjectImpl
+{
+public:
+
+/**
+ * Null's the id member of an SPObject without attempting to free prior contents.
+ */
+ static void setIdNull( SPObject* obj ) {
+ if (obj) {
+ obj->id = 0;
+ }
+ }
+
+/**
+ * Sets the id member of an object, freeing any prior content.
+ */
+ static void setId( SPObject* obj, gchar const* id ) {
+ if (obj && (id != obj->id) ) {
+ if (obj->id) {
+ g_free(obj->id);
+ obj->id = 0;
+ }
+ if (id) {
+ obj->id = g_strdup(id);
+ }
+ }
+ }
+};
+
+
static GObjectClass *parent_class;
/**
object->children = object->_last_child = NULL;
object->parent = object->next = NULL;
object->repr = NULL;
- object->id = NULL;
+ SPObjectImpl::setIdNull(object);
object->_collection_policy = SPObject::COLLECT_WITH_PARENT;
object->_successor = NULL;
// FIXME: now we create style for all objects, but per SVG, only the following can have style attribute:
- // vg, g, defs, desc, title, symbol, use, image, switch, path, rect, circle, ellipse, line, polyline,
- // polygon, text, tspan, tref, textPath, altGlyph, glyphRef, marker, linearGradient, radialGradient,
+ // vg, g, defs, desc, title, symbol, use, image, switch, path, rect, circle, ellipse, line, polyline,
+ // polygon, text, tspan, tref, textPath, altGlyph, glyphRef, marker, linearGradient, radialGradient,
// stop, pattern, clipPath, mask, filter, feImage, a, font, glyph, missing-glyph, foreignObject
object->style = sp_style_new_from_object(object);
}
+gchar const* SPObject::getId() const {
+ return id;
+}
+
/**
* Increase reference count of object, with possible debugging.
*
/** Queues the object for orphan collection */
-void
-SPObject::requestOrphanCollection() {
+void SPObject::requestOrphanCollection() {
g_return_if_fail(document != NULL);
- document->queueForOrphanCollection(this);
- /** \todo
- * This is a temporary hack added to make fill&stroke rebuild its
- * gradient list when the defs are vacuumed. gradient-vector.cpp
- * listens to the modified signal on defs, and now we give it that
- * signal. Mental says that this should be made automatic by
- * merging SPObjectGroup with SPObject; SPObjectGroup would issue
- * this signal automatically. Or maybe just derive SPDefs from
- * SPObjectGroup?
- */
+ // do not remove style or script elements (Bug #276244)
+ if (SP_IS_STYLE_ELEM(this)) {
+ // leave it
+ } else if (SP_IS_SCRIPT(this)) {
+ // leave it
+ } else if (SP_IS_PAINT_SERVER(this) && static_cast<SPPaintServer*>(this)->isSwatch() ) {
+ // leave it
+ } else if (IS_COLORPROFILE(this)) {
+ // leave it
+ } else {
+ document->queueForOrphanCollection(this);
+
+ /** \todo
+ * This is a temporary hack added to make fill&stroke rebuild its
+ * gradient list when the defs are vacuumed. gradient-vector.cpp
+ * listens to the modified signal on defs, and now we give it that
+ * signal. Mental says that this should be made automatic by
+ * merging SPObjectGroup with SPObject; SPObjectGroup would issue
+ * this signal automatically. Or maybe just derive SPDefs from
+ * SPObjectGroup?
+ */
- this->requestModified(SP_OBJECT_CHILD_MODIFIED_FLAG);
+ this->requestModified(SP_OBJECT_CHILD_MODIFIED_FLAG);
+ }
}
/** Sends the delete signal to all children of this object recursively */
@@ -799,8 +848,7 @@ sp_object_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
}
}
-void
-sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned)
+void sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned)
{
debug("id=%x, typename=%s", object, g_type_name_from_instance((GTypeInstance*)object));
@@ -811,13 +859,14 @@ sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::No
g_assert(object->document == NULL);
g_assert(object->repr == NULL);
- g_assert(object->id == NULL);
+ g_assert(object->getId() == NULL);
/* Bookkeeping */
object->document = document;
object->repr = repr;
- Inkscape::GC::anchor(repr);
+ if (!cloned)
+ Inkscape::GC::anchor(repr);
object->cloned = cloned;
if (!SP_OBJECT_IS_CLONED(object)) {
@@ -827,27 +876,30 @@ sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::No
/* If we are not cloned, and not seeking, force unique id */
gchar const *id = object->repr->attribute("id");
if (!document->isSeeking()) {
- gchar *realid = sp_object_get_unique_id(object, id);
- g_assert(realid != NULL);
+ {
+ gchar *realid = sp_object_get_unique_id(object, id);
+ g_assert(realid != NULL);
- object->document->bindObjectToId(realid, object);
- object->id = realid;
+ object->document->bindObjectToId(realid, object);
+ SPObjectImpl::setId(object, realid);
+ g_free(realid);
+ }
/* Redefine ID, if required */
- if ((id == NULL) || (strcmp(id, realid) != 0)) {
- object->repr->setAttribute("id", realid);
+ if ((id == NULL) || (strcmp(id, object->getId()) != 0)) {
+ object->repr->setAttribute("id", object->getId());
}
} else if (id) {
// bind if id, but no conflict -- otherwise, we can expect
// a subsequent setting of the id attribute
if (!object->document->getObjectById(id)) {
object->document->bindObjectToId(id, object);
- object->id = g_strdup(id);
+ SPObjectImpl::setId(object, id);
}
}
}
} else {
- g_assert(object->id == NULL);
+ g_assert(object->getId() == NULL);
}
/* Invoke derived methods, if any */
this->_default_label = NULL;
this->document->bindObjectToRepr(this->repr, NULL);
+
+ Inkscape::GC::release(this->repr);
} else {
g_assert(!this->id);
}
this->style = sp_style_unref(this->style);
}
- Inkscape::GC::release(this->repr);
-
this->document = NULL;
this->repr = NULL;
}
+
+SPObject *SPObject::getNext()
+{
+ return next;
+}
+
+SPObject *SPObject::getPrev()
+{
+ return sp_object_prev(this);
+}
+
/**
* Callback for child_added node event.
*/
@@ -972,16 +1035,14 @@ sp_object_private_set(SPObject *object, unsigned int key, gchar const *value)
}
}
- if (object->id) {
- document->bindObjectToId(object->id, NULL);
- g_free(object->id);
+ if (object->getId()) {
+ document->bindObjectToId(object->getId(), NULL);
+ SPObjectImpl::setId(object, 0);
}
if (new_id) {
- object->id = g_strdup((char const*)new_id);
- document->bindObjectToId(object->id, object);
- } else {
- object->id = NULL;
+ SPObjectImpl::setId(object, new_id);
+ document->bindObjectToId(object->getId(), object);
}
g_free(object->_default_label);
@@ -1120,7 +1181,7 @@ sp_object_private_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape
repr->setAttribute("inkscape:collect", NULL);
}
} else {
- repr->setAttribute("id", object->id);
+ repr->setAttribute("id", object->getId());
if (object->xml_space.set) {
char const *xml_space;
@@ -1135,7 +1196,7 @@ sp_object_private_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape
} else {
repr->setAttribute("inkscape:collect", NULL);
}
-
+
SPStyle const *const obj_style = SP_OBJECT_STYLE(object);
if (obj_style) {
gchar *s = sp_style_write_string(obj_style, SP_STYLE_FLAG_IFSET);
}
}
-/** Used both to create reprs in the original document, and to create
+/** Used both to create reprs in the original document, and to create
* reprs in another document (e.g. a temporary document used when
* saving as "Plain SVG"
*/
}
}
- if (((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update)
- ((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update(this, ctx, flags);
+ try
+ {
+ if (((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update)
+ ((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update(this, ctx, flags);
+ }
+ catch(...)
+ {
+ /** \todo
+ * in case of catching an exception we need to inform the user somehow that the document is corrupted
+ * maybe by implementing an document flag documentOk
+ * or by a modal error dialog
+ */
+ g_warning("SPObject::updateDisplay(SPCtx *ctx, unsigned int flags) : throw in ((SPObjectClass *) G_OBJECT_GET_CLASS(this))->update(this, ctx, flags);");
+ }
update_in_progress --;
}
/**
- * Request modified always bubbles *up* the tree, as opposed to
- * request display update, which trickles down and relies on the
+ * Request modified always bubbles *up* the tree, as opposed to
+ * request display update, which trickles down and relies on the
* flags set during this pass...
*/
void
}
}
-/**
+/**
* Emits the MODIFIED signal with the object's flags.
- * The object's mflags are the original set aside during the update pass for
+ * The object's mflags are the original set aside during the update pass for
* later delivery here. Once emitModified() is called, those flags don't
* need to be stored any longer.
*/
}
}
-/**
- * Return sodipodi version of first root ancestor or (0,0).
- */
-Inkscape::Version
-sp_object_get_sodipodi_version(SPObject *object)
-{
- static Inkscape::Version const zero_version(0, 0);
-
- while (object) {
- if (SP_IS_ROOT(object)) {
- return SP_ROOT(object)->version.sodipodi;
- }
- object = SP_OBJECT_PARENT(object);
- }
-
- return zero_version;
-}
-
/**
* Returns previous object in sibling list or NULL.
*/
for (const SPObject *child = firstChild(); child; child = child->next)
{
Inkscape::XML::NodeType child_type = child->repr->type();
-
+
if (child_type == Inkscape::XML::ELEMENT_NODE) {
GString * new_text = child->textualContent();
g_string_append(text, new_text->str);