Logo Search packages:      
Sourcecode: inkscape version File versions  Download package

static void sp_root_update ( SPObject object,
SPCtx ctx,
guint  flags 
) [static]

This callback routine updates the SPRoot object when its attributes have been changed.

Definition at line 405 of file sp-root.cpp.

References SPItemView::arenaitem, SPRoot::aspect_align, SPRoot::aspect_clip, SPRoot::c2p, SPItem::display, SPRoot::height, SPItemCtx::i2doc, SPItemCtx::i2vp, NR::identity(), SPItemView::next, SPObject::parent, NR::Matrix::set_identity(), SPRoot::viewBox, SPRoot::viewBox_set, SPItemCtx::vp, SPRoot::width, SPRoot::x, and SPRoot::y.

Referenced by sp_root_class_init().

{
    SPItemView *v;

    SPItem *item = SP_ITEM(object);
    SPRoot *root = SP_ROOT(object);
    SPItemCtx *ictx = (SPItemCtx *) ctx;

    /* fixme: This will be invoked too often (Lauris) */
    /* fixme: We should calculate only if parent viewport has changed (Lauris) */
    /* If position is specified as percentage, calculate actual values */
    if (root->x.unit == SVGLength::PERCENT) {
        root->x.computed = root->x.value * (ictx->vp.x1 - ictx->vp.x0);
    }
    if (root->y.unit == SVGLength::PERCENT) {
        root->y.computed = root->y.value * (ictx->vp.y1 - ictx->vp.y0);
    }
    if (root->width.unit == SVGLength::PERCENT) {
        root->width.computed = root->width.value * (ictx->vp.x1 - ictx->vp.x0);
    }
    if (root->height.unit == SVGLength::PERCENT) {
        root->height.computed = root->height.value * (ictx->vp.y1 - ictx->vp.y0);
    }

    /* Create copy of item context */
    SPItemCtx rctx = *ictx;

    /* Calculate child to parent transformation */
    root->c2p.set_identity();

    if (object->parent) {
        /*
         * fixme: I am not sure whether setting x and y does or does not
         * fixme: translate the content of inner SVG.
         * fixme: Still applying translation and setting viewport to width and
         * fixme: height seems natural, as this makes the inner svg element
         * fixme: self-contained. The spec is vague here.
         */
        root->c2p = NR::Matrix(NR::translate(root->x.computed,
                                             root->y.computed));
    }

    if (root->viewBox_set) {
        double x, y, width, height;
        /* Determine actual viewbox in viewport coordinates */
        if (root->aspect_align == SP_ASPECT_NONE) {
            x = 0.0;
            y = 0.0;
            width = root->width.computed;
            height = root->height.computed;
        } else {
            double scalex, scaley, scale;
            /* Things are getting interesting */
            scalex = root->width.computed / (root->viewBox.x1 - root->viewBox.x0);
            scaley = root->height.computed / (root->viewBox.y1 - root->viewBox.y0);
            scale = (root->aspect_clip == SP_ASPECT_MEET) ? MIN(scalex, scaley) : MAX(scalex, scaley);
            width = (root->viewBox.x1 - root->viewBox.x0) * scale;
            height = (root->viewBox.y1 - root->viewBox.y0) * scale;
            /* Now place viewbox to requested position */
            /* todo: Use an array lookup to find the 0.0/0.5/1.0 coefficients,
               as is done for dialogs/align.cpp. */
            switch (root->aspect_align) {
                case SP_ASPECT_XMIN_YMIN:
                    x = 0.0;
                    y = 0.0;
                    break;
                case SP_ASPECT_XMID_YMIN:
                    x = 0.5 * (root->width.computed - width);
                    y = 0.0;
                    break;
                case SP_ASPECT_XMAX_YMIN:
                    x = 1.0 * (root->width.computed - width);
                    y = 0.0;
                    break;
                case SP_ASPECT_XMIN_YMID:
                    x = 0.0;
                    y = 0.5 * (root->height.computed - height);
                    break;
                case SP_ASPECT_XMID_YMID:
                    x = 0.5 * (root->width.computed - width);
                    y = 0.5 * (root->height.computed - height);
                    break;
                case SP_ASPECT_XMAX_YMID:
                    x = 1.0 * (root->width.computed - width);
                    y = 0.5 * (root->height.computed - height);
                    break;
                case SP_ASPECT_XMIN_YMAX:
                    x = 0.0;
                    y = 1.0 * (root->height.computed - height);
                    break;
                case SP_ASPECT_XMID_YMAX:
                    x = 0.5 * (root->width.computed - width);
                    y = 1.0 * (root->height.computed - height);
                    break;
                case SP_ASPECT_XMAX_YMAX:
                    x = 1.0 * (root->width.computed - width);
                    y = 1.0 * (root->height.computed - height);
                    break;
                default:
                    x = 0.0;
                    y = 0.0;
                    break;
            }
        }

        /* Compose additional transformation from scale and position */
        NR::Point const viewBox_min(root->viewBox.x0,
                                    root->viewBox.y0);
        NR::Point const viewBox_max(root->viewBox.x1,
                                    root->viewBox.y1);
        NR::scale const viewBox_length( viewBox_max - viewBox_min );
        NR::scale const new_length(width, height);

        /* Append viewbox transformation */
        /* TODO: The below looks suspicious to me (pjrm): I wonder whether the RHS
           expression should have c2p at the beginning rather than at the end.  Test it. */
        root->c2p = NR::translate(-viewBox_min) * ( new_length / viewBox_length ) * NR::translate(x, y) * root->c2p;
    }

    rctx.i2doc = root->c2p * rctx.i2doc;

    /* Initialize child viewport */
    if (root->viewBox_set) {
        rctx.vp.x0 = root->viewBox.x0;
        rctx.vp.y0 = root->viewBox.y0;
        rctx.vp.x1 = root->viewBox.x1;
        rctx.vp.y1 = root->viewBox.y1;
    } else {
        /* fixme: I wonder whether this logic is correct (Lauris) */
        if (object->parent) {
            rctx.vp.x0 = root->x.computed;
            rctx.vp.y0 = root->y.computed;
        } else {
            rctx.vp.x0 = 0.0;
            rctx.vp.y0 = 0.0;
        }
        rctx.vp.x1 = root->width.computed;
        rctx.vp.y1 = root->height.computed;
    }

    rctx.i2vp = NR::identity();

    /* And invoke parent method */
    if (((SPObjectClass *) (parent_class))->update)
        ((SPObjectClass *) (parent_class))->update(object, (SPCtx *) &rctx, flags);

    /* As last step set additional transform of arena group */
    for (v = item->display; v != NULL; v = v->next) {
        nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), root->c2p);
    }
}


Generated by  Doxygen 1.6.0   Back to index