void DrawingItem::setBlendMode(unsigned mix_blend_mode) { _mix_blend_mode = mix_blend_mode; //if( mix_blend_mode != 0 ) std::cout << "setBlendMode: " << mix_blend_mode << std::endl; _markForRendering(); }
void DrawingItem::setIsolation(unsigned isolation) { _isolation = isolation; //if( isolation != 0 ) std::cout << "isolation: " << isolation << std::endl; _markForRendering(); }
void DrawingItem::setVisible(bool v) { if (_visible != v) { _visible = v; _markForRendering(); } }
void DrawingItem::setAntialiasing(bool a) { if (_antialias != a) { _antialias = a; _markForRendering(); } }
void DrawingItem::setOpacity(float opacity) { if (_opacity != opacity) { _opacity = opacity; _markForRendering(); } }
DrawingItem::~DrawingItem() { _drawing.signal_item_deleted.emit(this); //if (!_children.empty()) { // g_warning("Removing item with children"); //} // remove from the set of cached items and delete cache setCached(false, true); if (_has_cache_iterator) { _drawing._candidate_items.erase(_cache_iterator); } // remove this item from parent's children list // due to the effect of clearChildren(), this only happens for the top-level deleted item if (_parent) { _markForRendering(); } switch (_child_type) { case CHILD_NORMAL: { ChildrenList::iterator ithis = _parent->_children.iterator_to(*this); _parent->_children.erase(ithis); } break; case CHILD_CLIP: // we cannot call setClip(NULL) or setMask(NULL), // because that would be an endless loop _parent->_clip = NULL; break; case CHILD_MASK: _parent->_mask = NULL; break; case CHILD_ROOT: _drawing._root = NULL; break; case CHILD_FILL_PATTERN: _parent->_fill_pattern = NULL; break; case CHILD_STROKE_PATTERN: _parent->_stroke_pattern = NULL; break; default: ; } if (_parent) { _parent->_markForUpdate(STATE_ALL, false); } clearChildren(); delete _transform; delete _stroke_pattern; delete _fill_pattern; delete _clip; delete _mask; delete _filter; if(_style) sp_style_unref(_style); }
void DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &trans) { if (!font || !font->PathVector(glyph)) { return; } _markForRendering(); DrawingGlyphs *ng = new DrawingGlyphs(_drawing); ng->setGlyph(font, glyph, trans); appendChild(ng); }
void DrawingItem::setStrokePattern(DrawingPattern *pattern) { _markForRendering(); delete _stroke_pattern; _stroke_pattern = pattern; if (pattern) { pattern->_parent = this; assert(pattern->_child_type == CHILD_ORPHAN); pattern->_child_type = CHILD_STROKE_PATTERN; } _markForUpdate(STATE_ALL, true); }
void DrawingItem::setFillPattern(DrawingPattern *pattern) { _markForRendering(); delete _fill_pattern; _fill_pattern = pattern; if (pattern) { pattern->_parent = this; assert(pattern->_child_type == CHILD_ORPHAN); pattern->_child_type = CHILD_FILL_PATTERN; } _markForUpdate(STATE_ALL, true); }
void DrawingItem::setClip(DrawingItem *item) { _markForRendering(); delete _clip; _clip = item; if (item) { item->_parent = this; assert(item->_child_type == CHILD_ORPHAN); item->_child_type = CHILD_CLIP; } _markForUpdate(STATE_ALL, true); }
/// Move this item to the given place in the Z order of siblings. /// Does nothing if the item has no parent. void DrawingItem::setZOrder(unsigned z) { if (!_parent) return; ChildrenList::iterator it = _parent->_children.iterator_to(*this); _parent->_children.erase(it); ChildrenList::iterator i = _parent->_children.begin(); std::advance(i, std::min(z, unsigned(_parent->_children.size()))); _parent->_children.insert(i, *this); _markForRendering(); }
void DrawingItem::setMask(DrawingItem *item) { _markForRendering(); delete _mask; _mask = item; if (item) { item->_parent = this; assert(item->_child_type == CHILD_ORPHAN); item->_child_type = CHILD_MASK; } _markForUpdate(STATE_ALL, true); }
void DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &trans) { _markForRendering(); setTransform(trans); if (font) font->Ref(); if (_font) _font->Unref(); _font = font; _glyph = glyph; _markForUpdate(STATE_ALL, false); }
/// Delete all regular children of this item (not mask or clip). void DrawingItem::clearChildren() { if (_children.empty()) return; _markForRendering(); // prevent children from referencing the parent during deletion // this way, children won't try to remove themselves from a list // from which they have already been removed by clear_and_dispose for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { i->_parent = NULL; i->_child_type = CHILD_ORPHAN; } _children.clear_and_dispose(DeleteDisposer()); _markForUpdate(STATE_ALL, false); }
/** * Set additional transform for the group. * This is applied after the normal transform and mainly useful for * markers, clipping paths, etc. */ void DrawingGroup::setChildTransform(Geom::Affine const &new_trans) { Geom::Affine current; if (_child_transform) { current = *_child_transform; } if (!Geom::are_near(current, new_trans, 1e-18)) { // mark the area where the object was for redraw. _markForRendering(); if (new_trans.isIdentity()) { delete _child_transform; // delete NULL; is safe _child_transform = NULL; } else { _child_transform = new Geom::Affine(new_trans); } _markForUpdate(STATE_ALL, true); } }
void DrawingText::clear() { _markForRendering(); _children.clear_and_dispose(DeleteDisposer()); }
/** * Update derived data before operations. * The purpose of this call is to recompute internal data which depends * on the attributes of the object, but is not directly settable by the user. * Precomputing this data speeds up later rendering, because some items * can be omitted. * * Currently this method handles updating the visual and geometric bounding boxes * in pixels, storing the total transformation from item space to the screen * and cache invalidation. * * @param area Area to which the update should be restricted. Only takes effect * if the bounding box is known. * @param ctx A structure to store cascading state. * @param flags Which internal data should be recomputed. This can be any combination * of StateFlags. * @param reset State fields that should be reset before processing them. This is * a means to force a recomputation of internal data even if the item * considers it up to date. Mainly for internal use, such as * propagating bounding box recomputation to children when the item's * transform changes. */ void DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) { bool render_filters = _drawing.renderFilters(); bool outline = _drawing.outline(); // Set reset flags according to propagation status reset |= _propagate_state; _propagate_state = 0; _state &= ~reset; // reset state of this item if ((~_state & flags) == 0) return; // nothing to do // TODO this might be wrong if (_state & STATE_BBOX) { // we have up-to-date bbox if (!area.intersects(outline ? _bbox : _drawbox)) return; } // compute which elements need an update unsigned to_update = _state ^ flags; // this needs to be called before we recurse into children if (to_update & STATE_BACKGROUND) { _background_accumulate = _background_new; if (_child_type == CHILD_NORMAL && _parent->_background_accumulate) _background_accumulate = true; } UpdateContext child_ctx(ctx); if (_transform) { child_ctx.ctm = *_transform * ctx.ctm; } /* Remember the transformation matrix */ Geom::Affine ctm_change = _ctm.inverse() * child_ctx.ctm; _ctm = child_ctx.ctm; // update _bbox and call this function for children _state = _updateItem(area, child_ctx, flags, reset); if (to_update & STATE_BBOX) { // compute drawbox if (_filter && render_filters) { Geom::OptRect enlarged = _filter->filter_effect_area(_item_bbox); if (enlarged) { *enlarged *= ctm(); _drawbox = enlarged->roundOutwards(); } else { _drawbox = Geom::OptIntRect(); } } else { _drawbox = _bbox; } // Clipping if (_clip) { _clip->update(area, child_ctx, flags, reset); if (outline) { _bbox.unionWith(_clip->_bbox); } else { _drawbox.intersectWith(_clip->_bbox); } } // Masking if (_mask) { _mask->update(area, child_ctx, flags, reset); if (outline) { _bbox.unionWith(_mask->_bbox); } else { // for masking, we need full drawbox of mask _drawbox.intersectWith(_mask->_drawbox); } } } if (to_update & STATE_CACHE) { // Update cache score for this item if (_has_cache_iterator) { // remove old score information _drawing._candidate_items.erase(_cache_iterator); _has_cache_iterator = false; } double score = _cacheScore(); if (score >= _drawing._cache_score_threshold) { CacheRecord cr; cr.score = score; // if _cacheRect() is empty, a negative score will be returned from _cacheScore(), // so this will not execute (cache score threshold must be positive) cr.cache_size = _cacheRect()->area() * 4; cr.item = this; _drawing._candidate_items.push_front(cr); _cache_iterator = _drawing._candidate_items.begin(); _has_cache_iterator = true; } /* Update cache if enabled. * General note: here we only tell the cache how it has to transform * during the render phase. The transformation is deferred because * after the update the item can have its caching turned off, * e.g. because its filter was removed. This way we avoid tempoerarily * using more memory than the cache budget */ if (_cache) { Geom::OptIntRect cl = _cacheRect(); if (_visible && cl) { // never create cache for invisible items // this takes care of invalidation on transform _cache->scheduleTransform(*cl, ctm_change); } else { // Destroy cache for this item - outside of canvas or invisible. // The opposite transition (invisible -> visible or object // entering the canvas) is handled during the render phase delete _cache; _cache = NULL; } } } if (to_update & STATE_RENDER) { // now that we know drawbox, dirty the corresponding rect on canvas // unless filtered, groups do not need to render by themselves, only their members if (_fill_pattern) { _fill_pattern->update(area, child_ctx, flags, reset); } if (_stroke_pattern) { _stroke_pattern->update(area, child_ctx, flags, reset); } if (!is_drawing_group(this) || (_filter && render_filters)) { _markForRendering(); } } }