sp-item.cpp revision 13c319a736cfdceadb24e10d6cb38386ec30a372
#ifdef HAVE_CONFIG_H
# include "config.h"
#include "sp-item.h"
#include "print.h"
#include "display/drawing-item.h"
#include "attributes.h"
#include "document.h"
#include "uri.h"
#include "inkscape.h"
#include "desktop.h"
#include "desktop-handles.h"
#include "style.h"
#include "sp-root.h"
#include "sp-clippath.h"
#include "sp-mask.h"
#include "sp-rect.h"
#include "sp-use.h"
#include "sp-text.h"
#include "sp-item-rm-unsatisfied-cns.h"
#include "sp-pattern.h"
#include "sp-paint-server.h"
#include "sp-switch.h"
#include "sp-guide-constraint.h"
#include "gradient-chemistry.h"
#include "preferences.h"
#include "conn-avoid-ref.h"
#include "conditions.h"
#include "sp-filter-reference.h"
#include "filter-chemistry.h"
#include "sp-guide.h"
#include "sp-title.h"
#include "sp-desc.h"
#include "util/find-last-if.h"
#include "util/reverse-list.h"
#include "extract-uri.h"
#include "live_effects/lpeobject.h"
#include "live_effects/effect.h"
#include "live_effects/lpeobject-reference.h"
#define noSP_ITEM_DEBUG_IDLE
this->sensitive = 0;
this->_is_evaluated = false;
this->stop_paint = 0;
this->bbox_valid = 0;
this->freeze_stroke_width = false;
this->transform_center_x = 0;
this->transform_center_y = 0;
transform_center_x = 0;
transform_center_y = 0;
_is_evaluated = true;
freeze_stroke_width = false;
updateRepr();
if (!isEvaluated())
updateRepr();
if (!isEvaluated())
return _is_evaluated;
updateRepr();
if (bbox) {
transform_center_x = 0;
transform_center_y = 0;
transform_center_x = 0;
transform_center_y = 0;
if (bbox) {
if (topmost) {
if (next_higher) {
if (next_lower) {
++next_lower;
if (bottom) {
++bottom;
if (!target_ref) {
if (intoafter) {
} else if (!first) {
switch (key) {
case SP_ATTR_TRANSFORM: {
case SP_PROP_CLIP_PATH: {
if (uri) {
case SP_PROP_MASK: {
if (uri) {
case SP_ATTR_CONNECTOR_AVOID:
if (value) {
if (value) {
case SP_PROP_SYSTEM_LANGUAGE:
if (old_clip) {
SPItemView *v;
if (old_mask) {
// any of the modifications defined in sp-object.h might change bbox,
if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) {
if (clip_path) {
if (mask) {
Inkscape::XML::Node* SPItem::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
if (crepr) {
g_free(c);
return repr;
return bbox;
using Geom::X;
using Geom::Y;
bbox = const_cast<SPItem*>(this)->bbox(Geom::identity(), SPItem::GEOMETRIC_BBOX); // see LP Bug 1229971
SVGLength x, y, w, h;
x = filter->x;
y = filter->y;
return bbox;
if (!bbox_valid) {
bbox_valid = true;
return doc_bbox;
return documentGeometricBounds();
return documentVisualBounds();
return ret;
return desktopGeometricBounds();
return desktopVisualBounds();
unsigned int pos = 0;
if (iter == this) {
return pos;
pos++;
void SPItem::snappoints(std::vector<Inkscape::SnapCandidatePoint> & /*p*/, Inkscape::SnapPreferences const */*snapprefs*/) const {
* see for example sp_genericellipse_snappoints in sp-ellipse.cpp
void SPItem::getSnappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const
p.push_back(Inkscape::SnapCandidatePoint(getCenter(), Inkscape::SNAPSOURCE_ROTATION_CENTER, Inkscape::SNAPTARGET_ROTATION_CENTER));
for (std::list<SPObject const *>::const_iterator o = clips_and_masks.begin(); o != clips_and_masks.end(); ++o) {
for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator p_orig = p_clip_or_mask.begin(); p_orig != p_clip_or_mask.end(); ++p_orig) {
p.push_back(Inkscape::SnapCandidatePoint(pt, (*p_orig).getSourceType(), (*p_orig).getTargetType()));
if ( !isHidden() ) {
g_free (s);
s = snew;
g_free (s);
s = snew;
if (label) {
g_free (s);
s = snew;
* Returns true if the item is filtered, false otherwise. Used with groups/lists to determine how many, or if any, are filtered
static unsigned dkey = 0;
Inkscape::DrawingItem* SPItem::show(Inkscape::Drawing& /*drawing*/, unsigned int /*key*/, unsigned int /*flags*/) {
Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned key, unsigned flags)
return ai;
while (v != NULL) {
if (!ref) {
delete v->arenaitem;
g_free(v);
ref = v;
v = next;
if (freeze_stroke_width) {
updateRepr();
if (t_attr) {
t_old = t;
return t_old;
if ( !SP_IS_USE(this) ) {
if (SP_IS_ITEM(o)) {
if ( !SP_IS_USE(this) ) {
if (SP_IS_ITEM(o)) {
if (SP_IS_ITEM(o))
void SPItem::adjust_paint_recursive (Geom::Affine advertized_transform, Geom::Affine t_ancestors, bool is_pattern)
// _After_ full pattern/gradient transform: t_paint_new * t_item * t_ancestors * advertised_transform
Geom::Affine paint_delta = t_item * t_ancestors * advertized_transform * t_ancestors.inverse() * t_item.inverse();
if (SP_IS_ITEM(o)) {
// and paintservers on leaves inheriting their values from ancestors could adjust themselves properly
if (is_pattern) {
if ( SP_IS_LPE_ITEM(this) ) {
return transform;
void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &transform, Geom::Affine const *adv, bool compensate)
if (compensate) {
// recursively compensating for stroke scaling will not always work, because it can be scaled to zero or infinite
// from which we cannot ever recover by applying an inverse scale; therefore we temporarily block any changes
// (as reported in https://bugs.launchpad.net/inkscape/+bug/825840/comments/4)
// This will only work if the item has a set_transform method (in this method adjust_stroke() will be called)
// We will still have to apply the inverse scaling to other items, not having a set_transform method
// PS: We cannot use this freeze_stroke_width_recursive() trick in all circumstances. For example, it will
// break pasting objects within their group (because in such a case the transformation of the group will affect
// the strokewidth, and has to be compensated for. See https://bugs.launchpad.net/inkscape/+bug/959223/comments/10)
/// \todo FIXME: add the same else branch as for gradients below, to convert patterns to userSpaceOnUse as well
// If onSetTransform is not overridden, CItem::onSetTransform will return the transform it was given as a parameter.
!(!transform.isTranslation() && style && style->getFilter()) // the object does not have a filter, or the transform is translation (which is supposed to not affect filters)
if (freeze_stroke_width) {
freeze_stroke_width_recursive(false);
if (freeze_stroke_width) {
freeze_stroke_width_recursive(false);
if (compensate) {
// (As to why we need to do this, see the comment a few lines above near the freeze_stroke_width_recursive(true) call)
updateRepr();
return FALSE;
sp_item_rm_unsatisfied_cns(*this);
return ret;
* Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
if ( desktop ) {
return ret;
if (parent) {
SPItemView *SPItem::sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, Inkscape::DrawingItem *drawing_item)
return new_view;
static SPItemView*
return ret;
return NULL;
return child;
if (!bbox) {