summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2014-03-01 15:28:39 +0000
committerJabiertxof <jtx@jtx.marker.es>2014-03-01 15:28:39 +0000
commitefabd8330ec1bfda05e46c5315debc43e6dbca34 (patch)
treeee0a4d3a0898beca0aa9345c71fb5c5c9a55d9a8
parentSubstitute isBSpline property by a cached function isBSpline(bool) (diff)
parentupdate po/POTFILES.in (add new INX file from r13080) (diff)
downloadinkscape-efabd8330ec1bfda05e46c5315debc43e6dbca34.tar.gz
inkscape-efabd8330ec1bfda05e46c5315debc43e6dbca34.zip
update to trunk
(bzr r11950.1.262)
-rw-r--r--po/POTFILES.in3
-rw-r--r--share/extensions/Makefile.am2
-rw-r--r--share/extensions/tar_layers.inx19
-rwxr-xr-xshare/extensions/tar_layers.py113
-rw-r--r--src/display/nr-filter-primitive.cpp53
-rw-r--r--src/libavoid/router.cpp3
-rw-r--r--src/libnrtype/Layout-TNG-OutIter.cpp3
-rw-r--r--src/sp-filter-primitive.cpp100
-rw-r--r--src/sp-filter.cpp20
9 files changed, 232 insertions, 84 deletions
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b9fc708db..00f79b240 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,6 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
-# Generated by ./generate_POTFILES.sh at Mo 11. Nov 22:57:25 CET 2013
+# Generated by ./generate_POTFILES.sh at Sat Mar 1 11:37:53 CET 2014
[encoding: UTF-8]
inkscape.desktop.in
share/filters/filters.svg.h
@@ -551,6 +551,7 @@ share/extensions/wireframe_sphere.py
[type: gettext/xml] share/extensions/svgcalendar.inx
[type: gettext/xml] share/extensions/svgfont2layers.inx
[type: gettext/xml] share/extensions/synfig_output.inx
+[type: gettext/xml] share/extensions/tar_layers.inx
[type: gettext/xml] share/extensions/text_braille.inx
[type: gettext/xml] share/extensions/text_extract.inx
[type: gettext/xml] share/extensions/text_flipcase.inx
diff --git a/share/extensions/Makefile.am b/share/extensions/Makefile.am
index b53446999..c107f7646 100644
--- a/share/extensions/Makefile.am
+++ b/share/extensions/Makefile.am
@@ -159,6 +159,7 @@ extensions = \
synfig_prepare.py \
text_extract.py \
svg_transform.py \
+ tar_layers.py \
text_uppercase.py \
text_lowercase.py \
text_sentencecase.py \
@@ -342,6 +343,7 @@ modules = \
svg_and_media_zip_output.inx \
svgcalendar.inx \
synfig_output.inx \
+ tar_layers.inx \
text_extract.inx \
text_uppercase.inx\
text_lowercase.inx \
diff --git a/share/extensions/tar_layers.inx b/share/extensions/tar_layers.inx
new file mode 100644
index 000000000..43664c910
--- /dev/null
+++ b/share/extensions/tar_layers.inx
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
+ <_name>Collection of SVG files One per root layer</_name>
+ <id>org.inkscape.output.LAYERS</id>
+ <dependency type="extension">org.inkscape.output.svg.inkscape</dependency>
+ <dependency type="executable" location="extensions">tar_layers.py</dependency>
+ <dependency type="executable" location="extensions">inkex.py</dependency>
+ <output>
+ <extension>.tar</extension>
+ <mimetype>application/tar</mimetype>
+ <_filetypename>Layers as Seperate SVG (*.tar)</_filetypename>
+ <_filetypetooltip>Each layer split into it's own svg file and collected as a tape archive (tar file)</_filetypetooltip>
+ <dataloss>false</dataloss>
+ </output>
+ <script>
+ <command reldir="extensions" interpreter="python">tar_layers.py</command>
+ <helper_extension>org.inkscape.output.svg.inkscape</helper_extension>
+ </script>
+</inkscape-extension>
diff --git a/share/extensions/tar_layers.py b/share/extensions/tar_layers.py
new file mode 100755
index 000000000..8d7ce0541
--- /dev/null
+++ b/share/extensions/tar_layers.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2014 Martin Owens, email@doctormo.org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+"""
+An extention to export multiple svg files from a single svg file containing layers.
+
+Each defs is duplicated for each svg outputed.
+"""
+import os
+import sys
+import copy
+import tarfile
+import StringIO
+
+# Inkscape Libraries
+import inkex
+import simplestyle
+
+GROUP = "{http://www.w3.org/2000/svg}g"
+LABEL = "{http://www.inkscape.org/namespaces/inkscape}label"
+GROUPMODE = "{http://www.inkscape.org/namespaces/inkscape}groupmode"
+
+
+def oprint(item):
+ """DEBUG print an object"""
+ for name in dir(item):
+ value = getattr(item, name)
+ if callable(value):
+ yield "%s()" % name
+ else:
+ yield "%s = %s" % (name, str(value))
+
+def fprint(data):
+ """DEBUG print something"""
+ if isinstance(data, basestring):
+ sys.stderr.write("DEBUG: %s\n" % data)
+ else:
+ return fprint("%s(%s)\n " % (str(data), type(data).__name__) \
+ + "\n ".join(oprint(data)))
+
+
+class LayersOutput(inkex.Effect):
+ """Entry point to our layers export"""
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ if os.name == 'nt':
+ self.encoding = "cp437"
+ else:
+ self.encoding = "latin-1"
+
+ def make_template(self):
+ """Returns the current document as a new empty document with the same defs"""
+ newdoc = copy.deepcopy(self.document)
+ for (name, layer) in self.layers(newdoc):
+ layer.getparent().remove(layer)
+ return newdoc
+
+ def layers(self, document):
+ for node in document.getroot().iterchildren():
+ if self.is_layer(node):
+ name = node.attrib.get(LABEL, None)
+ if name:
+ yield (name, node)
+
+ def is_layer(self, node):
+ return node.tag == GROUP and node.attrib.get(GROUPMODE,'').lower() == 'layer'
+
+ def io_document(self, name, doc):
+ string = StringIO.StringIO()
+ doc.write(string)
+ string.seek(0)
+ info = tarfile.TarInfo(name=name+'.svg')
+ info.size=len(string.buf)
+ return dict(tarinfo=info, fileobj=string)
+
+ def effect(self):
+ # open output tar file as a stream (to stdout)
+ tar = tarfile.open(fileobj=sys.stdout, mode='w|')
+
+ template = self.make_template()
+
+ previous = None
+ for (name, _layer) in self.layers(self.document):
+ layer = copy.deepcopy(_layer)
+ if previous != None:
+ template.getroot().replace(previous, layer)
+ else:
+ template.getroot().append(layer)
+ previous = layer
+
+ tar.addfile(**self.io_document(name, template))
+
+
+if __name__ == '__main__': #pragma: no cover
+ e = LayersOutput()
+ e.affect()
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp
index 95d5d4b09..b065ac445 100644
--- a/src/display/nr-filter-primitive.cpp
+++ b/src/display/nr-filter-primitive.cpp
@@ -121,30 +121,10 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
fa = *fa_opt;
}
- // This is definitely a hack... but what else to do?
- // Current viewport might not be document viewport... but how to find?
- SPDocument* document = inkscape_active_document();
- SPRoot* root = document->getRoot();
- Geom::Rect viewport;
- if( root->viewBox_set ) {
- viewport = root->viewBox;
- } else {
- // Pick some random values
- viewport = Geom::Rect::from_xywh(0,0,480,360);
- }
-
- /* Update computed values for ex, em, %. For %, assumes primitive unit is objectBoundingBox. */
- /* TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. */
- double len_x = bb.width();
- double len_y = bb.height();
- _subregion_x.update(12, 6, len_x);
- _subregion_y.update(12, 6, len_y);
- _subregion_width.update(12, 6, len_x);
- _subregion_height.update(12, 6, len_y);
// x, y, width, and height are independently defined (i.e. one can be defined, by default, to
- // the filter area while another is defined relative to the bounding box). It is better to keep
- // track of them separately and then compose the Rect at the end.
+ // the filter area (via default value ) while another is defined relative to the bounding
+ // box). It is better to keep track of them separately and then compose the Rect at the end.
double x = 0;
double y = 0;
double width = 0;
@@ -157,10 +137,21 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
if( !_subregion_height._set ) height = fa.height();
if( units.get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) {
+
+ // Update computed values for ex, em, %.
+ // For %, assumes primitive unit is objectBoundingBox.
+ // TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values.
+ double len_x = bb.width();
+ double len_y = bb.height();
+ _subregion_x.update(12, 6, len_x);
+ _subregion_y.update(12, 6, len_y);
+ _subregion_width.update(12, 6, len_x);
+ _subregion_height.update(12, 6, len_y);
+
// Values are in terms of fraction of bounding box.
if( _subregion_x._set && (_subregion_x.unit != SVGLength::PERCENT) ) x = bb.min()[X] + bb.width() * _subregion_x.value;
if( _subregion_y._set && (_subregion_y.unit != SVGLength::PERCENT) ) y = bb.min()[Y] + bb.height() * _subregion_y.value;
- if( _subregion_width._set && (_subregion_width.unit != SVGLength::PERCENT) ) width = bb.width() * _subregion_width.value;
+ if( _subregion_width._set && (_subregion_width.unit != SVGLength::PERCENT) ) width = bb.width() * _subregion_width.value;
if( _subregion_height._set && (_subregion_height.unit != SVGLength::PERCENT) ) height = bb.height() * _subregion_height.value;
// Values are in terms of percent
if( _subregion_x._set && (_subregion_x.unit == SVGLength::PERCENT) ) x = bb.min()[X] + _subregion_x.computed;
@@ -168,17 +159,11 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
if( _subregion_width._set && (_subregion_width.unit == SVGLength::PERCENT) ) width = _subregion_width.computed;
if( _subregion_height._set && (_subregion_height.unit == SVGLength::PERCENT) ) height = _subregion_height.computed;
} else {
- // Values are in terms of user space coordinates or percent of viewbox (yuck!),
- // which is usually the size of SVG drawing. Default.
- if( _subregion_x._set && (_subregion_x.unit != SVGLength::PERCENT) ) x = _subregion_x.computed;
- if( _subregion_y._set && (_subregion_y.unit != SVGLength::PERCENT) ) y = _subregion_y.computed;
- if( _subregion_width._set && (_subregion_width.unit != SVGLength::PERCENT) ) width = _subregion_width.computed;
- if( _subregion_height._set && (_subregion_height.unit != SVGLength::PERCENT) ) height = _subregion_height.computed;
- // Percent of viewport
- if( _subregion_x._set && (_subregion_x.unit == SVGLength::PERCENT) ) x = _subregion_x.value * viewport.width();
- if( _subregion_y._set && (_subregion_y.unit == SVGLength::PERCENT) ) y = _subregion_y.value * viewport.height();
- if( _subregion_width._set && (_subregion_width.unit == SVGLength::PERCENT) ) width = _subregion_width.value * viewport.width();
- if( _subregion_height._set && (_subregion_height.unit == SVGLength::PERCENT) ) height = _subregion_height.value * viewport.height();
+ // Values are in terms of user space coordinates or percent of viewport (already calculated in sp-filter-primitive.cpp).
+ if( _subregion_x._set ) x = _subregion_x.computed;
+ if( _subregion_y._set ) y = _subregion_y.computed;
+ if( _subregion_width._set ) width = _subregion_width.computed;
+ if( _subregion_height._set ) height = _subregion_height.computed;
}
return Geom::Rect (Geom::Point(x,y), Geom::Point(x + width, y + height));
diff --git a/src/libavoid/router.cpp b/src/libavoid/router.cpp
index 35f921bb4..55098b9d8 100644
--- a/src/libavoid/router.cpp
+++ b/src/libavoid/router.cpp
@@ -793,7 +793,6 @@ void Router::improveCrossings(void)
}
// Determine if this pair cross.
Avoid::Polygon& jRoute = (*j)->routeRef();
- CrossingsInfoPair crossingInfo = std::make_pair(0, 0);
bool meetsPenaltyCriteria = false;
for (size_t jInd = 1; jInd < jRoute.size(); ++jInd)
{
@@ -1434,7 +1433,6 @@ bool Router::existsOrthogonalPathOverlap(void)
{
// Determine if this pair overlap
Avoid::Polygon jRoute = (*j)->displayRoute();
- CrossingsInfoPair crossingInfo = std::make_pair(0, 0);
for (size_t jInd = 1; jInd < jRoute.size(); ++jInd)
{
const bool finalSegment = ((jInd + 1) == jRoute.size());
@@ -1468,7 +1466,6 @@ bool Router::existsOrthogonalTouchingCorners(void)
{
// Determine if this pair overlap
Avoid::Polygon jRoute = (*j)->displayRoute();
- CrossingsInfoPair crossingInfo = std::make_pair(0, 0);
for (size_t jInd = 1; jInd < jRoute.size(); ++jInd)
{
const bool finalSegment = ((jInd + 1) == jRoute.size());
diff --git a/src/libnrtype/Layout-TNG-OutIter.cpp b/src/libnrtype/Layout-TNG-OutIter.cpp
index 8d8621d64..6dc42d998 100644
--- a/src/libnrtype/Layout-TNG-OutIter.cpp
+++ b/src/libnrtype/Layout-TNG-OutIter.cpp
@@ -181,9 +181,10 @@ Layout::iterator Layout::sourceToIterator(void *source_cookie /*, Glib::ustring:
if (_input_stream[source_index]->Type() != TEXT_SOURCE)
return iterator(this, char_index);
- InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[source_index]);
return iterator(this, char_index);
/* This code was never used, the text_iterator argument was "NULL" in all calling code
+ InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[source_index]);
+
if (text_iterator <= text_source->text_begin) return iterator(this, char_index);
if (text_iterator >= text_source->text_end) {
if (source_index == _input_stream.size() - 1) return end();
diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp
index f6b89bc21..ceb91c984 100644
--- a/src/sp-filter-primitive.cpp
+++ b/src/sp-filter-primitive.cpp
@@ -24,13 +24,14 @@
#include "sp-filter-primitive.h"
#include "xml/repr.h"
#include "sp-filter.h"
+#include "sp-item.h"
#include "display/nr-filter-primitive.h"
#include "display/nr-filter-types.h"
// CPPIFY: Make pure virtual.
//void SPFilterPrimitive::build_renderer(Inkscape::Filters::Filter* filter) {
- // throw;
+// throw;
//}
SPFilterPrimitive::SPFilterPrimitive() : SPObject() {
@@ -57,75 +58,72 @@ SPFilterPrimitive::~SPFilterPrimitive() {
* sp-object-repr.cpp's repr_name_entries array.
*/
void SPFilterPrimitive::build(SPDocument *document, Inkscape::XML::Node *repr) {
- SPFilterPrimitive* object = this;
+ SPFilterPrimitive* object = this;
object->readAttr( "style" ); // struct not derived from SPItem, we need to do this ourselves.
- object->readAttr( "in" );
- object->readAttr( "result" );
- object->readAttr( "x" );
- object->readAttr( "y" );
- object->readAttr( "width" );
- object->readAttr( "height" );
-
- SPObject::build(document, repr);
+ object->readAttr( "in" );
+ object->readAttr( "result" );
+ object->readAttr( "x" );
+ object->readAttr( "y" );
+ object->readAttr( "width" );
+ object->readAttr( "height" );
+
+ SPObject::build(document, repr);
}
/**
* Drops any allocated memory.
*/
void SPFilterPrimitive::release() {
- SPObject::release();
+ SPObject::release();
}
/**
* Sets a specific value in the SPFilterPrimitive.
*/
void SPFilterPrimitive::set(unsigned int key, gchar const *value) {
- SPFilterPrimitive* object = this;
- SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object);
- (void)filter_primitive;
int image_nr;
switch (key) {
case SP_ATTR_IN:
if (value) {
- image_nr = sp_filter_primitive_read_in(filter_primitive, value);
+ image_nr = sp_filter_primitive_read_in(this, value);
} else {
image_nr = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
}
- if (image_nr != filter_primitive->image_in) {
- filter_primitive->image_in = image_nr;
- object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ if (image_nr != this->image_in) {
+ this->image_in = image_nr;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
break;
case SP_ATTR_RESULT:
if (value) {
- image_nr = sp_filter_primitive_read_result(filter_primitive, value);
+ image_nr = sp_filter_primitive_read_result(this, value);
} else {
image_nr = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
}
- if (image_nr != filter_primitive->image_out) {
- filter_primitive->image_out = image_nr;
- object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ if (image_nr != this->image_out) {
+ this->image_out = image_nr;
+ this->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
break;
/* Filter primitive sub-region */
case SP_ATTR_X:
- filter_primitive->x.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ this->x.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_Y:
- filter_primitive->y.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ this->y.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_WIDTH:
- filter_primitive->width.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ this->width.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_HEIGHT:
- filter_primitive->height.readOrUnset(value);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ this->height.readOrUnset(value);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
}
@@ -137,19 +135,32 @@ void SPFilterPrimitive::set(unsigned int key, gchar const *value) {
* Receives update notifications.
*/
void SPFilterPrimitive::update(SPCtx *ctx, guint flags) {
- SPFilterPrimitive* object = this;
-
- //SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object);
-
- // Is this required?
- if (flags & SP_OBJECT_MODIFIED_FLAG) {
- object->readAttr( "style" );
- object->readAttr( "in" );
- object->readAttr( "result" );
- object->readAttr( "x" );
- object->readAttr( "y" );
- object->readAttr( "width" );
- object->readAttr( "height" );
+
+ SPItemCtx *ictx = (SPItemCtx *) ctx;
+
+ // Do here since we know viewport (Bounding box case handled during rendering)
+ SPFilter *parent = SP_FILTER(this->parent);
+
+ if( parent->primitiveUnits == SP_FILTER_UNITS_USERSPACEONUSE ) {
+ if (this->x.unit == SVGLength::PERCENT) {
+ this->x._set = true;
+ this->x.computed = this->x.value * ictx->viewport.width();
+ }
+
+ if (this->y.unit == SVGLength::PERCENT) {
+ this->y._set = true;
+ this->y.computed = this->y.value * ictx->viewport.height();
+ }
+
+ if (this->width.unit == SVGLength::PERCENT) {
+ this->width._set = true;
+ this->width.computed = this->width.value * ictx->viewport.width();
+ }
+
+ if (this->height.unit == SVGLength::PERCENT) {
+ this->height._set = true;
+ this->height.computed = this->height.value * ictx->viewport.height();
+ }
}
SPObject::update(ctx, flags);
@@ -159,7 +170,7 @@ void SPFilterPrimitive::update(SPCtx *ctx, guint flags) {
* Writes its settings to an incoming repr object, if any.
*/
Inkscape::XML::Node* SPFilterPrimitive::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) {
- SPFilterPrimitive* object = this;
+ SPFilterPrimitive* object = this;
SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE(object);
SPFilter *parent = SP_FILTER(object->parent);
@@ -261,6 +272,7 @@ void sp_filter_primitive_renderer_common(SPFilterPrimitive *sp_prim, Inkscape::F
nr_prim->set_output(sp_prim->image_out);
/* TODO: place here code to handle input images, filter area etc. */
+ // We don't know current viewport or bounding box, this is wrong approach.
nr_prim->set_subregion( sp_prim->x, sp_prim->y, sp_prim->width, sp_prim->height );
// Give renderer access to filter properties
diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp
index 0e3d2d5ce..e8319baca 100644
--- a/src/sp-filter.cpp
+++ b/src/sp-filter.cpp
@@ -213,7 +213,6 @@ void SPFilter::update(SPCtx *ctx, guint flags) {
// Note: This only works for root viewport since this routine is not called after
// setting a new viewport. A true fix requires a strategy like SPItemView or SPMarkerView.
if(this->filterUnits == SP_FILTER_UNITS_USERSPACEONUSE) {
- std::cout << " userSpaceOnUse" << std::endl;
if (this->x.unit == SVGLength::PERCENT) {
this->x._set = true;
this->x.computed = this->x.value * ictx->viewport.width();
@@ -238,6 +237,25 @@ void SPFilter::update(SPCtx *ctx, guint flags) {
}
+ // Update filter primitives in order to update filter primitive area
+ // (SPObject::ActionUpdate is not actually used)
+ unsigned childflags = flags;
+
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
+ }
+ childflags &= SP_OBJECT_MODIFIED_CASCADE;
+
+ GSList *l = g_slist_reverse(this->childList(true, SPObject::ActionUpdate));
+ while (l) {
+ SPObject *child = SP_OBJECT (l->data);
+ l = g_slist_remove (l, child);
+ if( SP_IS_FILTER_PRIMITIVE( child ) ) {
+ child->updateDisplay(ctx, childflags);
+ }
+ sp_object_unref(child);
+ }
+
SPObject::update(ctx, flags);
}