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);
}
Exemple #7
0
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);
}
Exemple #10
0
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);
}
Exemple #11
0
/// 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();
}
Exemple #12
0
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);
}
Exemple #13
0
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);
}
Exemple #14
0
/// 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);
}
Exemple #15
0
/**
 * 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);
    }
}
Exemple #16
0
void
DrawingText::clear()
{
    _markForRendering();
    _children.clear_and_dispose(DeleteDisposer());
}
Exemple #17
0
/**
 * 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();
        }
    }
}