# Micro SVG Document Structure

## Intro

SVG Micro represents a strip down SVG Full 1.1 subset.

Here is the main differences between SVG Full and SVG Micro.

- No XML DTD.

- No CSS.

- `use`, `marker` and nested `svg` will be resolved.

- Simplified path notation. Only absolute MoveTo, LineTo, CurveTo and ClosePath segments are allowed.

- No inheritable attributes.

- No `xlink:href`, except the `image` element.

- No recursive references.

- Only valid elements and attributes.

- No unused elements.

- No redundant groups.

- No units.

- No `objectBoundingBox` units.

- No `viewBox` and `preserveAspectRatio` attributes.

- No `style` attribute, except for `mix-blend-mode` and `isolation`

- Default attributes are implicit.

You can use usvg to convert a random SVG into a SVG Micro almost losslessly.

## Elements

### The `svg` element

The `svg` element is the root element of the document. It’s defined only once and can’t be nested, unlike by the SVG spec.

Children:

- defs

- g

- path

- image

Attributes:

- `width` = <positive-number>
  The width of the rectangular region into which the referenced document is placed.

- `height` = <positive-number>
  The height of the rectangular region into which the referenced document is placed.

### The `defs` element

Always present. Always the first `svg` child. Can be empty.

Children:

- linearGradient

- radialGradient

- clipPath

- mask

- pattern

- filter

- g

- path

- image

Attributes:

- none

### The `linearGradient` element

Doesn’t have a `xlink:href` attribute because all attributes and `stop` children will be resolved.

Children:

- At least two stop

Attributes:

- `id` = <string>
  The element ID. Always set. Guarantee to be unique.

- `x1` = <number>

- `y1` = <number>

- `x2` = <number>

- `y2` = <number>

- `gradientUnits` = `userSpaceOnUse`?

- `spreadMethod` = `reflect | repeat`?

- `gradientTransform` = <transform> ?

### The `radialGradient` element

Doesn’t have a `xlink:href` attribute because all attributes and `stop` children will be resolved.

Children:

- At least two stop

Attributes:

- `id` = <string>
  The element ID. Always set. Guarantee to be unique.

- `cx` = <number>

- `cy` = <number>

- `fx` = <number>
  Guarantee to be the circle defined by `cx`, `cy` and `r`.

- `fy` = <number>
  Guarantee to be inside the circle defined by `cx`, `cy` and `r`.

- `r` = <positive-number>

- `gradientUnits` = `userSpaceOnUse`

- `spreadMethod` = `reflect | repeat`?

- `gradientTransform` = <transform> ?

### The `stop` element

Gradient’s `stop` children will always have unique, ordered `offset` values in the 0..1 range.

Children:

- none

Attributes:

- `offset` = <offset>

- `stop-color` = <color>

- `stop-opacity` = <opacity> ?
  Default: 1

### The `pattern` element

Doesn’t have a `xlink:href` attribute because all attributes and children will be resolved.

Children:

- `g`

- `path`

- `image`

Attributes:

- `id` = <string>
  The element ID. Always set. Guarantee to be unique.

- `x` = <number>

- `y` = <number>

- `width` = <positive-number>

- `height` = <positive-number>

- `patternUnits` = `userSpaceOnUse`

- `patternTransform` = <transform> ?

### The `clipPath` element

Children:

- `path`

Attributes:

- `id` = <string>
  The element ID. Always set. Guarantee to be unique.

- `clip-path` = <FuncIRI> ?
  An optional reference to a supplemental `clipPath`.
  Default: none

- `transform` = <transform> ?

### The `mask` element

Children:

- `g`

- `path`

- `image`

Attributes:

- `id` = <string>
  The element ID. Always set. Guarantee to be unique.

- `mask` = <FuncIRI> ?
  An optional reference to a supplemental `mask`.
  Default: none

- `x` = <number>

- `y` = <number>

- `width` = <positive-number>

- `height` = <positive-number>

- `mask-type` = `alpha`?
  Default: luminance

- `maskUnits` = `userSpaceOnUse`

### The `filter` element

Doesn’t have a `xlink:href` attribute because all attributes and children will be resolved.

Children:

- Filter primitives

Attributes:

- `id` = <string>
  The element ID. Always set. Guarantee to be unique.

- `x` = <number>

- `y` = <number>

- `width` = <positive-number>

- `height` = <positive-number>

- `filterUnits` = `userSpaceOnUse`

### The `g` element

The group element indicates that a new canvas should be created. All group’s children elements will be rendered on it and then merged into the parent canvas.

Since it’s pretty expensive, especially memory wise, usvg will remove as many groups as possible. And all the remaining one will indicate that a new canvas must be created.

A group can have no children when it has a `filter` attribute.

A group will have at least one of the attributes present.

Children:

- g

- path

- image

Attributes:

- `id` = <string> ?
  An optional, but never empty, element ID.

- `opacity` = <opacity> ?

- `clip-path` = <FuncIRI> ?
  Cannot be set to `none`.

- `mask` = <FuncIRI> ?
  Cannot be set to `none`.

- `filter` = <FuncIRI> +
  Cannot be set to `none`.

- `transform` = <transform> ?

- `style` = <string> ?
  This is the only place where the `style` attribute is used. For reasons unknown, `mix-blend-mode` and `isolation` properties must not be set as attributes, only as part of the `style` attribute.
  The set attribute will look like `mix-blend-mode:screen;isolation:isolate`. Both properties are always set.
  The attribute is not present only in case of `mix-blend-mode:norma;isolation:auto`

### The `path` element

Children:

- none

Attributes:

- `id` = <string> ?
  An optional, but never empty, element ID.

- `d` = <path-data>

- `fill` = `none` | <color> | <FuncIRI>
  If set to `none` than all fill-* attributes will not be set too.
  Default: black

- `fill-opacity` = <opacity> ?
  Default: 1

- `fill-rule` = `evenodd`?
  Default: nonzero

- `stroke` = `none` | <color> | <FuncIRI>
  If set to `none` than all stroke-* attributes will not be set too.
  Default: none

- `stroke-width` = <positive-number> ?
  Default: 1

- `stroke-linecap` = `round | square`?
  Default: butt

- `stroke-linejoin` = `round | bevel`?
  Default: miter

- `stroke-miterlimit` = <positive-number> ?
  Guarantee to be > 1.
  Default: 4

- `stroke-dasharray` = `<list-of-numbers>`?
  Guarantee to have even amount of numbers.
  Default: none

- `stroke-dashoffset` = <number> ?

- `stroke-opacity` = <opacity> ?
  Default: 1

- `paint-order` = `normal | stroke`?
  Default: `normal`
  Only `stroke` will be written.

- `clip-rule` = `evenodd`?
  Will be set only inside the clipPath, instead of `fill-rule`.

- `clip-path` = <FuncIRI> ?
  Available only inside the clipPath.

- `shape-rendering` = `optimizeSpeed | crispEdges`?
  Default: geometricPrecision

- `visibility` = `hidden`?
  Default: visible

- `transform` = <transform> ?
  Can only be set on paths inside of `clipPath`.

### The `image` element

Children:

- none

Attributes:

- `id` = <string> ?
  An optional, but never empty, element ID.

- `xlink:href` = <IRI>
  The IRI contains a base64 encoded image.

- `width` = <positive-number>

- `height` = <positive-number>

- `image-rendering` = `optimizeSpeed`?
  Default: optimizeQuality

- `visibility` = `hidden`?
  Default: visible

## Filter primitives

### Filter primitive attributes

The attributes below are the same for all filter primitives.

- `color-interpolation-filters` = `sRGB`?
  Default: linearRGB

- `x` = <number> ?

- `y` = <number> ?

- `width` = <number> ?

- `height` = <number> ?

- `result` = <string>

The `x`, `y`, `width` and `height` attributes can be omitted. SVG has a pretty complex rules of resolving them and I don’t fully understand them yet. Neither do others, because they are pretty poorly implemented.

### Filter primitive `feBlend`

Attributes:

- `in` = <filter-input>

- `in2` = <filter-input>

- `mode` = `normal | multiply | screen | overlay | darken | lighten | color-dodge |color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity`

- Filter primitive attributes

### Filter primitive `feColorMatrix`

Attributes:

- `in` = <filter-input>

- `type` = `matrix | saturate | hueRotate | luminanceToAlpha`

- `values` = `<list-of-numbers>`?

  - For `type=matrix`, contains 20 numbers.

  - For `type=saturate`, contains a single number in a 0..1 range.

  - For `type=hueRotate`, contains a single number.

  - Not present for `type=luminanceToAlpha`.

- Filter primitive attributes

### Filter primitive `feComponentTransfer`

Children:

- `feFuncR`

- `feFuncG`

- `feFuncB`

- `feFuncA`

The all four will always be present.

Attributes:

- `in` = <filter-input>

- Filter primitive attributes

`feFunc(R|G|B|A)` attributes:

- `type` = `identity | table | discrete | linear | gamma`

- `tableValues` = `<list-of-numbers>`?
  Present only when `type=table | discrete`. Can be empty.

- `slope` = <number> ?
  Present only when `type=linear`.

- `intercept` = <number> ?
  Present only when `type=linear`.

- `amplitude` = <number> ?
  Present only when `type=gamma`.

- `exponent` = <number> ?
  Present only when `type=gamma`.

- `offset` = <number> ?
  Present only when `type=gamma`.

### Filter primitive `feComposite`

Attributes:

- `in` = <filter-input>

- `in2` = <filter-input>

- `operator` = `over | in | out | atop | xor | arithmetic`

- `k1` = <number> ?
  Present only when `operator=arithmetic`.

- `k2` = <number> ?
  Present only when `operator=arithmetic`.

- `k3` = <number> ?
  Present only when `operator=arithmetic`.

- `k4` = <number> ?
  Present only when `operator=arithmetic`.

- Filter primitive attributes

### Filter primitive `feConvolveMatrix`

Attributes:

- `in` = <filter-input>

- `order` = <positive-integer> " " <positive-integer>
  Both numbers are never 0.

- `kernelMatrix` = `<list-of-numbers>`

- `divisor` = <number>
  Never 0.

- `bias` = <number>

- `targetX` = <positive-integer>
  Always smaller than the number of columns in the matrix.

- `targetY` = <positive-integer>
  Always smaller than the number of rows in the matrix.

- `edgeMode` = `none | duplicate | wrap`

- `preserveAlpha` = `true | false`

- Filter primitive attributes

### Filter primitive `feDiffuseLighting`

Children:

Only one of:

- `feDistantLight`

- `fePointLight`

- `feSpotLight`

Attributes:

- `in` = <filter-input>

- `surfaceScale` = <number>

- `diffuseConstant` = <number>

- `lighting-color` = <color>

- Filter primitive attributes

`feDistantLight` attributes:

- `azimuth` = <number>

- `elevation` = <number>

`fePointLight` attributes:

- `x` = <number>

- `y` = <number>

- `z` = <number>

`feSpotLight` attributes:

- `x` = <number>

- `y` = <number>

- `z` = <number>

- `pointsAtX` = <number>

- `pointsAtY` = <number>

- `pointsAtZ` = <number>

- `specularExponent` = <positive-number>

- `limitingConeAngle` = <number> ?

### Filter primitive `feDisplacementMap`

Attributes:

- `in` = <filter-input>

- `in2` = <filter-input>

- `scale` = <number>

- `xChannelSelector` = `R | G | B | A`

- `yChannelSelector` = `R | G | B | A`

- Filter primitive attributes

### Filter primitive `feDropShadow`

Attributes:

- `in` = <filter-input>

- `stdDeviation` = <positive-number> " " <positive-number>

- `dx` = <number>

- `dy` = <number>

- `flood-color` = <color>

- `flood-opacity` = <opacity>

- Filter primitive attributes

### Filter primitive `feFlood`

Attributes:

- `flood-color` = <color>

- `flood-opacity` = <opacity>

- Filter primitive attributes

### Filter primitive `feGaussianBlur`

Attributes:

- `in` = <filter-input>

- `stdDeviation` = <positive-number> " " <positive-number>

- Filter primitive attributes

### Filter primitive `feImage`

Attributes:

- `xlink:href` = <IRI>
  The IRI contains a link to an element (like `use`). base64 encoded is not allowed and will be represented as a link to an `image`.

- Filter primitive attributes

### Filter primitive `feMerge`

Children:

- `feMergeNode`

Attributes:

- Filter primitive attributes

`feMergeNode` attributes:

- `in` = <filter-input>

### Filter primitive `feMorphology`

Attributes:

- `in` = <filter-input>

- `operator` = `erode | dilate`

- `radius` = <positive-number> " " <positive-number>

- Filter primitive attributes

### Filter primitive `feOffset`

Attributes:

- `in` = <filter-input>

- `dx` = <number>

- `dy` = <number>

- Filter primitive attributes

### Filter primitive `feSpecularLighting`

Children:

Only one of:

- `feDistantLight`

- `fePointLight`

- `feSpotLight`

Attributes:

- `in` = <filter-input>

- `surfaceScale` = <number>

- `specularConstant` = <number>

- `specularExponent` = <number>
  Number in a 1..128 range.

- `lighting-color` = <color>

- Filter primitive attributes

`feDistantLight` attributes:

- `azimuth` = <number>

- `elevation` = <number>

`fePointLight` attributes:

- `x` = <number>

- `y` = <number>

- `z` = <number>

`feSpotLight` attributes:

- `x` = <number>

- `y` = <number>

- `z` = <number>

- `pointsAtX` = <number>

- `pointsAtY` = <number>

- `pointsAtZ` = <number>

- `specularExponent` = <positive-number>

- `limitingConeAngle` = <number> ?

### Filter primitive `feTile`

Attributes:

- `in` = <filter-input>

- Filter primitive attributes

### Filter primitive `feTurbulence`

Attributes:

- `baseFrequency` = <positive-number> " " <positive-number>

- `numOctaves` = <positive-integer>

- `seed` = <integer>

- `stitchTiles` = `stitch | noStitch`

- `type` = `fractalNoise | turbulence`

- Filter primitive attributes

## Data types

If an attribute has the `?` symbol after the type that’s mean that that this attribute is optional.

<string> - A Unicode (UTF-8) string.

<number> - A real number.
`number ::= [-]? [0-9]+ "." [0-9]+`

<positive-number> - A positive real number.
`positive-number ::= [0-9]+ "." [0-9]+`

<integer> - An integer.
`integer ::= [-]? [0-9]+`

<positive-integer> - A positive integer.
`positive-integer ::= [0-9]+`

<opacity> - A real number in a 0..1 range.
`opacity ::= positive-number`

<offset> - A real number in a 0..1 range.
`offset ::= positive-number`

<color> - A hex-encoded RGB color.

    color    ::= "#" hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit
    hexdigit ::= [0-9a-f]

<IRI> - An Internationalized Resource Identifier. Always a valid, local reference.
`IRI ::= string`

<FuncIRI> - Functional notation for an IRI. Always a valid, local reference.
`FuncIRI ::= url( <IRI> )`

<filter-input> - A filter source. A reference to a result guarantee to be valid.

    filter-input ::= SourceGraphic | SourceAlpha | <string>

We do not support `FillPaint`, `StrokePaint`, `BackgroundImage` and `BackgroundAlpha`.

<transform> - A transformation matrix. Always a `matrix` and not `translate`, `scale`, etc. Numbers are space-separated.
`transform ::= matrix( <number> " " <number> " " <number> " " <number> " " <number> " " <number> )`

<path-data> - A path data.

- Contains only absolute MoveTo, LineTo, CurveTo and ClosePath segments.

- All segments are explicit.

- The first segment is guarantee to be MoveTo.

- Segments, commands and coordinates are separated only by space.

- Path and all subpaths are guarantee to have at least two segments.

Grammar:

    svg-path:
        moveto-drawto-command-groups
    moveto-drawto-command-groups:
        moveto-drawto-command-group
        | moveto-drawto-command-group " " moveto-drawto-command-groups
    moveto-drawto-command-group:
        moveto " " drawto-commands
    drawto-commands:
        drawto-command
        | drawto-command " " drawto-commands
    drawto-command:
        closepath
        | lineto
        | curveto
    moveto:
        "M " coordinate-pair
    lineto:
        "L " coordinate-pair
    curveto:
        "C " coordinate-pair " " coordinate-pair " " coordinate-pair
    closepath:
        "Z"
    coordinate-pair:
        coordinate " " coordinate
    coordinate:
        sign? digit-sequence "." digit-sequence
    sign:
        "-"
    digit-sequence:
        digit
        | digit digit-sequence
    digit:
        "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

Basically, a path looks like this: `M 10.5 20 L 30 40`. Commands and numbers are separated by a space. Numbers with an exponent are not allowed. Trimmed numbers like `-.5` are not allowed.