sp-item.cpp revision 1eb4534a71df4ce43561ff82b33dbd4d7696c919
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Base class for visual SVG elements
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Lauris Kaplinski <lauris@kaplinski.com>
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * bulia byak <buliabyak@users.sf.net>
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Copyright (C) 2001-2006 authors
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Copyright (C) 2001 Ximian, Inc.
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * Released under GNU GPL, read the file 'COPYING' for more information
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac/** \class SPItem
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * SPItem is an abstract base class for all graphic (visible) SVG nodes. It
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * is a subclass of SPObject, with great deal of specific functionality.
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void sp_item_class_init(SPItemClass *klass);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void sp_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void sp_item_set(SPObject *object, unsigned key, gchar const *value);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void sp_item_update(SPObject *object, SPCtx *ctx, guint flags);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic Inkscape::XML::Node *sp_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic gchar *sp_item_private_description(SPItem *item);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void sp_item_private_snappoints(SPItem const *item, SnapPointsIter p);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic SPItemView *sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, NRArenaItem *arenaitem);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic SPItemView *sp_item_view_list_remove(SPItemView *list, SPItemView *view);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void clip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonstatic void mask_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Registers SPItem class and returns its type number.
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson type = g_type_register_static(SP_TYPE_OBJECT, "SPItem", &info, (GTypeFlags)0);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * SPItem vtable initialization.
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson SPObjectClass *sp_object_class = (SPObjectClass *) klass;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson parent_class = (SPObjectClass *)g_type_class_ref(SP_TYPE_OBJECT);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson klass->snappoints = sp_item_private_snappoints;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Callback for SPItem object initialization.
1a70437cb8d25051f6259cbe5889eb67de86716eabobrov this->_is_evaluated = true;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson this->clip_ref = new SPClipPathReference(this);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sigc::signal<void, SPObject *, SPObject *> cs1=this->clip_ref->changedSignal();
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sigc::slot2<void,SPObject*, SPObject *> sl1=sigc::bind(sigc::ptr_fun(clip_ref_changed), this);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sigc::signal<void, SPObject *, SPObject *> cs2=this->mask_ref->changedSignal();
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sigc::slot2<void,SPObject*, SPObject *> sl2=sigc::bind(sigc::ptr_fun(mask_ref_changed), this);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson if (!this->style) this->style = sp_style_new_from_object(this);
1a70437cb8d25051f6259cbe5889eb67de86716eabobrov new (&this->_transformed_signal) sigc::signal<void, NR::Matrix const *, SPItem *>();
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonbool SPItem::isVisibleAndUnlocked(unsigned display_key) const {
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return (!isHidden(display_key) && !isLocked());
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson for (SPObject *o = SP_OBJECT(this); o != NULL; o = SP_OBJECT_PARENT(o)) {
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson if (SP_IS_ITEM(o) && !(SP_ITEM(o)->sensitive))
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return false;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson SP_OBJECT_REPR(this)->setAttribute("sodipodi:insensitive",
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return style->display.computed == SP_CSS_DISPLAY_NONE;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson style->display.value = ( hide ? SP_CSS_DISPLAY_NONE : SP_CSS_DISPLAY_INLINE );
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson style->display.computed = style->display.value;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonbool SPItem::isHidden(unsigned display_key) const {
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson for ( SPItemView *view(display) ; view ; view = view->next ) {
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson for ( NRArenaItem *arenaitem = view->arenaitem ;
d25372dc8e65a9ed019a88fdf659ca61313f1b31jcduff return true;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return false;
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson if ( StatusCalculated == _evaluated_status ) {
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson SPObject const *const parent = SP_OBJECT_PARENT(this);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Returns something suitable for the `Hide' checkbox in the Object Properties dialog box.
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Corresponds to setExplicitlyHidden.
d25372dc8e65a9ed019a88fdf659ca61313f1b31jcduff && this->style->display.value == SP_CSS_DISPLAY_NONE);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * Sets the display CSS property to `hidden' if \a val is true,
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson * otherwise makes it unset
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson this->style->display.value = ( val ? SP_CSS_DISPLAY_NONE : SP_CSS_DISPLAY_INLINE );
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson this->style->display.computed = this->style->display.value;
1a70437cb8d25051f6259cbe5889eb67de86716eabobrov * Sets the transform_center_x and transform_center_y properties to retain the rotation centre
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson NR::Maybe<NR::Rect> bbox = getBounds(sp_item_i2d_affine(this));
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson transform_center_x = object_centre[NR::X] - bbox->midpoint()[NR::X];
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson if (fabs(transform_center_x) < 1e-5) // rounding error
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson transform_center_y = object_centre[NR::Y] - bbox->midpoint()[NR::Y];
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson if (fabs(transform_center_y) < 1e-5) // rounding error
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return (transform_center_x != 0 || transform_center_y != 0);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson NR::Maybe<NR::Rect> bbox = getBounds(sp_item_i2d_affine(this));
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return bbox->midpoint() + NR::Point (this->transform_center_x, this->transform_center_y);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson return NR::Point (0, 0); // something's wrong!
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson SPObject *topmost=find_last_if<SPObject::SiblingIterator>(
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson Inkscape::XML::Node *repr=SP_OBJECT_REPR(this);
d25372dc8e65a9ed019a88fdf659ca61313f1b31jcduff sp_repr_parent(repr)->changeOrder(repr, SP_OBJECT_REPR(topmost));
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson SPObject *next_higher=std::find_if<SPObject::SiblingIterator>(
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson Inkscape::XML::Node *ref=SP_OBJECT_REPR(next_higher);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson MutableList<SPObject &> next_lower=std::find_if(
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson Inkscape::XML::Node *repr=SP_OBJECT_REPR(this);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson Inkscape::XML::Node *ref=( next_lower ? SP_OBJECT_REPR(&*next_lower) : NULL );
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson Inkscape::XML::Node *repr=SP_OBJECT_REPR(this);
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson Inkscape::XML::Node *ref=( bottom ? SP_OBJECT_REPR(&*bottom) : NULL );
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilsonsp_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sp_object_read_attr(object, "sodipodi:insensitive");
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sp_object_read_attr(object, "sodipodi:nonprintable");
d25372dc8e65a9ed019a88fdf659ca61313f1b31jcduff sp_object_read_attr(object, "inkscape:transform-center-x");
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sp_object_read_attr(object, "inkscape:transform-center-y");
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson sp_object_read_attr(object, "inkscape:connector-avoid");
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson if (((SPObjectClass *) (parent_class))->build) {
52867003bf09a12f814bf427e6f7e2fa34016d03neil_a_wilson (* ((SPObjectClass *) (parent_class))->build)(object, document, repr);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift if (((SPObjectClass *) (parent_class))->release) {
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift ((SPObjectClass *) parent_class)->release(object);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift nr_arena_item_unparent(item->display->arenaitem);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift item->display = sp_item_view_list_remove(item->display, item->display);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swiftsp_item_set(SPObject *object, unsigned key, gchar const *value)
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift if (value && sp_svg_transform_read(value, &t)) {
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift sp_item_set_item_transform(item, NR::identity());
0a873588d0c3ba63e71d8dae4b914e4ff99ae8c8abobrov for (SPItemView *v = item->display; v != NULL; v = v->next) {
0a873588d0c3ba63e71d8dae4b914e4ff99ae8c8abobrov nr_arena_item_set_sensitive(v->arenaitem, item->sensitive);
0a873588d0c3ba63e71d8dae4b914e4ff99ae8c8abobrov object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
c3690e9ed9bf853b95a31df6d7c8e169bf167050abobrov object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift // pass to default handler
c3690e9ed9bf853b95a31df6d7c8e169bf167050abobrov object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift (* ((SPObjectClass *) (parent_class))->set)(object, key, value);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swiftclip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item)
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift /* Hide clippath */
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift for (v = item->display; v != NULL; v = v->next) {
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift sp_clippath_hide(SP_CLIPPATH(old_clip), NR_ARENA_ITEM_GET_KEY(v->arenaitem));
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift sp_item_invoke_bbox(item, &bbox, NR::identity(), TRUE);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift for (SPItemView *v = item->display; v != NULL; v = v->next) {
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift NR_ARENA_ITEM_SET_KEY(v->arenaitem, sp_item_display_key_new(3));
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift NRArenaItem *ai = sp_clippath_show(SP_CLIPPATH(clip),
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift sp_clippath_set_bbox(SP_CLIPPATH(clip), NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift SP_OBJECT(clip)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swiftmask_ref_changed(SPObject *old_mask, SPObject *mask, SPItem *item)
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift /* Hide mask */
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift for (SPItemView *v = item->display; v != NULL; v = v->next) {
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift sp_mask_hide(SP_MASK(old_mask), NR_ARENA_ITEM_GET_KEY(v->arenaitem));
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov sp_item_invoke_bbox(item, &bbox, NR::identity(), TRUE);
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov for (SPItemView *v = item->display; v != NULL; v = v->next) {
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov NR_ARENA_ITEM_SET_KEY(v->arenaitem, sp_item_display_key_new(3));
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov sp_mask_set_bbox(SP_MASK(mask), NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox);
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov SP_OBJECT(mask)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrovsp_item_update(SPObject *object, SPCtx *ctx, guint flags)
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov (* ((SPObjectClass *) (parent_class))->update)(object, ctx, flags);
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) {
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov for (SPItemView *v = item->display; v != NULL; v = v->next) {
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov nr_arena_item_set_transform(v->arenaitem, item->transform);
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov SPClipPath *clip_path = item->clip_ref->getObject();
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov sp_item_invoke_bbox(item, &bbox, NR::identity(), TRUE);
c8d962c30776d1b772e3f4d0c72760bd05f68647abobrov for (SPItemView *v = item->display; v != NULL; v = v->next) {
b1af91c303f77cdd421dc0519e363b2d60c15a63matthew_swift sp_clippath_set_bbox(clip_path, NR_ARENA_ITEM_GET_KEY(v->arenaitem), &bbox);
g_free(c);
if (parent) {
if (obj_style) {
g_free(s);
if (!style_str) {
return repr;
unsigned int dkey) const
NRRect r;
sp_item_invoke_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const clear)
sp_item_invoke_bbox_full(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags, unsigned const clear)
if (clear) {
NRRect b;
unsigned pos=0;
return pos;
pos++;
if (result) {
return *result;
if (bbox) {
static gchar *
gchar *
g_free (s);
s = snew;
g_free (s);
s = snew;
return NULL;
static unsigned dkey = 0;
return ai;
while (v != NULL) {
if (!ref) {
g_free(v);
ref = v;
v = next;
if (t_attr) {
t_old = t;
return t_old;
if (SP_IS_ITEM(o))
if (SP_IS_ITEM(o))
sp_item_adjust_paint_recursive (SPItem *item, NR::Matrix advertized_transform, NR::Matrix t_ancestors, bool is_pattern)
// _After_ full pattern/gradient transform: t_paint_new * t_item * t_ancestors * advertised_transform
NR::Matrix paint_delta = t_item * t_ancestors * advertized_transform * t_ancestors.inverse() * t_item.inverse();
if (is_pattern)
if (SP_IS_ITEM(o)) {
sp_item_adjust_paint_recursive (SP_ITEM(o), advertized_transform, t_item * t_ancestors, is_pattern);
sp_item_write_transform(SPItem *item, Inkscape::XML::Node *repr, NRMatrix const *transform, NR::Matrix const *adv)
sp_item_write_transform(SPItem *item, Inkscape::XML::Node *repr, NR::Matrix const &transform, NR::Matrix const *adv, bool compensate)
if (compensate) {
/// \todo FIXME: add the same else branch as for gradients below, to convert patterns to userSpaceOnUse as well
// the object does not have a filter, or the transform is translation (which is supposed to not affect filters)
return FALSE;
return ret;
* Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
* Returns the accumulated transformation of the item and all its ancestors, but excluding root's viewport.
return ret;
return ret;
return ret;
return ret;
return ret;
static SPItemView *
sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, NRArenaItem *arenaitem)
return new_view;
static SPItemView *
return list;
return NULL;
SPItem *
return NULL;