Logo Search packages:      
Sourcecode: inkscape version File versions

void sp_item_invoke_bbox_full ( SPItem const *  item,
Geom::OptRect bbox,
Geom::Matrix const &  transform,
unsigned const   flags,
unsigned const   clear 
)

Calls item's subclass' bounding box method; clips it by the bbox of clippath, if any; and unions the resulting bbox with bbox. If clear is true, empties bbox first. Passes the transform and the flags to the actual bbox methods. Note that many of subclasses (e.g. groups, clones), in turn, call this function in their bbox methods.

Return values:
bbox Note that there is no guarantee that bbox will contain a rectangle when the function returns. If this item does not have a boundingbox, this might well be empty.

Definition at line 765 of file sp-item.cpp.

References SPItem::clip_ref, Geom::Matrix::expansionX(), Geom::Matrix::expansionY(), and sp_item_i2d_affine().

Referenced by SPItem::getBounds().

{
    g_assert(item != NULL);
    g_assert(SP_IS_ITEM(item));

    if (clear) {
        bbox = Geom::OptRect();
    }

    // TODO: replace NRRect by Geom::Rect, for all SPItemClasses, and for SP_CLIPPATH

    NRRect temp_bbox;
    temp_bbox.x0 = temp_bbox.y0 = NR_HUGE;
    temp_bbox.x1 = temp_bbox.y1 = -NR_HUGE;

    // call the subclass method
    if (((SPItemClass *) G_OBJECT_GET_CLASS(item))->bbox) {
        ((SPItemClass *) G_OBJECT_GET_CLASS(item))->bbox(item, &temp_bbox, transform, flags);
    }

    // unless this is geometric bbox, extend by filter area and crop the bbox by clip path, if any
    if ((SPItem::BBoxType) flags != SPItem::GEOMETRIC_BBOX) {
        if (SP_OBJECT_STYLE(item) && SP_OBJECT_STYLE(item)->filter.href) {
            SPObject *filter = SP_OBJECT_STYLE(item)->getFilter();
            if (filter && SP_IS_FILTER(filter)) {
                // default filer area per the SVG spec:
                double x = -0.1;
                double y = -0.1;
                double w = 1.2;
                double h = 1.2;

                // if area is explicitly set, override:
                if (SP_FILTER(filter)->x._set)
                    x = SP_FILTER(filter)->x.computed;
                if (SP_FILTER(filter)->y._set)
                    y = SP_FILTER(filter)->y.computed;
                if (SP_FILTER(filter)->width._set)
                    w = SP_FILTER(filter)->width.computed;
                if (SP_FILTER(filter)->height._set)
                    h = SP_FILTER(filter)->height.computed;

                double dx0 = 0;
                double dx1 = 0;
                double dy0 = 0;
                double dy1 = 0;
                if (filter_is_single_gaussian_blur(SP_FILTER(filter))) {
                    // if this is a single blur, use 2.4*radius
                    // which may be smaller than the default area;
                    // see set_filter_area for why it's 2.4
                    double r = get_single_gaussian_blur_radius (SP_FILTER(filter));
                    dx0 = -2.4 * r;
                    dx1 = 2.4 * r;
                    dy0 = -2.4 * r;
                    dy1 = 2.4 * r;
                } else {
                    // otherwise, calculate expansion from relative to absolute units:
                    dx0 = x * (temp_bbox.x1 - temp_bbox.x0);
                    dx1 = (w + x - 1) * (temp_bbox.x1 - temp_bbox.x0);
                    dy0 = y * (temp_bbox.y1 - temp_bbox.y0);
                    dy1 = (h + y - 1) * (temp_bbox.y1 - temp_bbox.y0);
                }

                // transform the expansions by the item's transform:
                Geom::Matrix i2d(sp_item_i2d_affine (item));
                dx0 *= i2d.expansionX();
                dx1 *= i2d.expansionX();
                dy0 *= i2d.expansionY();
                dy1 *= i2d.expansionY();

                // expand the bbox
                temp_bbox.x0 += dx0;
                temp_bbox.x1 += dx1;
                temp_bbox.y0 += dy0;
                temp_bbox.y1 += dy1;
            }
        }
        if (item->clip_ref->getObject()) {
            NRRect b;
            sp_clippath_get_bbox(SP_CLIPPATH(item->clip_ref->getObject()), &b, transform, flags);
            nr_rect_d_intersect (&temp_bbox, &temp_bbox, &b);
        }
    }

    if (temp_bbox.x0 > temp_bbox.x1 || temp_bbox.y0 > temp_bbox.y1) {
        // Either the bbox hasn't been touched by the SPItemClass' bbox method
        // (it still has its initial values, see above: x0 = y0 = NR_HUGE and x1 = y1 = -NR_HUGE)
        // or it has explicitely been set to be like this (e.g. in sp_shape_bbox)

        // When x0 > x1 or y0 > y1, the bbox is considered to be "nothing", although it has not been
        // explicitely defined this way for NRRects (as opposed to Geom::OptRect)
        // So union bbox with nothing = do nothing, just return
        return;
    }

    // Do not use temp_bbox.upgrade() here, because it uses a test that returns an empty Geom::OptRect()
    // for any rectangle with zero area. The geometrical bbox of for example a vertical line
    // would therefore be translated into empty Geom::OptRect() (see bug https://bugs.launchpad.net/inkscape/+bug/168684)
    Geom::OptRect temp_bbox_new = Geom::Rect(Geom::Point(temp_bbox.x0, temp_bbox.y0), Geom::Point(temp_bbox.x1, temp_bbox.y1));

    bbox = Geom::unify(bbox, temp_bbox_new);
}


Generated by  Doxygen 1.6.0   Back to index