X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-object.cpp;h=fd17b3c12f521daeb688391ae93946cbc7aefe6c;hb=8cd8b6ee0c2bd47add62310866479d49a2070057;hp=83bb7282c44dd5b617192d5c7d3cdbf397365f93;hpb=037770d289d0ef4c78c279e1dd3f3b4f2140c751;p=inkscape.git diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 83bb7282c..fd17b3c12 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -38,10 +38,13 @@ #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" @@ -51,8 +54,8 @@ #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; @@ -110,6 +113,37 @@ Inkscape::XML::NodeEventVector object_event_vector = { 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; /** @@ -175,7 +209,7 @@ sp_object_init(SPObject *object) 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; @@ -186,8 +220,8 @@ sp_object_init(SPObject *object) 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); @@ -257,6 +291,10 @@ public: } +gchar const* SPObject::getId() const { + return id; +} + /** * Increase reference count of object, with possible debugging. * @@ -502,22 +540,33 @@ SPObject::setLabel(gchar const *label) { /** 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(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 */ @@ -885,6 +937,8 @@ void SPObject::releaseReferences() { this->_default_label = NULL; this->document->bindObjectToRepr(this->repr, NULL); + + Inkscape::GC::release(this->repr); } else { g_assert(!this->id); } @@ -893,12 +947,21 @@ void SPObject::releaseReferences() { 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); @@ -1191,7 +1252,7 @@ SPObject::updateRepr(unsigned int flags) { } } -/** 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" */ @@ -1294,15 +1355,27 @@ SPObject::updateDisplay(SPCtx *ctx, unsigned int flags) } } - 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 @@ -1333,9 +1406,9 @@ SPObject::requestModified(unsigned int flags) } } -/** +/** * 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. */ @@ -1531,24 +1604,6 @@ SPObject::_requireSVGVersion(Inkscape::Version version) { } } -/** - * 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. */ @@ -1744,7 +1799,7 @@ SPObject::textualContent() const 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);