libmsvg v0.16

Programmer's guide

Last update: May 22, 2020


Abstract

libmsvg is a minimal and generic C library to read and write static SVG files.

SVG stand for Scalable Vector Graphics, it is a standard defined by the World Wide Web Consortium (see http://www.w3.org/Graphics/SVG/).

libmsvg concentrates on a small subset of SVG to be useful. More specifically on a subset of the SVG Tiny 1.2 specification. The subset is described in Appendix A.

Contents

  • Starting with examples
  • The MsvgElement tree
  • The MsvgElement structure
  • Reading SVG files
  • Building a RAW MsvgElement tree by program
  • Building a COOKED MsvgElement tree by program
  • Manipulating a MsvgElement tree
  • Finding elements in a MsvgElement tree
  • Working with cooked transformation matrix
  • Serialize a COOKED MsvgElement tree
  • Writing SVG files
  • Appendix A, the libmsvg SVG subset
  • Appendix B, parameters values

  • Starting with examples

    I think the best way to start with a programmer's guide is to show examples, so here there are.

    Example 1

    This example read a SVG file in a MsvgElement tree

    #include <stdio.h>
    #include <msvg.h>
    
    int main(int argc, char **argv)
    {
        MsvgElement *root;
        int error;
    
        if (argc <2) {
            printf("Usage: example svgfile\n");
            return 0;
        }
    
        root = MsvgReadSvgFile(argv[1], &error);
        
        if (root == NULL) {
            printf("Error %d reading %s\n", error, argv[1]);
            return 0;
        }
    
        // Now you can process the structure. By example:
        MsvgPrintRawElementTree(stdout, root, 0);
    
        return 1;
    }
    

    Example 2

    This example builds a MsvgElement tree and writes it to a file

    #include <stdio.h>
    #include <msvg.h>
    
    #define TESTFILE "msvgt2.svg"
    
    int main(int argc, char **argv)
    {
        MsvgElement *root, *son;
    
        root = MsvgNewElement(EID_SVG, NULL);
        MsvgAddRawAttribute(root, "xmlns", "http://www.w3.org/2000/svg");
        MsvgAddRawAttribute(root, "version", "1.2");
        MsvgAddRawAttribute(root, "baseProfile", "tiny");
        MsvgAddRawAttribute(root, "viewBox", "0 0 400 400");
    
        son = MsvgNewElement(EID_RECT, root);
        MsvgAddRawAttribute(son, "x", "1");
        MsvgAddRawAttribute(son, "y", "1");
        MsvgAddRawAttribute(son, "width", "398");
        MsvgAddRawAttribute(son, "height", "398");
        MsvgAddRawAttribute(son, "stroke", "#F00");
        MsvgAddRawAttribute(son, "fill", "#FFF");
    
        son = MsvgNewElement(EID_RECT, root);
        MsvgAddRawAttribute(son, "x", "11");
        MsvgAddRawAttribute(son, "y", "11");
        MsvgAddRawAttribute(son, "width", "380");
        MsvgAddRawAttribute(son, "height", "380");
        MsvgAddRawAttribute(son, "stroke", "#0F0");
        MsvgAddRawAttribute(son, "fill", "none");
    
        MsvgPrintRawElementTree(stdout, root, 0);
    
        if (!MsvgWriteSvgFile(root, TESTFILE)) {
            printf("Error writing %s\n", TESTFILE);
            return 0;
        }
    
        return 1;
    }
    

    How to compile the example programs

    We assume here that you have the libmsvg library previously installed. If not, please read the "readme" file for installation instructions.

    These are the command lines to compile the examples for the three supported platforms:


    The MsvgElement tree

    The central structure of libmsvg is the MsvgElement tree. Every MsvgElement has an element type id (eid), a pointer to his father, pointers to his previous and next siblings and a pointer to his first son. The root element must be a EID_SVG. In this version of libmsvg only EID_SVG, EID_DEFS and EID_G can have child elements. The other supported elements are EID_RECT, EID_CIRCLE, EID_ELLIPSE, EID_LINE, EID_POLYLINE, EID_POLYGON, EID_PATH, EID_TEXT and EID_USE.

    This graph represents an example of a MsvgElement tree:

    MsvgElement tree example

    Every MsvgElement can have attributes, they can be of two types: raw or cooked. The type of MsvgElement attributes in a tree is determined by a variable in the root element: root->psvgattr->tree_type. If this variable is RAW_SVGTREE all attributes are raw. Raw attributes are simple key,value strings pairs. If the variable is COOKED_SVGTREE the tree has cooked attributes too. Cooked attributes are typed variables and can be generic or specific, all elements have the generic ones, each element type id has his specific ones.

    The RAW_SVGTREE tree type

    After a SVG file is loaded to a MsvgElement tree by the MsvgReadSvgFile function it is marked as a RAW_SVGTREE. Only the supported elements are inserted in the tree, but all the read attributes are stored like raw attributes. This stage of the tree can suffice for some programs. Elements and attributes can be added, deleted or reordered and finally be written to a file using the MsvgWriteSvgFile function.

    The COOKED_SVGTREE tree type

    Using the MsvgRaw2CookedTree funtion you can convert a MsvgElement tree to the COOKED_SVGTREE type. Only the supported attributes are processed and converted to cooked attributes. In this state the tree is easier to be manipulated and/or rasterized by a program.

    Content

    In addition to attributes an element can have one or more contents, the contents are stored in a simple linked list. In this version of the library only EID_TEXT element contents are stored in the tree.


    The MsvgElement structure

    After reading the previous section it must be easy to undestand the MsvgElement structure from the msvg.h include file:

    typedef struct _MsvgElement *MsvgElementPtr;
    
    typedef struct _MsvgElement {
        enum EID eid;               /* element type id */
        MsvgElementPtr father;      /* pointer to father element */
        MsvgElementPtr psibling;    /* pointer to previous sibling element */
        MsvgElementPtr nsibling;    /* pointer to next sibling element */
        MsvgElementPtr fson;        /* pointer to first son element */
    
        MsvgRawAttributePtr frattr; /* pointer to first raw attribute */
        MsvgContentPtr fcontent;    /* pointer to first content */
    
        /* cooked generic attributes */
        char *id;                   /* id attribute */
        MsvgPaintCtx pctx;          /* painting context */
    
        /* cooked specific attributes */
        union {
            MsvgSvgAttributes *psvgattr;
            MsvgGAttributes *pgattr;
            MsvgRectAttributes *prectattr;
            MsvgCircleAttributes *pcircleattr;
            MsvgEllipseAttributes *pellipseattr;
            MsvgLineAttributes *plineattr;
            MsvgPolylineAttributes *ppolylineattr;
            MsvgPolygonAttributes *ppolygonattr;
            MsvgTextAttributes *ptextattr;
            MsvgDefsAttributes *pdefsattr;
            MsvgPathAttributes *ppathattr;
            MsvgUseAttributes *puseattr;
        };
    } MsvgElement;
    

    Raw attributes are stored in a simple linked list of MsvgRawAttribute variables:

    typedef struct _MsvgRawAttribute *MsvgRawAttributePtr;
    
    typedef struct _MsvgRawAttribute {
        char *key;                  /* key attribute */
        char *value;                /* value attribute */
        MsvgRawAttributePtr nrattr; /* pointer to next raw attribute */
    } MsvgRawAttribute;
    

    Similarly contents are stored in a simple linked list of MsvgContent variables:

    typedef struct _MsvgConten *MsvgContentPtr;
    
    typedef struct _MsvgConten {
        MsvgContentPtr ncontent; /* next content */
        int len;                 /* len content */
        char s[1];               /* content (not actual size) */
    } MsvgContent;
    

    Cooked generic attributes are the same for all elements, the "id" attribute (that can be NULL) and a MsvgPaintCtx structure:

    typedef struct {
        double a, b, c, d, e, f;
    } TMatrix;
    
    typedef struct _MsvgPaintCtx {
        rgbcolor fill;         /* fill color attribute */
        double fill_opacity;   /* fill-opacity attribute */
        rgbcolor stroke;       /* stroke color attribute */
        double stroke_width;   /* stroke-width attribute */
        double stroke_opacity; /* stroke-opacity attribute */
        TMatrix tmatrix;       /* transformation matrix */
    } MsvgPaintCtx;
    

    it is important to note that all attributes in the MsvgPaintCtx can be inherited from his father element. This can be do explicitly with the value INHERIT_COLOR (for colors) or INHERIT_VALUE (for doubles), that correspond to the raw keyword value "inherit", or implicitly when the value is NODEFINED_COLOR (for colors) or NODEFINED_VALUE, that occurs when the raw value is not defined, and the father value is defined.

    fill and stroke colors can have the value NO_COLOR, that correspond to the raw keyword value "none" that means fill or stroke must not be done.

    tmatrix is special, if undefined it defaults to the identity matrix. Before rasterizing any element it is neceary to calculate the Current Transformation Matrix, multiplying all the ancestors transformation matrix in order and finally with the own element transformation matrix.

    Cooked specific attributes are different for each element type id and are stored in a union, you can inspect each one in the msvg.h include file.


    Reading SVG files

    Using the MsvgReadSvgFile function you load a SVG file in a MsvgElement tree.

        MsvgElement *root;
        int error;
        root = MsvgReadSvgFile("filein.svg", &error);
    

    If the file doesn't exists or if it isn't a valid SVG file, root will be NULL and error will be filled with the error number, so you must check it. Only the supported elements are stored in the tree, the not supported ones are silently ignored. The tree will be a RAW tree, with all the element attributes stored as raw attributes. If you want a COOKED tree you can use the MsvgRaw2CookedTree funtion:

        int result;
        result = MsvgRaw2CookedTree(root);
    

    result will be true if all was right, false otherwise. Note that after calling this function you have really a mixed RAW/COOKED tree, because all raw parameters are preserved. If you are sure you don't need the raw parameters anymore you can call the MsvgDelAllTreeRawAttributes function:

        int result;
        result = MsvgDelAllTreeRawAttributes(root);
    

    result will be the number of raw parameters deleted.


    Building a RAW MsvgElement tree by program

    Using only two function we can construct a MsvgElement tree by program. The MsvgNewElement function takes two parameters: the element type id and the father element, that can be NULL, it returns the pointer to the constructed element. The MsvgAddRawAttribute takes three parameters: an element pointer, a key and a value.

    Let's see an example. We begin constructing the SVG element passing NULL in the father parameter, because it is the root element. By default the tree will be RAW_SVGTREE.

        MsvgElement *root;
        root = MsvgNewElement(EID_SVG, NULL);
    

    Now, we add attributes to identify the svg element properly and set the drawing limits using the MsvgAddRawAttribute function.

        MsvgAddRawAttribute(root, "xmlns", "http://www.w3.org/2000/svg");
        MsvgAddRawAttribute(root, "version", "1.2");
        MsvgAddRawAttribute(root, "baseProfile", "tiny");
        MsvgAddRawAttribute(root, "viewBox", "0 0 400 400");
    

    We continue adding two child elements, a RECT element and a translated G element.

        MsvgElement *son;
        son = MsvgNewElement(EID_RECT, root);
        MsvgAddRawAttribute(son, "x", "1");
        MsvgAddRawAttribute(son, "y", "1");
        MsvgAddRawAttribute(son, "width", "398");
        MsvgAddRawAttribute(son, "height", "398");
        MsvgAddRawAttribute(son, "stroke", "#F00");
        MsvgAddRawAttribute(son, "fill", "#FFF");
        son = MsvgNewElement(EID_G, root);
        MsvgAddRawAttribute(son, "stroke", "#0F0");
        MsvgAddRawAttribute(son, "fill", "none");
        MsvgAddRawAttribute(son, "transform", "translate(50)");
    

    Finally we add two child CIRCLE elements to the G element, one directly and the other indirectly by an USE element. Note that they will inherit the stroke and fill attributes and the transformation matrix.

        MsvgElement *son2;
        son2 = MsvgNewElement(EID_CIRCLE, son);
        MsvgAddRawAttribute(son2, "id", "myrect");
        MsvgAddRawAttribute(son2, "cx", "100");
        MsvgAddRawAttribute(son2, "cy", "200");
        MsvgAddRawAttribute(son2, "r", "80");
        son2 = MsvgNewElement(EID_USE, son);
        MsvgAddRawAttribute(son2, "xlink:href", "#myrect");
        MsvgAddRawAttribute(son2, "x", "100");
    

    We have now our MsvgElement tree and we can manipulate it or write it to a file.


    Building a COOKED MsvgElement tree by program

    Here you have two options, you can construct a RAW MsvgElement tree and them call MsvgRaw2CookedTree or you can construct a COOKED tree directly.

    Constructing a COOKED tree is the same like constructing a RAW one, except we don't use the MsvgAddRawAttribute function. Instead we set directly the element cooked attributes, there are no functions to hide the variables, because we are programmers and we know what are we doing, doesn't it. The only precaution to take into account is to reserve memory when the parameter to be assigned is a pointer. This space will be freed if we delete the element.

        MsvgElement *root;
        root = MsvgNewElement(EID_SVG, NULL);
        root->psvgattr->vb_min_x = 0;
        root->psvgattr->vb_min_y = 0;
        root->psvgattr->vb_width = 400;
        root->psvgattr->vb_height = 400;
        root->psvgattr->tree_type = COOKED_SVGTREE;
    
        MsvgElement *son;
        son = MsvgNewElement(EID_RECT, root);
        son->prectattr->x = 1;
        son->prectattr->y = 1;
        son->prectattr->width = 398;
        son->prectattr->height = 398;
        son->pctx.fill = 0XFFFFFF;
        son->pctx.stroke = 0XFF0000;
        son = MsvgNewElement(EID_G, root);
        son->pctx.fill = NO_COLOR;
        son->pctx.stroke = 0X00FF00;
        TMSetTranslation(&(son->pctx.tmatrix), 50, 50);
    
        MsvgElement *son2;
        son2 = MsvgNewElement(EID_CIRCLE, son);
        son2->id = strdup(myrect);
        son2->pcircleattr->cx = 100;
        son2->pcircleattr->cy = 200;
        son2->pcircleattr->r = 80;
        son2 = MsvgNewElement(EID_USE, son);
        son2->puseattr->refel = strdup(myrect);
        son2->puseattr->x = 100;
    

    Manipulating a MsvgElement tree

    There are some functions to manipulate a MsvgElement tree.

    void MsvgPruneElement(MsvgElement *el);
    

    The MsvgPruneElement function prune an element from his tree and them we can insert it in another tree or in another point of the same tree. Note that if the pruned element has child, it retains them after pruned.

    void MsvgDeleteElement(MsvgElement *el);
    

    The MsvgDeleteElement does two things, prunes the element from his tree and deletes it, freeing the allocated memory used. Note that if the deleted element has child, they are deleted too.

    int MsvgInsertSonElement(MsvgElement *el, MsvgElement *father);
    int MsvgInsertPSiblingElement(MsvgElement *el, MsvgElement *sibling);
    int MsvgInsertNSiblingElement(MsvgElement *el, MsvgElement *sibling);
    

    This three functios insert an element (that can be a subtree if it has child) in the desired point of a tree. The MsvgInsertSonElement fucntion inserts the element like the last son of the indicated father. The MsvgInsertPSiblingElement function inserts the element like a previous sibling to the indicated sibling. And the MsvgInsertNSiblingElement function inserts the element like a next sibling. The three functions return 1 if all was ok, 0 otherwise.

    MsvgElement *MsvgDupElement(MsvgElement *el);
    

    The MsvgDupElement duplicates the element passed as parameter, if that element is a container (like EID_SVG or EID_G) it duplicates all the element child too.


    Finding elements in a MsvgElement tree

    There are some functions to find elements in a MsvgElement tree.

    MsvgElement *MsvgFindFirstFather(MsvgElement *el);
    

    returns the first father of an element, normally a EID_SVG element

    typedef struct {
        int nelem[EID_LAST+1];  // num elements per type
        int totelem;            // total num elements
        int totelwid;           // num elements with id != NULL
    } MsvgTreeCounts;
    
    void MsvgCalcCountsCookedTree(MsvgElement *el, MsvgTreeCounts *tc);
    void MsvgCalcCountsRawTree(MsvgElement *el, MsvgTreeCounts *tc);
    

    fill a MsvgTreeCounts structure counting elements for the tree pointed by el, note that there are a version for raw trees and another for cooked trees, this is necsary to populate the totelwid variable because in raw trees is necesary to check the raw attribute "id" and for cooked trees we can use the id cooked attribute. Note that the root EID_SVG element is not counted

    MsvgElement * MsvgFindIdCookedTree(MsvgElement *el, char *id);
    MsvgElement * MsvgFindIdRawTree(MsvgElement *el, char *id);
    

    find for the element with the provided id in the tree pointed by el, again there is a version for raw trees and another for cooked trees. It returns NULL if not found

    The above functions walk all the tree comparing ids to find the element every time they are called, if you have to find lot of elements it is better to construct first a MsvgTableId structure calling one of these functions ( one for raw trees and one for cooked trees):

    MsvgTableId * MsvgBuildTableIdCookedTree(MsvgElement *el);
    MsvgTableId * MsvgBuildTableIdRawTree(MsvgElement *el);
    

    After that you can use next function to find elements (it does an efficient binary search):

    MsvgElement *MsvgFindIdTableId(MsvgTableId *tid, char *id);
    

    Note that if you add or delete elements in the tree you have to build a new MsvgTableId structure. when it is no longer necessary use next function to free memory:

    void MsvgDestroyTableId(MsvgTableId *tid);
    

    Working with cooked transformation matrix

    libmsvg has a number of functions to work with the transformation matrix cooked parameter TMatrix. Note that the transformation matrix is like that:

        a c e
        b d f
        0 0 1
    

    so only the a, b, c, d, e, f values are stored int the TMatrix structure. Here are the functions:

    void TMSetIdentity(TMatrix *des);
    int TMIsIdentity(TMatrix *t);
    int TMHaveRotation(TMatrix *t);
    void TMSetFromArray(TMatrix *des, double *p);
    void TMMpy(TMatrix *des, TMatrix *op1, TMatrix *op2);
    void TMSetTranslation(TMatrix *des, double tx, double ty);
    void TMSetScaling(TMatrix *des, double sx, double sy);
    void TMSetRotationOrigin(TMatrix *des, double ang);
    void TMSetRotation(TMatrix *des, double ang, double cx, double cy);
    void TMTransformCoord(double *x, double *y, TMatrix *ctm);
    

    TMSetIdentity stores in des the identity matrix (1 0 0 1 0 0)
    TMIsIdentity returns 1 if it is the identity matrix
    TMHaveRotation returns 1 if it includes a rotation (b or c != 0)
    TMSetFromArray set des from the double array p of dimension 6
    TMMpy multiply op1 by op2 and stores the result in des
    TMSetTranslation sets des with a traslation
    TMSetScaling sets des with a scaling
    TMSetRotationOrigin sets des with a rotation about the origin
    TMSetRotation sets des with a rotation about cx, cy
    TMTransformCoord changes x, y coordinates using ctm


    Serialize a COOKED MsvgElement tree

    libmsvg provides a function to serialize a COOKED MsvgElement tree. Using this function is the easier way to rasterize a MsvgElement tree.

    int MsvgSerCookedTree(MsvgElement *root, MsvgSerUserFn sufn);
    

    this function will process the tree and call the supply user function for every drawable element (not for container elements). The user function must be defined as:

    typedef void (*MsvgSerUserFn)(MsvgElement *el, MsvgPaintCtx *pctx);
    

    where "el" is the pointer to the drawable element and pctx a pointer to a constructed MsvgPaintCtx whit all the inherit and initial values processed and the current transformation matrix calculated, so the user program must use this painting context instead the element one to do the drawing.

    The serialization process has into account the EID_USE elements, replacing them with the referenced element (that can be a subtree).

    Another function that libmsvg provides can be called by the user function:

    MsvgElement * MsvgTransformCookedElement(MsvgElement *el, MsvgPaintCtx *pctx, int bef);
    

    that process the element parameters using the current transformation matrix (pctx->tmatrix) and returns a new drawable element that can be of different type that the original one, by example if an EID_RECT has to be rotated an EID_POLYGON is returned. . The function adjust too the element paint context parameters and sets the transformation matrix to the identity matrix. Note that you have to delete the new element returned after using it.

    There are some cases where MsvgTransformCookedElement cannot returns a properly transformed element (by example in this version a rotated EID_RECT with rounded borders). For these cases if the bef parameter (best effort) is 1, it returns the best transformed element it can. If bef is 0 it returns NULL and it is the user function responsability to manage correctly the element.

    So using all the pieces the code to rasterize a SVG image will be like that:

    static void userfn(MsvgElement *el, MsvgPaintCtx *pctx)
    {
        MsvgElement *newel;
    
        newel = MsvgTransformCookedElement(el, pctx, 1);
        if (newel == NULL) return; // or manage "el" + "pctx" by coding
    
        switch (newel->eid) {
            case EID_RECT :
                YourDrawRectElement(newel);
                break;
            case EID_CIRCLE :
                YourDrawCircleElement(newel);
                break;
            case EID_ELLIPSE :
                YourDrawEllipseElement(newel);
                break;
            case EID_LINE :
                YourDrawLineElement(newel);
                break;
            case EID_POLYLINE :
                YourDrawPolylineElement(newel);
                break;
            case EID_POLYGON :
                YourDrawPolygonElement(newel);
                break;
            default :
                break;
        }
    
        MsvgDeleteElement(newel);
    }
    
    ...
    // in main
        MsvgElement *root
    ...
    // read or build the Msvg tree and convert it to a COOKED tree
    ...
    // set the graphics coordinates using the information in the EID_SVG element
    ...
        MsvgSerCookedTree(root, userfn);
    ...
    

    Writing SVG files

    Using the MsvgWriteSvgFile function you can write a MsvgElement tree to a file.

        MsvgElement *root;
        int result;
        // construct the root tree
        result = MsvgWriteSvgFile(root, "fileout.svg")
    

    MsvgWriteSvgFile only know how to write RAW trees. If you want to write a COOKED only tree you need to use the MsvgCooked2RawTree funtion first:

        int result;
        MsvgDelAllTreeRawAttributes(root);
        result = MsvgCooked2RawTree(root);
    

    Note that after call MsvgCooked2RawTree you continue to have a COOKED tree, but with all the raw parameters populated. Because the function doesn't delete any previous raw parameters, it is good idea to delete them in advance


    Appendix A, the libmsvg SVG subset

    This table lists the SVG elementes and attributes that will be supported when libmsvg reaches version 0.20.

    Each row lists an element, the supported attributes and the possible child elements.

    Note that attributes listed only affects to COOKED trees, RAW trees can have any attribute.

    A status mark is added to each attribute: (ok) means it is already supported, (TO DO) means... you know: to do.

    Element

    Specific supported attributes (status)

    Notes

    <svg>

    xmlns="http://www.w3.org/2000/svg" (fixed value)

    version="1.2" (fixed value)

    baseprofile="tiny" (fixed value)

    viewbox="min-x min-y width height" (ok)

    width="width" (need to record units)

    height="height" (need to record units)

    preserveaspectratio="valor" (TO DO)

    viewport-fill="color" (ok)

    viewport-fill-opacity="n" (ok)

    id="valor" (ok)

    --- for inheritance ---

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)

    -- possible child elements --

    <defs>, <g>, <use>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>, <text>

    <defs>

    id="valor" (ok)

    --- for inheritance ---

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)

    -- possible child elements --

    <g>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>, <text>

    <g>

    id="valor" (ok)

    --- for inheritance ---

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)

    -- possible child elements --

    <g>, <use>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>, <text>

    <use>

    xlink:href ="#id" (ok)

    x="n" (ok)

    y="n" (ok)

    --- for inheritance ---

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)

    only a local reference is supported, it will be stored in the "refel" cooked parameter.

    <rect>

    id="valor" (ok)

    x="n" (ok)

    y="n" (ok)

    width="n" (ok)

    height="n" (ok)

    rx="n" (ok)

    ry="n" (ok)

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)


    <circle>

    id="valor" (ok)

    cx="n" (ok)

    cy="n" (ok)

    r="n" (ok)

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)


    <ellipse>

    id="valor" (ok)

    cx="n" (ok)

    cy="n" (ok)

    rx="n" (ok)

    ry="n" (ok)

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)

    using the "rx" and "ry" raw parameters there will be populated the "rx_x", "rx_y", "ry_x", "ry_y" cooked parameters, storing the real semi-axis points, so it will be easier to transforming and rasterizing an ellipse

    <line>

    id="valor" (ok)

    x1="n" (ok)

    y1="n" (ok)

    x2="n" (ok)

    y2="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)


    <polyline>

    id="valor" (ok)

    points="data" (ok)

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)


    <polygon>

    id="valor" (ok)

    points="data" (ok)

    fill="color" (ok)

    fill-opacity="n" (ok)

    stroke="color" (ok)

    stroke-width="n" (ok)

    stroke-opacity="n" (ok)

    transform="transformation" (ok)


    <path> (TO DO)

    id="valor" (TO DO)

    d="path-data" (TO DO)

    fill="color" (TO DO)

    fill-opacity="n" (TO DO)

    stroke="color" (TO DO)

    stroke-width="n" (TO DO)

    stroke-opacity="n" (TO DO)

    transform="transformation" (TO DO)


    <text> (TO DO)

    id="valor" (TO DO)

    x="n" (TO DO)

    y="n" (TO DO)

    font-size="n" (TO DO)

    font-family="string" (TO DO)

    fill="color" (TO DO)

    fill-opacity="n" (TO DO)

    stroke="color" (TO DO)

    stroke-width="n" (TO DO)

    stroke-opacity="n" (TO DO)

    transform="transformation" (TO DO)

    Note that the TEXT contents are in MsvgContent variables


    Appendix B, parameters values

    This table list the possible values that some parameters can have.

    Note that these are the values that are expected when converting to a COOKED tree, RAW parameters can have any value.

    A status mark is added to each value: (ok) means it is already supported, (TO DO) means... you know: to do.

    Parameters

    Raw value => Cooked value (status)

    Notes

    viewport-fill

    fill

    stroke

    NO DEFINED => NODEFINED_COLOR (ok)

    none => NO_COLOR (ok)

    currentColor => INHERIT_COLOR (ok)

    inherit => INHERIT_COLOR (ok)

    black => 0x000000 (ok)

    silver => 0xc0c0c0 (ok)

    gray => 0x808080 (ok)

    white => 0xffffff (ok)

    maroon => 0x800000 (ok)

    red => 0xff0000 (ok)

    purple => 0x800080 (ok)

    fuchsia => 0xff00ff (ok)

    green => 0x008000 (ok)

    lime => 0x00ff00 (ok)

    olive => 0x808000 (ok)

    yellow => 0xffff00 (ok)

    navy => 0x000080 (ok)

    blue => 0x0000ff (ok)

    teal => 0x008080 (ok)

    aqua => 0x00ffff (ok)

    #rgb => 0xrrggbb (ok)

    #rrggbb => 0xrrggbb (ok)

    rgb(rrr, ggg, bbb) => 0xrrggbb (TO DO)

    If viewport-fill is not defined it will be NO_COLOR

    If after the inheritance process fill is not defined it will be 0x000000

    If after the inheritance process stroke is not defined it will be NO_COLOR

    viewport-fill-opacity

    fill-opacity

    stroke-opacity

    NO DEFINED => NODEFINED_VALUE (ok)

    inherit => INHERIT_VALUE (ok)

    number between 0.0 and 1.0 => same value (ok)

    If viewport-fill-opacity is not defined it will be 1

    If after the inheritance process fill-opacity is not defined it will be 1

    If after the inheritance process stroke-opacity is not defined it will be 1

    stroke-width

    NO DEFINED => NODEFINED_VALUE (ok)

    inherit => INHERIT_VALUE (ok)

    number > 0.0 => same value (ok)

    If after the inheritance process stroke-width is not defined it will be 1

    transform

    NO DEFINED => (1 0 0 1 0 0) (ok)

    none => (1 0 0 1 0 0) (ok)

    matrix(a b c d e f) => (a b c d e f) (ok)

    translate(x) => (1 0 0 1 x 0) (ok)

    translate(x y) => (1 0 0 1 x y) (ok)

    rotate(ang) => (cos(ang) sin(ang) -sin(ang) cos(ang) 0 0) (ok)

    rotate(ang cx cy) => traslate(cx cy) * rotate(ang) * translate(-cx -cy) (ok)

    scale(sx) => (sx 0 0 sx 0 0) (ok)

    scale(sx sy) => (sx 0 0 sy 0 0) (ok)

    ref(svg) => no transform for this element (TO DO)

    Note that before a drawable element can be rasterized it is necesary to calculate the current transformation matrix multiplying all transformation matrix from his parents elements.

    points

    x1,y1 x2,y2 ... => same values (ok)