summaryrefslogtreecommitdiffstats
path: root/src/document.cpp
diff options
context:
space:
mode:
authorMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:01:17 +0000
committerMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:01:17 +0000
commit509ca3687330fea576ea67ae6c7f31d16e66b800 (patch)
tree9097520c54e355ded9bd0b4d6618af4e8dacdd91 /src/document.cpp
parentupdated to latest trunk (diff)
parent[Bug #1695016] Xaml export misses some radialGradients. (diff)
downloadinkscape-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.cpp275
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;