= Micro SVG Document Structure
:toc:

== 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 `style` attribute.
- Default attributes are implicit.

You can use
https://github.com/RazrFalcon/resvg/tree/master/usvg[usvg]
to convert a random SVG into a SVG Micro almost losslessly.

== Elements

[[svg-element]]

=== 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-element,defs>>
* <<g-element,g>>
* <<path-element,path>>
* <<image-element,image>>

*Attributes:*

* `width` = <<positive-number-type,<positive-number> >> +
  The width of the rectangular region into which the referenced document is placed.
* `height` = <<positive-number-type,<positive-number> >> +
  The height of the rectangular region into which the referenced document is placed.
* `viewBox` = <<viewBox-type,<viewBox> >>
* `preserveAspectRatio` = <<preserveAspectRatio-type,<preserveAspectRatio> >>?

[[defs-element]]

=== The `defs` element

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

*Children:*

* <<linearGradient-element,linearGradient>>
* <<radialGradient-element,radialGradient>>
* <<clipPath-element,clipPath>>
* <<mask-element,mask>>
* <<pattern-element,pattern>>
* <<filter-element,filter>>

*Attributes:*

* none

[[linearGradient-element]]

=== The `linearGradient` element

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

*Children:*

* At least two <<stop-element,stop>>

*Attributes:*

* `id` = <<string-type,<string> >> +
  The element ID. Always set. Guarantee to be unique.
* `x1` = <<number-type,<number> >>
* `y1` = <<number-type,<number> >>
* `x2` = <<number-type,<number> >>
* `y2` = <<number-type,<number> >>
* `gradientUnits` = `userSpaceOnUse`?
* `spreadMethod` = `reflect | repeat`?
* `gradientTransform` = <<transform-type,<transform> >>?

[[radialGradient-element]]

=== The `radialGradient` element

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

*Children:*

* At least two <<stop-element,stop>>

*Attributes:*

* `id` = <<string-type,<string> >> +
  The element ID. Always set. Guarantee to be unique.
* `cx` = <<number-type,<number> >>
* `cy` = <<number-type,<number> >>
* `fx` = <<number-type,<number> >> +
  Guarantee to be the circle defined by `cx`, `cy` and `r`.
* `fy` = <<number-type,<number> >> +
  Guarantee to be inside the circle defined by `cx`, `cy` and `r`.
* `r` = <<positive-number-type,<positive-number> >>
* `gradientUnits` = `userSpaceOnUse`?
* `spreadMethod` = `reflect | repeat`?
* `gradientTransform` = <<transform-type,<transform> >>?

[[stop-element]]

=== The `stop` element

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

*Children:*

* none

*Attributes:*

* `offset` = <<offset-type,<offset> >>
* `stop-color` = <<color-type,<color> >>
* `stop-opacity` = <<opacity-type,<opacity> >>? +
  Default: 1

[[pattern-element]]

=== 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-type,<string> >> +
  The element ID. Always set. Guarantee to be unique.
* `x` = <<number-type,<number> >>
* `y` = <<number-type,<number> >>
* `width` = <<positive-number-type,<positive-number> >>
* `height` = <<positive-number-type,<positive-number> >>
* `viewBox` = <<viewBox-type,<viewBox> >>?
* `preserveAspectRatio` = <<preserveAspectRatio-type,<preserveAspectRatio> >>?
* `patternUnits` = `userSpaceOnUse`? +
  Default: objectBoundingBox
* `patternContentUnits` = `objectBoundingBox`? +
  Default: userSpaceOnUse
* `patternTransform` = <<transform-type,<transform> >>?

[[clipPath-element]]

=== The `clipPath` element

*Children:*

* `path`

*Attributes:*

* `id` = <<string-type,<string> >> +
  The element ID. Always set. Guarantee to be unique.
* `clip-path` = <<func-iri-type,<FuncIRI> >>? +
  An optional reference to a supplemental `clipPath`. +
  Default: none
* `clipPathUnits` = `objectBoundingBox`? +
  Default: userSpaceOnUse
* `transform` = <<transform-type,<transform> >>?

[[mask-element]]

=== The `mask` element

*Children:*

* `g`
* `path`
* `image`

*Attributes:*

* `id` = <<string-type,<string> >> +
  The element ID. Always set. Guarantee to be unique.
* `mask` = <<func-iri-type,<FuncIRI> >>? +
  An optional reference to a supplemental `mask`. +
  Default: none
* `x` = <<number-type,<number> >>
* `y` = <<number-type,<number> >>
* `width` = <<positive-number-type,<positive-number> >>
* `height` = <<positive-number-type,<positive-number> >>
* `maskUnits` = `userSpaceOnUse`? +
  Default: objectBoundingBox
* `maskContentUnits` = `objectBoundingBox`? +
  Default: userSpaceOnUse

[[filter-element]]

=== The `filter` element

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

*Children:*

* <<Filter primitives>>

*Attributes:*

* `id` = <<string-type,<string> >> +
  The element ID. Always set. Guarantee to be unique.
* `x` = <<number-type,<number> >>
* `y` = <<number-type,<number> >>
* `width` = <<positive-number-type,<positive-number> >>
* `height` = <<positive-number-type,<positive-number> >>
* `filterUnits` = `userSpaceOnUse`? +
  Default: objectBoundingBox
* `primitiveUnits` = `objectBoundingBox`? +
  Default: userSpaceOnUse

[[g-element]]

=== 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-element,g>>
* <<path-element,path>>
* <<image-element,image>>

*Attributes:*

* `id` = <<string-type,<string> >>? +
  An optional, but never empty, element ID.
* `opacity` = <<opacity-type,<opacity> >>?
* `clip-path` = <<func-iri-type,<FuncIRI> >>? +
  Cannot be set to `none`.
* `mask` = <<func-iri-type,<FuncIRI> >>? +
  Cannot be set to `none`.
* `filter` = <<func-iri-type,<FuncIRI> >>? +
  Cannot be set to `none`.
* `transform` = <<transform-type,<transform> >>?

[[path-element]]

=== The `path` element

*Children:*

* none

*Attributes:*

* `id` = <<string-type,<string> >>? +
  An optional, but never empty, element ID.
* `d` = <<path-data-type,<path-data> >> +
* `fill` = `none` | <<color-type,<color> >> | <<func-iri-type,<FuncIRI> >>? +
  If not set, than all fill-* attributes will not be set too. +
  Default: black
* `fill-opacity` = <<opacity-type,<opacity> >>? +
  Default: 1
* `fill-rule` = `evenodd`? +
  Default: nonzero
* `stroke` = <<color-type,<color> >> | <<func-iri-type,<FuncIRI> >>? +
  If not set, than all stroke-* attributes will not be set too. +
  Default: none
* `stroke-width` = <<positive-number-type,<positive-number> >>? +
  Default: 1
* `stroke-linecap` = `round | square`? +
  Default: butt
* `stroke-linejoin` = `round | bevel`? +
  Default: miter
* `stroke-miterlimit` = <<positive-number-type,<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-type,<number> >>?
* `stroke-opacity` = <<opacity-type,<opacity> >>? +
  Default: 1
* `clip-rule` = `evenodd`? +
  Will be set only inside the <<clipPath-element,clipPath>>, instead of `fill-rule`.
* `clip-path` = <<func-iri-type,<FuncIRI> >>? +
  Available only inside the <<clipPath-element,clipPath>>.
* `shape-rendering` = `optimizeSpeed | crispEdges`? +
  Default: geometricPrecision
* `visibility` = `hidden | collapse`? +
  Default: visible
* `transform` = <<transform-type,<transform> >>?

[[image-element]]

=== The `image` element

*Children:*

* none

*Attributes:*

* `id` = <<string-type,<string> >>? +
  An optional, but never empty, element ID.
* `xlink:href` = <<iri-type,<IRI> >> +
  The IRI contains a file path or base64 encoded image.
* `x` = <<number-type,<number> >>
* `y` = <<number-type,<number> >>
* `width` = <<positive-number-type,<positive-number> >>
* `height` = <<positive-number-type,<positive-number> >>
* `preserveAspectRatio` = <<preserveAspectRatio-type,<preserveAspectRatio> >>?
* `image-rendering` = `optimizeSpeed`? +
  Default: optimizeQuality
* `visibility` = `hidden | collapse`? +
  Default: visible
* `transform` = <<transform-type,<transform> >>?

== Filter primitives

=== Filter primitive attributes

The attributes below are the same for all filter primitives.

* `color-interpolation-filters` = `sRGB`? +
  Default: linearRGB
* `x` = <<number-type,<number> >>?
* `y` = <<number-type,<number> >>?
* `width` = <<number-type,<number> >>?
* `height` = <<number-type,<number> >>?
* `result` = <<string-type,<string> >>

The `x`, `y`, `width` and `height` attributes can be omited.
SVG has a pretty complex
https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveSubRegion[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-type,<filter-input> >>
* `in2` = <<filter-input-type,<filter-input> >>
* `mode` = `normal | multiply | screen | darken | lighten`
* <<Filter primitive attributes>>

=== Filter primitive `feColorMatrix`

*Attributes:*

* `in` = <<filter-input-type,<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-type,<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-type,<number> >>? +
  Present only when `type=linear`.
* `intercept` = <<number-type,<number> >>? +
  Present only when `type=linear`.
* `amplitude` = <<number-type,<number> >>? +
  Present only when `type=gamma`.
* `exponent` = <<number-type,<number> >>? +
  Present only when `type=gamma`.
* `offset` = <<number-type,<number> >>? +
  Present only when `type=gamma`.

=== Filter primitive `feComposite`

*Attributes:*

* `in` = <<filter-input-type,<filter-input> >>
* `in2` = <<filter-input-type,<filter-input> >>
* `operator` = `over | in | out | atop | xor | arithmetic`
* `k1` = <<compositing-coefficient-type,<compositing-coefficient> >>? +
  Present only when `operator=arithmetic`.
* `k2` = <<compositing-coefficient-type,<compositing-coefficient> >>? +
  Present only when `operator=arithmetic`.
* `k3` = <<compositing-coefficient-type,<compositing-coefficient> >>? +
  Present only when `operator=arithmetic`.
* `k4` = <<compositing-coefficient-type,<compositing-coefficient> >>? +
  Present only when `operator=arithmetic`.
* <<Filter primitive attributes>>

=== Filter primitive `feFlood`

*Attributes:*

* `flood-color` = <<color-type,<color> >>
* `flood-opacity` = <<opacity-type,<opacity> >>
* <<Filter primitive attributes>>

=== Filter primitive `feGaussianBlur`

*Attributes:*

* `in` = <<filter-input-type,<filter-input> >>
* `stdDeviation` = <<positive-number-type,<positive-number> >> " " <<positive-number-type,<positive-number> >>
* <<Filter primitive attributes>>

=== Filter primitive `feImage`

*Attributes:*

* `preserveAspectRatio` = <<preserveAspectRatio-type,<preserveAspectRatio> >>
* `image-rendering` = `optimizeSpeed`? +
  Default: optimizeQuality
* `xlink:href` = <<iri-type,<IRI> >>? +
  The IRI contains a file path or base64 encoded image.
  Link to an element (like in `use`) is not supported. +
  Unlike the `image` element, `feImage` can be without the `href` attribute.
  In this case the filter primitive is an empty canvas.
* <<Filter primitive attributes>>

=== Filter primitive `feMerge`

*Children:*

* `feMergeNode`

*Attributes:*

* <<Filter primitive attributes>>

*`feMergeNode` attributes:*

* `in` = <<filter-input-type,<filter-input> >>

=== Filter primitive `feOffset`

*Attributes:*

* `in` = <<filter-input-type,<filter-input> >>
* `dx` = <<number-type,<number> >>
* `dy` = <<number-type,<number> >>
* <<Filter primitive attributes>>

=== Filter primitive `feTile`

*Attributes:*

* `in` = <<filter-input-type,<filter-input> >>
* <<Filter primitive attributes>>

== Data types

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

[[string-type]]

*<string>* - A Unicode string.


[[number-type]]

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


[[positive-number-type]]

*<positive-number>* - A positive, non-zero real <<number-type,number>>. +
`positive-number ::= [0-9]* "." [0-9]+`


[[opacity-type]]

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


[[offset-type]]

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


[[compositing-coefficient-type]]

*<compositing-coefficient>* - A real <<number-type,number>> in a 0..1 range. +
`compositing-coefficient ::= positive-number`


[[color-type]]

*<color>* - A hex-encoded RGB color.
```
color    ::= "#" hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit
hexdigit ::= [0-9a-f]
```


[[iri-type]]

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


[[func-iri-type]]

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


[[filter-input-type]]

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

```
filter-input ::= SourceGraphic | SourceAlpha | BackgroundImage
                 | BackgroundAlpha | FillPaint | StrokePaint
                 | <string>
```


[[viewBox-type]]

*<viewBox>* - Defines an element viewBox.
`viewBox ::= <number> " " <number> " " <positive-number> " " <positive-number>`


[[preserveAspectRatio-type]]

*<preserveAspectRatio>* - A scaling method definition.
Works exactly the same
https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute[as described]
in the SVG spec.


[[transform-type]]

*<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-type]]

*<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"
```
