void sp_document_set_height (SPDocument * document, gdouble height, const SPUnit *unit)
{
    SPRoot *root = SP_ROOT(document->root);

    if (root->height.unit == SVGLength::PERCENT && root->viewBox_set) { // set to viewBox=
        root->viewBox.y1 = root->viewBox.y0 + sp_units_get_pixels (height, *unit);
    } else { // set to height=
        gdouble old_computed = root->height.computed;
        root->height.computed = sp_units_get_pixels (height, *unit);
        /* SVG does not support meters as a unit, so we must translate meters to
         * cm when writing */
        if (!strcmp(unit->abbr, "m")) {
            root->height.value = 100*height;
            root->height.unit = SVGLength::CM;
        } else {
            root->height.value = height;
            root->height.unit = (SVGLength::Unit) sp_unit_get_svg_unit(unit);
        }

        if (root->viewBox_set)
            root->viewBox.y1 = root->viewBox.y0 + (root->height.computed / old_computed) * (root->viewBox.y1 - root->viewBox.y0);
    }

    SP_OBJECT (root)->updateRepr();
}
void
sp_document_setup_viewport (SPDocument *doc, SPItemCtx *ctx)
{
    ctx->ctx.flags = 0;
    ctx->i2doc = Geom::identity();
    /* Set up viewport in case svg has it defined as percentages */
    if (SP_ROOT(doc->root)->viewBox_set) { // if set, take from viewBox
        ctx->vp.x0 = SP_ROOT(doc->root)->viewBox.x0;
        ctx->vp.y0 = SP_ROOT(doc->root)->viewBox.y0;
        ctx->vp.x1 = SP_ROOT(doc->root)->viewBox.x1;
        ctx->vp.y1 = SP_ROOT(doc->root)->viewBox.y1;
    } else { // as a last resort, set size to A4
        ctx->vp.x0 = 0.0;
        ctx->vp.y0 = 0.0;
        ctx->vp.x1 = 210 * PX_PER_MM;
        ctx->vp.y1 = 297 * PX_PER_MM;
    }
    ctx->i2vp = Geom::identity();
}
gdouble sp_document_height(SPDocument *document)
{
    g_return_val_if_fail(document != NULL, 0.0);
    g_return_val_if_fail(document->priv != NULL, 0.0);
    g_return_val_if_fail(document->root != NULL, 0.0);

    SPRoot *root = SP_ROOT(document->root);

    if (root->height.unit == SVGLength::PERCENT && root->viewBox_set)
        return root->viewBox.y1 - root->viewBox.y0;
    return root->height.computed;
}
void SPDocument::add_persp3d (Persp3D * const /*persp*/)
{
    SPDefs *defs = SP_ROOT(this->root)->defs;
    for (SPObject *i = sp_object_first_child(SP_OBJECT(defs)); i != NULL; i = SP_OBJECT_NEXT(i) ) {
        if (SP_IS_PERSP3D(i)) {
            g_print ("Encountered a Persp3D in defs\n");
        }
    }

    g_print ("Adding Persp3D to defs\n");
    persp3d_create_xml_element (this);
}
Exemple #5
0
/**
 * Virtual print callback.
 */
static void sp_root_print(SPItem *item, SPPrintContext *ctx)
{
    SPRoot *root = SP_ROOT(item);

    sp_print_bind(ctx, root->c2p, 1.0);

    if (((SPItemClass *) (parent_class))->print) {
        ((SPItemClass *) (parent_class))->print(item, ctx);
    }

    sp_print_release(ctx);
}
Exemple #6
0
/**
 * Calls the <tt>modified</tt> routine of the SPRoot object's parent class.
 * Also, if the viewport has been modified, it sets the document size to the new
 * height and width.
 */
static void sp_root_modified(SPObject *object, guint flags)
{
    SPRoot *root = SP_ROOT(object);

    if (((SPObjectClass *) (parent_class))->modified)
        (* ((SPObjectClass *) (parent_class))->modified)(object, flags);

    /* fixme: (Lauris) */
    if (!object->parent && (flags & SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
        root->document->emitResizedSignal(root->width.computed, root->height.computed);
    }
}
Exemple #7
0
/**
 * Displays the SPRoot item on the drawing.
 */
static Inkscape::DrawingItem *
sp_root_show(SPItem *item, Inkscape::Drawing &drawing, unsigned int key, unsigned int flags)
{
    SPRoot *root = SP_ROOT(item);

    Inkscape::DrawingItem *ai;
    if (((SPItemClass *) (parent_class))->show) {
        ai = ((SPItemClass *) (parent_class))->show(item, drawing, key, flags);
        if (ai) {
            Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(ai);
            g->setChildTransform(root->c2p);
        }
    } else {
        ai = NULL;
    }

    return ai;
}
Exemple #8
0
/**
 * Writes the object into the repr object, then calls the parent's write routine.
 */
static Inkscape::XML::Node *
sp_root_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
    SPRoot *root = SP_ROOT(object);

    if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
        repr = xml_doc->createElement("svg:svg");
    }

    if (flags & SP_OBJECT_WRITE_EXT) {
        repr->setAttribute("inkscape:version", Inkscape::version_string);
    }

    if ( !repr->attribute("version") ) {
        gchar* myversion = sp_version_to_string(root->version.svg);
        repr->setAttribute("version", myversion);
        g_free(myversion);
    }

    if (fabs(root->x.computed) > 1e-9)
        sp_repr_set_svg_double(repr, "x", root->x.computed);
    if (fabs(root->y.computed) > 1e-9)
        sp_repr_set_svg_double(repr, "y", root->y.computed);

    /* Unlike all other SPObject, here we want to preserve absolute units too (and only here,
     * according to the recommendation in http://www.w3.org/TR/SVG11/coords.html#Units).
     */
    repr->setAttribute("width", sp_svg_length_write_with_units(root->width).c_str());
    repr->setAttribute("height", sp_svg_length_write_with_units(root->height).c_str());

    if (root->viewBox_set) {
        Inkscape::SVGOStringStream os;
        os << root->viewBox.left() << " " << root->viewBox.top() << " "
           << root->viewBox.width() << " " << root->viewBox.height();
        repr->setAttribute("viewBox", os.str().c_str());
    }

    if (((SPObjectClass *) (parent_class))->write)
        ((SPObjectClass *) (parent_class))->write(object, xml_doc, repr, flags);

    return repr;
}
SPDocument *
sp_document_create(Inkscape::XML::Document *rdoc,
                   gchar const *uri,
                   gchar const *base,
                   gchar const *name,
                   unsigned int keepalive)
{
    SPDocument *document;
    Inkscape::XML::Node *rroot;
    Inkscape::Version sodipodi_version;
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    rroot = rdoc->root();

    document = new SPDocument();

    document->keepalive = keepalive;

    document->rdoc = rdoc;
    document->rroot = rroot;

#ifndef WIN32
    prepend_current_dir_if_relative(&(document->uri), uri);
#else
    // FIXME: it may be that prepend_current_dir_if_relative works OK on windows too, test!
    document->uri = uri? g_strdup(uri) : NULL;
#endif

    // base is simply the part of the path before filename; e.g. when running "inkscape ../file.svg" the base is "../"
    // which is why we use g_get_current_dir() in calculating the abs path above
    //This is NULL for a new document
    if (base)
        document->base = g_strdup(base);
    else
        document->base = NULL;
    document->name = g_strdup(name);

    document->root = sp_object_repr_build_tree(document, rroot);

    sodipodi_version = SP_ROOT(document->root)->version.sodipodi;

    /* fixme: Not sure about this, but lets assume ::build updates */
    rroot->setAttribute("sodipodi:version", SODIPODI_VERSION);
    rroot->setAttribute("inkscape:version", Inkscape::version_string);
    /* fixme: Again, I moved these here to allow version determining in ::build (Lauris) */

    /* Quick hack 2 - get default image size into document */
    if (!rroot->attribute("width")) rroot->setAttribute("width", "100%");
    if (!rroot->attribute("height")) rroot->setAttribute("height", "100%");
    /* End of quick hack 2 */

    /* Quick hack 3 - Set uri attributes */
    if (uri) {
        rroot->setAttribute("sodipodi:docname", uri);
    }
    /* End of quick hack 3 */

    /* Eliminate obsolete sodipodi:docbase, for privacy reasons */
    rroot->setAttribute("sodipodi:docbase", NULL);
    
    /* Eliminate any claim to adhere to a profile, as we don't try to */
    rroot->setAttribute("baseProfile", NULL);

    // creating namedview
    if (!sp_item_group_get_child_by_name((SPGroup *) document->root, NULL, "sodipodi:namedview")) {
        // if there's none in the document already,
        Inkscape::XML::Node *rnew = NULL;
        
        rnew = rdoc->createElement("sodipodi:namedview");
        //rnew->setAttribute("id", "base");

        // Add namedview data from the preferences
        // we can't use getAllEntries because this could produce non-SVG doubles
        Glib::ustring pagecolor = prefs->getString("/template/base/pagecolor");
        if (!pagecolor.empty()) {
            rnew->setAttribute("pagecolor", pagecolor.data());
        }
        Glib::ustring bordercolor = prefs->getString("/template/base/bordercolor");
        if (!bordercolor.empty()) {
            rnew->setAttribute("bordercolor", bordercolor.data());
        }
        sp_repr_set_svg_double(rnew, "borderopacity",
            prefs->getDouble("/template/base/borderopacity", 1.0));
        sp_repr_set_svg_double(rnew, "objecttolerance",
            prefs->getDouble("/template/base/objecttolerance", 10.0));
        sp_repr_set_svg_double(rnew, "gridtolerance",
            prefs->getDouble("/template/base/gridtolerance", 10.0));
        sp_repr_set_svg_double(rnew, "guidetolerance",
            prefs->getDouble("/template/base/guidetolerance", 10.0));
        sp_repr_set_svg_double(rnew, "inkscape:pageopacity",
            prefs->getDouble("/template/base/inkscape:pageopacity", 0.0));
        sp_repr_set_int(rnew, "inkscape:pageshadow",
            prefs->getInt("/template/base/inkscape:pageshadow", 2));
        sp_repr_set_int(rnew, "inkscape:window-width",
            prefs->getInt("/template/base/inkscape:window-width", 640));
        sp_repr_set_int(rnew, "inkscape:window-height",
            prefs->getInt("/template/base/inkscape:window-height", 480));
        
        // insert into the document
        rroot->addChild(rnew, NULL);
        // clean up
        Inkscape::GC::release(rnew);
    }

    /* Defs */
    if (!SP_ROOT(document->root)->defs) {
        Inkscape::XML::Node *r;
        r = rdoc->createElement("svg:defs");
        rroot->addChild(r, NULL);
        Inkscape::GC::release(r);
        g_assert(SP_ROOT(document->root)->defs);
    }

    /* Default RDF */
    rdf_set_defaults( document );

    if (keepalive) {
        inkscape_ref();
    }

    // Remark: Here, we used to create a "currentpersp3d" element in the document defs.
    // But this is probably a bad idea since we need to adapt it for every change of selection, which will
    // completely clutter the undo history. Maybe rather save it to prefs on exit and re-read it on startup?

    document->current_persp3d = persp3d_document_first_persp(document);
    if (!document->current_persp3d) {
        document->current_persp3d = persp3d_create_xml_element (document);
    }

    sp_document_set_undo_sensitive(document, true);

    // reset undo key when selection changes, so that same-key actions on different objects are not coalesced
    if (!Inkscape::NSApplication::Application::getNewGui()) {
        g_signal_connect(G_OBJECT(INKSCAPE), "change_selection",
                         G_CALLBACK(sp_document_reset_key), document);
        g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop",
                         G_CALLBACK(sp_document_reset_key), document);
    } else {
        document->_selection_changed_connection = Inkscape::NSApplication::Editor::connectSelectionChanged (sigc::mem_fun (*document, &SPDocument::reset_key));
        document->_desktop_activated_connection = Inkscape::NSApplication::Editor::connectDesktopActivated (sigc::mem_fun (*document, &SPDocument::reset_key));
    }

    return document;
}
Geom::Matrix const sp_desktop_root2dt_affine (SPDesktop const *dt)
{
    SPRoot const *root = SP_ROOT(SP_DOCUMENT_ROOT(dt->doc()));
    return root->c2p * dt->doc2dt();
}
Exemple #11
0
/**
 * This callback routine updates the SPRoot object when its attributes have been changed.
 */
static void sp_root_update(SPObject *object, SPCtx *ctx, guint flags)
{
    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->viewport.width();
    }
    if (root->y.unit == SVGLength::PERCENT) {
        root->y.computed = root->y.value * ictx->viewport.height();
    }
    if (root->width.unit == SVGLength::PERCENT) {
        root->width.computed = root->width.value * ictx->viewport.width();
    }
    if (root->height.unit == SVGLength::PERCENT) {
        root->height.computed = root->height.value * ictx->viewport.height();
    }

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

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

    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 = Geom::Affine(Geom::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.width();
            scaley = root->height.computed / root->viewBox.height();
            scale = (root->aspect_clip == SP_ASPECT_MEET) ? MIN(scalex, scaley) : MAX(scalex, scaley);
            width = root->viewBox.width() * scale;
            height = root->viewBox.height() * 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 */
        Geom::Scale const viewBox_length( root->viewBox.dimensions() );
        Geom::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 = Geom::Translate(-root->viewBox.min()) * ( new_length * viewBox_length.inverse() ) * Geom::Translate(x, y) * root->c2p;
    }

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

    /* Initialize child viewport */
    if (root->viewBox_set) {
        rctx.viewport = root->viewBox;
    } else {
        /* fixme: I wonder whether this logic is correct (Lauris) */
        Geom::Point minp(0,0);
        if (object->parent) {
            minp = Geom::Point(root->x.computed, root->y.computed);
        }
        rctx.viewport = Geom::Rect::from_xywh(minp[Geom::X], minp[Geom::Y], root->width.computed, root->height.computed);
    }

    rctx.i2vp = Geom::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 drawing group */
    for (SPItemView *v = root->display; v != NULL; v = v->next) {
        Inkscape::DrawingGroup *g = dynamic_cast<Inkscape::DrawingGroup *>(v->arenaitem);
        g->setChildTransform(root->c2p);
    }
}
Exemple #12
0
/**
 * Sets the attribute given by key for SPRoot objects to the value specified by value.
 */
static void sp_root_set(SPObject *object, unsigned int key, gchar const *value)
{
    SPRoot *root = SP_ROOT(object);

    switch (key) {
        case SP_ATTR_VERSION:
            if (!sp_version_from_string(value, &root->version.svg)) {
                root->version.svg = root->original.svg;
            }
            break;
        case SP_ATTR_INKSCAPE_VERSION:
            if (!sp_version_from_string(value, &root->version.inkscape)) {
                root->version.inkscape = root->original.inkscape;
            }
            break;
        case SP_ATTR_X:
            if (!root->x.readAbsolute(value)) {
                /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
                root->x.unset();
            }
            /* fixme: I am almost sure these do not require viewport flag (Lauris) */
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
            break;
        case SP_ATTR_Y:
            if (!root->y.readAbsolute(value)) {
                /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
                root->y.unset();
            }
            /* fixme: I am almost sure these do not require viewport flag (Lauris) */
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
            break;
        case SP_ATTR_WIDTH:
            if (!root->width.readAbsolute(value) || !(root->width.computed > 0.0)) {
                /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
                root->width.unset(SVGLength::PERCENT, 1.0, 1.0);
            }
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
            break;
        case SP_ATTR_HEIGHT:
            if (!root->height.readAbsolute(value) || !(root->height.computed > 0.0)) {
                /* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
                root->height.unset(SVGLength::PERCENT, 1.0, 1.0);
            }
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
            break;
        case SP_ATTR_VIEWBOX:
            if (value) {
                double x, y, width, height;
                char *eptr;
                /* fixme: We have to take original item affine into account */
                /* fixme: Think (Lauris) */
                eptr = (gchar *) value;
                x = g_ascii_strtod(eptr, &eptr);
                while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
                y = g_ascii_strtod(eptr, &eptr);
                while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
                width = g_ascii_strtod(eptr, &eptr);
                while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
                height = g_ascii_strtod(eptr, &eptr);
                while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
                if ((width > 0) && (height > 0)) {
                    /* Set viewbox */
                    root->viewBox = Geom::Rect::from_xywh(x, y, width, height);
                    root->viewBox_set = TRUE;
                } else {
                    root->viewBox_set = FALSE;
                }
            } else {
                root->viewBox_set = FALSE;
            }
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
            break;
        case SP_ATTR_PRESERVEASPECTRATIO:
            /* Do setup before, so we can use break to escape */
            root->aspect_set = FALSE;
            root->aspect_align = SP_ASPECT_XMID_YMID;
            root->aspect_clip = SP_ASPECT_MEET;
            object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG);
            if (value) {
                int len;
                gchar c[256];
                gchar const *p, *e;
                unsigned int align, clip;
                p = value;
                while (*p && *p == 32) p += 1;
                if (!*p) break;
                e = p;
                while (*e && *e != 32) e += 1;
                len = e - p;
                if (len > 8) break;
                memcpy(c, value, len);
                c[len] = 0;
                /* Now the actual part */
                if (!strcmp(c, "none")) {
                    align = SP_ASPECT_NONE;
                } else if (!strcmp(c, "xMinYMin")) {
                    align = SP_ASPECT_XMIN_YMIN;
                } else if (!strcmp(c, "xMidYMin")) {
                    align = SP_ASPECT_XMID_YMIN;
                } else if (!strcmp(c, "xMaxYMin")) {
                    align = SP_ASPECT_XMAX_YMIN;
                } else if (!strcmp(c, "xMinYMid")) {
                    align = SP_ASPECT_XMIN_YMID;
                } else if (!strcmp(c, "xMidYMid")) {
                    align = SP_ASPECT_XMID_YMID;
                } else if (!strcmp(c, "xMaxYMid")) {
                    align = SP_ASPECT_XMAX_YMID;
                } else if (!strcmp(c, "xMinYMax")) {
                    align = SP_ASPECT_XMIN_YMAX;
                } else if (!strcmp(c, "xMidYMax")) {
                    align = SP_ASPECT_XMID_YMAX;
                } else if (!strcmp(c, "xMaxYMax")) {
                    align = SP_ASPECT_XMAX_YMAX;
                } else {
                    break;
                }
                clip = SP_ASPECT_MEET;
                while (*e && *e == 32) e += 1;
                if (*e) {
                    if (!strcmp(e, "meet")) {
                        clip = SP_ASPECT_MEET;
                    } else if (!strcmp(e, "slice")) {
                        clip = SP_ASPECT_SLICE;
                    } else {
                        break;
                    }
                }
                root->aspect_set = TRUE;
                root->aspect_align = align;
                root->aspect_clip = clip;
            }
            break;
        case SP_ATTR_ONLOAD:
            root->onload = (char *) value;
            break;
        default:
            /* Pass the set event to the parent */
            if (((SPObjectClass *) parent_class)->set) {
                ((SPObjectClass *) parent_class)->set(object, key, value);
            }
            break;
    }
}