diff options
| author | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:01:17 +0000 |
|---|---|---|
| committer | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:01:17 +0000 |
| commit | 509ca3687330fea576ea67ae6c7f31d16e66b800 (patch) | |
| tree | 9097520c54e355ded9bd0b4d6618af4e8dacdd91 /src/document.cpp | |
| parent | updated to latest trunk (diff) | |
| parent | [Bug #1695016] Xaml export misses some radialGradients. (diff) | |
| download | inkscape-509ca3687330fea576ea67ae6c7f31d16e66b800.tar.gz inkscape-509ca3687330fea576ea67ae6c7f31d16e66b800.zip | |
updated to latest trunk
(bzr r14876.2.4)
Diffstat (limited to 'src/document.cpp')
| -rw-r--r-- | src/document.cpp | 275 |
1 files changed, 215 insertions, 60 deletions
diff --git a/src/document.cpp b/src/document.cpp index d8c3f1269..2141f65e9 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -37,7 +37,7 @@ #define noSP_DOCUMENT_DEBUG_UNDO #ifdef HAVE_CONFIG_H -# include "config.h" +#include <config.h> #endif #include <string> #include <cstring> @@ -47,26 +47,25 @@ #include "desktop.h" #include "dir-util.h" #include "display/drawing.h" -#include "display/drawing-item.h" #include "document-private.h" #include "document-undo.h" +#include "file.h" #include "id-clash.h" #include "inkscape.h" #include "inkscape-version.h" #include "libavoid/router.h" #include "persp3d.h" -#include "preferences.h" #include "profile-manager.h" #include "rdf.h" #include "sp-factory.h" -#include "sp-item-group.h" #include "sp-namedview.h" #include "sp-symbol.h" -#include "transf_mat_3x4.h" -#include "util/units.h" -#include "xml/repr.h" #include "xml/rebase-hrefs.h" -#include "libcroco/cr-cascade.h" + +#include "libcroco/cr-sel-eng.h" +#include "libcroco/cr-selector.h" +#include "libcroco/cr-parser.h" +#include "src/xml/croco-node-iface.h" using Inkscape::DocumentUndo; using Inkscape::Util::unit_table; @@ -78,7 +77,7 @@ using Inkscape::Util::unit_table; // since we want it to happen when there are no more updates. #define SP_DOCUMENT_REROUTING_PRIORITY (G_PRIORITY_HIGH_IDLE - 1) - +bool sp_no_convert_text_baseline_spacing = false; static gint sp_document_idle_handler(gpointer data); static gint sp_document_rerouting_handler(gpointer data); @@ -257,9 +256,9 @@ void SPDocument::setCurrentPersp3D(Persp3D * const persp) { void SPDocument::getPerspectivesInDefs(std::vector<Persp3D*> &list) const { - for (SPObject *i = root->defs->firstChild(); i; i = i->getNext() ) { - if (SP_IS_PERSP3D(i)) { - list.push_back(SP_PERSP3D(i)); + for (auto& i: root->defs->children) { + if (SP_IS_PERSP3D(&i)) { + list.push_back(SP_PERSP3D(&i)); } } } @@ -393,6 +392,7 @@ SPDocument *SPDocument::createDoc(Inkscape::XML::Document *rdoc, if (!bordercolor.empty()) { rnew->setAttribute("bordercolor", bordercolor.data()); } + sp_repr_set_svg_double(rnew, "inkscape:document-rotation", 0.); sp_repr_set_svg_double(rnew, "borderopacity", prefs->getDouble("/template/base/borderopacity", 1.0)); sp_repr_set_svg_double(rnew, "objecttolerance", @@ -414,6 +414,11 @@ SPDocument *SPDocument::createDoc(Inkscape::XML::Document *rdoc, rroot->addChild(rnew, NULL); // clean up Inkscape::GC::release(rnew); + } else { + Inkscape::XML::Node *nv_repr = sp_item_group_get_child_by_name(document->root, NULL, "sodipodi:namedview")->getRepr(); + if (!nv_repr->attribute("inkscape:document-rotation")) { + sp_repr_set_svg_double(nv_repr, "inkscape:document-rotation", 0.); + } } // Defs @@ -453,6 +458,22 @@ SPDocument *SPDocument::createDoc(Inkscape::XML::Document *rdoc, )); document->oldSignalsConnected = true; + /** Fix baseline spacing (pre-92 files) **/ + if ( (!sp_no_convert_text_baseline_spacing) + && sp_version_inside_range( document->root->version.inkscape, 0, 1, 0, 92 ) ) { + sp_file_convert_text_baseline_spacing(document); + } + + /** Fix font names in legacy documents (pre-92 files) **/ + if ( sp_version_inside_range( document->root->version.inkscape, 0, 1, 0, 92 ) ) { + sp_file_convert_font_name(document); + } + + /** Fix dpi (pre-92 files) **/ + if ( !(INKSCAPE.use_gui()) && sp_version_inside_range( document->root->version.inkscape, 0, 1, 0, 92 ) ) { + sp_file_convert_dpi(document); + } + return document; } @@ -465,7 +486,7 @@ SPDocument *SPDocument::createChildDoc(std::string const &uri) SPDocument *document = NULL; while(parent != NULL && parent->getURI() != NULL && document == NULL) { - // Check myself and any parents int he chain + // Check myself and any parents in the chain if(uri == parent->getURI()) { document = parent; break; @@ -484,8 +505,14 @@ SPDocument *SPDocument::createChildDoc(std::string const &uri) // Load a fresh document from the svg source. if(!document) { - const char *path = uri.c_str(); - document = createNewDoc(path, false, false, this); + std::string path; + if(uri.find('/') == -1) { + path = this->getBase() + uri; + } else { + path = uri; + } + std::cout << "Added base: '" << path << "'\n"; + document = createNewDoc(path.c_str(), false, false, this); } return document; } @@ -955,6 +982,10 @@ SPDocument::emitReconstructionFinish(void) { // printf("Finishing Reconstruction\n"); priv->_reconstruction_finish_signal.emit(); + // indicates that gradients are reloaded (to rebuild the Auto palette) + priv->resources_changed_signals[g_quark_from_string("gradient")].emit(); + priv->resources_changed_signals[g_quark_from_string("filter")].emit(); + /** // Reference to the old persp3d object is invalid after reconstruction. @@ -1050,6 +1081,104 @@ sigc::connection SPDocument::connectIdChanged(gchar const *id, return priv->id_changed_signals[g_quark_from_string(id)].connect(slot); } +void _getObjectsByClassRecursive(Glib::ustring const &klass, SPObject *parent, std::vector<SPObject *> &objects) +{ + if (parent) { + Glib::ustring class_attribute; + char const *temp = parent->getAttribute("class"); + if (temp) { + class_attribute = temp; + } + + if (class_attribute.find( klass ) != std::string::npos) { + objects.push_back( parent ); + } + + // Check children + for (auto& child : parent->children) { + _getObjectsByClassRecursive( klass, &child, objects ); + } + } +} + +std::vector<SPObject *> SPDocument::getObjectsByClass(Glib::ustring const &klass) const +{ + std::vector<SPObject *> objects; + g_return_val_if_fail(!klass.empty(), objects); + + _getObjectsByClassRecursive(klass, root, objects); + return objects; +} + +void _getObjectsByElementRecursive(Glib::ustring const &element, SPObject *parent, + std::vector<SPObject *> &objects) +{ + if (parent) { + Glib::ustring prefixed = "svg:" + element; + if (parent->getRepr()->name() == prefixed) { + objects.push_back(parent); + } + + // Check children + for (auto& child : parent->children) { + _getObjectsByElementRecursive(element, &child, objects); + } + } +} + +std::vector<SPObject *> SPDocument::getObjectsByElement(Glib::ustring const &element) const +{ + std::vector<SPObject *> objects; + g_return_val_if_fail(!element.empty(), objects); + + _getObjectsByElementRecursive(element, root, objects); + return objects; +} + +void _getObjectsBySelectorRecursive(SPObject *parent, + CRSelEng *sel_eng, CRSimpleSel *simple_sel, + std::vector<SPObject *> &objects) +{ + if (parent) { + gboolean result = false; + cr_sel_eng_matches_node( sel_eng, simple_sel, parent->getRepr(), &result ); + if (result) { + objects.push_back(parent); + } + + // Check children + for (auto& child : parent->children) { + _getObjectsBySelectorRecursive(&child, sel_eng, simple_sel, objects); + } + } +} + +std::vector<SPObject *> SPDocument::getObjectsBySelector(Glib::ustring const &selector) const +{ + // std::cout << "\nSPDocument::getObjectsBySelector: " << selector << std::endl; + + std::vector<SPObject *> objects; + g_return_val_if_fail(!selector.empty(), objects); + + static CRSelEng *sel_eng = NULL; + if (!sel_eng) { + sel_eng = cr_sel_eng_new(); + cr_sel_eng_set_node_iface(sel_eng, &Inkscape::XML::croco_node_iface); + } + + Glib::ustring my_selector = selector + " {"; // Parsing fails sometimes without '{'. Fix me + CRSelector *cr_selector = cr_selector_parse_from_buf ((guchar*)my_selector.c_str(), CR_UTF_8); + // char * cr_string = (char*)cr_selector_to_string( cr_selector ); + // std::cout << " selector: |" << (cr_string?cr_string:"Empty") << "|" << std::endl; + CRSelector const *cur = NULL; + for (cur = cr_selector; cur; cur = cur->next) { + if (cur->simple_sel ) { + _getObjectsBySelectorRecursive(root, sel_eng, cur->simple_sel, objects); + } + } + return objects; +} + void SPDocument::bindObjectToRepr(Inkscape::XML::Node *repr, SPObject *object) { if (object) { @@ -1256,12 +1385,12 @@ static std::vector<SPItem*> &find_items_in_area(std::vector<SPItem*> &s, SPGroup { g_return_val_if_fail(SP_IS_GROUP(group), s); - for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { - if ( SP_IS_ITEM(o) ) { - if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) { - s = find_items_in_area(s, SP_GROUP(o), dkey, area, test, take_insensitive, into_groups); + for (auto& o: group->children) { + if ( SP_IS_ITEM(&o) ) { + if (SP_IS_GROUP(&o) && (SP_GROUP(&o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) { + s = find_items_in_area(s, SP_GROUP(&o), dkey, area, test, take_insensitive, into_groups); } else { - SPItem *child = SP_ITEM(o); + SPItem *child = SP_ITEM(&o); Geom::OptRect box = child->desktopVisualBounds(); if ( box && test(area, *box) && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { s.push_back(child); @@ -1278,17 +1407,16 @@ Returns true if an item is among the descendants of group (recursively). */ static bool item_is_in_group(SPItem *item, SPGroup *group) { - bool inGroup = false; - for ( SPObject *o = group->firstChild() ; o && !inGroup; o = o->getNext() ) { - if ( SP_IS_ITEM(o) ) { - if (SP_ITEM(o) == item) { - inGroup = true; - } else if ( SP_IS_GROUP(o) ) { - inGroup = item_is_in_group(item, SP_GROUP(o)); + for (auto& o: group->children) { + if ( SP_IS_ITEM(&o) ) { + if (SP_ITEM(&o) == item) { + return true; + } else if (SP_IS_GROUP(&o) && item_is_in_group(item, SP_GROUP(&o))) { + return true; } } } - return inGroup; + return false; } SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, std::vector<SPItem*> const &list,Geom::Point const &p, bool take_insensitive) @@ -1299,21 +1427,24 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); - for ( SPObject *o = group->firstChild() ; o && !bottomMost; o = o->getNext() ) { - if ( SP_IS_ITEM(o) ) { - SPItem *item = SP_ITEM(o); + for (auto& o: group->children) { + if (bottomMost) { + break; + } + if (SP_IS_ITEM(&o)) { + SPItem *item = SP_ITEM(&o); Inkscape::DrawingItem *arenaitem = item->get_arenaitem(dkey); arenaitem->drawing().update(); if (arenaitem && arenaitem->pick(p, delta, 1) != NULL && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { - if (find(list.begin(),list.end(),item)!=list.end() ) { + if (find(list.begin(), list.end(), item) != list.end()) { bottomMost = item; } } - if ( !bottomMost && SP_IS_GROUP(o) ) { + if (!bottomMost && SP_IS_GROUP(&o)) { // return null if not found: - bottomMost = getItemFromListAtPointBottom(dkey, SP_GROUP(o), list, p, take_insensitive); + bottomMost = getItemFromListAtPointBottom(dkey, SP_GROUP(&o), list, p, take_insensitive); } } } @@ -1326,15 +1457,15 @@ The list can be persisted, which improves "find at multiple points" speed. */ void SPDocument::build_flat_item_list(unsigned int dkey, SPGroup *group, gboolean into_groups) const { - for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { - if (!SP_IS_ITEM(o)) { + for (auto& o: group->children) { + if (!SP_IS_ITEM(&o)) { continue; } - if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) { - build_flat_item_list(dkey, SP_GROUP(o), into_groups); + if (SP_IS_GROUP(&o) && (SP_GROUP(&o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) { + build_flat_item_list(dkey, SP_GROUP(&o), into_groups); } else { - SPItem *child = SP_ITEM(o); + SPItem *child = SP_ITEM(&o); if (child->isVisibleAndUnlocked(dkey)) { _node_cache.push_front(child); @@ -1390,20 +1521,22 @@ static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Poin Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); - for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { - if (!SP_IS_ITEM(o)) { + for (auto& o: group->children) { + if (!SP_IS_ITEM(&o)) { continue; } - if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER) { - SPItem *newseen = find_group_at_point(dkey, SP_GROUP(o), p); + if (SP_IS_GROUP(&o) && SP_GROUP(&o)->effectiveLayerMode(dkey) == SPGroup::LAYER) { + SPItem *newseen = find_group_at_point(dkey, SP_GROUP(&o), p); if (newseen) { seen = newseen; } } - if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) { - SPItem *child = SP_ITEM(o); + if (SP_IS_GROUP(&o) && SP_GROUP(&o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) { + SPItem *child = SP_ITEM(&o); Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); - arenaitem->drawing().update(); + if (arenaitem) { + arenaitem->drawing().update(); + } // seen remembers the last (topmost) of groups pickable at this point if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) { @@ -1595,32 +1728,48 @@ static unsigned int count_objects_recursive(SPObject *obj, unsigned int count) { count++; // obj itself - for ( SPObject *i = obj->firstChild(); i; i = i->getNext() ) { - count = count_objects_recursive(i, count); + for (auto& i: obj->children) { + count = count_objects_recursive(&i, count); } return count; } +/** + * Count the number of objects in a given document recursively using the count_objects_recursive helper function + * + * @param[in] document Pointer to the document for counting objects + * @return Numer of objects in the document + */ static unsigned int objects_in_document(SPDocument *document) { return count_objects_recursive(document->getRoot(), 0); } +/** + * Remove unused definitions etc. recursively from an object and its siblings + * + * @param[inout] obj Object which shall be "cleaned" + */ static void vacuum_document_recursive(SPObject *obj) { if (SP_IS_DEFS(obj)) { - for ( SPObject *def = obj->firstChild(); def; def = def->getNext()) { + for (auto& def: obj->children) { // fixme: some inkscape-internal nodes in the future might not be collectable - def->requestOrphanCollection(); + def.requestOrphanCollection(); } } else { - for ( SPObject *i = obj->firstChild(); i; i = i->getNext() ) { - vacuum_document_recursive(i); + for (auto& i: obj->children) { + vacuum_document_recursive(&i); } } } +/** + * Remove unused definitions etc. recursively from an entire document. + * + * @return Number of removed objects + */ unsigned int SPDocument::vacuumDocument() { unsigned int start = objects_in_document(this); @@ -1639,6 +1788,7 @@ unsigned int SPDocument::vacuumDocument() newend = objects_in_document(this); } while (iterations < 100 && newend < end); + // We stop if vacuum_document_recursive doesn't remove any more objects or after 100 iterations, whichever occurs first. return start - newend; } @@ -1647,6 +1797,11 @@ bool SPDocument::isSeeking() const { return priv->seeking; } +/** + * Indicate to the user if the document has been modified since the last save by displaying a "*" in front of the name of the file in the window title. + * + * @param[in] modified True if the document has been modified. + */ void SPDocument::setModifiedSinceSave(bool modified) { this->modified_since_save = modified; if (SP_ACTIVE_DESKTOP) { @@ -1733,14 +1888,14 @@ void SPDocument::importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, I // Prevent duplicates of solid swatches by checking if equivalent swatch already exists if (src && SP_IS_GRADIENT(src)) { SPGradient *s_gr = SP_GRADIENT(src); - for (SPObject *trg = this->getDefs()->firstChild() ; trg ; trg = trg->getNext()) { - if (trg && (src != trg) && SP_IS_GRADIENT(trg)) { - SPGradient *t_gr = SP_GRADIENT(trg); + for (auto& trg: getDefs()->children) { + if (&trg && (src != &trg) && SP_IS_GRADIENT(&trg)) { + SPGradient *t_gr = SP_GRADIENT(&trg); if (t_gr && s_gr->isEquivalent(t_gr)) { // Change object references to the existing equivalent gradient - Glib::ustring newid = trg->getId(); + Glib::ustring newid = trg.getId(); if(newid != defid){ // id could be the same if it is a second paste into the same document - change_def_references(src, trg); + change_def_references(src, &trg); } gchar *longid = g_strdup_printf("%s_%9.9d", DuplicateDefString.c_str(), stagger++); def->setAttribute("id", longid ); @@ -1804,9 +1959,9 @@ void SPDocument::importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, I id.erase( pos ); // Check that it really is a duplicate - for (SPObject *trg = this->getDefs()->firstChild() ; trg ; trg = trg->getNext()) { - if( trg && SP_IS_SYMBOL(trg) && src != trg ) { - std::string id2 = trg->getRepr()->attribute("id"); + for (auto& trg: getDefs()->children) { + if(&trg && SP_IS_SYMBOL(&trg) && src != &trg ) { + std::string id2 = trg.getRepr()->attribute("id"); if( !id.compare( id2 ) ) { duplicate = true; |
